/*
* 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;
}