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 int idx = 0;
221
222 mpp_assert(iep2);
223
224 memset(&checkcrc, 0, sizeof(checkcrc));
225 checkcrc.sum = mpp_malloc(RK_ULONG, 512);
226
227 mpp_buffer_get(NULL, &srcbuf[0], srcfrmsize);
228 mpp_buffer_get(NULL, &srcbuf[1], srcfrmsize);
229 mpp_buffer_get(NULL, &srcbuf[2], srcfrmsize);
230 mpp_buffer_get(NULL, &dstbuf[0], dstfrmsize);
231 mpp_buffer_get(NULL, &dstbuf[1], dstfrmsize);
232 mpp_assert(srcbuf[0] && srcbuf[1] && srcbuf[2] && dstbuf[0] && dstbuf[1]);
233
234 psrc[0] = mpp_buffer_get_ptr(srcbuf[0]);
235 psrc[1] = mpp_buffer_get_ptr(srcbuf[1]);
236 psrc[2] = mpp_buffer_get_ptr(srcbuf[2]);
237
238 pdst[0] = mpp_buffer_get_ptr(dstbuf[0]);
239 pdst[1] = mpp_buffer_get_ptr(dstbuf[1]);
240
241 fdsrc[0] = mpp_buffer_get_fd(srcbuf[0]);
242 fdsrc[1] = mpp_buffer_get_fd(srcbuf[1]);
243 fdsrc[2] = mpp_buffer_get_fd(srcbuf[2]);
244
245 fddst[0] = mpp_buffer_get_fd(dstbuf[0]);
246 fddst[1] = mpp_buffer_get_fd(dstbuf[1]);
247
248 iep2->ops->init(&iep2->priv);
249
250 if (srcfrmsize > fread(psrc[0], 1, srcfrmsize, cfg->fp_src)) {
251 mpp_log("source exhaused\n");
252 goto ret;
253 }
254
255 if (srcfrmsize > fread(psrc[1], 1, srcfrmsize, cfg->fp_src)) {
256 mpp_log("source exhaused\n");
257 goto ret;
258 }
259
260 curr = 1;
261
262 // set running mode.
263 /* if deinterlacing mode is one in the following list:
264 IEP2_DIL_MODE_I5O2,
265 IEP2_DIL_MODE_I5O1T,
266 IEP2_DIL_MODE_I5O1B,
267 IEP2_DIL_MODE_DECT
268 field order will auto detect by iep2 library.
269 so don't try to set field order during the playback.
270 */
271 params.ptype = IEP2_PARAM_TYPE_MODE;
272 params.param.mode.dil_mode = IEP2_DIL_MODE_I5O2;
273 params.param.mode.out_mode = IEP2_OUT_MODE_LINE;
274 params.param.mode.dil_order = cfg->field_order;
275
276 iep2->ops->control(iep2->priv, IEP_CMD_SET_DEI_CFG, ¶ms);
277
278 // set the image format.
279 params.ptype = IEP2_PARAM_TYPE_COM;
280 params.param.com.sfmt = cfg->src_fmt;
281 params.param.com.dfmt = cfg->dst_fmt;
282 params.param.com.sswap = cfg->src_swa;
283 params.param.com.dswap = cfg->dst_swa;
284 params.param.com.width = cfg->w;
285 params.param.com.height = cfg->h;
286 params.param.com.hor_stride = cfg->w;
287 iep2->ops->control(iep2->priv, IEP_CMD_SET_DEI_CFG, ¶ms);
288
289 for (i = 0; i < MPP_ARRAY_ELEMS(imgsrc); i++)
290 imgsrc[i].format = cfg->src_fmt;
291
292 for (i = 0; i < MPP_ARRAY_ELEMS(imgdst); i++)
293 imgdst[i].format = cfg->dst_fmt;
294
295 while (1) {
296 prev = (curr - 1) % 3;
297 curr = curr % 3;
298 next = (curr + 1) % 3;
299
300 if (srcfrmsize > fread(psrc[next], 1, srcfrmsize, cfg->fp_src)) {
301 mpp_log("source exhaused\n");
302 break;
303 }
304
305 // notice the order of the input frames.
306 iep2_test_set_img(iep2, cfg->w, cfg->h,
307 &imgsrc[curr], fdsrc[curr], IEP_CMD_SET_SRC);
308 iep2_test_set_img(iep2, cfg->w, cfg->h,
309 &imgsrc[next], fdsrc[next], IEP_CMD_SET_DEI_SRC1);
310 iep2_test_set_img(iep2, cfg->w, cfg->h,
311 &imgsrc[prev], fdsrc[prev], IEP_CMD_SET_DEI_SRC2);
312 iep2_test_set_img(iep2, cfg->w, cfg->h,
313 &imgdst[0], fddst[0], IEP_CMD_SET_DST);
314 iep2_test_set_img(iep2, cfg->w, cfg->h,
315 &imgdst[1], fddst[1], IEP_CMD_SET_DEI_DST1);
316
317 memset(pdst[0], 0, dstfrmsize);
318 memset(pdst[1], 0, dstfrmsize);
319 iep2->ops->control(iep2->priv, IEP_CMD_RUN_SYNC, &dei_info);
320
321 if (cfg->fp_slt) {
322 calc_data_crc(pdst[out_order], dstfrmsize, &checkcrc);
323 write_data_crc(cfg->fp_slt, &checkcrc);
324 calc_data_crc(pdst[1 - out_order], dstfrmsize, &checkcrc);
325 write_data_crc(cfg->fp_slt, &checkcrc);
326 }
327
328 out_order = dei_info.dil_order == IEP2_FIELD_ORDER_BFF ? 1 : 0;
329
330 if (dstfrmsize > fwrite(pdst[out_order], 1, dstfrmsize, cfg->fp_dst)) {
331 mpp_err("destination dump failed\n");
332 break;
333 }
334
335 if (dstfrmsize > fwrite(pdst[1 - out_order], 1, dstfrmsize, cfg->fp_dst)) {
336 mpp_err("destination dump failed\n");
337 break;
338 }
339
340 curr++;
341 idx++;
342 }
343
344 ret:
345 mpp_buffer_put(srcbuf[0]);
346 mpp_buffer_put(srcbuf[1]);
347 mpp_buffer_put(srcbuf[2]);
348
349 mpp_buffer_put(dstbuf[0]);
350 mpp_buffer_put(dstbuf[1]);
351
352 MPP_FREE(checkcrc.sum);
353
354 iep2->ops->deinit(iep2->priv);
355
356 rockchip_iep2_api_release_ctx(iep2);
357 }
358
main(int argc,char ** argv)359 int main(int argc, char **argv)
360 {
361 iep2_test_cfg cfg;
362 int ch;
363
364 if (argc < 2) {
365 iep2_test_help();
366 return 0;
367 }
368
369 memset(&cfg, 0, sizeof(cfg));
370 cfg.src_fmt = IEP2_FMT_YUV420;
371 cfg.src_swa = IEP2_YUV_SWAP_SP_UV;
372 cfg.dst_fmt = IEP2_FMT_YUV420;
373 cfg.dst_swa = IEP2_YUV_SWAP_SP_UV;
374
375 /// get options
376 opterr = 0;
377 while ((ch = getopt(argc, argv, "i:w:h:c:o:C:v:f:")) != -1) {
378 switch (ch) {
379 case 'w': {
380 cfg.w = atoi(optarg);
381 } break;
382 case 'h': {
383 cfg.h = atoi(optarg);
384 } break;
385 case 'c': {
386 cfg.src_fmt = str_to_iep2_fmt(optarg);
387 cfg.src_swa = str_to_iep2_swa(optarg);
388 } break;
389 case 'C': {
390 cfg.dst_fmt = str_to_iep2_fmt(optarg);
391 cfg.dst_swa = str_to_iep2_swa(optarg);
392 } break;
393 case 'i': {
394 mpp_log("input filename: %s\n", optarg);
395 strncpy(cfg.src_url, optarg, sizeof(cfg.src_url) - 1);
396 cfg.fp_src = fopen(cfg.src_url, "rb");
397 } break;
398 case 'o': {
399 mpp_log("output filename: %s\n", optarg);
400 strncpy(cfg.dst_url, optarg, sizeof(cfg.dst_url) - 1);
401 cfg.fp_dst = fopen(cfg.dst_url, "w+b");
402 } break;
403 case 'v': {
404 mpp_log("verify file: %s\n", optarg);
405 strncpy(cfg.slt_url, optarg, sizeof(cfg.slt_url) - 1);
406 cfg.fp_slt = fopen(cfg.slt_url, "w+b");
407 } break;
408 case 'f': {
409 if (!strcmp(optarg, "TFF"))
410 cfg.field_order = IEP2_FIELD_ORDER_TFF;
411 else
412 cfg.field_order = IEP2_FIELD_ORDER_BFF;
413 } break;
414 default: {
415 } break;
416 }
417 }
418
419 if (check_input_cmd(&cfg)) {
420 mpp_err("failed to pass cmd line check\n");
421 iep2_test_help();
422 return -1;
423 }
424
425 iep2_test(&cfg);
426
427 if (cfg.fp_src) {
428 fclose(cfg.fp_src);
429 cfg.fp_src = NULL;
430 }
431
432 if (cfg.fp_dst) {
433 fclose(cfg.fp_dst);
434 cfg.fp_dst = NULL;
435 }
436
437 if (cfg.fp_slt) {
438 fclose(cfg.fp_slt);
439 cfg.fp_slt = NULL;
440 }
441
442 return 0;
443 }
444