xref: /rockchip-linux_mpp/test/vpu_api_test.c (revision 437bfbeb9567cca9cd9080e3f6954aa9d6a94f18)
1 /* SPDX-License-Identifier: Apache-2.0 OR MIT */
2 /*
3  * Copyright (c) 2015 Rockchip Electronics Co., Ltd.
4  */
5 
6 #include <stdio.h>
7 #include <stdlib.h>
8 #include <string.h>
9 #include <dlfcn.h>
10 #include <unistd.h>
11 
12 #include "vpu_api.h"
13 
14 #define FOR_TEST_ENCODE 1
15 
16 #define BSWAP32(x) \
17     ((((x) & 0xff000000) >> 24) | (((x) & 0x00ff0000) >>  8) | \
18      (((x) & 0x0000ff00) <<  8) | (((x) & 0x000000ff) << 24))
19 
20 #define DEMO_ERR_RET(err) do { ret = err; goto DEMO_OUT; } while (0)
21 #define DECODE_ERR_RET(err) do { ret = err; goto DECODE_OUT; } while (0)
22 #define ENCODE_ERR_RET(err) do { ret = err; goto ENCODE_OUT; } while (0)
23 
24 typedef enum VPU_API_DEMO_RET {
25     VPU_DEMO_OK             = 0,
26     VPU_DEMO_PARSE_HELP_OK  = 1,
27 
28     VPU_DEMO_ERROR_BASE     = -100,
29     ERROR_INVALID_PARAM     = VPU_DEMO_ERROR_BASE - 1,
30     ERROR_INVALID_STREAM    = VPU_DEMO_ERROR_BASE - 2,
31     ERROR_IO                = VPU_DEMO_ERROR_BASE - 3,
32     ERROR_MEMORY            = VPU_DEMO_ERROR_BASE - 4,
33     ERROR_INIT_VPU          = VPU_DEMO_ERROR_BASE - 5,
34 
35     ERROR_VPU_DECODE        = VPU_DEMO_ERROR_BASE - 90,
36 } VPU_API_DEMO_RET;
37 
38 typedef struct VpuApiDemoCmdContext {
39     RK_U32  width;
40     RK_U32  height;
41     CODEC_TYPE  codec_type;
42     OMX_RK_VIDEO_CODINGTYPE coding;
43     char    input_file[200];
44     char    output_file[200];
45     RK_U8   have_input;
46     RK_U8   have_output;
47     RK_U32  record_frames;
48     RK_S64  record_start_ms;
49 } VpuApiDemoCmdContext_t;
50 
51 typedef struct VpuApiEncInput {
52     EncInputStream_t stream;
53     RK_U32 capability;
54 } VpuApiEncInput;
55 
56 typedef struct VpuApiOptionInfo_t {
57     const char*     name;
58     const char*     argname;
59     const char*     help;
60 } VpuApiOptionInfo;
61 
62 static VpuApiOptionInfo vpuApiCmd[] = {
63     { "i",       "input_file",  "input bitstream file" },
64     { "o",       "output_file", "output bitstream file, " },
65     { "w",       "width",       "the width of input bitstream" },
66     { "h",       "height",      "the height of input bitstream" },
67     { "t",       "codec_type",  "the codec type, dec: deoder, enc: encoder, default: decoder" },
68     { "coding",  "coding_type", "encoding type of the bitstream" },
69     { "vframes", "number",      "set the number of video frames to record" },
70     { "ss",      "time_off",    "set the start time offset, use Ms as the unit." },
71 };
72 
73 static void *vpuapi_hdl = NULL;
74 static VpuCodecContext_t *ctx;
75 RK_S32 (*vpuapi_open_ctx)(VpuCodecContext_t **ctx);
76 RK_S32 (*vpuapi_close_ctx)(VpuCodecContext_t **ctx);
77 RK_S32 (*vpuapi_mem_link)(VPUMemLinear_t *p);
78 RK_S32 (*vpuapi_mem_free)(VPUMemLinear_t *p);
79 
show_usage()80 static void show_usage()
81 {
82     printf("usage: vpu_apiDemo [options] input_file, \n\n");
83 
84     printf("Getting help:\n");
85     printf("-help  --print options of vpu api demo\n");
86 }
87 
show_help()88 static RK_S32 show_help()
89 {
90     RK_S32 i;
91     RK_S32 count = sizeof(vpuApiCmd) / sizeof(vpuApiCmd[0]);
92     VpuApiOptionInfo *opt = vpuApiCmd;
93 
94     printf("usage: vpu_apiDemo [opt] input_file, \n\n");
95     for (i = 0; i < count; i++)
96         printf("-%s  %-16s\t%s\n", opt[i].name, opt[i].argname, opt[i].help);
97 
98     return 0;
99 }
100 
parse_options(int argc,char ** argv,VpuApiDemoCmdContext_t * cmdCxt)101 static RK_S32 parse_options(int argc, char **argv, VpuApiDemoCmdContext_t *cmdCxt)
102 {
103     char *opt;
104     RK_S32 optindex, handleoptions = 1, ret = 0;
105 
106     if ((argc < 2) || (cmdCxt == NULL)) {
107         printf("vpu api demo, input parameter invalid\n");
108         show_usage();
109         return ERROR_INVALID_PARAM;
110     }
111 
112     /* parse options */
113     optindex = 1;
114     while (optindex < argc) {
115         opt = argv[optindex++];
116 
117         if (handleoptions && opt[0] == '-' && opt[1] != '\0') {
118             if (opt[1] == '-') {
119                 if (opt[2] != '\0') {
120                     opt++;
121                 } else {
122                     handleoptions = 0;
123                     continue;
124                 }
125             }
126 
127             opt++;
128 
129             switch (*opt) {
130             case 'i':
131                 if (argv[optindex]) {
132                     memcpy(cmdCxt->input_file, argv[optindex], strlen(argv[optindex]));
133                     cmdCxt->input_file[strlen(argv[optindex])] = '\0';
134                     cmdCxt->have_input = 1;
135                 } else {
136                     printf("input file is invalid\n");
137                     ret = -1;
138                     goto PARSE_OPINIONS_OUT;
139                 }
140                 break;
141             case 'o':
142                 if (argv[optindex]) {
143                     memcpy(cmdCxt->output_file, argv[optindex], strlen(argv[optindex]));
144                     cmdCxt->output_file[strlen(argv[optindex])] = '\0';
145                     cmdCxt->have_output = 1;
146                     break;
147                 } else {
148                     printf("out file is invalid\n");
149                     ret = -1;
150                     goto PARSE_OPINIONS_OUT;
151                 }
152             case 'w':
153                 if (argv[optindex]) {
154                     cmdCxt->width = atoi(argv[optindex]);
155                     break;
156                 } else {
157                     printf("input width is invalid\n");
158                     ret = -1;
159                     goto PARSE_OPINIONS_OUT;
160                 }
161             case 'h':
162                 if ((*(opt + 1) != '\0') && !strncmp(opt, "help", 4)) {
163                     show_help();
164                     ret = VPU_DEMO_PARSE_HELP_OK;
165                     goto PARSE_OPINIONS_OUT;
166                 } else if (argv[optindex]) {
167                     cmdCxt->height = atoi(argv[optindex]);
168                 } else {
169                     printf("input height is invalid\n");
170                     ret = -1;
171                     goto PARSE_OPINIONS_OUT;
172                 }
173                 break;
174             case 't':
175                 if (argv[optindex]) {
176                     cmdCxt->codec_type = atoi(argv[optindex]);
177                     break;
178                 } else {
179                     printf("input codec_type is invalid\n");
180                     ret = -1;
181                     goto PARSE_OPINIONS_OUT;
182                 }
183 
184             default:
185                 if ((*(opt + 1) != '\0') && argv[optindex]) {
186                     if (!strncmp(opt, "coding", 6)) {
187                         printf("coding, argv[optindex]: %s",
188                                argv[optindex]);
189                         cmdCxt->coding = atoi(argv[optindex]);
190                     } else if (!strncmp(opt, "vframes", 7)) {
191                         cmdCxt->record_frames = atoi(argv[optindex]);
192                     } else if (!strncmp(opt, "ss", 2)) {
193                         cmdCxt->record_start_ms = atoi(argv[optindex]);
194                     } else {
195                         ret = -1;
196                         goto PARSE_OPINIONS_OUT;
197                     }
198                 } else {
199                     ret = -1;
200                     goto PARSE_OPINIONS_OUT;
201                 }
202                 break;
203             }
204 
205             optindex += ret;
206         }
207     }
208 
209 PARSE_OPINIONS_OUT:
210     if (ret < 0) {
211         printf("vpu api demo, input parameter invalid\n");
212         show_usage();
213         return ERROR_INVALID_PARAM;
214     }
215     return ret;
216 }
217 
readBytesFromFile(RK_U8 * buf,RK_S32 aBytes,FILE * file)218 static RK_S32 readBytesFromFile(RK_U8 *buf, RK_S32 aBytes, FILE *file)
219 {
220     RK_S32 ret = 0;
221 
222     if ((NULL == buf) || (NULL == file) || (0 == aBytes)) {
223         return -1;
224     }
225 
226     ret = (RK_S32)fread(buf, 1, aBytes, file);
227     if (ret != aBytes) {
228         printf("read %d bytes from file fail\n", aBytes);
229         return -1;
230     }
231 
232     return 0;
233 }
234 
vpu_encode_demo(VpuApiDemoCmdContext_t * cmd)235 static RK_S32 vpu_encode_demo(VpuApiDemoCmdContext_t *cmd)
236 {
237     FILE *pInFile = NULL;
238     FILE *pOutFile = NULL;
239     RK_S32 nal = 0x00000001;
240     RK_S32 fileSize;
241     RK_S32 ret = 0;
242     RK_S32 size;
243     RK_U32 readOneFrameSize = 0;
244     EncoderOut_t    enc_out_yuv;
245     EncoderOut_t *enc_out = NULL;
246     VpuApiEncInput enc_in_strm;
247     VpuApiEncInput *api_enc_in = &enc_in_strm;
248     EncInputStream_t *enc_in = NULL;
249     EncParameter_t *enc_param = NULL;
250     RK_S64 fakeTimeUs = 0;
251     RK_U32 w_align = 0;
252     RK_U32 h_align = 0;
253 
254     int Format = ENC_INPUT_YUV420_PLANAR;
255 
256     if (cmd == NULL) {
257         return -1;
258     }
259 
260     if ((cmd->have_input == 0) || (cmd->width <= 0) || (cmd->height <= 0)
261         || (cmd->coding <= OMX_RK_VIDEO_CodingAutoDetect)) {
262         printf("Warning: missing needed parameters for vpu api demo\n");
263     }
264 
265     if (cmd->have_input) {
266         printf("input bitstream w: %d, h: %d, coding: %d(%s), path: %s\n",
267                cmd->width, cmd->height, cmd->coding,
268                cmd->codec_type == CODEC_DECODER ? "decode" : "encode",
269                cmd->input_file);
270 
271         pInFile = fopen(cmd->input_file, "rb");
272         if (pInFile == NULL) {
273             printf("input file not exsist\n");
274             ENCODE_ERR_RET(ERROR_INVALID_PARAM);
275         }
276     } else {
277         printf("please set input bitstream file\n");
278         ENCODE_ERR_RET(ERROR_INVALID_PARAM);
279     }
280 
281     if (cmd->have_output) {
282         printf("vpu api demo output file: %s\n",
283                cmd->output_file);
284         pOutFile = fopen(cmd->output_file, "wb");
285         if (pOutFile == NULL) {
286             printf("can not write output file\n");
287             ENCODE_ERR_RET(ERROR_INVALID_PARAM);
288         }
289     }
290 
291 #ifdef FOR_TEST_ENCODE
292     ctx = (struct VpuCodecContext *)malloc(sizeof(struct VpuCodecContext));
293     if (!ctx) {
294         printf("Input context has not been properly allocated");
295         return -1;
296     }
297     memset(ctx, 0, sizeof(struct VpuCodecContext));
298 
299     ctx->videoCoding = OMX_RK_VIDEO_CodingAVC;
300     ctx->codecType = CODEC_ENCODER;
301     ctx->width  = cmd->width;
302     ctx->height = cmd->height;
303 #endif
304 
305     fseek(pInFile, 0L, SEEK_END);
306     fileSize = ftell(pInFile);
307     fseek(pInFile, 0L, SEEK_SET);
308 
309     memset(&enc_in_strm, 0, sizeof(VpuApiEncInput));
310     enc_in = &enc_in_strm.stream;
311     enc_in->buf = NULL;
312 
313     memset(&enc_out_yuv, 0, sizeof(EncoderOut_t));
314     enc_out = &enc_out_yuv;
315     enc_out->data = (RK_U8 *)malloc(cmd->width * cmd->height);
316     if (enc_out->data == NULL) {
317         ENCODE_ERR_RET(ERROR_MEMORY);
318     }
319 
320     ret = vpuapi_open_ctx(&ctx);
321     if (ret || (ctx == NULL)) {
322         ENCODE_ERR_RET(ERROR_MEMORY);
323     }
324 
325     /*
326      ** now init vpu api context. codecType, codingType, width ,height
327      ** are all needed before init.
328     */
329     ctx->codecType = cmd->codec_type;
330     ctx->videoCoding = cmd->coding;
331     ctx->width = cmd->width;
332     ctx->height = cmd->height;
333     ctx->no_thread = 1;
334 
335     ctx->private_data = malloc(sizeof(EncParameter_t));
336     memset(ctx->private_data, 0, sizeof(EncParameter_t));
337 
338     enc_param = (EncParameter_t *)ctx->private_data;
339     enc_param->width        = cmd->width;
340     enc_param->height       = cmd->height;
341     enc_param->format       = ENC_INPUT_YUV420_PLANAR;
342     enc_param->rc_mode      = 0;
343     enc_param->bitRate      = 4000000;
344     enc_param->framerate    = 25;
345     enc_param->enableCabac  = 1;
346     enc_param->cabacInitIdc = 0;
347     enc_param->intraPicRate = 30;
348     enc_param->profileIdc   = 100;
349     enc_param->levelIdc     = 40;
350 
351     if ((ret = ctx->init(ctx, NULL, 0)) != 0) {
352         printf("init vpu api context fail, ret: 0x%X\n", ret);
353         ENCODE_ERR_RET(ERROR_INIT_VPU);
354     }
355 
356     /*
357      ** init of VpuCodecContext while running encode, it returns
358      ** sps and pps of encoder output, you need to save sps and pps
359      ** after init.
360     */
361     printf("encode init ok, sps len: %d\n", ctx->extradata_size);
362     if (pOutFile && (ctx->extradata_size > 0)) {
363         printf("dump %d bytes enc output stream to file\n",
364                ctx->extradata_size);
365 
366         /* save sps and pps */
367         fwrite(ctx->extradata, 1, ctx->extradata_size, pOutFile);
368         fflush(pOutFile);
369     }
370 
371     ret = ctx->control(ctx, VPU_API_ENC_SETFORMAT, &Format);
372     if (ret)
373         printf("VPU_API_ENC_SETFORMAT ret %d\n", ret);
374 
375     ret = ctx->control(ctx, VPU_API_ENC_GETCFG, enc_param);
376     if (ret)
377         printf("VPU_API_ENC_GETCFG ret %d\n", ret);
378 
379     enc_param->rc_mode = 1;
380 
381     ret = ctx->control(ctx, VPU_API_ENC_SETCFG, enc_param);
382     if (ret)
383         printf("VPU_API_ENC_SETCFG ret %d\n", ret);
384 
385     /*
386      ** vpu api encode process.
387     */
388     printf("init vpu api context ok, input yuv stream file size: %d\n", fileSize);
389     w_align = ((ctx->width + 15) & (~15));
390     h_align = ((ctx->height + 15) & (~15));
391     size = w_align * h_align * 3 / 2;
392     readOneFrameSize = ctx->width * ctx->height * 3 / 2;
393     printf("%d %d %d %d %d", ctx->width, ctx->height, w_align, h_align, size);
394     nal = BSWAP32(nal);
395 
396     do {
397         if (ftell(pInFile) >= fileSize) {
398             printf("read end of file, complete\n");
399             break;
400         }
401 
402         if (enc_in && (enc_in->size == 0)) {
403             if (enc_in->buf == NULL) {
404                 enc_in->buf = (RK_U8 *)(malloc)(size);
405                 if (enc_in->buf == NULL) {
406                     ENCODE_ERR_RET(ERROR_MEMORY);
407                 }
408                 api_enc_in->capability = size;
409             }
410 
411             if (api_enc_in->capability < ((RK_U32)size)) {
412                 enc_in->buf = (RK_U8 *)(realloc)((void *)(enc_in->buf), size);
413                 if (enc_in->buf == NULL) {
414                     ENCODE_ERR_RET(ERROR_MEMORY);
415                 }
416                 api_enc_in->capability = size;
417             }
418 
419             if (readBytesFromFile(enc_in->buf, readOneFrameSize, pInFile)) {
420                 break;
421             } else {
422                 enc_in->size = size;
423                 enc_in->timeUs = fakeTimeUs;
424                 fakeTimeUs += 40000;
425             }
426 
427             printf("read one frame, size: %d, timeUs: %lld, filePos: %ld\n",
428                    enc_in->size, enc_in->timeUs, ftell(pInFile));
429         }
430 
431         if ((ret = ctx->encode(ctx, enc_in, enc_out)) < 0) {
432             ENCODE_ERR_RET(ERROR_VPU_DECODE);
433         } else {
434             enc_in->size = 0;  // TODO encode completely, and set enc_in->size to 0
435             printf("vpu encode one frame, out len: %d, left size: %d\n",
436                    enc_out->size, enc_in->size);
437 
438             /*
439              ** encoder output stream is raw bitstream, you need to add nal
440              ** head by yourself.
441             */
442             if ((enc_out->size) && (enc_out->data)) {
443                 if (pOutFile) {
444                     printf("dump %d bytes enc output stream to file\n",
445                            enc_out->size);
446                     //fwrite((RK_U8*)&nal, 1, 4, pOutFile);  // because output stream have start code, so here mask this code
447                     fwrite(enc_out->data, 1, enc_out->size, pOutFile);
448                     fflush(pOutFile);
449                 }
450 
451                 enc_out->size = 0;
452             }
453         }
454 
455         usleep(3000);
456     } while (1);
457 
458 ENCODE_OUT:
459     if (enc_in && enc_in->buf) {
460         free(enc_in->buf);
461         enc_in->buf = NULL;
462     }
463     if (enc_out && (enc_out->data)) {
464         free(enc_out->data);
465         enc_out->data = NULL;
466     }
467     if (ctx) {
468         if (ctx->private_data) {
469             free(ctx->private_data);
470             ctx->private_data = NULL;
471         }
472         vpuapi_close_ctx(&ctx);
473         ctx = NULL;
474     }
475     if (pInFile) {
476         fclose(pInFile);
477         pInFile = NULL;
478     }
479     if (pOutFile) {
480         fclose(pOutFile);
481         pOutFile = NULL;
482     }
483 
484     if (ret) {
485         printf("encode demo fail, err: %d\n", ret);
486     } else {
487         printf("encode demo complete OK.\n");
488     }
489     return ret;
490 
491 }
492 
vpu_decode_demo(VpuApiDemoCmdContext_t * cmd)493 static RK_S32 vpu_decode_demo(VpuApiDemoCmdContext_t *cmd)
494 {
495     FILE *pInFile = NULL;
496     FILE *pOutFile = NULL;
497     RK_S32 fileSize = 0, pkt_size = 0;
498     RK_S32 ret = 0;
499     RK_U32 frame_count = 0;
500     DecoderOut_t    decOut;
501     VideoPacket_t demoPkt;
502     VideoPacket_t *pkt = NULL;
503     DecoderOut_t *pOut = NULL;
504     VPU_FRAME *frame = NULL;
505     RK_S64 fakeTimeUs = 0;
506     RK_U8 *pExtra = NULL;
507     RK_U32 extraSize = 0;
508     RK_U32 wAlign16  = 0;
509     RK_U32 hAlign16  = 0;
510     RK_U32 frameSize = 0;
511 
512     if (cmd == NULL) {
513         return -1;
514     }
515 
516     if ((cmd->have_input == 0) || (cmd->width <= 0) || (cmd->height <= 0)
517         || (cmd->coding <= OMX_RK_VIDEO_CodingAutoDetect)) {
518         printf("Warning: missing needed parameters for vpu api demo\n");
519     }
520 
521     if (cmd->have_input) {
522         printf("input bitstream w: %d, h: %d, coding: %d(%s), path: %s\n",
523                cmd->width, cmd->height, cmd->coding,
524                cmd->codec_type == CODEC_DECODER ? "decode" : "encode",
525                cmd->input_file);
526 
527         pInFile = fopen(cmd->input_file, "rb");
528         if (pInFile == NULL) {
529             printf("input file not exsist\n");
530             DECODE_ERR_RET(ERROR_INVALID_PARAM);
531         }
532     } else {
533         printf("please set input bitstream file\n");
534         DECODE_ERR_RET(ERROR_INVALID_PARAM);
535     }
536 
537     if (cmd->have_output) {
538         printf("vpu api demo output file: %s\n",
539                cmd->output_file);
540         pOutFile = fopen(cmd->output_file, "wb");
541         if (pOutFile == NULL) {
542             printf("can not write output file\n");
543             DECODE_ERR_RET(ERROR_INVALID_PARAM);
544         }
545         if (cmd->record_frames == 0)
546             cmd->record_frames = 5;
547     }
548 
549     fseek(pInFile, 0L, SEEK_END);
550     fileSize = ftell(pInFile);
551     fseek(pInFile, 0L, SEEK_SET);
552 
553     memset(&demoPkt, 0, sizeof(VideoPacket_t));
554     pkt = &demoPkt;
555     pkt->data = NULL;
556     pkt->pts = VPU_API_NOPTS_VALUE;
557     pkt->dts = VPU_API_NOPTS_VALUE;
558 
559     memset(&decOut, 0, sizeof(DecoderOut_t));
560     pOut = &decOut;
561 
562     ret = vpuapi_open_ctx(&ctx);
563     if (ret || (ctx == NULL)) {
564         DECODE_ERR_RET(ERROR_MEMORY);
565     }
566 
567     /*
568      ** read codec extra data from input stream file.
569     */
570     if (readBytesFromFile((RK_U8 *)(&extraSize), 4, pInFile)) {
571         DECODE_ERR_RET(ERROR_IO);
572     }
573 
574     printf("codec extra data size: %d\n", extraSize);
575 
576     pExtra = (RK_U8 *)(malloc)(extraSize);
577     if (pExtra == NULL) {
578         DECODE_ERR_RET(ERROR_MEMORY);
579     }
580     memset(pExtra, 0, extraSize);
581 
582     if (readBytesFromFile(pExtra, extraSize, pInFile)) {
583         DECODE_ERR_RET(ERROR_IO);
584     }
585 
586     /*
587      ** now init vpu api context. codecType, codingType, width ,height
588      ** are all needed before init.
589     */
590     ctx->codecType = cmd->codec_type;
591     ctx->videoCoding = cmd->coding;
592     ctx->width = cmd->width;
593     ctx->height = cmd->height;
594     ctx->no_thread = 1;
595 
596     if ((ret = ctx->init(ctx, pExtra, extraSize)) != 0) {
597         printf("init vpu api context fail, ret: 0x%X\n", ret);
598         DECODE_ERR_RET(ERROR_INIT_VPU);
599     }
600 
601     /*
602      ** vpu api decoder process.
603     */
604     printf("init vpu api context ok, fileSize: %d\n", fileSize);
605 
606     do {
607         if (ftell(pInFile) >= fileSize) {
608             printf("read end of file, complete\n");
609             break;
610         }
611 
612         if (pkt && (pkt->size == 0)) {
613             if (readBytesFromFile((RK_U8 *)(&pkt_size), 4, pInFile)) {
614                 break;
615             }
616 
617             if (pkt->data == NULL) {
618                 pkt->data = (RK_U8 *)(malloc)(pkt_size);
619                 if (pkt->data == NULL) {
620                     DECODE_ERR_RET(ERROR_MEMORY);
621                 }
622                 pkt->capability = pkt_size;
623             }
624 
625             if (pkt->capability < ((RK_U32)pkt_size)) {
626                 pkt->data = (RK_U8 *)(realloc)((void *)(pkt->data), pkt_size);
627                 if (pkt->data == NULL) {
628                     DECODE_ERR_RET(ERROR_MEMORY);
629                 }
630                 pkt->capability = pkt_size;
631             }
632 
633             if (readBytesFromFile(pkt->data, pkt_size, pInFile)) {
634                 break;
635             } else {
636                 pkt->size = pkt_size;
637                 pkt->pts = fakeTimeUs;
638                 fakeTimeUs += 40000;
639             }
640 
641             printf("read one packet, size: %d, pts: %lld, filePos: %ld\n",
642                    pkt->size, pkt->pts, ftell(pInFile));
643         }
644 
645         /* note: must set out put size to 0 before do decoder. */
646         pOut->size = 0;
647 
648         if (ctx->decode_sendstream(ctx, pkt) != 0) {
649             printf("send packet failed");
650             DECODE_ERR_RET(ERROR_VPU_DECODE);
651         }
652 
653 
654         if ((ret = ctx->decode_getframe(ctx, pOut)) != 0) {
655             printf("get decoded data failed\n");
656             DECODE_ERR_RET(ERROR_VPU_DECODE);
657         } else {
658             printf("vpu decode one frame, out len: %d, left size: %d\n",
659                    pOut->size, pkt->size);
660 
661             /*
662              ** both virtual and physical address of the decoded frame are contained
663              ** in structure named VPU_FRAME, if you want to use virtual address, make
664              ** sure you have done VPUMemLink before.
665             */
666             if ((pOut->size) && (pOut->data)) {
667                 frame = (VPU_FRAME *)(pOut->data);
668                 vpuapi_mem_link(&frame->vpumem);
669                 wAlign16 = ((frame->DisplayWidth + 15) & (~15));
670                 hAlign16 = ((frame->DisplayHeight + 15) & (~15));
671                 frameSize = wAlign16 * hAlign16 * 3 / 2;
672 
673                 if (pOutFile && (frame_count++ < cmd->record_frames)) {
674                     printf("write %d frame(yuv420sp) data, %d bytes to file\n",
675                            frame_count, frameSize);
676 
677                     fwrite((RK_U8 *)(frame->vpumem.vir_addr), 1, frameSize, pOutFile);
678                     fflush(pOutFile);
679                 }
680 
681                 /*
682                  ** remember use VPUFreeLinear to free, other wise memory leak will
683                  ** give you a surprise.
684                 */
685                 vpuapi_mem_free(&frame->vpumem);
686                 // NOTE: pOut->data is malloc from vpu_api we need to free it.
687                 free(pOut->data);
688                 pOut->data = NULL;
689                 pOut->size = 0;
690             }
691         }
692 
693         usleep(3000);
694     } while (!(ctx->decoder_err));
695 
696 DECODE_OUT:
697     if (pkt && pkt->data) {
698         free(pkt->data);
699         pkt->data = NULL;
700     }
701     if (pOut && (pOut->data)) {
702         free(pOut->data);
703         pOut->data = NULL;
704     }
705     if (pExtra) {
706         free(pExtra);
707         pExtra = NULL;
708     }
709     if (ctx) {
710         vpuapi_close_ctx(&ctx);
711         ctx = NULL;
712     }
713     if (pInFile) {
714         fclose(pInFile);
715         pInFile = NULL;
716     }
717     if (pOutFile) {
718         fclose(pOutFile);
719         pOutFile = NULL;
720     }
721 
722     if (ret) {
723         printf("decode demo fail, err: %d\n", ret);
724     } else {
725         printf("encode demo complete OK.\n");
726     }
727     return ret;
728 }
729 
730 /* vpu_api is only on Android platform */
main(int argc,char ** argv)731 int main(int argc, char **argv)
732 {
733     RK_S32 ret = 0;
734     VpuApiDemoCmdContext_t demoCmdCtx;
735     VpuApiDemoCmdContext_t *cmd = NULL;
736 
737     printf("/*******  vpu api demo in *******/\n");
738     if (argc == 1) {
739         show_usage();
740         return 0;
741     }
742 
743     /* open library for access */
744     vpuapi_hdl = dlopen("libvpu.so", RTLD_LAZY | RTLD_GLOBAL);
745     if (NULL == vpuapi_hdl) {
746         printf("failed to open libvpu.so\n");
747         ret = -1;
748         goto DEMO_OUT;
749     }
750 
751     vpuapi_open_ctx = (RK_S32 (*)(VpuCodecContext_t **ctx))dlsym(vpuapi_hdl, "vpu_open_context");
752     vpuapi_close_ctx = (RK_S32 (*)(VpuCodecContext_t **ctx))dlsym(vpuapi_hdl, "vpu_close_context");
753     vpuapi_mem_link = (RK_S32 (*)(VPUMemLinear_t * p))dlsym(vpuapi_hdl, "VPUMemLink");
754     vpuapi_mem_free = (RK_S32 (*)(VPUMemLinear_t * p))dlsym(vpuapi_hdl, "VPUFreeLinear");
755 
756     if (NULL == vpuapi_open_ctx || NULL == vpuapi_close_ctx ||
757         NULL == vpuapi_mem_link || NULL == vpuapi_mem_free) {
758         printf("failed to open vpu_open_context %p vpu_close_context %p\n",
759                vpuapi_open_ctx, vpuapi_close_ctx);
760         printf("failed to open VPUMemLink %p VPUFreeLinear %p\n",
761                vpuapi_mem_link, vpuapi_mem_free);
762         ret = -1;
763         goto DEMO_OUT;
764     }
765 
766     printf("get vpuapi handle %p vpu_open_context %p vpu_close_context %p\n",
767            vpuapi_hdl, vpuapi_open_ctx, vpuapi_close_ctx);
768 
769     cmd = &demoCmdCtx;
770     memset(cmd, 0, sizeof(VpuApiDemoCmdContext_t));
771     cmd->codec_type = CODEC_DECODER;
772     if ((ret = parse_options(argc, argv, cmd)) != 0) {
773         if (ret == VPU_DEMO_PARSE_HELP_OK) {
774             return 0;
775         }
776 
777         printf("parse_options fail\n\n");
778         show_usage();
779         DEMO_ERR_RET(ERROR_INVALID_PARAM);
780     }
781 
782     switch (cmd->codec_type) {
783     case CODEC_DECODER : {
784         ret = vpu_decode_demo(cmd);
785     } break;
786     case CODEC_ENCODER : {
787         ret = vpu_encode_demo(cmd);
788     } break;
789     default : {
790         ret = ERROR_INVALID_PARAM;
791     } break;
792     }
793 
794 DEMO_OUT:
795     if (ret) {
796         printf("vpu api demo fail, err: %d\n", ret);
797         if (vpuapi_hdl) {
798             dlclose(vpuapi_hdl);
799             vpuapi_hdl = NULL;
800         }
801     } else {
802         printf("vpu api demo complete OK.\n");
803     }
804     return ret;
805 }
806