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