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