/* * Copyright (c) 2009-2011 Intel Corporation. All rights reserved. * * 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. */ #include <va/va.h> #include "VideoDecoderBase.h" #include "VideoDecoderAVC.h" #include "VideoDecoderTrace.h" #include "vbp_loader.h" #include "VideoDecoderAVCSecure.h" #include "VideoFrameInfo.h" #include <string.h> #define MAX_SLICEHEADER_BUFFER_SIZE 4096 #define STARTCODE_PREFIX_LEN 3 #define NALU_TYPE_MASK 0x1F #define MAX_NALU_HEADER_BUFFER 8192 static const uint8_t startcodePrefix[STARTCODE_PREFIX_LEN] = {0x00, 0x00, 0x01}; /* H264 start code values */ typedef enum _h264_nal_unit_type { h264_NAL_UNIT_TYPE_unspecified = 0, h264_NAL_UNIT_TYPE_SLICE, h264_NAL_UNIT_TYPE_DPA, h264_NAL_UNIT_TYPE_DPB, h264_NAL_UNIT_TYPE_DPC, h264_NAL_UNIT_TYPE_IDR, h264_NAL_UNIT_TYPE_SEI, h264_NAL_UNIT_TYPE_SPS, h264_NAL_UNIT_TYPE_PPS, h264_NAL_UNIT_TYPE_Acc_unit_delimiter, h264_NAL_UNIT_TYPE_EOSeq, h264_NAL_UNIT_TYPE_EOstream, h264_NAL_UNIT_TYPE_filler_data, h264_NAL_UNIT_TYPE_SPS_extension, h264_NAL_UNIT_TYPE_ACP = 19, h264_NAL_UNIT_TYPE_Slice_extension = 20 } h264_nal_unit_type_t; VideoDecoderAVCSecure::VideoDecoderAVCSecure(const char *mimeType) : VideoDecoderAVC(mimeType){ mFrameSize = 0; mFrameData = NULL; mIsEncryptData = 0; mClearData = NULL; mCachedHeader = NULL; setParserType(VBP_H264SECURE); mFrameIdx = 0; mModularMode = 0; mSliceNum = 0; } Decode_Status VideoDecoderAVCSecure::start(VideoConfigBuffer *buffer) { VTRACE("VideoDecoderAVCSecure::start"); Decode_Status status = VideoDecoderAVC::start(buffer); if (status != DECODE_SUCCESS) { return status; } mClearData = new uint8_t [MAX_NALU_HEADER_BUFFER]; if (mClearData == NULL) { ETRACE("Failed to allocate memory for mClearData"); return DECODE_MEMORY_FAIL; } mCachedHeader= new uint8_t [MAX_SLICEHEADER_BUFFER_SIZE]; if (mCachedHeader == NULL) { ETRACE("Failed to allocate memory for mCachedHeader"); return DECODE_MEMORY_FAIL; } return status; } void VideoDecoderAVCSecure::stop(void) { VTRACE("VideoDecoderAVCSecure::stop"); VideoDecoderAVC::stop(); if (mClearData) { delete [] mClearData; mClearData = NULL; } if (mCachedHeader) { delete [] mCachedHeader; mCachedHeader = NULL; } } Decode_Status VideoDecoderAVCSecure::processModularInputBuffer(VideoDecodeBuffer *buffer, vbp_data_h264 **data) { VTRACE("processModularInputBuffer +++"); Decode_Status status; int32_t clear_data_size = 0; uint8_t *clear_data = NULL; int32_t nalu_num = 0; uint8_t nalu_type = 0; int32_t nalu_offset = 0; uint32_t nalu_size = 0; uint8_t naluType = 0; uint8_t *nalu_data = NULL; uint32_t sliceidx = 0; frame_info_t *pFrameInfo = NULL; mSliceNum = 0; memset(&mSliceInfo, 0, sizeof(mSliceInfo)); mIsEncryptData = 0; if (buffer->flag & IS_SECURE_DATA) { VTRACE("Decoding protected video ..."); pFrameInfo = (frame_info_t *) buffer->data; if (pFrameInfo == NULL) { ETRACE("Invalid parameter: pFrameInfo is NULL!"); return DECODE_MEMORY_FAIL; } mFrameData = (uint8_t *)pFrameInfo + pFrameInfo->data_offset_from_frameinfo; mFrameSize = pFrameInfo->size; VTRACE("mFrameData = %p, mFrameSize = %d", mFrameData, mFrameSize); nalu_num = pFrameInfo->num_nalus; VTRACE("nalu_num = %d", nalu_num); if (nalu_num <= 0 || nalu_num >= MAX_NUM_NALUS) { ETRACE("Invalid parameter: nalu_num = %d", nalu_num); return DECODE_MEMORY_FAIL; } for (int32_t i = 0; i < nalu_num; i++) { nalu_size = pFrameInfo->nalus[i].length; nalu_type = pFrameInfo->nalus[i].type; nalu_offset = pFrameInfo->nalus[i].offset; nalu_data = ((uint8_t *)pFrameInfo) + pFrameInfo->nalus[i].data_offset_from_frameinfo; naluType = nalu_type & NALU_TYPE_MASK; VTRACE("nalu_type = 0x%x, nalu_size = %d, nalu_offset = 0x%x", nalu_type, nalu_size, nalu_offset); // FIXME: this is a w/a to handle the case when two frame data was wrongly packed into one buffer // especially IDR + Slice. let it gracefully quit. if ((naluType == h264_NAL_UNIT_TYPE_SLICE) && (i > 0)) { uint8_t former_naluType = pFrameInfo->nalus[i-1].type & NALU_TYPE_MASK; if (former_naluType == h264_NAL_UNIT_TYPE_IDR) { ETRACE("Invalid parameter: IDR slice + SLICE in one buffer"); break; // abandon this slice } } if (naluType >= h264_NAL_UNIT_TYPE_SLICE && naluType <= h264_NAL_UNIT_TYPE_IDR) { mIsEncryptData = 1; VTRACE("slice idx = %d", sliceidx); mSliceInfo[sliceidx].sliceHeaderByte = nalu_type; mSliceInfo[sliceidx].sliceStartOffset = (nalu_offset >> 4) << 4; mSliceInfo[sliceidx].sliceByteOffset = nalu_offset - mSliceInfo[sliceidx].sliceStartOffset; mSliceInfo[sliceidx].sliceLength = mSliceInfo[sliceidx].sliceByteOffset + nalu_size; mSliceInfo[sliceidx].sliceSize = (mSliceInfo[sliceidx].sliceByteOffset + nalu_size + 0xF) & ~0xF; VTRACE("sliceHeaderByte = 0x%x", mSliceInfo[sliceidx].sliceHeaderByte); VTRACE("sliceStartOffset = %d", mSliceInfo[sliceidx].sliceStartOffset); VTRACE("sliceByteOffset = %d", mSliceInfo[sliceidx].sliceByteOffset); VTRACE("sliceSize = %d", mSliceInfo[sliceidx].sliceSize); VTRACE("sliceLength = %d", mSliceInfo[sliceidx].sliceLength); #if 0 uint32_t testsize; uint8_t *testdata; testsize = mSliceInfo[sliceidx].sliceSize > 64 ? 64 : mSliceInfo[sliceidx].sliceSize ; testdata = (uint8_t *)(mFrameData); for (int i = 0; i < testsize; i++) { VTRACE("testdata[%d] = 0x%x", i, testdata[i]); } #endif sliceidx++; } else if (naluType == h264_NAL_UNIT_TYPE_SPS || naluType == h264_NAL_UNIT_TYPE_PPS) { if (nalu_data == NULL) { ETRACE("Invalid parameter: nalu_data = NULL for naluType 0x%x", naluType); return DECODE_MEMORY_FAIL; } memcpy(mClearData + clear_data_size, nalu_data, nalu_size); clear_data_size += nalu_size; } else { ITRACE("Nalu type = 0x%x is skipped", naluType); continue; } } clear_data = mClearData; mSliceNum = sliceidx; } else { VTRACE("Decoding clear video ..."); mIsEncryptData = 0; mFrameSize = buffer->size; mFrameData = (uint8_t *)pFrameInfo + (int)pFrameInfo->data_offset_from_frameinfo; clear_data = (uint8_t *)pFrameInfo + (int)pFrameInfo->data_offset_from_frameinfo; clear_data_size = buffer->size; } if (clear_data_size > 0) { status = VideoDecoderBase::parseBuffer( clear_data, clear_data_size, false, (void**)data); CHECK_STATUS("VideoDecoderBase::parseBuffer"); } else { status = VideoDecoderBase::queryBuffer((void**)data); CHECK_STATUS("VideoDecoderBase::queryBuffer"); } return DECODE_SUCCESS; } Decode_Status VideoDecoderAVCSecure::processClassicInputBuffer(VideoDecodeBuffer *buffer, vbp_data_h264 **data) { Decode_Status status; int32_t clear_data_size = 0; uint8_t *clear_data = NULL; uint8_t naluType = 0; int32_t num_nalus; int32_t offset; uint8_t *data_src; uint8_t *nalu_data; uint32_t nalu_size; if (buffer->flag & IS_SECURE_DATA) { VTRACE("Decoding protected video ..."); mIsEncryptData = 1; mFrameData = buffer->data; mFrameSize = buffer->size; VTRACE("mFrameData = %p, mFrameSize = %d", mFrameData, mFrameSize); num_nalus = *(uint32_t *)(buffer->data + buffer->size + sizeof(uint32_t)); VTRACE("num_nalus = %d", num_nalus); offset = 4; for (int32_t i = 0; i < num_nalus; i++) { VTRACE("%d nalu, offset = %d", i, offset); data_src = buffer->data + buffer->size + sizeof(uint32_t) + offset; nalu_size = *(uint32_t *)(data_src + 2 * sizeof(uint32_t)); nalu_size = (nalu_size + 0x03) & (~0x03); nalu_data = data_src + 3 *sizeof(uint32_t); naluType = nalu_data[0] & NALU_TYPE_MASK; offset += nalu_size + 3 *sizeof(uint32_t); VTRACE("naluType = 0x%x", naluType); VTRACE("nalu_size = %d, nalu_data = %p", nalu_size, nalu_data); if (naluType >= h264_NAL_UNIT_TYPE_SLICE && naluType <= h264_NAL_UNIT_TYPE_IDR) { ETRACE("Slice NALU received!"); return DECODE_INVALID_DATA; } else if (naluType >= h264_NAL_UNIT_TYPE_SEI && naluType <= h264_NAL_UNIT_TYPE_PPS) { memcpy(mClearData + clear_data_size, startcodePrefix, STARTCODE_PREFIX_LEN); clear_data_size += STARTCODE_PREFIX_LEN; memcpy(mClearData + clear_data_size, nalu_data, nalu_size); clear_data_size += nalu_size; } else { ETRACE("Failure: DECODE_FRAME_DROPPED"); return DECODE_FRAME_DROPPED; } } clear_data = mClearData; } else { VTRACE("Decoding clear video ..."); mIsEncryptData = 0; mFrameSize = buffer->size; mFrameData = buffer->data; clear_data = buffer->data; clear_data_size = buffer->size; } if (clear_data_size > 0) { status = VideoDecoderBase::parseBuffer( clear_data, clear_data_size, false, (void**)data); CHECK_STATUS("VideoDecoderBase::parseBuffer"); } else { status = VideoDecoderBase::queryBuffer((void**)data); CHECK_STATUS("VideoDecoderBase::queryBuffer"); } return DECODE_SUCCESS; } Decode_Status VideoDecoderAVCSecure::decode(VideoDecodeBuffer *buffer) { VTRACE("VideoDecoderAVCSecure::decode"); Decode_Status status; vbp_data_h264 *data = NULL; if (buffer == NULL) { return DECODE_INVALID_DATA; } #if 0 uint32_t testsize; uint8_t *testdata; testsize = buffer->size > 16 ? 16:buffer->size ; testdata = (uint8_t *)(buffer->data); for (int i = 0; i < 16; i++) { VTRACE("testdata[%d] = 0x%x", i, testdata[i]); } #endif if (buffer->flag & IS_SUBSAMPLE_ENCRYPTION) { mModularMode = 1; } if (mModularMode) { status = processModularInputBuffer(buffer,&data); CHECK_STATUS("processModularInputBuffer"); } else { status = processClassicInputBuffer(buffer,&data); CHECK_STATUS("processClassicInputBuffer"); } if (!mVAStarted) { if (data->has_sps && data->has_pps) { status = startVA(data); CHECK_STATUS("startVA"); } else { WTRACE("Can't start VA as either SPS or PPS is still not available."); return DECODE_SUCCESS; } } status = decodeFrame(buffer, data); return status; } Decode_Status VideoDecoderAVCSecure::decodeFrame(VideoDecodeBuffer *buffer, vbp_data_h264 *data) { VTRACE("VideoDecoderAVCSecure::decodeFrame"); Decode_Status status; VTRACE("data->has_sps = %d, data->has_pps = %d", data->has_sps, data->has_pps); #if 0 // Don't remove the following codes, it can be enabled for debugging DPB. for (unsigned int i = 0; i < data->num_pictures; i++) { VAPictureH264 &pic = data->pic_data[i].pic_parms->CurrPic; VTRACE("%d: decoding frame %.2f, poc top = %d, poc bottom = %d, flags = %d, reference = %d", i, buffer->timeStamp/1E6, pic.TopFieldOrderCnt, pic.BottomFieldOrderCnt, pic.flags, (pic.flags & VA_PICTURE_H264_SHORT_TERM_REFERENCE) || (pic.flags & VA_PICTURE_H264_LONG_TERM_REFERENCE)); } #endif if (data->new_sps || data->new_pps) { status = handleNewSequence(data); CHECK_STATUS("handleNewSequence"); } if (mModularMode && (!mIsEncryptData)) { if (data->pic_data[0].num_slices == 0) { ITRACE("No slice available for decoding."); status = mSizeChanged ? DECODE_FORMAT_CHANGE : DECODE_SUCCESS; mSizeChanged = false; return status; } } uint64_t lastPTS = mCurrentPTS; mCurrentPTS = buffer->timeStamp; // start decoding a new frame status = acquireSurfaceBuffer(); CHECK_STATUS("acquireSurfaceBuffer"); if (mModularMode) { status = parseModularSliceHeader(data); if (status != DECODE_SUCCESS) status = parseModularSliceHeader(data); } else { status = parseClassicSliceHeader(data); } if (status != DECODE_SUCCESS) { endDecodingFrame(true); if (status == DECODE_PARSER_FAIL) { ETRACE("parse frame failed with DECODE_PARSER_FAIL"); status = DECODE_INVALID_DATA; } return status; } status = beginDecodingFrame(data); CHECK_STATUS("beginDecodingFrame"); // finish decoding the last frame status = endDecodingFrame(false); CHECK_STATUS("endDecodingFrame"); if (isNewFrame(data, lastPTS == mCurrentPTS) == 0) { ETRACE("Can't handle interlaced frames yet"); return DECODE_FAIL; } return DECODE_SUCCESS; } Decode_Status VideoDecoderAVCSecure::beginDecodingFrame(vbp_data_h264 *data) { VTRACE("VideoDecoderAVCSecure::beginDecodingFrame"); Decode_Status status; VAPictureH264 *picture = &(data->pic_data[0].pic_parms->CurrPic); if ((picture->flags & VA_PICTURE_H264_SHORT_TERM_REFERENCE) || (picture->flags & VA_PICTURE_H264_LONG_TERM_REFERENCE)) { mAcquiredBuffer->referenceFrame = true; } else { mAcquiredBuffer->referenceFrame = false; } if (picture->flags & VA_PICTURE_H264_TOP_FIELD) { mAcquiredBuffer->renderBuffer.scanFormat = VA_BOTTOM_FIELD | VA_TOP_FIELD; } else { mAcquiredBuffer->renderBuffer.scanFormat = VA_FRAME_PICTURE; } mAcquiredBuffer->renderBuffer.flag = 0; mAcquiredBuffer->renderBuffer.timeStamp = mCurrentPTS; mAcquiredBuffer->pictureOrder = getPOC(picture); if (mSizeChanged) { mAcquiredBuffer->renderBuffer.flag |= IS_RESOLUTION_CHANGE; mSizeChanged = false; } status = continueDecodingFrame(data); return status; } Decode_Status VideoDecoderAVCSecure::continueDecodingFrame(vbp_data_h264 *data) { VTRACE("VideoDecoderAVCSecure::continueDecodingFrame"); Decode_Status status; vbp_picture_data_h264 *picData = data->pic_data; if (mAcquiredBuffer == NULL || mAcquiredBuffer->renderBuffer.surface == VA_INVALID_SURFACE) { ETRACE("mAcquiredBuffer is NULL. Implementation bug."); return DECODE_FAIL; } VTRACE("data->num_pictures = %d", data->num_pictures); for (uint32_t picIndex = 0; picIndex < data->num_pictures; picIndex++, picData++) { if (picData == NULL || picData->pic_parms == NULL || picData->slc_data == NULL || picData->num_slices == 0) { return DECODE_PARSER_FAIL; } if (picIndex > 0 && (picData->pic_parms->CurrPic.flags & (VA_PICTURE_H264_TOP_FIELD | VA_PICTURE_H264_BOTTOM_FIELD)) == 0) { ETRACE("Packed frame is not supported yet!"); return DECODE_FAIL; } VTRACE("picData->num_slices = %d", picData->num_slices); for (uint32_t sliceIndex = 0; sliceIndex < picData->num_slices; sliceIndex++) { status = decodeSlice(data, picIndex, sliceIndex); if (status != DECODE_SUCCESS) { endDecodingFrame(true); // remove current frame from DPB as it can't be decoded. removeReferenceFromDPB(picData->pic_parms); return status; } } } mDecodingFrame = true; return DECODE_SUCCESS; } Decode_Status VideoDecoderAVCSecure::parseClassicSliceHeader(vbp_data_h264 *data) { Decode_Status status; VAStatus vaStatus; VABufferID sliceheaderbufferID; VABufferID pictureparameterparsingbufferID; VABufferID mSlicebufferID; if (mFrameSize <= 0) { return DECODE_SUCCESS; } vaStatus = vaBeginPicture(mVADisplay, mVAContext, mAcquiredBuffer->renderBuffer.surface); CHECK_VA_STATUS("vaBeginPicture"); vaStatus = vaCreateBuffer( mVADisplay, mVAContext, VAParseSliceHeaderGroupBufferType, MAX_SLICEHEADER_BUFFER_SIZE, 1, NULL, &sliceheaderbufferID); CHECK_VA_STATUS("vaCreateSliceHeaderGroupBuffer"); void *sliceheaderbuf; vaStatus = vaMapBuffer( mVADisplay, sliceheaderbufferID, &sliceheaderbuf); CHECK_VA_STATUS("vaMapBuffer"); memset(sliceheaderbuf, 0, MAX_SLICEHEADER_BUFFER_SIZE); vaStatus = vaUnmapBuffer( mVADisplay, sliceheaderbufferID); CHECK_VA_STATUS("vaUnmapBuffer"); vaStatus = vaCreateBuffer( mVADisplay, mVAContext, VASliceDataBufferType, mFrameSize, //size 1, //num_elements mFrameData, &mSlicebufferID); CHECK_VA_STATUS("vaCreateSliceDataBuffer"); data->pic_parse_buffer->frame_buf_id = mSlicebufferID; data->pic_parse_buffer->slice_headers_buf_id = sliceheaderbufferID; data->pic_parse_buffer->frame_size = mFrameSize; data->pic_parse_buffer->slice_headers_size = MAX_SLICEHEADER_BUFFER_SIZE; #if 0 VTRACE("flags.bits.frame_mbs_only_flag = %d", data->pic_parse_buffer->flags.bits.frame_mbs_only_flag); VTRACE("flags.bits.pic_order_present_flag = %d", data->pic_parse_buffer->flags.bits.pic_order_present_flag); VTRACE("flags.bits.delta_pic_order_always_zero_flag = %d", data->pic_parse_buffer->flags.bits.delta_pic_order_always_zero_flag); VTRACE("flags.bits.redundant_pic_cnt_present_flag = %d", data->pic_parse_buffer->flags.bits.redundant_pic_cnt_present_flag); VTRACE("flags.bits.weighted_pred_flag = %d", data->pic_parse_buffer->flags.bits.weighted_pred_flag); VTRACE("flags.bits.entropy_coding_mode_flag = %d", data->pic_parse_buffer->flags.bits.entropy_coding_mode_flag); VTRACE("flags.bits.deblocking_filter_control_present_flag = %d", data->pic_parse_buffer->flags.bits.deblocking_filter_control_present_flag); VTRACE("flags.bits.weighted_bipred_idc = %d", data->pic_parse_buffer->flags.bits.weighted_bipred_idc); VTRACE("pic_parse_buffer->expected_pic_parameter_set_id = %d", data->pic_parse_buffer->expected_pic_parameter_set_id); VTRACE("pic_parse_buffer->num_slice_groups_minus1 = %d", data->pic_parse_buffer->num_slice_groups_minus1); VTRACE("pic_parse_buffer->chroma_format_idc = %d", data->pic_parse_buffer->chroma_format_idc); VTRACE("pic_parse_buffer->log2_max_pic_order_cnt_lsb_minus4 = %d", data->pic_parse_buffer->log2_max_pic_order_cnt_lsb_minus4); VTRACE("pic_parse_buffer->pic_order_cnt_type = %d", data->pic_parse_buffer->pic_order_cnt_type); VTRACE("pic_parse_buffer->residual_colour_transform_flag = %d", data->pic_parse_buffer->residual_colour_transform_flag); VTRACE("pic_parse_buffer->num_ref_idc_l0_active_minus1 = %d", data->pic_parse_buffer->num_ref_idc_l0_active_minus1); VTRACE("pic_parse_buffer->num_ref_idc_l1_active_minus1 = %d", data->pic_parse_buffer->num_ref_idc_l1_active_minus1); #endif vaStatus = vaCreateBuffer( mVADisplay, mVAContext, VAParsePictureParameterBufferType, sizeof(VAParsePictureParameterBuffer), 1, data->pic_parse_buffer, &pictureparameterparsingbufferID); CHECK_VA_STATUS("vaCreatePictureParameterParsingBuffer"); vaStatus = vaRenderPicture( mVADisplay, mVAContext, &pictureparameterparsingbufferID, 1); CHECK_VA_STATUS("vaRenderPicture"); vaStatus = vaMapBuffer( mVADisplay, sliceheaderbufferID, &sliceheaderbuf); CHECK_VA_STATUS("vaMapBuffer"); status = updateSliceParameter(data,sliceheaderbuf); CHECK_STATUS("processSliceHeader"); vaStatus = vaUnmapBuffer( mVADisplay, sliceheaderbufferID); CHECK_VA_STATUS("vaUnmapBuffer"); return DECODE_SUCCESS; } Decode_Status VideoDecoderAVCSecure::parseModularSliceHeader(vbp_data_h264 *data) { Decode_Status status; VAStatus vaStatus; VABufferID sliceheaderbufferID; VABufferID pictureparameterparsingbufferID; VABufferID mSlicebufferID; int32_t sliceIdx; vaStatus = vaBeginPicture(mVADisplay, mVAContext, mAcquiredBuffer->renderBuffer.surface); CHECK_VA_STATUS("vaBeginPicture"); if (mFrameSize <= 0 || mSliceNum <=0) { return DECODE_SUCCESS; } void *sliceheaderbuf; memset(mCachedHeader, 0, MAX_SLICEHEADER_BUFFER_SIZE); int32_t offset = 0; int32_t size = 0; for (sliceIdx = 0; sliceIdx < mSliceNum; sliceIdx++) { vaStatus = vaCreateBuffer( mVADisplay, mVAContext, VAParseSliceHeaderGroupBufferType, MAX_SLICEHEADER_BUFFER_SIZE, 1, NULL, &sliceheaderbufferID); CHECK_VA_STATUS("vaCreateSliceHeaderGroupBuffer"); vaStatus = vaMapBuffer( mVADisplay, sliceheaderbufferID, &sliceheaderbuf); CHECK_VA_STATUS("vaMapBuffer"); memset(sliceheaderbuf, 0, MAX_SLICEHEADER_BUFFER_SIZE); vaStatus = vaUnmapBuffer( mVADisplay, sliceheaderbufferID); CHECK_VA_STATUS("vaUnmapBuffer"); vaStatus = vaCreateBuffer( mVADisplay, mVAContext, VASliceDataBufferType, mSliceInfo[sliceIdx].sliceSize, //size 1, //num_elements mFrameData + mSliceInfo[sliceIdx].sliceStartOffset, &mSlicebufferID); CHECK_VA_STATUS("vaCreateSliceDataBuffer"); data->pic_parse_buffer->frame_buf_id = mSlicebufferID; data->pic_parse_buffer->slice_headers_buf_id = sliceheaderbufferID; data->pic_parse_buffer->frame_size = mSliceInfo[sliceIdx].sliceLength; data->pic_parse_buffer->slice_headers_size = MAX_SLICEHEADER_BUFFER_SIZE; data->pic_parse_buffer->nalu_header.value = mSliceInfo[sliceIdx].sliceHeaderByte; data->pic_parse_buffer->slice_offset = mSliceInfo[sliceIdx].sliceByteOffset; #if 0 VTRACE("data->pic_parse_buffer->slice_offset = 0x%x", data->pic_parse_buffer->slice_offset); VTRACE("pic_parse_buffer->nalu_header.value = %x", data->pic_parse_buffer->nalu_header.value = mSliceInfo[sliceIdx].sliceHeaderByte); VTRACE("flags.bits.frame_mbs_only_flag = %d", data->pic_parse_buffer->flags.bits.frame_mbs_only_flag); VTRACE("flags.bits.pic_order_present_flag = %d", data->pic_parse_buffer->flags.bits.pic_order_present_flag); VTRACE("flags.bits.delta_pic_order_always_zero_flag = %d", data->pic_parse_buffer->flags.bits.delta_pic_order_always_zero_flag); VTRACE("flags.bits.redundant_pic_cnt_present_flag = %d", data->pic_parse_buffer->flags.bits.redundant_pic_cnt_present_flag); VTRACE("flags.bits.weighted_pred_flag = %d", data->pic_parse_buffer->flags.bits.weighted_pred_flag); VTRACE("flags.bits.entropy_coding_mode_flag = %d", data->pic_parse_buffer->flags.bits.entropy_coding_mode_flag); VTRACE("flags.bits.deblocking_filter_control_present_flag = %d", data->pic_parse_buffer->flags.bits.deblocking_filter_control_present_flag); VTRACE("flags.bits.weighted_bipred_idc = %d", data->pic_parse_buffer->flags.bits.weighted_bipred_idc); VTRACE("pic_parse_buffer->expected_pic_parameter_set_id = %d", data->pic_parse_buffer->expected_pic_parameter_set_id); VTRACE("pic_parse_buffer->num_slice_groups_minus1 = %d", data->pic_parse_buffer->num_slice_groups_minus1); VTRACE("pic_parse_buffer->chroma_format_idc = %d", data->pic_parse_buffer->chroma_format_idc); VTRACE("pic_parse_buffer->log2_max_pic_order_cnt_lsb_minus4 = %d", data->pic_parse_buffer->log2_max_pic_order_cnt_lsb_minus4); VTRACE("pic_parse_buffer->pic_order_cnt_type = %d", data->pic_parse_buffer->pic_order_cnt_type); VTRACE("pic_parse_buffer->residual_colour_transform_flag = %d", data->pic_parse_buffer->residual_colour_transform_flag); VTRACE("pic_parse_buffer->num_ref_idc_l0_active_minus1 = %d", data->pic_parse_buffer->num_ref_idc_l0_active_minus1); VTRACE("pic_parse_buffer->num_ref_idc_l1_active_minus1 = %d", data->pic_parse_buffer->num_ref_idc_l1_active_minus1); #endif vaStatus = vaCreateBuffer( mVADisplay, mVAContext, VAParsePictureParameterBufferType, sizeof(VAParsePictureParameterBuffer), 1, data->pic_parse_buffer, &pictureparameterparsingbufferID); CHECK_VA_STATUS("vaCreatePictureParameterParsingBuffer"); vaStatus = vaRenderPicture( mVADisplay, mVAContext, &pictureparameterparsingbufferID, 1); CHECK_VA_STATUS("vaRenderPicture"); vaStatus = vaMapBuffer( mVADisplay, sliceheaderbufferID, &sliceheaderbuf); CHECK_VA_STATUS("vaMapBuffer"); size = *(uint32 *)((uint8 *)sliceheaderbuf + 4) + 4; VTRACE("slice header size = 0x%x, offset = 0x%x", size, offset); if (offset + size <= MAX_SLICEHEADER_BUFFER_SIZE - 4) { memcpy(mCachedHeader+offset, sliceheaderbuf, size); offset += size; } else { WTRACE("Cached slice header is not big enough!"); } vaStatus = vaUnmapBuffer( mVADisplay, sliceheaderbufferID); CHECK_VA_STATUS("vaUnmapBuffer"); } memset(mCachedHeader + offset, 0xFF, 4); status = updateSliceParameter(data,mCachedHeader); CHECK_STATUS("processSliceHeader"); return DECODE_SUCCESS; } Decode_Status VideoDecoderAVCSecure::updateSliceParameter(vbp_data_h264 *data, void *sliceheaderbuf) { VTRACE("VideoDecoderAVCSecure::updateSliceParameter"); Decode_Status status; status = VideoDecoderBase::updateBuffer( (uint8_t *)sliceheaderbuf, MAX_SLICEHEADER_BUFFER_SIZE, (void**)&data); CHECK_STATUS("updateBuffer"); return DECODE_SUCCESS; } Decode_Status VideoDecoderAVCSecure::decodeSlice(vbp_data_h264 *data, uint32_t picIndex, uint32_t sliceIndex) { Decode_Status status; VAStatus vaStatus; uint32_t bufferIDCount = 0; // maximum 3 buffers to render a slice: picture parameter, IQMatrix, slice parameter VABufferID bufferIDs[3]; vbp_picture_data_h264 *picData = &(data->pic_data[picIndex]); vbp_slice_data_h264 *sliceData = &(picData->slc_data[sliceIndex]); VAPictureParameterBufferH264 *picParam = picData->pic_parms; VASliceParameterBufferH264 *sliceParam = &(sliceData->slc_parms); uint32_t slice_data_size = 0; uint8_t* slice_data_addr = NULL; if (sliceParam->first_mb_in_slice == 0 || mDecodingFrame == false) { // either condition indicates start of a new frame if (sliceParam->first_mb_in_slice != 0) { WTRACE("The first slice is lost."); } VTRACE("Current frameidx = %d", mFrameIdx++); // Update the reference frames and surface IDs for DPB and current frame status = updateDPB(picParam); CHECK_STATUS("updateDPB"); //We have to provide a hacked DPB rather than complete DPB for libva as workaround status = updateReferenceFrames(picData); CHECK_STATUS("updateReferenceFrames"); mDecodingFrame = true; vaStatus = vaCreateBuffer( mVADisplay, mVAContext, VAPictureParameterBufferType, sizeof(VAPictureParameterBufferH264), 1, picParam, &bufferIDs[bufferIDCount]); CHECK_VA_STATUS("vaCreatePictureParameterBuffer"); bufferIDCount++; vaStatus = vaCreateBuffer( mVADisplay, mVAContext, VAIQMatrixBufferType, sizeof(VAIQMatrixBufferH264), 1, data->IQ_matrix_buf, &bufferIDs[bufferIDCount]); CHECK_VA_STATUS("vaCreateIQMatrixBuffer"); bufferIDCount++; } status = setReference(sliceParam); CHECK_STATUS("setReference"); if (mModularMode) { if (mIsEncryptData) { sliceParam->slice_data_size = mSliceInfo[sliceIndex].sliceSize; slice_data_size = mSliceInfo[sliceIndex].sliceSize; slice_data_addr = mFrameData + mSliceInfo[sliceIndex].sliceStartOffset; } else { slice_data_size = sliceData->slice_size; slice_data_addr = sliceData->buffer_addr + sliceData->slice_offset; } } else { sliceParam->slice_data_size = mFrameSize; slice_data_size = mFrameSize; slice_data_addr = mFrameData; } vaStatus = vaCreateBuffer( mVADisplay, mVAContext, VASliceParameterBufferType, sizeof(VASliceParameterBufferH264), 1, sliceParam, &bufferIDs[bufferIDCount]); CHECK_VA_STATUS("vaCreateSliceParameterBuffer"); bufferIDCount++; vaStatus = vaRenderPicture( mVADisplay, mVAContext, bufferIDs, bufferIDCount); CHECK_VA_STATUS("vaRenderPicture"); VABufferID slicebufferID; vaStatus = vaCreateBuffer( mVADisplay, mVAContext, VASliceDataBufferType, slice_data_size, //size 1, //num_elements slice_data_addr, &slicebufferID); CHECK_VA_STATUS("vaCreateSliceDataBuffer"); vaStatus = vaRenderPicture( mVADisplay, mVAContext, &slicebufferID, 1); CHECK_VA_STATUS("vaRenderPicture"); return DECODE_SUCCESS; } Decode_Status VideoDecoderAVCSecure::getCodecSpecificConfigs( VAProfile profile, VAConfigID *config) { VAStatus vaStatus; VAConfigAttrib attrib[2]; if (config == NULL) { ETRACE("Invalid parameter!"); return DECODE_FAIL; } attrib[0].type = VAConfigAttribRTFormat; attrib[0].value = VA_RT_FORMAT_YUV420; attrib[1].type = VAConfigAttribDecSliceMode; attrib[1].value = VA_DEC_SLICE_MODE_NORMAL; if (mModularMode) { attrib[1].value = VA_DEC_SLICE_MODE_SUBSAMPLE; } vaStatus = vaCreateConfig( mVADisplay, profile, VAEntrypointVLD, &attrib[0], 2, config); CHECK_VA_STATUS("vaCreateConfig"); return DECODE_SUCCESS; }