diff --git a/src/codec/video/VideoDecoderVPU.cpp b/src/codec/video/VideoDecoderVPU.cpp index ead8ef61..b3b23564 100644 --- a/src/codec/video/VideoDecoderVPU.cpp +++ b/src/codec/video/VideoDecoderVPU.cpp @@ -38,7 +38,7 @@ extern "C" { #include "utils/Logger.h" //avformat ctx: flag CODEC_FLAG_TRUNCATED - +// PPU disabled //#define ENC_SOURCE_FRAME_DISPLAY #define ENC_RECON_FRAME_DISPLAY @@ -51,32 +51,21 @@ extern "C" { #undef VPU_DEC_TIMEOUT #define VPU_DEC_TIMEOUT 1000 #endif - - #define MAX_CHUNK_HEADER_SIZE 1024 #define MAX_DYNAMIC_BUFCOUNT 3 #define NUM_FRAME_BUF 19 #define MAX_ROT_BUF_NUM 2 #define EXTRA_FRAME_BUFFER_NUM 1 - #define ENC_SRC_BUF_NUM 2 #define STREAM_BUF_SIZE 0x300000 // max bitstream size - //#define STREAM_FILL_SIZE (512 * 16) // 4 * 1024 | 512 | 512+256( wrap around test ) #define STREAM_FILL_SIZE 0x2000 // 4 * 1024 | 512 | 512+256( wrap around test ) - #define STREAM_END_SIZE 0 #define STREAM_END_SET_FLAG 0 #define STREAM_END_CLEAR_FLAG -1 #define STREAM_READ_SIZE (512 * 16) #define FORCE_SET_VSYNC_FLAG -//#define TEST_USER_FRAME_BUFFER - -#ifdef TEST_USER_FRAME_BUFFER -#define TEST_MULTIPLE_CALL_REGISTER_FRAME_BUFFER -#endif - #define VPU_ENSURE(x, ...) \ do { \ @@ -103,9 +92,7 @@ class VideoDecoderVPU : public VideoDecoder public: VideoDecoderVPU(); VideoDecoderId id() const Q_DECL_OVERRIDE; - QString description() const Q_DECL_OVERRIDE { - return QStringLiteral("Coda VPU"); - } + QString description() const Q_DECL_OVERRIDE; bool decode(const Packet& packet) Q_DECL_OVERRIDE; void flush() Q_DECL_OVERRIDE; VideoFrame frame() Q_DECL_OVERRIDE; @@ -113,6 +100,7 @@ public: extern VideoDecoderId VideoDecoderId_VPU; FACTORY_REGISTER(VideoDecoder, VPU, "VPU") +int x; class VideoDecoderVPUPrivate Q_DECL_FINAL: public VideoDecoderPrivate { public: @@ -121,16 +109,223 @@ public: {} ~VideoDecoderVPUPrivate() { } - bool open() Q_DECL_OVERRIDE; + QString getVPUInfo(quint32 core_idx) { + Uint32 version; + Uint32 revision; + Uint32 productId; + VPU_GetVersionInfo(core_idx, &version, &revision, &productId); + return QString("VPU core@%1. projectId:%2, version:%3.%4.%5 r%6, hw version:%7, API:%8") + .arg(core_idx) + .arg(version>>16, 0, 16).arg((version>>12)&0x0f).arg((version>>8)&0x0f).arg(version&0xff).arg(revision) + .arg(productId).arg(API_VERSION); + } + + bool open() Q_DECL_OVERRIDE; + void close() Q_DECL_OVERRIDE; bool flush(); - int insIdx, coreIdx; - int map_type; + bool flushBuffer(); // do decode + bool initSeq(); + // user config + int instIdx, coreIdx; //0 + bool useRot; //false + bool useDering; //false + bool tiled2LinearEnable; + TiledMapConfig mapType; + + // vpu status + bool chunkReuseRequired; //false + bool seqInited; //false + bool seqFilled; //false + int bsfillSize; //0 + bool decodefinish; //false + int int_reason; //0 + int totalNumofErrMbs; //0 + bool ppuEnable; // depends on useRot, useDering vpu_buffer_t vbStream; - DecHandle handle; + DecHandle handle; // 0 DecOpenParam decOP; DecOutputInfo outputInfo; + int framebufWidth, framebufHeight; + int framebufStride; // align 16 + FrameBufferFormat framebufFormat; + SecAxiUse secAxiUse; + + #define MAX_PPU_SRC_NUM 2 + FrameBuffer fbPPU[MAX_PPU_SRC_NUM]; + + frame_queue_item_t *display_queue; //TODO: FrameBuffer queue + + QByteArray seqHeader; + QByteArray picHeader; + QString description; }; +// codec_id in vpuhelper.c is wrong, so copy it here +typedef struct { + CodStd codStd; + int mp4Class; + int codec_id; + unsigned int fourcc; +} CodStdTab; +#ifndef MKTAG +#define MKTAG(a,b,c,d) (a | (b << 8) | (c << 16) | (d << 24)) +#endif +const CodStdTab codstd_tab[] = { + { STD_AVC, 0, AV_CODEC_ID_H264, MKTAG('H', '2', '6', '4') }, + { STD_AVC, 0, AV_CODEC_ID_H264, MKTAG('X', '2', '6', '4') }, + { STD_AVC, 0, AV_CODEC_ID_H264, MKTAG('A', 'V', 'C', '1') }, + { STD_AVC, 0, AV_CODEC_ID_H264, MKTAG('V', 'S', 'S', 'H') }, + { STD_H263, 0, AV_CODEC_ID_H263, MKTAG('H', '2', '6', '3') }, + { STD_H263, 0, AV_CODEC_ID_H263, MKTAG('X', '2', '6', '3') }, + { STD_H263, 0, AV_CODEC_ID_H263, MKTAG('T', '2', '6', '3') }, + { STD_H263, 0, AV_CODEC_ID_H263, MKTAG('L', '2', '6', '3') }, + { STD_H263, 0, AV_CODEC_ID_H263, MKTAG('V', 'X', '1', 'K') }, + { STD_H263, 0, AV_CODEC_ID_H263, MKTAG('Z', 'y', 'G', 'o') }, + { STD_H263, 0, AV_CODEC_ID_H263, MKTAG('H', '2', '6', '3') }, + { STD_H263, 0, AV_CODEC_ID_H263, MKTAG('I', '2', '6', '3') }, /* intel h263 */ + { STD_H263, 0, AV_CODEC_ID_H263, MKTAG('H', '2', '6', '1') }, + { STD_H263, 0, AV_CODEC_ID_H263, MKTAG('U', '2', '6', '3') }, + { STD_H263, 0, AV_CODEC_ID_H263, MKTAG('V', 'I', 'V', '1') }, + { STD_MPEG4, 0, AV_CODEC_ID_MPEG4, MKTAG('F', 'M', 'P', '4') }, + { STD_MPEG4, 5, AV_CODEC_ID_MPEG4, MKTAG('D', 'I', 'V', 'X') }, // DivX 4 + { STD_MPEG4, 1, AV_CODEC_ID_MPEG4, MKTAG('D', 'X', '5', '0') }, + { STD_MPEG4, 2, AV_CODEC_ID_MPEG4, MKTAG('X', 'V', 'I', 'D') }, + { STD_MPEG4, 0, AV_CODEC_ID_MPEG4, MKTAG('M', 'P', '4', 'S') }, + { STD_MPEG4, 0, AV_CODEC_ID_MPEG4, MKTAG('M', '4', 'S', '2') }, //MPEG-4 version 2 simple profile + { STD_MPEG4, 0, AV_CODEC_ID_MPEG4, MKTAG( 4 , 0 , 0 , 0 ) }, /* some broken avi use this */ + { STD_MPEG4, 0, AV_CODEC_ID_MPEG4, MKTAG('D', 'I', 'V', '1') }, + { STD_MPEG4, 0, AV_CODEC_ID_MPEG4, MKTAG('B', 'L', 'Z', '0') }, + { STD_MPEG4, 0, AV_CODEC_ID_MPEG4, MKTAG('M', 'P', '4', 'V') }, + { STD_MPEG4, 0, AV_CODEC_ID_MPEG4, MKTAG('U', 'M', 'P', '4') }, + { STD_MPEG4, 0, AV_CODEC_ID_MPEG4, MKTAG('W', 'V', '1', 'F') }, + { STD_MPEG4, 0, AV_CODEC_ID_MPEG4, MKTAG('S', 'E', 'D', 'G') }, + { STD_MPEG4, 0, AV_CODEC_ID_MPEG4, MKTAG('R', 'M', 'P', '4') }, + { STD_MPEG4, 0, AV_CODEC_ID_MPEG4, MKTAG('3', 'I', 'V', '2') }, + { STD_MPEG4, 0, AV_CODEC_ID_MPEG4, MKTAG('F', 'F', 'D', 'S') }, + { STD_MPEG4, 0, AV_CODEC_ID_MPEG4, MKTAG('F', 'V', 'F', 'W') }, + { STD_MPEG4, 0, AV_CODEC_ID_MPEG4, MKTAG('D', 'C', 'O', 'D') }, + { STD_MPEG4, 0, AV_CODEC_ID_MPEG4, MKTAG('M', 'V', 'X', 'M') }, + { STD_MPEG4, 0, AV_CODEC_ID_MPEG4, MKTAG('P', 'M', '4', 'V') }, + { STD_MPEG4, 0, AV_CODEC_ID_MPEG4, MKTAG('S', 'M', 'P', '4') }, + { STD_MPEG4, 0, AV_CODEC_ID_MPEG4, MKTAG('D', 'X', 'G', 'M') }, + { STD_MPEG4, 0, AV_CODEC_ID_MPEG4, MKTAG('V', 'I', 'D', 'M') }, + { STD_MPEG4, 0, AV_CODEC_ID_MPEG4, MKTAG('M', '4', 'T', '3') }, + { STD_MPEG4, 0, AV_CODEC_ID_MPEG4, MKTAG('G', 'E', 'O', 'X') }, + { STD_MPEG4, 0, AV_CODEC_ID_MPEG4, MKTAG('H', 'D', 'X', '4') }, /* flipped video */ + { STD_MPEG4, 0, AV_CODEC_ID_MPEG4, MKTAG('D', 'M', 'K', '2') }, + { STD_MPEG4, 0, AV_CODEC_ID_MPEG4, MKTAG('D', 'I', 'G', 'I') }, + { STD_MPEG4, 0, AV_CODEC_ID_MPEG4, MKTAG('I', 'N', 'M', 'C') }, + { STD_MPEG4, 0, AV_CODEC_ID_MPEG4, MKTAG('E', 'P', 'H', 'V') }, /* Ephv MPEG-4 */ + { STD_MPEG4, 0, AV_CODEC_ID_MPEG4, MKTAG('E', 'M', '4', 'A') }, + { STD_MPEG4, 0, AV_CODEC_ID_MPEG4, MKTAG('M', '4', 'C', 'C') }, /* Divio MPEG-4 */ + { STD_MPEG4, 0, AV_CODEC_ID_MPEG4, MKTAG('S', 'N', '4', '0') }, + { STD_MPEG4, 0, AV_CODEC_ID_MPEG4, MKTAG('V', 'S', 'P', 'X') }, + { STD_MPEG4, 0, AV_CODEC_ID_MPEG4, MKTAG('U', 'L', 'D', 'X') }, + { STD_MPEG4, 0, AV_CODEC_ID_MPEG4, MKTAG('G', 'E', 'O', 'V') }, + { STD_MPEG4, 0, AV_CODEC_ID_MPEG4, MKTAG('S', 'I', 'P', 'P') }, /* Samsung SHR-6040 */ + { STD_DIV3, 0, AV_CODEC_ID_MSMPEG4V3, MKTAG('D', 'I', 'V', '3') }, /* default signature when using MSMPEG4 */ + { STD_DIV3, 0, AV_CODEC_ID_MSMPEG4V3, MKTAG('M', 'P', '4', '3') }, + { STD_DIV3, 0, AV_CODEC_ID_MSMPEG4V3, MKTAG('M', 'P', 'G', '3') }, + { STD_MPEG4, 1, AV_CODEC_ID_MSMPEG4V3, MKTAG('D', 'I', 'V', '5') }, + { STD_MPEG4, 1, AV_CODEC_ID_MSMPEG4V3, MKTAG('D', 'I', 'V', '6') }, + { STD_MPEG4, 5, AV_CODEC_ID_MSMPEG4V3, MKTAG('D', 'I', 'V', '4') }, + { STD_DIV3, 0, AV_CODEC_ID_MSMPEG4V3, MKTAG('D', 'V', 'X', '3') }, + { STD_DIV3, 0, AV_CODEC_ID_MSMPEG4V3, MKTAG('A', 'P', '4', '1') }, //Another hacked version of Microsoft's MP43 codec. + { STD_MPEG4, 0, AV_CODEC_ID_MSMPEG4V3, MKTAG('C', 'O', 'L', '1') }, + { STD_MPEG4, 0, AV_CODEC_ID_MSMPEG4V3, MKTAG('C', 'O', 'L', '0') }, // not support ms mpeg4 v1, 2 + { STD_MPEG4, 256, AV_CODEC_ID_FLV1, MKTAG('F', 'L', 'V', '1') }, /* Sorenson spark */ + { STD_VC1, 0, AV_CODEC_ID_WMV1, MKTAG('W', 'M', 'V', '1') }, + { STD_VC1, 0, AV_CODEC_ID_WMV2, MKTAG('W', 'M', 'V', '2') }, + { STD_MPEG2, 0, AV_CODEC_ID_MPEG1VIDEO, MKTAG('M', 'P', 'G', '1') }, + { STD_MPEG2, 0, AV_CODEC_ID_MPEG1VIDEO, MKTAG('M', 'P', 'G', '2') }, + { STD_MPEG2, 0, AV_CODEC_ID_MPEG2VIDEO, MKTAG('M', 'P', 'G', '2') }, + { STD_MPEG2, 0, AV_CODEC_ID_MPEG2VIDEO, MKTAG('M', 'P', 'E', 'G') }, + { STD_MPEG2, 0, AV_CODEC_ID_MPEG1VIDEO, MKTAG('M', 'P', '2', 'V') }, + { STD_MPEG2, 0, AV_CODEC_ID_MPEG1VIDEO, MKTAG('P', 'I', 'M', '1') }, + { STD_MPEG2, 0, AV_CODEC_ID_MPEG2VIDEO, MKTAG('P', 'I', 'M', '2') }, + { STD_MPEG2, 0, AV_CODEC_ID_MPEG1VIDEO, MKTAG('V', 'C', 'R', '2') }, + { STD_MPEG2, 0, AV_CODEC_ID_MPEG1VIDEO, MKTAG( 1 , 0 , 0 , 16) }, + { STD_MPEG2, 0, AV_CODEC_ID_MPEG2VIDEO, MKTAG( 2 , 0 , 0 , 16) }, + { STD_MPEG4, 0, AV_CODEC_ID_MPEG4, MKTAG( 4 , 0 , 0 , 16) }, + { STD_MPEG2, 0, AV_CODEC_ID_MPEG2VIDEO, MKTAG('D', 'V', 'R', ' ') }, + { STD_MPEG2, 0, AV_CODEC_ID_MPEG2VIDEO, MKTAG('M', 'M', 'E', 'S') }, + { STD_MPEG2, 0, AV_CODEC_ID_MPEG2VIDEO, MKTAG('L', 'M', 'P', '2') }, /* Lead MPEG2 in avi */ + { STD_MPEG2, 0, AV_CODEC_ID_MPEG2VIDEO, MKTAG('S', 'L', 'I', 'F') }, + { STD_MPEG2, 0, AV_CODEC_ID_MPEG2VIDEO, MKTAG('E', 'M', '2', 'V') }, + { STD_VC1, 0, AV_CODEC_ID_WMV3, MKTAG('W', 'M', 'V', '3') }, + { STD_VC1, 0, AV_CODEC_ID_VC1, MKTAG('W', 'V', 'C', '1') }, + { STD_VC1, 0, AV_CODEC_ID_VC1, MKTAG('W', 'M', 'V', 'A') }, + + + { STD_RV, 0, AV_CODEC_ID_RV30, MKTAG('R','V','3','0') }, + { STD_RV, 0, AV_CODEC_ID_RV40, MKTAG('R','V','4','0') }, + + { STD_AVS, 0, AV_CODEC_ID_CAVS, MKTAG('C','A','V','S') }, + { STD_AVS, 0, AV_CODEC_ID_AVS, MKTAG('A','V','S','2') }, + { STD_VP3, 0, AV_CODEC_ID_VP3, MKTAG('V', 'P', '3', '0') }, + { STD_VP3, 0, AV_CODEC_ID_VP3, MKTAG('V', 'P', '3', '1') }, + { STD_THO, 0, AV_CODEC_ID_THEORA, MKTAG('T', 'H', 'E', 'O') }, + { STD_VP8, 0, AV_CODEC_ID_VP8, MKTAG('V', 'P', '8', '0') } + // { STD_VP6, 0, AV_CODEC_ID_VP6, MKTAG('V', 'P', '6', '0') }, + // { STD_VP6, 0, AV_CODEC_ID_VP6, MKTAG('V', 'P', '6', '1') }, + // { STD_VP6, 0, AV_CODEC_ID_VP6, MKTAG('V', 'P', '6', '2') }, + // { STD_VP6, 0, AV_CODEC_ID_VP6F, MKTAG('V', 'P', '6', 'F') }, + // { STD_VP6, 0, AV_CODEC_ID_VP6F, MKTAG('F', 'L', 'V', '4') }, + +}; + +int fourCCToMp4Class(unsigned int fourcc) +{ + char str[5]; + str[0] = toupper((char)fourcc); + str[1] = toupper((char)(fourcc>>8)); + str[2] = toupper((char)(fourcc>>16)); + str[3] = toupper((char)(fourcc>>24)); + str[4] = '\0'; + for(int i=0; i>8)); + str[2] = toupper((char)(fourcc>>16)); + str[3] = toupper((char)(fourcc>>24)); + str[4] = '\0'; + for(int i=0; iextradata_size + MAX_CHUNK_HEADER_SIZE); // allocate more buffer to fill the vpu specific header. - if (!seqHeader) { - qWarning("fail to allocate the seqHeader buffer"); - goto ERR_DEC_INIT; + if (codecIdToCodStd(codec_ctx->codec_id) < 0) { + qWarning("Unsupported codec"); + return false; } - memset(seqHeader, 0x00, codec_ctx->extradata_size+MAX_CHUNK_HEADER_SIZE); - - BYTE *picHeader = osal_malloc(MAX_CHUNK_HEADER_SIZE); - if (!picHeader) { - qWarning("fail to allocate the picHeader buffer\n"); - goto ERR_DEC_INIT; - } - memset(picHeader, 0x00, MAX_CHUNK_HEADER_SIZE); RetCode ret = VPU_Init(coreIdx); #ifndef BIT_CODE_FILE_PATH @@ -165,392 +354,457 @@ bool VideoDecoderVPUPrivate::open() if (ret != RETCODE_SUCCESS && ret != RETCODE_CALLED_BEFORE) { qWarning("VPU_Init failed Error code is 0x%x \n", ret ); - goto ERR_DEC_INIT; + return false; } + decodefinish = false; + int_reason = 0; + totalNumofErrMbs = 0; + description = getVPUInfo(coreIdx); - CheckVersion(coreIdx); - + instIdx = VPU_GetOpenInstanceNum(pVpu->coreIdx); //omx use it. vpurun set from other + if (instIdx > MAX_NUM_INSTANCE) { + qDebug("exceed the opened instance num than %d num", MAX_NUM_INSTANCE); + return false; + } + //omx_vpudec_component_vpuLibInit + memset(&outputInfo, 0, sizeof(outputInfo)); memset(&decOP, 0, sizeof(decOP)); decOP.bitstreamFormat = fourCCToCodStd(codec_ctx->codec_tag); - if (decOP.bitstreamFormat == -1) + if (decOP.bitstreamFormat < 0) decOP.bitstreamFormat = codecIdToCodStd(codec_ctx->codec_id); - - if (decOP.bitstreamFormat == -1) { + if (decOP.bitstreamFormat < 0) { qWarning("can not support video format in VPU tag=%c%c%c%c, codec_id=0x%x \n", ctxVideo->codec_tag>>0, ctxVideo->codec_tag>>8, ctxVideo->codec_tag>>16, ctxVideo->codec_tag>>24, ctxVideo->codec_id ); - goto ERR_DEC_INIT; + return false; } - + decOP.mp4Class = fourCCToMp4Class(codec_ctx->codec_tag); + if (decOP.mp4Class < 0) + decOP.mp4Class = codecIdToMp4Class(codec_ctx->codec_id); +//!USE_OMX_HEADER_BUFFER_AS_DECODER_BITSTREAM_BUFFER memset(&vbStream, 0, sizeof(vbStream)); - vbStream.size = STREAM_BUF_SIZE; //STREAM_BUF_SIZE; - vbStream.size = ((vbStream.size+1023)&~1023); + vbStream.size = STREAM_BUF_SIZE; + vbStream.size = FFALIGN(vbStream.size, 1024); if (vdi_allocate_dma_memory(coreIdx, &vbStream) < 0) { qWarning("fail to allocate bitstream buffer\n" ); - goto ERR_DEC_INIT; + return false; } - decOP.bitstreamBuffer = vbStream.phys_addr; decOP.bitstreamBufferSize = vbStream.size; decOP.mp4DeblkEnable = 0; - decOP.mp4Class = fourCCToMp4Class(ctxVideo->codec_tag); - if (decOP.mp4Class == -1) - decOP.mp4Class = codecIdToMp4Class(ctxVideo->codec_id); if(decOP.bitstreamFormat == STD_THO || decOP.bitstreamFormat == STD_VP3) { } - - decOP.tiled2LinearEnable = (map_type>>4)&0x1; - int mapType = map_type & 0xf; + decOP.tiled2LinearEnable = tiled2LinearEnable; +#if 0 //not in omx if (mapType) { - decOP.wtlEnable = decConfig.wtlEnable; //TODO: + //decOP.wtlEnable = decConfig.wtlEnable; //TODO: if (decOP.wtlEnable) { //decConfig.rotAngle; //decConfig.mirDir; - //decConfig.useRot = 0; - //decConfig.useDering = 0; + //useRot = false; + //useDering = false; decOP.mp4DeblkEnable = 0; decOP.tiled2LinearEnable = 0; } } - +#endif decOP.cbcrInterleave = CBCR_INTERLEAVE; if (mapType == TILED_FRAME_MB_RASTER_MAP || mapType == TILED_FIELD_MB_RASTER_MAP) { decOP.cbcrInterleave = 1; } + decOP.cbcrOrder = CBCR_ORDER_NORMAL; + if (true) { //output nv12 + decOP.cbcrInterleave = 1; + decOP.cbcrOrder = CBCR_ORDER_NORMAL; + } else { //output yuv420p + decOP.cbcrInterleave = 0; +#ifdef ANDROID + decOP.cbcrOrder = CBCR_ORDER_REVERSED; +#else + decOP.cbcrOrder = CBCR_ORDER_NORMAL; +#endif + } decOP.bwbEnable = VPU_ENABLE_BWB; decOP.frameEndian = VPU_FRAME_ENDIAN; decOP.streamEndian = VPU_STREAM_ENDIAN; - decOP.bitstreamMode = decConfig.bitstreamMode; + decOP.bitstreamMode = BS_MODE_PIC_END; //omx - int ppuEnable = (decConfig.useRot || decConfig.useDering || decOP.tiled2LinearEnable); //TODO: + ppuEnable = (useRot || useDering || decOP.tiled2LinearEnable); + seqHeader = QByteArray(codec_ctx->extradata_size + MAX_CHUNK_HEADER_SIZE); // allocate more buffer to fill the vpu specific header. + picHeader = QByteArray(MAX_CHUNK_HEADER_SIZE); - memset(&handle, 0, sizeof(handle)); - VPU_ENSURE(VPU_decOPen(&handle, &decOP), false); //TODO: goto ERR_DEC_OPEN - - DRAMConfig dramCfg = {0}; - VPU_ENSURE(VPU_DecGiveCommand(handle, GET_DRAM_CONFIG, &dramCfg), false); //TODO: goto ERR_DEC_OPEN - qDebug("Dec Start : Press enter key to show menu."); - qDebug(" : Press space key to stop."); - - int seqInited = 0; - int seqFilled = 0; - int bsfillSize = 0; - int reUseChunk = 0; + VPU_ENSURE(VPU_DecOpen(&handle, &decOP), false); display_queue = frame_queue_init(MAX_REG_FRAME); init_VSYNC_flag(); + // TODO: omx GET_DRAM_CONFIG is not in open + DRAMConfig dramCfg = {0}; + VPU_ENSURE(VPU_DecGiveCommand(handle, GET_DRAM_CONFIG, &dramCfg), false); + seqInited = false; + seqFilled = false; + bsfillSize = 0; + chunkReuseRequired = false; + return true; } +void VideoDecoderVPUPrivate::close() +{ + if (!handle) + return; + RetCode ret = VPU_DecClose(handle); + if (ret == RETCODE_FRAME_NOT_COMPLETE) { + VPU_DecGetOutputInfo(handle, &outputInfo); + VPU_DecClose(handle); + } + if (vbStream.size) + vdi_free_dma_memory(coreIdx, &vbStream); + seqHeader.clear(); + picHeader.clear(); + if (display_queue) { + frame_queue_dequeue_all(display_queue); + frame_queue_deinit(display_queue); + } +} + bool VideoDecoderVPUPrivate::flush() { VPU_DecUpdateBitstreamBuffer(handle, STREAM_END_SIZE); //tell VPU to reach the end of stream. starting flush decoded output in VPU +} +bool VideoDecoderVPUPrivate::initSeq() +{ + if (seqInited) + return true; + ConfigSeqReport(coreIdx, handle, decOP.bitstreamFormat); // TODO: remove + DecInitialInfo initialInfo = {0}; + if (decOP.bitstreamMode == BS_MODE_PIC_END) { //TODO: no check in omx (always BS_MODE_PIC_END) + ret = VPU_DecGetInitialInfo(handle, &initialInfo); + if (ret != RETCODE_SUCCESS) { + if (ret == RETCODE_MEMORY_ACCESS_VIOLATION) + PrintMemoryAccessViolationReason(coreIdx, NULL); + qWarning("VPU_DecGetInitialInfo failed Error code is %#x", ret); + return false; //TODO: omx wait for next chunk + } + VPU_ClearInterrupt(coreIdx); + } else { + // d.int_reason + if ((int_reason & (1<coreIdx, NULL); + TiledMapConfig mapCfg = {{0}}; + VPU_ENSURE(VPU_DecGiveCommand(handle, GET_TILEDMAP_CONFIG, &mapCfg), false); + if (ppuEnable) { +#if 0 + ppIdx = 0; + fbAllocInfo.format = framebufFormat; + fbAllocInfo.cbcrInterleave = decOP.cbcrInterleave; + if (decOP.tiled2LinearEnable) + fbAllocInfo.mapType = LINEAR_FRAME_MAP; + else + fbAllocInfo.mapType = mapType; + + fbAllocInfo.stride = rotStride; + fbAllocInfo.height = rotbufHeight; + fbAllocInfo.num = MAX_ROT_BUF_NUM; + fbAllocInfo.endian = decOP.frameEndian; + fbAllocInfo.type = FB_TYPE_PPU; + VPU_ENSURE(VPU_DecAllocateFrameBuffer(handle, fbAllocInfo, fbPPU), false); + + ppIdx = 0; + + if (decConfig.useRot) { + VPU_DecGiveCommand(handle, SET_ROTATION_ANGLE, &(decConfig.rotAngle)); + VPU_DecGiveCommand(handle, SET_MIRROR_DIRECTION, &(decConfig.mirDir)); + } + if (decConfig.useDering) + VPU_DecGiveCommand(handle, ENABLE_DERING, 0); + VPU_DecGiveCommand(handle, SET_ROTATOR_STRIDE, &rotStride); +#endif + } + seqInited = true; } bool VideoDecoderVPU::decode(const Packet &packet) { DPTR_D(VideoDecoderVPU); + if (d.decodefinish) { + qWarning("decode finished"); + return false; + } if (packet.data.isEmpty()) return true; - QByteArray chunkData(packet.data); - DecOpenParam &decOP = d.decOP; - if (decOP.bitstreamMode == BS_MODE_PIC_END) { - if (reUseChunk) { - reUseChunk = 0; - goto FLUSH_BUFFER; - } - VPU_DecSetRdPtr(handle, decOP.bitstreamBuffer, 1); - } - if (packet.isEOF()) { + if (packet.isEOF()) { //decode the trailing frames if (!d.flush()) { qDebug("Error decode EOS"); // when? return false; } - return true; + goto FLUSH_BUFFER; } - - if (!seqInited && !seqFilled) { - seqHeaderSize = BuildSeqHeader(seqHeader, decOP.bitstreamFormat, ic->streams[idxVideo]); // make sequence data as reference file header to support VPU decoder. - if (headerSize < 0) // indicate the stream dose not support in VPU. - { - DEBUG(DEB_LEV_ERR, "BuildOmxSeqHeader the stream does not support in VPU \n"); - goto ERR_DEC; + QByteArray chunkData(packet.data); + DecOpenParam &decOP = d.decOP; + if (decOP.bitstreamMode == BS_MODE_PIC_END) { //TODO: no check in omx. it's always true here + if (d.chunkReuseRequired) { + d.chunkReuseRequired = false; + goto FLUSH_BUFFER; } - // TODO: omx always WriteBsBufFromBufHelper + VPU_DecSetRdPtr(handle, decOP.bitstreamBuffer, 1); + } + int seqHeaderSize = 0; //also used in FLUSH_BUFFER + if (!d.seqInited && !d.seqFilled) { + // FIXME: copy from omx or vpuhelper + seqHeaderSize = BuildSeqHeader((BYTE*)d.seqHeader.constData(), decOP.bitstreamFormat, ic->streams[idxVideo]); // make sequence data as reference file header to support VPU decoder. + if (headerSize < 0) {// indicate the stream dose not support in VPU. + qWarning("BuildSeqHeader the stream does not support in VPU"); + return false; + } + // TODO: vpurun check STD_THO, STD_VP3 + if (seqHeaderSize > 0) { //write to vbStream + const int size = WriteBsBufFromBufHelper(d.coreIdx, d.handle, &d.vbStream, seqHeader, seqHeaderSize, decOP.streamEndian); + if (size < 0) { + qWarning("WriteBsBufFromBufHelper failed Error code is 0x%x", size); + return false; + } + d.bsfillSize += size; + } + d.seqFilled = 1; + } + // Build and Fill picture Header data which is dedicated for VPU + //picHeaderSize is also used in FLUSH_BUFFER + int picHeaderSize = BuildPicHeader((BYTE*)d.picHeader.constData(), decOP.bitstreamFormat, ic->streams[idxVideo], pkt); //FIXME + if (picHeaderSize > 0) { // TODO: no check in vpurun switch(decOP.bitstreamFormat) { case STD_THO: case STD_VP3: break; - default: { - size = WriteBsBufFromBufHelper(d.coreIdx, d.handle, &d.vbStream, seqHeader, seqHeaderSize, decOP.streamEndian); - if (size < 0) { - qWarning("WriteBsBufFromBufHelper failed Error code is 0x%x \n", size ); - goto ERR_DEC_OPEN; //// - } - - bsfillSize += size; + default: // write to vbStream + const int size = WriteBsBufFromBufHelper(coreIdx, handle, &d.vbStream, d.picHeader.constData(), picHeaderSize, decOP.streamEndian); + if (size < 0) { + qWarning("WriteBsBufFromBufHelper failed Error code is 0x%x", size); + return false; } + d.bsfillSize += size; // TODO: not in omx break; } - seqFilled = 1; - } - - - // Build and Fill picture Header data which is dedicated for VPU - picHeaderSize = BuildPicHeader(picHeader, decOP.bitstreamFormat, ic->streams[idxVideo], pkt); - switch(decOP.bitstreamFormat) { - case STD_THO: - case STD_VP3: - break; - default: - size = WriteBsBufFromBufHelper(coreIdx, handle, &vbStream, picHeader, picHeaderSize, decOP.streamEndian); - if (size < 0) { - VLOG(ERR, "WriteBsBufFromBufHelper failed Error code is 0x%x \n", size ); - goto ERR_DEC_OPEN; - } - bsfillSize += size; - break; } // Fill VCL data switch(decOP.bitstreamFormat) { case STD_VP3: case STD_THO: + //const int size = WriteBsBufFromBufHelper(coreIdx, handle, &vbStream, picHeader, picHeaderSize, decOP.streamEndian); break; default: { if (decOP.bitstreamFormat == STD_RV) { chunkData.remove(0, 1+(cSlice*8)); } - size = WriteBsBufFromBufHelper(d.coreIdx, d.handle, &d.vbStream, chunkData.constData(), chunkData.size(), decOP.streamEndian); + const int size = WriteBsBufFromBufHelper(d.coreIdx, d.handle, &d.vbStream, chunkData.constData(), chunkData.size(), decOP.streamEndian); if (size <0) { qWarning("WriteBsBufFromBufHelper failed Error code is 0x%x", size); - goto ERR_DEC_OPEN; + return false; } - bsfillSize += size; + d.bsfillSize += size; } break; } chunkIdx++; + if (!d.initSeq()) + return false; - if (!seqInited) { - ConfigSeqReport(coreIdx, handle, decOP.bitstreamFormat); // TODO: remove - if (decOP.bitstreamMode == BS_MODE_PIC_END) { - ret = VPU_DecGetInitialInfo(handle, &initialInfo); - if (ret != RETCODE_SUCCESS) { - if (ret == RETCODE_MEMORY_ACCESS_VIOLATION) - PrintMemoryAccessViolationReason(coreIdx, NULL); - qWarning("VPU_DecGetInitialInfo failed Error code is %#x", ret); - goto ERR_DEC_OPEN; - } - VPU_ClearInterrupt(coreIdx); - } else { - // d.int_reason - if ((int_reason & (1<coreIdx, NULL); - VPU_DecGiveCommand(handle, GET_TILEDMAP_CONFIG, &mapCfg); - if (ppuEnable) { - ppIdx = 0; - fbAllocInfo.format = framebufFormat; - fbAllocInfo.cbcrInterleave = decOP.cbcrInterleave; - if (decOP.tiled2LinearEnable) - fbAllocInfo.mapType = LINEAR_FRAME_MAP; - else - fbAllocInfo.mapType = mapType; - - fbAllocInfo.stride = rotStride; - fbAllocInfo.height = rotbufHeight; - fbAllocInfo.num = MAX_ROT_BUF_NUM; - fbAllocInfo.endian = decOP.frameEndian; - fbAllocInfo.type = FB_TYPE_PPU; - VPU_ENSURE(VPU_DecAllocateFrameBuffer(handle, fbAllocInfo, fbPPU), false); - - ppIdx = 0; - - if (decConfig.useRot) { - VPU_DecGiveCommand(handle, SET_ROTATION_ANGLE, &(decConfig.rotAngle)); - VPU_DecGiveCommand(handle, SET_MIRROR_DIRECTION, &(decConfig.mirDir)); - } - if (decConfig.useDering) - VPU_DecGiveCommand(handle, ENABLE_DERING, 0); - VPU_DecGiveCommand(handle, SET_ROTATOR_STRIDE, &rotStride); - } - seqInited = 1; - } + PhysicalAddress rdPtr, wrPtr; + int room; + DecParam decParam = {0}; + RetCode ret = RETCODE_SUCCESS; //can not use VPU_ENSURE() below because it needs a local var FLUSH_BUFFER: - if((int_reason & (1<= 0) // omx: <0 goto no display - frame_queue_enqueue(display_queue, outputInfo.indexFrameDisplay); +#endif + if (d.outputInfo.indexFrameDisplay >= 0) + frame_queue_enqueue(d.display_queue, d.outputInfo.indexFrameDisplay); +// TODO: to be continue here if (!saveImage) { if (!ppuEnable) { // TODO: fill out buffer. used by VideoFrame and XImage (GPU scale) vdi_read_memory(coreIdx, d.outputInfo.dispFrame.bufY, (BYTE *)dst, (stride*picHeight*3/2), endian); //OmxSaveYuvImageBurstFormat(d.coreIdx, &d.outputInfo.dispFrame, framebufStride, framebufHeight); } else { ppIdx = (ppIdx+1)%MAX_ROT_BUF_NUM; - OmxSaveYuvImageBurstFormat(&outputInfo.dispFrame, rotStride, rotbufHeight); + OmxSaveYuvImageBurstFormat(&d.outputInfo.dispFrame, rotStride, rotbufHeight); } #ifdef FORCE_SET_VSYNC_FLAG set_VSYNC_flag(); @@ -637,8 +897,8 @@ FLUSH_BUFFER: rcPrevDisp = d.outputInfo.rcDisplay; if (d.outputInfo.numOfErrMBs) { - totalNumofErrMbs += outputInfo.numOfErrMBs; - VLOG(ERR, "Num of Error Mbs : %d, in Frame : %d \n", outputInfo.numOfErrMBs, frameIdx); + d.totalNumofErrMbs += d.outputInfo.numOfErrMBs; + VLOG(ERR, "Num of Error Mbs : %d, in Frame : %d \n", d.outputInfo.numOfErrMBs, frameIdx); } frameIdx++; @@ -654,6 +914,15 @@ void VideoDecoderVPU::flush() VideoFrame VideoDecoderVPU::frame() { DPTR_D(VideoDecoderVPU); + int dispIdx = -1; + // 0 on success + if (frame_queue_dequeue(d.display_queue, &dispIdx) < 0) { + qDebug("VPU has no frame decoded"); + return VideoFrame(); + } + // TODO: timestamp is packet pts in OMX! + VideoFrame frame; + frame.setMetaData(QStringLiteral("vpu_disp"), dispIdx); return frame; }