From 52d5ffb33228f5c8e9eb33e940b7f659e0275fff Mon Sep 17 00:00:00 2001 From: ChenHengming Date: Wed, 12 Aug 2015 03:34:28 +0000 Subject: [PATCH] [vpu_api_test]: add vpu_api_demo for testing and add msleep to mpp_time.h git-svn-id: https://10.10.10.66:8443/svn/MediaProcessPlatform/trunk/mpp@73 6e48237b-75ef-9749-8fc9-41990f28c85a --- CMakeLists.txt | 5 + mpp/CMakeLists.txt | 4 +- osal/inc/mpp_thread.h | 2 - osal/inc/mpp_time.h | 11 + osal/test/mpp_thread_test.c | 1 + test/CMakeLists.txt | 24 ++ test/vpu_api_test.c | 761 ++++++++++++++++++++++++++++++++++++ 7 files changed, 804 insertions(+), 4 deletions(-) create mode 100644 test/CMakeLists.txt create mode 100644 test/vpu_api_test.c diff --git a/CMakeLists.txt b/CMakeLists.txt index 8bbb07f1..bf63a172 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -351,3 +351,8 @@ add_subdirectory(osal) # Media Process Platform include include_directories(mpp/inc) add_subdirectory(mpp) + +# ---------------------------------------------------------------------------- +# test / demo +# ---------------------------------------------------------------------------- +add_subdirectory(test) diff --git a/mpp/CMakeLists.txt b/mpp/CMakeLists.txt index 03141634..f91fe048 100644 --- a/mpp/CMakeLists.txt +++ b/mpp/CMakeLists.txt @@ -23,8 +23,8 @@ add_library(mpp STATIC mpp_info.cpp ) -target_link_libraries(mpp osal) - add_subdirectory(legacy) add_subdirectory(test) + +target_link_libraries(mpp mpp_legacy osal) diff --git a/osal/inc/mpp_thread.h b/osal/inc/mpp_thread.h index 4271f6a7..a2c0430c 100644 --- a/osal/inc/mpp_thread.h +++ b/osal/inc/mpp_thread.h @@ -30,9 +30,7 @@ * NOTE: POSIX Threads for Win32 * Downloaded from http://www.sourceware.org/pthreads-win32/ */ -#include #include "pthread.h" -#define sleep Sleep #pragma comment(lib, "pthreadVC2.lib") #else diff --git a/osal/inc/mpp_time.h b/osal/inc/mpp_time.h index d0fa08ed..ebfb0da6 100644 --- a/osal/inc/mpp_time.h +++ b/osal/inc/mpp_time.h @@ -19,6 +19,17 @@ #include "rk_type.h" +// TODO: add usleep function on windows + +#if defined(_WIN32) && !defined(__MINGW32CE__) +#include +#define msleep Sleep +#define sleep(x) Sleep((x)*1000) +#else +#include +#define msleep(x) usleep((x)*1000) +#endif + #ifdef __cplusplus extern "C" { #endif diff --git a/osal/test/mpp_thread_test.c b/osal/test/mpp_thread_test.c index aef85892..ddf8bd1a 100644 --- a/osal/test/mpp_thread_test.c +++ b/osal/test/mpp_thread_test.c @@ -25,6 +25,7 @@ #include "mpp_log.h" #include "mpp_thread.h" +#include "mpp_time.h" // TODO: add thread mutex and condition test case diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt new file mode 100644 index 00000000..63d1365a --- /dev/null +++ b/test/CMakeLists.txt @@ -0,0 +1,24 @@ +# vim: syntax=cmake +# ---------------------------------------------------------------------------- +# mpp built-in unit test case +# ---------------------------------------------------------------------------- +# macro for adding mpp sub-module unit test +macro(add_mpp_test module) + set(test_name ${module}_test) + string(TOUPPER ${test_name} test_tag) + #message(STATUS "moduule : ${module}") + #message(STATUS "test_name : ${test_name}") + #message(STATUS "test_tag : ${test_tag}") + + option(${test_tag} "Build mpp ${module} unit test" ON) + if(${test_tag}) + add_executable(${test_name} ${test_name}.c) + target_link_libraries(${test_name} mpp) + install(TARGETS ${test_name} RUNTIME DESTINATION ${TEST_INSTALL_DIR}) + endif() +endmacro() + +# info system unit test +add_mpp_test(vpu_api) + + diff --git a/test/vpu_api_test.c b/test/vpu_api_test.c new file mode 100644 index 00000000..ce56bcf6 --- /dev/null +++ b/test/vpu_api_test.c @@ -0,0 +1,761 @@ +/* + * Copyright 2010 Rockchip Electronics S.LSI Co. LTD + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#define LOG_TAG "vpu_api_demo" + +#include +#include +#include + +#include "mpp_log.h" +#include "mpp_time.h" + +#include "vpu_api.h" + +static RK_U32 VPU_API_DEMO_DEBUG_DISABLE = 0; + +#define BSWAP32(x) \ + ((((x) & 0xff000000) >> 24) | (((x) & 0x00ff0000) >> 8) | \ + (((x) & 0x0000ff00) << 8) | (((x) & 0x000000ff) << 24)) + +#define DEMO_ERR_RET(err) do { ret = err; goto DEMO_OUT; } while (0) +#define DECODE_ERR_RET(err) do { ret = err; goto DECODE_OUT; } while (0) +#define ENCODE_ERR_RET(err) do { ret = err; goto ENCODE_OUT; } while (0) + + +typedef enum VPU_API_DEMO_RET { + VPU_DEMO_OK = 0, + VPU_DEMO_PARSE_HELP_OK = 1, + + VPU_DEMO_ERROR_BASE = -100, + ERROR_INVALID_PARAM = VPU_DEMO_ERROR_BASE - 1, + ERROR_INVALID_STREAM = VPU_DEMO_ERROR_BASE - 2, + ERROR_IO = VPU_DEMO_ERROR_BASE - 3, + ERROR_MEMORY = VPU_DEMO_ERROR_BASE - 4, + ERROR_INIT_VPU = VPU_DEMO_ERROR_BASE - 5, + + ERROR_VPU_DECODE = VPU_DEMO_ERROR_BASE - 90, +} VPU_API_DEMO_RET; + +typedef struct VpuApiCmd { + RK_U8* name; + RK_U8* argname; + RK_U8* help; +} VpuApiCmd_t; + +typedef struct VpuApiDemoCmdContext { + RK_U32 width; + RK_U32 height; + CODEC_TYPE codec_type; + OMX_RK_VIDEO_CODINGTYPE coding; + RK_U8 input_file[200]; + RK_U8 output_file[200]; + RK_U8 have_input; + RK_U8 have_output; + RK_U8 disable_debug; + RK_U32 record_frames; + RK_S64 record_start_ms; +} VpuApiDemoCmdContext_t; + +typedef struct VpuApiEncInput { + EncInputStream_t stream; + RK_U32 capability; +} VpuApiEncInput; + +static VpuApiCmd_t vpuApiCmd[] = { + {"i", "input_file", "input bitstream file"}, + {"o", "output_file", "output bitstream file, "}, + {"w", "width", "the width of input bitstream"}, + {"h", "height", "the height of input bitstream"}, + {"t", "codec_type", "the codec type, dec: deoder, enc: encoder, default: decoder"}, + {"coding", "coding_type", "encoding type of the bitstream"}, + {"vframes", "number", "set the number of video frames to record"}, + {"ss", "time_off", "set the start time offset, use Ms as the unit."}, + {"d", "disable", "disable the debug output info."}, +}; + +static void show_usage() +{ + mpp_log("usage: vpu_apiDemo [options] input_file, \n\n"); + + mpp_log("Getting help:\n"); + mpp_log("-help --print options of vpu api demo\n"); +} + +static RK_S32 show_help() +{ + mpp_log("usage: vpu_apiDemo [options] input_file, \n\n"); + + RK_S32 i =0; + RK_S32 n = sizeof(vpuApiCmd)/sizeof(VpuApiCmd_t); + for (i = 0; i < n; i++) { + mpp_log("-%s %s\t\t%s\n", + vpuApiCmd[i].name, vpuApiCmd[i].argname, vpuApiCmd[i].help); + } + + return 0; +} + +static RK_S32 parse_options(int argc, char **argv, VpuApiDemoCmdContext_t* cmdCxt) +{ + RK_S8 *opt; + RK_S32 optindex, handleoptions = 1, ret =0; + + if ((argc <2) || (cmdCxt == NULL)) { + mpp_log("vpu api demo, input parameter invalid\n"); + show_usage(); + return ERROR_INVALID_PARAM; + } + + /* parse options */ + optindex = 1; + while (optindex < argc) { + opt = argv[optindex++]; + + if (handleoptions && opt[0] == '-' && opt[1] != '\0') { + if (opt[1] == '-') { + if (opt[2] != '\0') { + opt++; + } else { + handleoptions = 0; + continue; + } + } + + opt++; + + switch (*opt) { + case 'i': + if (argv[optindex]) { + memcpy(cmdCxt->input_file, argv[optindex], strlen(argv[optindex])); + cmdCxt->input_file[strlen(argv[optindex])] = '\0'; + cmdCxt->have_input = 1; + } else { + mpp_log("input file is invalid\n"); + ret = -1; + goto PARSE_OPINIONS_OUT; + } + break; + case 'o': + if (argv[optindex]) { + memcpy(cmdCxt->output_file, argv[optindex], strlen(argv[optindex])); + cmdCxt->output_file[strlen(argv[optindex])] = '\0'; + cmdCxt->have_output = 1; + break; + } else { + mpp_log("out file is invalid\n"); + ret = -1; + goto PARSE_OPINIONS_OUT; + } + case 'd': + cmdCxt->disable_debug = 1; + break; + case 'w': + if (argv[optindex]) { + cmdCxt->width = atoi(argv[optindex]); + break; + } else { + mpp_log("input width is invalid\n"); + ret = -1; + goto PARSE_OPINIONS_OUT; + } + case 'h': + if ((*(opt+1) != '\0') && !strncmp(opt, "help", 4)) { + show_help(); + ret = VPU_DEMO_PARSE_HELP_OK; + goto PARSE_OPINIONS_OUT; + } else if (argv[optindex]) { + cmdCxt->height = atoi(argv[optindex]); + } else { + mpp_log("input height is invalid\n"); + ret = -1; + goto PARSE_OPINIONS_OUT; + } + break; + case 't': + if (argv[optindex]) { + cmdCxt->codec_type = atoi(argv[optindex]); + break; + } else { + mpp_log("input codec_type is invalid\n"); + ret = -1; + goto PARSE_OPINIONS_OUT; + } + + default: + if ((*(opt+1) != '\0') && argv[optindex]) { + if (!strncmp(opt, "coding", 6)) { + mpp_log("coding, argv[optindex]: %s", + argv[optindex]); + cmdCxt->coding = atoi(argv[optindex]); + } else if (!strncmp(opt, "vframes", 7)) { + cmdCxt->record_frames = atoi(argv[optindex]); + } else if (!strncmp(opt, "ss", 2)) { + cmdCxt->record_start_ms = atoi(argv[optindex]); + } else { + ret = -1; + goto PARSE_OPINIONS_OUT; + } + } else { + ret = -1; + goto PARSE_OPINIONS_OUT; + } + break; + } + + optindex += ret; + } + } + +PARSE_OPINIONS_OUT: + if (ret <0) { + mpp_log("vpu api demo, input parameter invalid\n"); + show_usage(); + return ERROR_INVALID_PARAM; + } + return ret; +} + +static RK_S32 readBytesFromFile(RK_U8* buf, RK_S32 aBytes, FILE* file) +{ + if ((NULL == buf) || (NULL == file) || (0 == aBytes)) { + return -1; + } + + RK_S32 ret = (RK_S32)fread(buf, 1, aBytes, file); + if(ret != aBytes) + { + mpp_log("read %d bytes from file fail\n", aBytes); + return -1; + } + + return 0; +} + +static RK_S32 vpu_encode_demo(VpuApiDemoCmdContext_t *cmd) +{ + if (cmd == NULL) { + return -1; + } + + FILE* pInFile = NULL; + FILE* pOutFile = NULL; + struct VpuCodecContext *ctx = NULL; + RK_S32 nal = 0x00000001; + RK_S32 fileSize, frame_count, ret, size; + EncoderOut_t enc_out_yuv; + EncoderOut_t *enc_out = NULL; + VpuApiEncInput enc_in_strm; + VpuApiEncInput *api_enc_in = &enc_in_strm; + EncInputStream_t *enc_in =NULL; + EncParameter_t *enc_param = NULL; + RK_S64 fakeTimeUs =0; + int Format = VPU_H264ENC_YUV420_SEMIPLANAR; + + if ((cmd->have_input == 0) || (cmd->width <=0) || (cmd->height <=0) + || (cmd->coding <= OMX_RK_VIDEO_CodingAutoDetect)) { + mpp_log("Warning: missing needed parameters for vpu api demo\n"); + } + + if (cmd->have_input) { + mpp_log("input bitstream w: %d, h: %d, coding: %d(%s), path: %s\n", + cmd->width, cmd->height, cmd->coding, + cmd->codec_type == CODEC_DECODER ? "decode" : "encode", + cmd->input_file); + + pInFile = fopen(cmd->input_file, "rb"); + if (pInFile == NULL) { + mpp_log("input file not exsist\n"); + ENCODE_ERR_RET(ERROR_INVALID_PARAM); + } + } else { + mpp_log("please set input bitstream file\n"); + ENCODE_ERR_RET(ERROR_INVALID_PARAM); + } + + if (cmd->have_output) { + mpp_log("vpu api demo output file: %s\n", + cmd->output_file); + pOutFile = fopen(cmd->output_file, "wb"); + if (pOutFile == NULL) { + mpp_log("can not write output file\n"); + ENCODE_ERR_RET(ERROR_INVALID_PARAM); + } + } + + fseek(pInFile, 0L, SEEK_END); + fileSize = ftell(pInFile); + fseek(pInFile, 0L, SEEK_SET); + + memset(&enc_in_strm, 0, sizeof(VpuApiEncInput)); + enc_in = &enc_in_strm.stream; + enc_in->buf = NULL; + + memset(&enc_out_yuv, 0, sizeof(EncoderOut_t)); + enc_out = &enc_out_yuv; + enc_out->data = (RK_U8*)malloc(cmd->width * cmd->height); + if (enc_out->data == NULL) { + ENCODE_ERR_RET(ERROR_MEMORY); + } + + ret = vpu_open_context(&ctx); + if (ret || (ctx ==NULL)) { + ENCODE_ERR_RET(ERROR_MEMORY); + } + + /* + ** now init vpu api context. codecType, codingType, width ,height + ** are all needed before init. + */ + ctx->codecType = cmd->codec_type; + ctx->videoCoding = cmd->coding; + ctx->width = cmd->width; + ctx->height = cmd->height; + ctx->no_thread = 1; + + ctx->private_data = malloc(sizeof(EncParameter_t)); + memset(ctx->private_data,0,sizeof(EncParameter_t)); + + enc_param = (EncParameter_t*)ctx->private_data; + enc_param->width = cmd->width; + enc_param->height = cmd->height; + enc_param->bitRate = 100000; + enc_param->framerate = 25; + enc_param->enableCabac = 0; + enc_param->cabacInitIdc = 0; + enc_param->intraPicRate = 30; + + if ((ret = ctx->init(ctx, NULL, 0)) !=0) { + mpp_log("init vpu api context fail, ret: 0x%X\n", ret); + ENCODE_ERR_RET(ERROR_INIT_VPU); + } + + /* + ** init of VpuCodecContext while running encode, it returns + ** sps and pps of encoder output, you need to save sps and pps + ** after init. + */ + mpp_log("encode init ok, sps len: %d\n", ctx->extradata_size); + if(pOutFile && (ctx->extradata_size >0)) { + mpp_log("dump %d bytes enc output stream to file\n", + ctx->extradata_size); + + /* save sps and pps */ + fwrite(ctx->extradata, 1, ctx->extradata_size, pOutFile); + fflush(pOutFile); + } + + ctx->control(ctx,VPU_API_ENC_SETFORMAT,&Format); + + ctx->control(ctx,VPU_API_ENC_GETCFG,enc_param); + enc_param->rc_mode = 1; + ctx->control(ctx,VPU_API_ENC_SETCFG,enc_param); + /* + ** vpu api encode process. + */ + mpp_log("init vpu api context ok, input yuv stream file size: %d\n", fileSize); + RK_U32 w_align = ((ctx->width + 15) & (~15)); + RK_U32 h_align = ((ctx->height + 15) & (~15)); + size = w_align * h_align * 3/2; + nal = BSWAP32(nal); + + do { + if (ftell(pInFile) >=fileSize) { + mpp_log("read end of file, complete\n"); + break; + } + + if (enc_in && (enc_in->size ==0)) { + if (enc_in->buf == NULL) { + enc_in->buf = (RK_U8*)(malloc)(size); + if (enc_in->buf == NULL) { + ENCODE_ERR_RET(ERROR_MEMORY); + } + api_enc_in->capability = size; + } + + if (api_enc_in->capability <((RK_U32)size)) { + enc_in->buf = (RK_U8*)(realloc)((void*)(enc_in->buf), size); + if (enc_in->buf == NULL) { + ENCODE_ERR_RET(ERROR_MEMORY); + } + api_enc_in->capability = size; + } + + if (readBytesFromFile(enc_in->buf, size, pInFile)) { + break; + } else { + enc_in->size = size; + enc_in->timeUs = fakeTimeUs; + fakeTimeUs +=40000; + } + + mpp_log("read one frame, size: %d, timeUs: %lld, filePos: %ld\n", + enc_in->size, enc_in->timeUs , ftell(pInFile)); + } + + if ((ret = ctx->encode(ctx, enc_in, enc_out)) < 0) { + ENCODE_ERR_RET(ERROR_VPU_DECODE); + } else { + mpp_log("vpu encode one frame, out len: %d, left size: %d\n", + enc_out->size, enc_in->size); + + /* + ** encoder output stream is raw bitstream, you need to add nal + ** head by yourself. + */ + if ((enc_out->size) && (enc_out->data)) { + if(pOutFile) { + mpp_log("dump %d bytes enc output stream to file\n", + enc_out->size); + fwrite((RK_U8*)&nal, 1, 4, pOutFile); + fwrite(enc_out->data, 1, enc_out->size, pOutFile); + fflush(pOutFile); + } + + enc_out->size = 0; + } + } + + msleep(3); + }while(1); + +ENCODE_OUT: + if (enc_in && enc_in->buf) { + free(enc_in->buf); + enc_in->buf = NULL; + } + if (enc_out && (enc_out->data)) { + free(enc_out->data); + enc_out->data = NULL; + } + if (ctx) { + if (ctx->private_data) { + free(ctx->private_data); + ctx->private_data = NULL; + } + vpu_close_context(&ctx); + ctx = NULL; + } + if (pInFile) { + fclose(pInFile); + pInFile = NULL; + } + if (pOutFile) { + fclose(pOutFile); + pOutFile = NULL; + } + + if (ret) { + mpp_log("encode demo fail, err: %d\n", ret); + } else { + mpp_log("encode demo complete OK.\n"); + } + return ret; + +} + +static RK_S32 vpu_decode_demo(VpuApiDemoCmdContext_t *cmd) +{ + if (cmd == NULL) { + return -1; + } + + FILE* pInFile = NULL; + FILE* pOutFile = NULL; + struct VpuCodecContext* ctx = NULL; + RK_S32 fileSize =0, pkt_size =0; + RK_S32 ret = 0, frame_count = 0; + DecoderOut_t decOut; + VideoPacket_t demoPkt; + VideoPacket_t* pkt =NULL; + DecoderOut_t *pOut = NULL; +#if HAVE_VPU_FRME + VPU_FRAME *frame = NULL; +#endif + RK_S64 fakeTimeUs =0; + RK_U8* pExtra = NULL; + RK_U32 extraSize = 0; + + if ((cmd->have_input == 0) || (cmd->width <=0) || (cmd->height <=0) + || (cmd->coding <= OMX_RK_VIDEO_CodingAutoDetect)) { + mpp_log("Warning: missing needed parameters for vpu api demo\n"); + } + + if (cmd->have_input) { + mpp_log("input bitstream w: %d, h: %d, coding: %d(%s), path: %s\n", + cmd->width, cmd->height, cmd->coding, + cmd->codec_type == CODEC_DECODER ? "decode" : "encode", + cmd->input_file); + + pInFile = fopen(cmd->input_file, "rb"); + if (pInFile == NULL) { + mpp_log("input file not exsist\n"); + DECODE_ERR_RET(ERROR_INVALID_PARAM); + } + } else { + mpp_log("please set input bitstream file\n"); + DECODE_ERR_RET(ERROR_INVALID_PARAM); + } + + if (cmd->have_output) { + mpp_log("vpu api demo output file: %s\n", + cmd->output_file); + pOutFile = fopen(cmd->output_file, "wb"); + if (pOutFile == NULL) { + mpp_log("can not write output file\n"); + DECODE_ERR_RET(ERROR_INVALID_PARAM); + } + if (cmd->record_frames ==0) + cmd->record_frames = 5; + } + + fseek(pInFile, 0L, SEEK_END); + fileSize = ftell(pInFile); + fseek(pInFile, 0L, SEEK_SET); + + memset(&demoPkt, 0, sizeof(VideoPacket_t)); + pkt = &demoPkt; + pkt->data = NULL; + pkt->pts = VPU_API_NOPTS_VALUE; + pkt->dts = VPU_API_NOPTS_VALUE; + + memset(&decOut, 0, sizeof(DecoderOut_t)); + pOut = &decOut; + +#if HAVE_VPU_FRAME + pOut->data = (RK_U8*)(malloc)(sizeof(VPU_FRAME)); + if (pOut->data ==NULL) { + DECODE_ERR_RET(ERROR_MEMORY); + } + memset(pOut->data, 0, sizeof(VPU_FRAME)); +#endif + + ret = vpu_open_context(&ctx); + if (ret || (ctx ==NULL)) { + DECODE_ERR_RET(ERROR_MEMORY); + } + + /* + ** read codec extra data from input stream file. + */ + if (readBytesFromFile((RK_U8*)(&extraSize), 4, pInFile)) { + DECODE_ERR_RET(ERROR_IO); + } + + mpp_log("codec extra data size: %d\n", extraSize); + + pExtra = (RK_U8*)(malloc)(extraSize); + if (pExtra ==NULL) { + DECODE_ERR_RET(ERROR_MEMORY); + } + memset(pExtra, 0, extraSize); + + if (readBytesFromFile(pExtra, extraSize, pInFile)) { + DECODE_ERR_RET(ERROR_IO); + } + + /* + ** now init vpu api context. codecType, codingType, width ,height + ** are all needed before init. + */ + ctx->codecType = cmd->codec_type; + ctx->videoCoding = cmd->coding; + ctx->width = cmd->width; + ctx->height = cmd->height; + ctx->no_thread = 1; + + if ((ret = ctx->init(ctx, pExtra, extraSize)) !=0) { + mpp_log("init vpu api context fail, ret: 0x%X\n", ret); + DECODE_ERR_RET(ERROR_INIT_VPU); + } + + /* + ** vpu api decoder process. + */ + mpp_log("init vpu api context ok, fileSize: %d\n", fileSize); + + do { + if (ftell(pInFile) >=fileSize) { + mpp_log("read end of file, complete\n"); + break; + } + + if (pkt && (pkt->size ==0)) { + if (readBytesFromFile((RK_U8*)(&pkt_size), 4, pInFile)) { + break; + } + + if (pkt->data ==NULL) { + pkt->data = (RK_U8*)(malloc)(pkt_size); + if (pkt->data ==NULL) { + DECODE_ERR_RET(ERROR_MEMORY); + } + pkt->capability = pkt_size; + } + + if (pkt->capability <((RK_U32)pkt_size)) { + pkt->data = (RK_U8*)(realloc)((void*)(pkt->data), pkt_size); + if (pkt->data ==NULL) { + DECODE_ERR_RET(ERROR_MEMORY); + } + pkt->capability = pkt_size; + } + + if (readBytesFromFile(pkt->data, pkt_size, pInFile)) { + break; + } else { + pkt->size = pkt_size; + pkt->pts = fakeTimeUs; + fakeTimeUs +=40000; + } + + mpp_log("read one packet, size: %d, pts: %lld, filePos: %ld\n", + pkt->size, pkt->pts, ftell(pInFile)); + } + + /* note: must set out put size to 0 before do decoder. */ + pOut->size = 0; + + if ((ret = ctx->decode(ctx, pkt, pOut)) !=0) { + DECODE_ERR_RET(ERROR_VPU_DECODE); + } else { + mpp_log("vpu decode one frame, out len: %d, left size: %d\n", + pOut->size, pkt->size); + + /* + ** both virtual and physical address of the decoded frame are contained + ** in structure named VPU_FRAME, if you want to use virtual address, make + ** sure you have done VPUMemLink before. + */ +#if HAVE_VPU_FRAME + if ((pOut->size) && (pOut->data)) { + VPU_FRAME *frame = (VPU_FRAME *)(pOut->data); + VPUMemLink(&frame->vpumem); + RK_U32 wAlign16 = ((frame->DisplayWidth+ 15) & (~15)); + RK_U32 hAlign16 = ((frame->DisplayHeight + 15) & (~15)); + RK_U32 frameSize = wAlign16*hAlign16*3/2; + + if(pOutFile && (frame_count++ record_frames)) { + mpp_log("write %d frame(yuv420sp) data, %d bytes to file\n", + frame_count, frameSize); + + fwrite((RK_U8*)(frame->vpumem.vir_addr), 1, frameSize, pOutFile); + fflush(pOutFile); + } + + /* + ** remember use VPUFreeLinear to free, other wise memory leak will + ** give you a surprise. + */ + VPUFreeLinear(&frame->vpumem); + pOut->size = 0; + } +#else + (void)frame_count; +#endif + } + + msleep(3); + }while(!(ctx->decoder_err)); + +DECODE_OUT: + if (pkt && pkt->data) { + free(pkt->data); + pkt->data = NULL; + } + if (pOut && (pOut->data)) { + free(pOut->data); + pOut->data = NULL; + } + if (pExtra) { + free(pExtra); + pExtra = NULL; + } + if (ctx) { + vpu_close_context(&ctx); + ctx = NULL; + } + if (pInFile) { + fclose(pInFile); + pInFile = NULL; + } + if (pOutFile) { + fclose(pOutFile); + pOutFile = NULL; + } + + if (ret) { + mpp_log("decode demo fail, err: %d\n", ret); + } else { + mpp_log("encode demo complete OK.\n"); + } + return ret; +} + + +int main(int argc, char **argv) +{ + mpp_log("/******* vpu api demo in *******/\n"); + + VpuApiDemoCmdContext_t demoCmdCtx; + RK_S32 ret =0; + VPU_API_DEMO_DEBUG_DISABLE = 0; + + if (argc == 1) { + show_usage(); + mpp_log("vpu api demo complete directly\n"); + return 0; + } + + VpuApiDemoCmdContext_t* cmd = &demoCmdCtx; + memset (cmd, 0, sizeof(VpuApiDemoCmdContext_t)); + cmd->codec_type = CODEC_DECODER; + if ((ret = parse_options(argc, argv, cmd)) !=0) { + if (ret == VPU_DEMO_PARSE_HELP_OK) { + return 0; + } + + mpp_log("parse_options fail\n\n"); + show_usage(); + DEMO_ERR_RET(ERROR_INVALID_PARAM); + } + + if (cmd->disable_debug) { + VPU_API_DEMO_DEBUG_DISABLE = 1; + } + + switch (cmd->codec_type) { + case CODEC_DECODER: + ret = vpu_decode_demo(cmd); + break; + case CODEC_ENCODER: + ret = vpu_encode_demo(cmd); + break; + + default: + ret = ERROR_INVALID_PARAM; + break; + } + +DEMO_OUT: + if (ret) { + mpp_log("vpu api demo fail, err: %d\n", ret); + } else { + mpp_log("vpu api demo complete OK.\n"); + } + return ret; +}