1 /*
2 * Copyright 2020 Rockchip Electronics Co. LTD
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17 #define MODULE_TAG "iep2_test"
18
19 #include <string.h>
20
21 #include "mpp_mem.h"
22 #include "mpp_time.h"
23 #include "mpp_debug.h"
24 #include "mpp_common.h"
25 #include "mpp_thread.h"
26 #include "mpp_buffer.h"
27
28 #include "iep2_api.h"
29 #include "utils.h"
30 //#include "iniparser.h"
31
32 #define MAX_URL_LEN (100)
33
34 typedef struct iep2_test_cfg_t {
35 RK_S32 w;
36 RK_S32 h;
37 RK_S32 src_fmt;
38 RK_S32 src_swa;
39
40 RK_S32 dst_fmt;
41 RK_S32 dst_swa;
42
43 char src_url[MAX_URL_LEN];
44 char dst_url[MAX_URL_LEN];
45 char slt_url[MAX_URL_LEN];
46
47 FILE *fp_src;
48 FILE *fp_dst;
49 FILE *fp_slt;
50 RK_U32 field_order;
51 } iep2_test_cfg;
52
53 static OptionInfo iep2_test_cmd[] = {
54 {"w", "width", "input image width"},
55 {"h", "height", "input image height"},
56 {"c", "format", "input image format in ASCII string"},
57 {"i", "src_file", "input image file name"},
58 {"C", "dst_format", "output image format in ASCII string"},
59 {"o", "dst_file", "output image file name"},
60 {"v", "slt_file", "slt verify data file"}
61 };
62
iep2_test_help()63 static void iep2_test_help()
64 {
65 mpp_log("usage: iep2_test [options]\n");
66 mpp_log("*******************************\n");
67 show_options(iep2_test_cmd);
68 mpp_log("*******************************\n");
69 mpp_log("supported ASCII format strings:\n");
70 mpp_log("1 - yuv422sp\n");
71 mpp_log("2 - yuv422p [just for source format]\n");
72 mpp_log("3 - yuv420sp\n");
73 mpp_log("4 - yuv420p [just for source format]\n");
74 mpp_log("5 - yvu422sp\n");
75 mpp_log("6 - yvu420sp\n");
76 mpp_log("************ sample ***********\n");
77 mpp_log("iep2_test -w 720 -h 480 -c yuv420p -i input.yuv -C yuv420p -o output.yuv\n");
78 }
79
str_to_iep2_fmt(const char * str)80 static RK_S32 str_to_iep2_fmt(const char *str)
81 {
82 RK_S32 fmt = -1;
83
84 mpp_log("format %s\n", str);
85
86 if (!strcmp(str, "yuv422sp") ||
87 !strcmp(str, "yuv422p") ||
88 !strcmp(str, "yvu422sp"))
89 fmt = IEP2_FMT_YUV422;
90 else if (!strcmp(str, "yuv420p") ||
91 !strcmp(str, "yuv420sp") ||
92 !strcmp(str, "yvu420sp"))
93 fmt = IEP2_FMT_YUV420;
94 else
95 mpp_err("invalid format %s\n", str);
96
97 return fmt;
98 }
99
str_to_iep2_swa(const char * str)100 static RK_S32 str_to_iep2_swa(const char *str)
101 {
102 RK_S32 swa = -1;
103
104 if (!strcmp(str, "yuv422p") ||
105 !strcmp(str, "yuv420p"))
106 swa = IEP2_YUV_SWAP_P;
107 else if (!strcmp(str, "yvu422sp") ||
108 !strcmp(str, "yvu420sp"))
109 swa = IEP2_YUV_SWAP_SP_VU;
110 else if (!strcmp(str, "yuv422sp") ||
111 !strcmp(str, "yuv420sp"))
112 swa = IEP2_YUV_SWAP_SP_UV;
113 else
114 mpp_err("invalid format %s\n", str);
115
116 return swa;
117 }
118
check_input_cmd(iep2_test_cfg * cfg)119 static MPP_RET check_input_cmd(iep2_test_cfg *cfg)
120 {
121 MPP_RET ret = MPP_OK;
122
123 if (cfg->w < 16 || cfg->w > 1920) {
124 mpp_err("invalid width %d\n", cfg->w);
125 ret = MPP_NOK;
126 }
127
128 if (cfg->h < 4 || cfg->h > 1088) {
129 mpp_err("invalid height %d\n", cfg->h);
130 ret = MPP_NOK;
131 }
132
133 mpp_log("src fmt %d, %d dst fmt %d, %d\n",
134 cfg->src_fmt, cfg->src_swa,
135 cfg->dst_fmt, cfg->dst_swa);
136
137 if (cfg->src_fmt < IEP2_FMT_YUV422 ||
138 cfg->src_fmt > IEP2_FMT_YUV420 ||
139 cfg->src_swa < IEP2_YUV_SWAP_SP_UV ||
140 cfg->src_swa > IEP2_YUV_SWAP_P) {
141 mpp_err("invalid input format\n");
142 ret = MPP_NOK;
143 }
144
145 if (cfg->fp_src == NULL) {
146 mpp_err("failed to open input file %s\n", cfg->src_url);
147 ret = MPP_NOK;
148 }
149
150 if (cfg->dst_fmt < IEP2_FMT_YUV422 ||
151 cfg->dst_fmt > IEP2_FMT_YUV420 ||
152 cfg->dst_swa < IEP2_YUV_SWAP_SP_UV ||
153 cfg->dst_swa > IEP2_YUV_SWAP_SP_VU) {
154 mpp_err("invalid output format\n");
155 ret = MPP_NOK;
156 }
157
158 return ret;
159 }
160
get_frm_size(RK_S32 fmt,int w,int h)161 static inline size_t get_frm_size(RK_S32 fmt, int w, int h)
162 {
163 switch (fmt) {
164 case IEP2_FMT_YUV422:
165 return w * h * 2;
166 case IEP2_FMT_YUV420:
167 return w * h * 3 / 2;
168 default:
169 abort();
170 return 0;
171 }
172 }
173
iep2_test_set_img(iep_com_ctx * ctx,int w,int h,IepImg * img,RK_S32 fd,IepCmd cmd)174 static void iep2_test_set_img(iep_com_ctx *ctx, int w, int h,
175 IepImg *img, RK_S32 fd, IepCmd cmd)
176 {
177 RK_S32 y_size = w * h;
178 img->mem_addr = fd;
179 img->uv_addr = fd + (y_size << 10);
180 switch (img->format) {
181 case IEP2_FMT_YUV422:
182 img->v_addr = fd + ((y_size + y_size / 2) << 10);
183 break;
184 case IEP2_FMT_YUV420:
185 img->v_addr = fd + ((y_size + y_size / 4) << 10);
186 break;
187 default:
188 break;
189 }
190
191 MPP_RET ret = ctx->ops->control(ctx->priv, cmd, img);
192 if (ret)
193 mpp_log_f("control %08x failed %d\n", cmd, ret);
194 }
195
iep2_test(iep2_test_cfg * cfg)196 void iep2_test(iep2_test_cfg *cfg)
197 {
198 iep_com_ctx* iep2 = rockchip_iep2_api_alloc_ctx();
199 size_t srcfrmsize = get_frm_size(cfg->src_fmt, cfg->w, cfg->h);
200 size_t dstfrmsize = get_frm_size(cfg->dst_fmt, cfg->w, cfg->h);
201 MppBuffer srcbuf[3];
202 MppBuffer dstbuf[2];
203 RK_U8 *psrc[3];
204 RK_U8 *pdst[2];
205 RK_S32 fdsrc[3];
206 RK_S32 fddst[2];
207 int prev, curr, next;
208 struct iep2_api_params params;
209 RK_U32 i;
210 RK_S32 field_order = IEP2_FIELD_ORDER_TFF;
211 RK_S32 out_order = field_order == IEP2_FIELD_ORDER_TFF ? 0 : 1;
212 DataCrc checkcrc;
213 struct iep2_api_info dei_info;
214
215 // NOTISE, used IepImg structure for version compatibility consideration,
216 // only addresses in this structure are useful in iep2
217 IepImg imgsrc[3];
218 IepImg imgdst[2];
219
220 mpp_assert(iep2);
221 MppBufferGroup memGroup;
222 MPP_RET ret = mpp_buffer_group_get_internal(&memGroup, MPP_BUFFER_TYPE_DRM);
223 if (MPP_OK != ret) {
224 mpp_err("memGroup mpp_buffer_group_get failed\n");
225 mpp_assert(0);
226 }
227
228 memset(&checkcrc, 0, sizeof(checkcrc));
229 checkcrc.sum = mpp_malloc(RK_ULONG, 512);
230
231 mpp_buffer_get(memGroup, &srcbuf[0], srcfrmsize);
232 mpp_buffer_get(memGroup, &srcbuf[1], srcfrmsize);
233 mpp_buffer_get(memGroup, &srcbuf[2], srcfrmsize);
234 mpp_buffer_get(memGroup, &dstbuf[0], dstfrmsize);
235 mpp_buffer_get(memGroup, &dstbuf[1], dstfrmsize);
236 mpp_assert(srcbuf[0] && srcbuf[1] && srcbuf[2] && dstbuf[0] && dstbuf[1]);
237
238 psrc[0] = mpp_buffer_get_ptr(srcbuf[0]);
239 psrc[1] = mpp_buffer_get_ptr(srcbuf[1]);
240 psrc[2] = mpp_buffer_get_ptr(srcbuf[2]);
241
242 pdst[0] = mpp_buffer_get_ptr(dstbuf[0]);
243 pdst[1] = mpp_buffer_get_ptr(dstbuf[1]);
244
245 fdsrc[0] = mpp_buffer_get_fd(srcbuf[0]);
246 fdsrc[1] = mpp_buffer_get_fd(srcbuf[1]);
247 fdsrc[2] = mpp_buffer_get_fd(srcbuf[2]);
248
249 fddst[0] = mpp_buffer_get_fd(dstbuf[0]);
250 fddst[1] = mpp_buffer_get_fd(dstbuf[1]);
251
252 iep2->ops->init(&iep2->priv);
253
254 if (srcfrmsize > fread(psrc[0], 1, srcfrmsize, cfg->fp_src)) {
255 mpp_log("source exhaused\n");
256 goto ret;
257 }
258
259 if (srcfrmsize > fread(psrc[1], 1, srcfrmsize, cfg->fp_src)) {
260 mpp_log("source exhaused\n");
261 goto ret;
262 }
263
264 curr = 1;
265
266 // set running mode.
267 /* if deinterlacing mode is one in the following list:
268 IEP2_DIL_MODE_I5O2,
269 IEP2_DIL_MODE_I5O1T,
270 IEP2_DIL_MODE_I5O1B,
271 IEP2_DIL_MODE_DECT
272 field order will auto detect by iep2 library.
273 so don't try to set field order during the playback.
274 */
275 params.ptype = IEP2_PARAM_TYPE_MODE;
276 params.param.mode.dil_mode = IEP2_DIL_MODE_I5O2;
277 params.param.mode.out_mode = IEP2_OUT_MODE_LINE;
278 params.param.mode.dil_order = cfg->field_order;
279
280 iep2->ops->control(iep2->priv, IEP_CMD_SET_DEI_CFG, ¶ms);
281
282 // set the image format.
283 params.ptype = IEP2_PARAM_TYPE_COM;
284 params.param.com.sfmt = cfg->src_fmt;
285 params.param.com.dfmt = cfg->dst_fmt;
286 params.param.com.sswap = cfg->src_swa;
287 params.param.com.dswap = cfg->dst_swa;
288 params.param.com.width = cfg->w;
289 params.param.com.height = cfg->h;
290 params.param.com.hor_stride = cfg->w;
291 iep2->ops->control(iep2->priv, IEP_CMD_SET_DEI_CFG, ¶ms);
292
293 for (i = 0; i < MPP_ARRAY_ELEMS(imgsrc); i++)
294 imgsrc[i].format = cfg->src_fmt;
295
296 for (i = 0; i < MPP_ARRAY_ELEMS(imgdst); i++)
297 imgdst[i].format = cfg->dst_fmt;
298
299 while (1) {
300 prev = (curr - 1) % 3;
301 curr = curr % 3;
302 next = (curr + 1) % 3;
303
304 if (srcfrmsize > fread(psrc[next], 1, srcfrmsize, cfg->fp_src)) {
305 mpp_log("source exhaused\n");
306 break;
307 }
308
309 // notice the order of the input frames.
310 iep2_test_set_img(iep2, cfg->w, cfg->h,
311 &imgsrc[curr], fdsrc[curr], IEP_CMD_SET_SRC);
312 iep2_test_set_img(iep2, cfg->w, cfg->h,
313 &imgsrc[next], fdsrc[next], IEP_CMD_SET_DEI_SRC1);
314 iep2_test_set_img(iep2, cfg->w, cfg->h,
315 &imgsrc[prev], fdsrc[prev], IEP_CMD_SET_DEI_SRC2);
316 iep2_test_set_img(iep2, cfg->w, cfg->h,
317 &imgdst[0], fddst[0], IEP_CMD_SET_DST);
318 iep2_test_set_img(iep2, cfg->w, cfg->h,
319 &imgdst[1], fddst[1], IEP_CMD_SET_DEI_DST1);
320
321 memset(pdst[0], 0, dstfrmsize);
322 memset(pdst[1], 0, dstfrmsize);
323 iep2->ops->control(iep2->priv, IEP_CMD_RUN_SYNC, &dei_info);
324
325 if (cfg->fp_slt) {
326 calc_data_crc(pdst[out_order], dstfrmsize, &checkcrc);
327 write_data_crc(cfg->fp_slt, &checkcrc);
328 calc_data_crc(pdst[1 - out_order], dstfrmsize, &checkcrc);
329 write_data_crc(cfg->fp_slt, &checkcrc);
330 }
331
332 out_order = dei_info.dil_order == IEP2_FIELD_ORDER_BFF ? 1 : 0;
333
334 if (cfg->fp_dst) {
335 if (dstfrmsize > fwrite(pdst[out_order], 1, dstfrmsize, cfg->fp_dst)) {
336 mpp_err("destination dump failed\n");
337 break;
338 }
339
340 if (dstfrmsize > fwrite(pdst[1 - out_order], 1, dstfrmsize, cfg->fp_dst)) {
341 mpp_err("destination dump failed\n");
342 break;
343 }
344 }
345
346 curr++;
347 }
348
349 ret:
350 mpp_buffer_put(srcbuf[0]);
351 mpp_buffer_put(srcbuf[1]);
352 mpp_buffer_put(srcbuf[2]);
353
354 mpp_buffer_put(dstbuf[0]);
355 mpp_buffer_put(dstbuf[1]);
356
357 MPP_FREE(checkcrc.sum);
358
359 if (memGroup) {
360 mpp_buffer_group_put(memGroup);
361 memGroup = NULL;
362 }
363
364 iep2->ops->deinit(iep2->priv);
365
366 rockchip_iep2_api_release_ctx(iep2);
367 }
368
main(int argc,char ** argv)369 int main(int argc, char **argv)
370 {
371 iep2_test_cfg cfg;
372 int ch;
373
374 if (argc < 2) {
375 iep2_test_help();
376 return 0;
377 }
378
379 memset(&cfg, 0, sizeof(cfg));
380 cfg.src_fmt = IEP2_FMT_YUV420;
381 cfg.src_swa = IEP2_YUV_SWAP_SP_UV;
382 cfg.dst_fmt = IEP2_FMT_YUV420;
383 cfg.dst_swa = IEP2_YUV_SWAP_SP_UV;
384
385 /// get options
386 opterr = 0;
387 while ((ch = getopt(argc, argv, "i:w:h:c:o:C:v:f:")) != -1) {
388 switch (ch) {
389 case 'w': {
390 cfg.w = atoi(optarg);
391 } break;
392 case 'h': {
393 cfg.h = atoi(optarg);
394 } break;
395 case 'c': {
396 cfg.src_fmt = str_to_iep2_fmt(optarg);
397 cfg.src_swa = str_to_iep2_swa(optarg);
398 } break;
399 case 'C': {
400 cfg.dst_fmt = str_to_iep2_fmt(optarg);
401 cfg.dst_swa = str_to_iep2_swa(optarg);
402 } break;
403 case 'i': {
404 mpp_log("input filename: %s\n", optarg);
405 strncpy(cfg.src_url, optarg, sizeof(cfg.src_url) - 1);
406 cfg.fp_src = fopen(cfg.src_url, "rb");
407 } break;
408 case 'o': {
409 mpp_log("output filename: %s\n", optarg);
410 strncpy(cfg.dst_url, optarg, sizeof(cfg.dst_url) - 1);
411 cfg.fp_dst = fopen(cfg.dst_url, "w+b");
412 } break;
413 case 'v': {
414 mpp_log("verify file: %s\n", optarg);
415 strncpy(cfg.slt_url, optarg, sizeof(cfg.slt_url) - 1);
416 cfg.fp_slt = fopen(cfg.slt_url, "w+b");
417 } break;
418 case 'f': {
419 if (!strcmp(optarg, "TFF"))
420 cfg.field_order = IEP2_FIELD_ORDER_TFF;
421 else
422 cfg.field_order = IEP2_FIELD_ORDER_BFF;
423 } break;
424 default: {
425 } break;
426 }
427 }
428
429 if (check_input_cmd(&cfg)) {
430 mpp_err("failed to pass cmd line check\n");
431 iep2_test_help();
432 return -1;
433 }
434
435 iep2_test(&cfg);
436
437 if (cfg.fp_src) {
438 fclose(cfg.fp_src);
439 cfg.fp_src = NULL;
440 }
441
442 if (cfg.fp_dst) {
443 fclose(cfg.fp_dst);
444 cfg.fp_dst = NULL;
445 }
446
447 if (cfg.fp_slt) {
448 fclose(cfg.fp_slt);
449 cfg.fp_slt = NULL;
450 }
451
452 return 0;
453 }
454