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