1 /* SPDX-License-Identifier: Apache-2.0 OR MIT */
2 /*
3 * Copyright (c) 2015 Rockchip Electronics Co., Ltd.
4 */
5
6 #if defined(_WIN32)
7 #include "vld.h"
8 #endif
9
10 #define MODULE_TAG "mpi_dec_test"
11
12 #include <string.h>
13 #include "rk_mpi.h"
14
15 #include "mpp_mem.h"
16 #include "mpp_env.h"
17 #include "mpp_time.h"
18 #include "mpp_common.h"
19 #include "mpi_dec_utils.h"
20
21 typedef struct {
22 MpiDecTestCmd *cmd;
23 MppCtx ctx;
24 MppApi *mpi;
25 RK_U32 quiet;
26
27 /* end of stream flag when set quit the loop */
28 RK_U32 loop_end;
29
30 /* input and output */
31 DecBufMgr buf_mgr;
32 MppBufferGroup frm_grp;
33 MppPacket packet;
34 MppFrame frame;
35
36 FILE *fp_output;
37 RK_S32 frame_count;
38 RK_S32 frame_num;
39
40 RK_S64 first_pkt;
41 RK_S64 first_frm;
42
43 size_t max_usage;
44 float frame_rate;
45 RK_S64 elapsed_time;
46 RK_S64 delay;
47 FILE *fp_verify;
48 FrmCrc checkcrc;
49 } MpiDecLoopData;
50
dec_simple(MpiDecLoopData * data)51 static int dec_simple(MpiDecLoopData *data)
52 {
53 RK_U32 pkt_done = 0;
54 RK_U32 pkt_eos = 0;
55 MPP_RET ret = MPP_OK;
56 MpiDecTestCmd *cmd = data->cmd;
57 MppCtx ctx = data->ctx;
58 MppApi *mpi = data->mpi;
59 MppPacket packet = data->packet;
60 FileBufSlot *slot = NULL;
61 RK_U32 quiet = data->quiet;
62 FrmCrc *checkcrc = &data->checkcrc;
63
64 // when packet size is valid read the input binary file
65 ret = reader_read(cmd->reader, &slot);
66
67 mpp_assert(ret == MPP_OK);
68 mpp_assert(slot);
69
70 pkt_eos = slot->eos;
71
72 if (pkt_eos) {
73 if (data->frame_num < 0 || data->frame_num > data->frame_count) {
74 mpp_log_q(quiet, "%p loop again\n", ctx);
75 reader_rewind(cmd->reader);
76 pkt_eos = 0;
77 } else {
78 mpp_log_q(quiet, "%p found last packet\n", ctx);
79 data->loop_end = 1;
80 }
81 }
82
83 mpp_packet_set_data(packet, slot->data);
84 mpp_packet_set_size(packet, slot->size);
85 mpp_packet_set_pos(packet, slot->data);
86 mpp_packet_set_length(packet, slot->size);
87 // setup eos flag
88 if (pkt_eos)
89 mpp_packet_set_eos(packet);
90
91 do {
92 RK_U32 frm_eos = 0;
93 RK_S32 times = 30;
94
95 // send the packet first if packet is not done
96 if (!pkt_done) {
97 ret = mpi->decode_put_packet(ctx, packet);
98 if (MPP_OK == ret) {
99 pkt_done = 1;
100 if (!data->first_pkt)
101 data->first_pkt = mpp_time();
102 }
103 }
104
105 // then get all available frame and release
106 do {
107 RK_S32 get_frm = 0;
108 MppFrame frame = NULL;
109
110 try_again:
111 ret = mpi->decode_get_frame(ctx, &frame);
112 if (MPP_ERR_TIMEOUT == ret) {
113 if (times > 0) {
114 times--;
115 msleep(1);
116 goto try_again;
117 }
118 mpp_err("%p decode_get_frame failed too much time\n", ctx);
119 }
120 if (ret) {
121 mpp_err("%p decode_get_frame failed ret %d\n", ret, ctx);
122 break;
123 }
124
125 if (frame) {
126 if (mpp_frame_get_info_change(frame)) {
127 RK_U32 width = mpp_frame_get_width(frame);
128 RK_U32 height = mpp_frame_get_height(frame);
129 RK_U32 hor_stride = mpp_frame_get_hor_stride(frame);
130 RK_U32 ver_stride = mpp_frame_get_ver_stride(frame);
131 RK_U32 buf_size = mpp_frame_get_buf_size(frame);
132 MppBufferGroup grp = NULL;
133
134 mpp_log_q(quiet, "%p decode_get_frame get info changed found\n", ctx);
135 mpp_log_q(quiet, "%p decoder require buffer w:h [%d:%d] stride [%d:%d] buf_size %d",
136 ctx, width, height, hor_stride, ver_stride, buf_size);
137
138 if (MPP_FRAME_FMT_IS_FBC(cmd->format)) {
139 MppFrame frm = NULL;
140
141 mpp_frame_init(&frm);
142 mpp_frame_set_width(frm, width);
143 mpp_frame_set_height(frm, height);
144 mpp_frame_set_fmt(frm, cmd->format);
145
146 ret = mpi->control(ctx, MPP_DEC_SET_FRAME_INFO, frm);
147 mpp_frame_deinit(&frm);
148
149 if (ret) {
150 mpp_err("set fbc frame info failed\n");
151 break;
152 }
153 }
154
155 grp = dec_buf_mgr_setup(data->buf_mgr, buf_size, 24, cmd->buf_mode);
156 /* Set buffer to mpp decoder */
157 ret = mpi->control(ctx, MPP_DEC_SET_EXT_BUF_GROUP, grp);
158 if (ret) {
159 mpp_err("%p set buffer group failed ret %d\n", ctx, ret);
160 break;
161 }
162 data->frm_grp = grp;
163
164 /*
165 * All buffer group config done. Set info change ready to let
166 * decoder continue decoding
167 */
168 ret = mpi->control(ctx, MPP_DEC_SET_INFO_CHANGE_READY, NULL);
169 if (ret) {
170 mpp_err("%p info change ready failed ret %d\n", ctx, ret);
171 break;
172 }
173 } else {
174 char log_buf[256];
175 RK_S32 log_size = sizeof(log_buf) - 1;
176 RK_S32 log_len = 0;
177 RK_U32 err_info = mpp_frame_get_errinfo(frame);
178 RK_U32 discard = mpp_frame_get_discard(frame);
179
180 if (!data->first_frm)
181 data->first_frm = mpp_time();
182
183 log_len += snprintf(log_buf + log_len, log_size - log_len,
184 "decode get frame %d", data->frame_count);
185
186 if (mpp_frame_has_meta(frame)) {
187 MppMeta meta = mpp_frame_get_meta(frame);
188 RK_S32 temporal_id = 0;
189
190 mpp_meta_get_s32(meta, KEY_TEMPORAL_ID, &temporal_id);
191
192 log_len += snprintf(log_buf + log_len, log_size - log_len,
193 " tid %d", temporal_id);
194 }
195
196 if (err_info || discard) {
197 log_len += snprintf(log_buf + log_len, log_size - log_len,
198 " err %x discard %x", err_info, discard);
199 }
200 mpp_log_q(quiet, "%p %s\n", ctx, log_buf);
201
202 data->frame_count++;
203 if (data->fp_output && !err_info)
204 dump_mpp_frame_to_file(frame, data->fp_output);
205
206 if (data->fp_verify) {
207 calc_frm_crc(frame, checkcrc);
208 write_frm_crc(data->fp_verify, checkcrc);
209 }
210
211 fps_calc_inc(cmd->fps);
212 }
213 frm_eos = mpp_frame_get_eos(frame);
214 mpp_frame_deinit(&frame);
215 get_frm = 1;
216 }
217
218 // try get runtime frame memory usage
219 if (data->frm_grp) {
220 size_t usage = mpp_buffer_group_usage(data->frm_grp);
221 if (usage > data->max_usage)
222 data->max_usage = usage;
223 }
224
225 // if last packet is send but last frame is not found continue
226 if (pkt_eos && pkt_done && !frm_eos) {
227 msleep(1);
228 continue;
229 }
230
231 if (frm_eos) {
232 mpp_log_q(quiet, "%p found last packet\n", ctx);
233 break;
234 }
235
236 if ((data->frame_num > 0 && (data->frame_count >= data->frame_num)) ||
237 ((data->frame_num == 0) && frm_eos))
238 break;
239
240 if (get_frm)
241 continue;
242 break;
243 } while (1);
244
245 if ((data->frame_num > 0 && (data->frame_count >= data->frame_num)) ||
246 ((data->frame_num == 0) && frm_eos)) {
247 data->loop_end = 1;
248 break;
249 }
250
251 if (pkt_done)
252 break;
253
254 /*
255 * why sleep here:
256 * mpi->decode_put_packet will failed when packet in internal queue is
257 * full,waiting the package is consumed .Usually hardware decode one
258 * frame which resolution is 1080p needs 2 ms,so here we sleep 1ms
259 * * is enough.
260 */
261 msleep(1);
262 } while (1);
263
264 return ret;
265 }
266
dec_advanced(MpiDecLoopData * data)267 static int dec_advanced(MpiDecLoopData *data)
268 {
269 MPP_RET ret = MPP_OK;
270 MpiDecTestCmd *cmd = data->cmd;
271 MppCtx ctx = data->ctx;
272 MppApi *mpi = data->mpi;
273 MppPacket packet = NULL;
274 MppPacket packet_ret = NULL;
275 MppFrame frame = data->frame;
276 MppFrame frame_ret = NULL;
277 MppMeta meta = NULL;
278 RK_U32 quiet = data->quiet;
279 FileBufSlot *slot = NULL;
280 FrmCrc *checkcrc = &data->checkcrc;
281
282 ret = reader_index_read(cmd->reader, 0, &slot);
283 mpp_assert(ret == MPP_OK);
284 mpp_assert(slot);
285
286 mpp_packet_init_with_buffer(&packet, slot->buf);
287
288 // setup eos flag
289 if (slot->eos)
290 mpp_packet_set_eos(packet);
291
292 /* use the MppFrame with prealloced buffer and do not release */
293 meta = mpp_packet_get_meta(packet);
294 if (meta)
295 mpp_meta_set_frame(meta, KEY_OUTPUT_FRAME, frame);
296
297 ret = mpi->decode_put_packet(ctx, packet);
298 if (ret) {
299 mpp_err("%p mpp decode put packet failed ret %d\n", ctx, ret);
300 data->loop_end = 1;
301 goto DONE;
302 }
303
304 if (!data->first_pkt)
305 data->first_pkt = mpp_time();
306
307 ret = mpi->decode_get_frame(ctx, &frame_ret);
308 if (ret || !frame_ret) {
309 mpp_err("%p mpp decode get frame failed ret %d frame %p\n", ctx, ret, frame_ret);
310 data->loop_end = 1;
311 goto DONE;
312 }
313
314 if (!data->first_frm)
315 data->first_frm = mpp_time();
316
317 if (frame_ret != frame)
318 mpp_err_f("mismatch frame %p -> %p\n", frame_ret, frame);
319
320 /* write frame to file here */
321 if (data->fp_output)
322 dump_mpp_frame_to_file(frame_ret, data->fp_output);
323
324 if (data->fp_verify) {
325 calc_frm_crc(frame_ret, checkcrc);
326 write_frm_crc(data->fp_verify, checkcrc);
327 }
328
329 mpp_log_q(quiet, "%p decoded frame %d\n", ctx, data->frame_count);
330 data->frame_count++;
331
332 if (mpp_frame_get_eos(frame_ret))
333 mpp_log_q(quiet, "%p found eos frame\n", ctx);
334
335 fps_calc_inc(cmd->fps);
336
337 meta = mpp_frame_get_meta(frame);
338 if (meta) {
339 ret = mpp_meta_get_packet(meta, KEY_INPUT_PACKET, &packet_ret);
340 if (ret || !packet_ret) {
341 mpp_err("%p mpp meta get packet failed ret %d\n", ctx, ret);
342 goto DONE;
343 }
344
345 if (packet_ret != packet)
346 mpp_err_f("mismatch packet %p -> %p\n", packet, packet_ret);
347 }
348
349 if (data->frame_num > 0) {
350 if (data->frame_count >= data->frame_num)
351 data->loop_end = 1;
352 } else if (data->frame_num == 0) {
353 if (slot->eos)
354 data->loop_end = 1;
355 }
356
357 DONE:
358 mpp_packet_deinit(&packet);
359
360 return ret;
361 }
362
thread_decode(void * arg)363 void *thread_decode(void *arg)
364 {
365 MpiDecLoopData *data = (MpiDecLoopData *)arg;
366 MpiDecTestCmd *cmd = data->cmd;
367 MppCtx ctx = data->ctx;
368 MppApi *mpi = data->mpi;
369 RK_S64 t_s, t_e;
370
371 memset(&data->checkcrc, 0, sizeof(data->checkcrc));
372 data->checkcrc.luma.sum = mpp_malloc(RK_ULONG, 512);
373 data->checkcrc.chroma.sum = mpp_malloc(RK_ULONG, 512);
374
375 t_s = mpp_time();
376
377 if (cmd->simple) {
378 while (!data->loop_end)
379 dec_simple(data);
380 } else {
381 /* NOTE: change output format before jpeg decoding */
382 if (MPP_FRAME_FMT_IS_YUV(cmd->format) || MPP_FRAME_FMT_IS_RGB(cmd->format)) {
383 MPP_RET ret = mpi->control(ctx, MPP_DEC_SET_OUTPUT_FORMAT, &cmd->format);
384 if (ret) {
385 mpp_err("Failed to set output format 0x%x\n", cmd->format);
386 return NULL;
387 }
388 }
389
390 while (!data->loop_end)
391 dec_advanced(data);
392 }
393
394 t_e = mpp_time();
395 data->elapsed_time = t_e - t_s;
396 data->frame_rate = (float)data->frame_count * 1000000 / data->elapsed_time;
397 data->delay = data->first_frm - data->first_pkt;
398
399 mpp_log("decode %d frames time %lld ms delay %3d ms fps %3.2f\n",
400 data->frame_count, (RK_S64)(data->elapsed_time / 1000),
401 (RK_S32)(data->delay / 1000), data->frame_rate);
402
403 MPP_FREE(data->checkcrc.luma.sum);
404 MPP_FREE(data->checkcrc.chroma.sum);
405
406 return NULL;
407 }
408
dec_decode(MpiDecTestCmd * cmd)409 int dec_decode(MpiDecTestCmd *cmd)
410 {
411 // base flow context
412 MppCtx ctx = NULL;
413 MppApi *mpi = NULL;
414
415 // input / output
416 MppPacket packet = NULL;
417 MppFrame frame = NULL;
418
419 // paramter for resource malloc
420 RK_U32 width = cmd->width;
421 RK_U32 height = cmd->height;
422 MppCodingType type = cmd->type;
423
424 // config for runtime mode
425 MppDecCfg cfg = NULL;
426 RK_U32 need_split = 1;
427
428 // resources
429 MppBuffer frm_buf = NULL;
430 pthread_t thd;
431 pthread_attr_t attr;
432 MpiDecLoopData data;
433 MPP_RET ret = MPP_OK;
434
435 mpp_log("mpi_dec_test start\n");
436 memset(&data, 0, sizeof(data));
437 pthread_attr_init(&attr);
438
439 cmd->simple = (cmd->type != MPP_VIDEO_CodingMJPEG) ? (1) : (0);
440
441 if (cmd->have_output) {
442 data.fp_output = fopen(cmd->file_output, "w+b");
443 if (NULL == data.fp_output) {
444 mpp_err("failed to open output file %s\n", cmd->file_output);
445 goto MPP_TEST_OUT;
446 }
447 }
448
449 if (cmd->file_slt) {
450 data.fp_verify = fopen(cmd->file_slt, "wt");
451 if (!data.fp_verify)
452 mpp_err("failed to open verify file %s\n", cmd->file_slt);
453 }
454
455 ret = dec_buf_mgr_init(&data.buf_mgr);
456 if (ret) {
457 mpp_err("dec_buf_mgr_init failed\n");
458 goto MPP_TEST_OUT;
459 }
460
461 if (cmd->simple) {
462 ret = mpp_packet_init(&packet, NULL, 0);
463 if (ret) {
464 mpp_err("mpp_packet_init failed\n");
465 goto MPP_TEST_OUT;
466 }
467 } else {
468 RK_U32 hor_stride = MPP_ALIGN(width, 16);
469 RK_U32 ver_stride = MPP_ALIGN(height, 16);
470
471 ret = mpp_frame_init(&frame); /* output frame */
472 if (ret) {
473 mpp_err("mpp_frame_init failed\n");
474 goto MPP_TEST_OUT;
475 }
476
477 data.frm_grp = dec_buf_mgr_setup(data.buf_mgr, hor_stride * ver_stride * 4, 4, cmd->buf_mode);
478 if (!data.frm_grp) {
479 mpp_err("failed to get buffer group for input frame ret %d\n", ret);
480 ret = MPP_NOK;
481 goto MPP_TEST_OUT;
482 }
483
484 /*
485 * NOTE: For jpeg could have YUV420 and YUV422 the buffer should be
486 * larger for output. And the buffer dimension should align to 16.
487 * YUV420 buffer is 3/2 times of w*h.
488 * YUV422 buffer is 2 times of w*h.
489 * So create larger buffer with 2 times w*h.
490 */
491 ret = mpp_buffer_get(data.frm_grp, &frm_buf, hor_stride * ver_stride * 4);
492 if (ret) {
493 mpp_err("failed to get buffer for input frame ret %d\n", ret);
494 goto MPP_TEST_OUT;
495 }
496
497 mpp_frame_set_buffer(frame, frm_buf);
498 }
499
500 // decoder demo
501 ret = mpp_create(&ctx, &mpi);
502 if (ret) {
503 mpp_err("mpp_create failed\n");
504 goto MPP_TEST_OUT;
505 }
506
507 mpp_log("%p mpi_dec_test decoder test start w %d h %d type %d\n",
508 ctx, width, height, type);
509
510 ret = mpp_init(ctx, MPP_CTX_DEC, type);
511 if (ret) {
512 mpp_err("%p mpp_init failed\n", ctx);
513 goto MPP_TEST_OUT;
514 }
515
516 mpp_dec_cfg_init(&cfg);
517
518 /* get default config from decoder context */
519 ret = mpi->control(ctx, MPP_DEC_GET_CFG, cfg);
520 if (ret) {
521 mpp_err("%p failed to get decoder cfg ret %d\n", ctx, ret);
522 goto MPP_TEST_OUT;
523 }
524
525 /*
526 * split_parse is to enable mpp internal frame spliter when the input
527 * packet is not aplited into frames.
528 */
529 ret = mpp_dec_cfg_set_u32(cfg, "base:split_parse", need_split);
530 if (ret) {
531 mpp_err("%p failed to set split_parse ret %d\n", ctx, ret);
532 goto MPP_TEST_OUT;
533 }
534
535 ret = mpi->control(ctx, MPP_DEC_SET_CFG, cfg);
536 if (ret) {
537 mpp_err("%p failed to set cfg %p ret %d\n", ctx, cfg, ret);
538 goto MPP_TEST_OUT;
539 }
540
541 data.cmd = cmd;
542 data.ctx = ctx;
543 data.mpi = mpi;
544 data.loop_end = 0;
545 data.packet = packet;
546 data.frame = frame;
547 data.frame_count = 0;
548 data.frame_num = cmd->frame_num;
549 data.quiet = cmd->quiet;
550
551 pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_JOINABLE);
552
553 ret = pthread_create(&thd, &attr, thread_decode, &data);
554 if (ret) {
555 mpp_err("failed to create thread for input ret %d\n", ret);
556 goto MPP_TEST_OUT;
557 }
558
559 if (cmd->frame_num < 0) {
560 // wait for input then quit decoding
561 mpp_log("*******************************************\n");
562 mpp_log("**** Press Enter to stop loop decoding ****\n");
563 mpp_log("*******************************************\n");
564
565 getc(stdin);
566 data.loop_end = 1;
567 }
568
569 pthread_join(thd, NULL);
570
571 cmd->max_usage = data.max_usage;
572
573 ret = mpi->reset(ctx);
574 if (ret) {
575 mpp_err("%p mpi->reset failed\n", ctx);
576 goto MPP_TEST_OUT;
577 }
578
579 MPP_TEST_OUT:
580 if (data.packet) {
581 mpp_packet_deinit(&data.packet);
582 data.packet = NULL;
583 }
584
585 if (frame) {
586 mpp_frame_deinit(&frame);
587 frame = NULL;
588 }
589
590 if (ctx) {
591 mpp_destroy(ctx);
592 ctx = NULL;
593 }
594
595 if (!cmd->simple) {
596 if (frm_buf) {
597 mpp_buffer_put(frm_buf);
598 frm_buf = NULL;
599 }
600 }
601
602 data.frm_grp = NULL;
603 if (data.buf_mgr) {
604 dec_buf_mgr_deinit(data.buf_mgr);
605 data.buf_mgr = NULL;
606 }
607
608 if (data.fp_output) {
609 fclose(data.fp_output);
610 data.fp_output = NULL;
611 }
612
613 if (data.fp_verify) {
614 fclose(data.fp_verify);
615 data.fp_verify = NULL;
616 }
617
618 if (cfg) {
619 mpp_dec_cfg_deinit(cfg);
620 cfg = NULL;
621 }
622
623 pthread_attr_destroy(&attr);
624
625 return ret;
626 }
627
main(int argc,char ** argv)628 int main(int argc, char **argv)
629 {
630 RK_S32 ret = 0;
631 MpiDecTestCmd cmd_ctx;
632 MpiDecTestCmd* cmd = &cmd_ctx;
633
634 memset((void*)cmd, 0, sizeof(*cmd));
635 cmd->format = MPP_FMT_BUTT;
636 cmd->pkt_size = MPI_DEC_STREAM_SIZE;
637
638 // parse the cmd option
639 ret = mpi_dec_test_cmd_init(cmd, argc, argv);
640 if (ret)
641 goto RET;
642
643 mpi_dec_test_cmd_options(cmd);
644
645 ret = dec_decode(cmd);
646 if (MPP_OK == ret)
647 mpp_log("test success max memory %.2f MB\n", cmd->max_usage / (float)(1 << 20));
648 else
649 mpp_err("test failed ret %d\n", ret);
650
651 RET:
652 mpi_dec_test_cmd_deinit(cmd);
653
654 return ret;
655 }
656
657