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