686 lines
27 KiB
C++
686 lines
27 KiB
C++
/*
|
|
* 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 "VideoDecoderMPEG4.h"
|
|
#include "VideoDecoderTrace.h"
|
|
#include <string.h>
|
|
|
|
#define MAX_PICTURE_WIDTH_MPEG4 1920
|
|
#define MAX_PICTURE_HEIGHT_MPEG4 1088
|
|
|
|
VideoDecoderMPEG4::VideoDecoderMPEG4(const char *mimeType)
|
|
: VideoDecoderBase(mimeType, VBP_MPEG4),
|
|
mLastVOPTimeIncrement(0),
|
|
mExpectingNVOP(false),
|
|
mSendIQMatrixBuf(false),
|
|
mLastVOPCodingType(MP4_VOP_TYPE_I),
|
|
mIsShortHeader(false) {
|
|
}
|
|
|
|
VideoDecoderMPEG4::~VideoDecoderMPEG4() {
|
|
stop();
|
|
}
|
|
|
|
Decode_Status VideoDecoderMPEG4::start(VideoConfigBuffer *buffer) {
|
|
Decode_Status status;
|
|
|
|
status = VideoDecoderBase::start(buffer);
|
|
CHECK_STATUS("VideoDecoderBase::start");
|
|
|
|
if (buffer->data == NULL || buffer->size == 0) {
|
|
WTRACE("No config data to start VA.");
|
|
return DECODE_SUCCESS;
|
|
}
|
|
|
|
vbp_data_mp42 *data = NULL;
|
|
status = VideoDecoderBase::parseBuffer(buffer->data, buffer->size, true, (void**)&data);
|
|
CHECK_STATUS("VideoDecoderBase::parseBuffer");
|
|
|
|
if (data->codec_data.video_object_layer_width > MAX_PICTURE_WIDTH_MPEG4 ||
|
|
data->codec_data.video_object_layer_height > MAX_PICTURE_HEIGHT_MPEG4) {
|
|
return DECODE_INVALID_DATA;
|
|
}
|
|
|
|
status = startVA(data);
|
|
return status;
|
|
}
|
|
|
|
void VideoDecoderMPEG4::stop(void) {
|
|
// drop the last frame and ignore return value
|
|
endDecodingFrame(true);
|
|
VideoDecoderBase::stop();
|
|
|
|
mLastVOPTimeIncrement = 0;
|
|
mExpectingNVOP = false;
|
|
mLastVOPCodingType = MP4_VOP_TYPE_I;
|
|
}
|
|
|
|
Decode_Status VideoDecoderMPEG4::decode(VideoDecodeBuffer *buffer) {
|
|
Decode_Status status;
|
|
vbp_data_mp42 *data = NULL;
|
|
bool useGraphicbuffer = mConfigBuffer.flag & USE_NATIVE_GRAPHIC_BUFFER;
|
|
if (buffer == NULL) {
|
|
return DECODE_INVALID_DATA;
|
|
}
|
|
if (buffer->flag & IS_SYNC_FRAME) {
|
|
mIsSyncFrame = true;
|
|
} else {
|
|
mIsSyncFrame = false;
|
|
}
|
|
buffer->ext = NULL;
|
|
status = VideoDecoderBase::parseBuffer(
|
|
buffer->data,
|
|
buffer->size,
|
|
false,
|
|
(void**)&data);
|
|
CHECK_STATUS("VideoDecoderBase::parseBuffer");
|
|
|
|
if (data->codec_data.video_object_layer_width > MAX_PICTURE_WIDTH_MPEG4 ||
|
|
data->codec_data.video_object_layer_height > MAX_PICTURE_HEIGHT_MPEG4) {
|
|
return DECODE_INVALID_DATA;
|
|
}
|
|
|
|
if (!mVAStarted) {
|
|
status = startVA(data);
|
|
CHECK_STATUS("startVA");
|
|
}
|
|
|
|
if (mSizeChanged && !useGraphicbuffer) {
|
|
// some container has the incorrect width/height.
|
|
// send the format change to OMX to update the crop info.
|
|
mSizeChanged = false;
|
|
ITRACE("Video size is changed during startVA");
|
|
return DECODE_FORMAT_CHANGE;
|
|
}
|
|
|
|
if ((mVideoFormatInfo.width != (uint32_t)data->codec_data.video_object_layer_width ||
|
|
mVideoFormatInfo.height != (uint32_t)data->codec_data.video_object_layer_height) &&
|
|
data->codec_data.video_object_layer_width &&
|
|
data->codec_data.video_object_layer_height) {
|
|
// update encoded image size
|
|
ITRACE("Video size is changed. from %dx%d to %dx%d\n", mVideoFormatInfo.width, mVideoFormatInfo.height,
|
|
data->codec_data.video_object_layer_width,data->codec_data.video_object_layer_height);
|
|
|
|
if (useGraphicbuffer && mStoreMetaData) {
|
|
pthread_mutex_lock(&mFormatLock);
|
|
}
|
|
mVideoFormatInfo.width = data->codec_data.video_object_layer_width;
|
|
mVideoFormatInfo.height = data->codec_data.video_object_layer_height;
|
|
bool needFlush = false;
|
|
if (useGraphicbuffer) {
|
|
if (mStoreMetaData) {
|
|
needFlush = true;
|
|
|
|
mVideoFormatInfo.valid = false;
|
|
pthread_mutex_unlock(&mFormatLock);
|
|
} else {
|
|
needFlush = (mVideoFormatInfo.width > mVideoFormatInfo.surfaceWidth)
|
|
|| (mVideoFormatInfo.height > mVideoFormatInfo.surfaceHeight);
|
|
}
|
|
}
|
|
if (needFlush) {
|
|
if (mStoreMetaData) {
|
|
status = endDecodingFrame(false);
|
|
CHECK_STATUS("endDecodingFrame");
|
|
} else {
|
|
flushSurfaceBuffers();
|
|
}
|
|
mSizeChanged = false;
|
|
return DECODE_FORMAT_CHANGE;
|
|
} else {
|
|
mSizeChanged = true;
|
|
}
|
|
|
|
setRenderRect();
|
|
} else {
|
|
if (useGraphicbuffer && mStoreMetaData) {
|
|
mVideoFormatInfo.valid = true;
|
|
}
|
|
}
|
|
|
|
status = decodeFrame(buffer, data);
|
|
CHECK_STATUS("decodeFrame");
|
|
|
|
return status;
|
|
}
|
|
|
|
void VideoDecoderMPEG4::flush(void) {
|
|
VideoDecoderBase::flush();
|
|
|
|
mExpectingNVOP = false;
|
|
mLastVOPTimeIncrement = 0;
|
|
mLastVOPCodingType = MP4_VOP_TYPE_I;
|
|
}
|
|
|
|
Decode_Status VideoDecoderMPEG4::decodeFrame(VideoDecodeBuffer *buffer, vbp_data_mp42 *data) {
|
|
Decode_Status status;
|
|
// check if any slice is parsed, we may just receive configuration data
|
|
if (data->number_picture_data == 0) {
|
|
WTRACE("number_picture_data == 0");
|
|
return DECODE_SUCCESS;
|
|
}
|
|
if (data->picture_data && (data->picture_data->picture_param.vop_width == 0 || data->picture_data->picture_param.vop_height == 0)) {
|
|
if (!data->codec_data.got_vol && data->codec_data.got_vop) {
|
|
// error enhancement if vol is missing
|
|
data->picture_data->picture_param.vop_width = mVideoFormatInfo.width;
|
|
data->picture_data->picture_param.vop_height = mVideoFormatInfo.height;
|
|
} else {
|
|
return DECODE_PARSER_FAIL;
|
|
}
|
|
}
|
|
|
|
uint64_t lastPTS = mCurrentPTS;
|
|
mCurrentPTS = buffer->timeStamp;
|
|
|
|
if (lastPTS != mCurrentPTS) {
|
|
// finish decoding the last frame
|
|
status = endDecodingFrame(false);
|
|
CHECK_STATUS("endDecodingFrame");
|
|
|
|
// start decoding a new frame
|
|
status = beginDecodingFrame(data);
|
|
if (status == DECODE_MULTIPLE_FRAME) {
|
|
buffer->ext = &mExtensionBuffer;
|
|
mExtensionBuffer.extType = PACKED_FRAME_TYPE;
|
|
mExtensionBuffer.extSize = sizeof(mPackedFrame);
|
|
mExtensionBuffer.extData = (uint8_t*)&mPackedFrame;
|
|
} else if (status != DECODE_SUCCESS) {
|
|
endDecodingFrame(true);
|
|
}
|
|
CHECK_STATUS("beginDecodingFrame");
|
|
} else {
|
|
status = continueDecodingFrame(data);
|
|
if (status == DECODE_MULTIPLE_FRAME) {
|
|
buffer->ext = &mExtensionBuffer;
|
|
mExtensionBuffer.extType = PACKED_FRAME_TYPE;
|
|
mExtensionBuffer.extSize = sizeof(mPackedFrame);
|
|
mExtensionBuffer.extData = (uint8_t*)&mPackedFrame;
|
|
} else if (status != DECODE_SUCCESS) {
|
|
endDecodingFrame(true);
|
|
}
|
|
CHECK_STATUS("continueDecodingFrame");
|
|
}
|
|
|
|
if (buffer->flag & HAS_COMPLETE_FRAME) {
|
|
// finish decoding current frame
|
|
status = endDecodingFrame(false);
|
|
CHECK_STATUS("endDecodingFrame");
|
|
}
|
|
|
|
return DECODE_SUCCESS;
|
|
}
|
|
|
|
Decode_Status VideoDecoderMPEG4::beginDecodingFrame(vbp_data_mp42 *data) {
|
|
|
|
Decode_Status status = DECODE_SUCCESS;
|
|
vbp_picture_data_mp42 *picData = data->picture_data;
|
|
VAPictureParameterBufferMPEG4 *picParam = &(picData->picture_param);
|
|
int codingType = picParam->vop_fields.bits.vop_coding_type;
|
|
|
|
// start sanity checking
|
|
if (mExpectingNVOP) {
|
|
// if we are waiting for n-vop for packed frame, and the new frame is coded, the coding type
|
|
// of this frame must be B
|
|
// for example: {PB} B N P B B P...
|
|
if (picData->vop_coded == 1 && codingType != MP4_VOP_TYPE_B) {
|
|
WTRACE("Invalid coding type while waiting for n-vop for packed frame.");
|
|
mExpectingNVOP = false;
|
|
}
|
|
}
|
|
|
|
// handle N-VOP picuture, it could be a skipped frame or a simple placeholder of packed frame
|
|
if (picData->vop_coded == 0) {
|
|
if (mLastReference == NULL) {
|
|
WTRACE("The last reference is unavailable to construct skipped frame.");
|
|
flush();
|
|
mExpectingNVOP = false;
|
|
// TODO: handle this case
|
|
return DECODE_SUCCESS;
|
|
}
|
|
|
|
if (mExpectingNVOP) {
|
|
// P frame is already in queue, just need to update time stamp.
|
|
mLastReference->renderBuffer.timeStamp = mCurrentPTS;
|
|
mExpectingNVOP = false;
|
|
}
|
|
else {
|
|
// Do nothing for skip frame as the last frame will be rendered agian by natively
|
|
// No needs to handle reference frame neither
|
|
#if 0
|
|
// this is skipped frame, use the last reference frame as output
|
|
status = acquireSurfaceBuffer();
|
|
CHECK_STATUS("acquireSurfaceBuffer");
|
|
mAcquiredBuffer->renderBuffer.timeStamp = mCurrentPTS;
|
|
mAcquiredBuffer->renderBuffer.flag = 0;
|
|
mAcquiredBuffer->renderBuffer.scanFormat = mLastReference->renderBuffer.scanFormat;
|
|
mAcquiredBuffer->renderBuffer.surface = mLastReference->renderBuffer.surface;
|
|
// No need to update mappedData for HW decoding
|
|
//mAcquiredBuffer->mappedData.data = mLastReference->mappedData.data;
|
|
mAcquiredBuffer->referenceFrame = true;
|
|
status = outputSurfaceBuffer();
|
|
CHECK_STATUS("outputSurfaceBuffer");
|
|
#endif
|
|
}
|
|
|
|
if (data->number_picture_data > 1) {
|
|
WTRACE("Unexpected to have more picture data following a non-coded VOP.");
|
|
//picture data is thrown away. No issue if picture data is for N-VOP. if picture data is for
|
|
// coded picture, a frame is lost.
|
|
// TODO: handle this case
|
|
// return DECODE_FAIL;
|
|
}
|
|
return DECODE_SUCCESS;
|
|
}
|
|
else {
|
|
// Check if we have reference frame(s) for decoding
|
|
if (codingType == MP4_VOP_TYPE_B) {
|
|
if (mForwardReference == NULL ||
|
|
mLastReference == NULL) {
|
|
if (mIsShortHeader) {
|
|
status = DECODE_SUCCESS;
|
|
VTRACE("%s: No reference frame but keep decoding", __FUNCTION__);
|
|
} else
|
|
return DECODE_NO_REFERENCE;
|
|
}
|
|
} else if (codingType == MP4_VOP_TYPE_P || codingType == MP4_VOP_TYPE_S) {
|
|
if (mLastReference == NULL && mIsSyncFrame == false) {
|
|
if (mIsShortHeader) {
|
|
status = DECODE_SUCCESS;
|
|
VTRACE("%s: No reference frame but keep decoding", __FUNCTION__);
|
|
} else
|
|
return DECODE_NO_REFERENCE;
|
|
}
|
|
}
|
|
// all sanity checks pass, continue decoding through continueDecodingFrame
|
|
status = continueDecodingFrame(data);
|
|
}
|
|
return status;
|
|
}
|
|
|
|
Decode_Status VideoDecoderMPEG4::continueDecodingFrame(vbp_data_mp42 *data) {
|
|
Decode_Status status = DECODE_SUCCESS;
|
|
VAStatus vaStatus = VA_STATUS_SUCCESS;
|
|
bool useGraphicBuffer = mConfigBuffer.flag & USE_NATIVE_GRAPHIC_BUFFER;
|
|
|
|
/*
|
|
Packed Frame Assumption:
|
|
|
|
1. In one packed frame, there's only one P or I frame and only one B frame.
|
|
2. In packed frame, there's no skipped frame (vop_coded = 0)
|
|
3. For one packed frame, there will be one N-VOP frame to follow the packed frame (may not immediately).
|
|
4. N-VOP frame is the frame with vop_coded = 0.
|
|
5. The timestamp of N-VOP frame will be used for P or I frame in the packed frame
|
|
|
|
|
|
I, P, {P, B}, B, N, P, N, I, ...
|
|
I, P, {P, B}, N, P, N, I, ...
|
|
|
|
The first N is placeholder for P frame in the packed frame
|
|
The second N is a skipped frame
|
|
*/
|
|
|
|
vbp_picture_data_mp42 *picData = data->picture_data;
|
|
for (uint32_t i = 0; i < data->number_picture_data; i++, picData = picData->next_picture_data) {
|
|
// each slice has its own picture data, video_packet_header following resync_marker may reset picture header, see MP4 spec
|
|
VAPictureParameterBufferMPEG4 *picParam = &(picData->picture_param);
|
|
int codingType = picParam->vop_fields.bits.vop_coding_type;
|
|
if (codingType == MP4_VOP_TYPE_S && picParam->no_of_sprite_warping_points > 1) {
|
|
WTRACE("Hardware only supports up to one warping point (stationary or translation)");
|
|
}
|
|
|
|
if (picData->vop_coded == 0) {
|
|
ETRACE("Unexpected to have non-coded VOP.");
|
|
return DECODE_FAIL;
|
|
}
|
|
if (picData->new_picture_flag == 1 || mDecodingFrame == false) {
|
|
// either condition indicates start of a new frame
|
|
if (picData->new_picture_flag == 0) {
|
|
WTRACE("First slice of picture is lost!");
|
|
// TODO: handle this case
|
|
}
|
|
if (mDecodingFrame) {
|
|
if (codingType == MP4_VOP_TYPE_B){
|
|
// this indicates the start of a new frame in the packed frame
|
|
// Update timestamp for P frame in the packed frame as timestamp here is for the B frame!
|
|
if (picParam->vop_time_increment_resolution){
|
|
uint64_t increment = mLastVOPTimeIncrement - picData->vop_time_increment +
|
|
picParam->vop_time_increment_resolution;
|
|
increment = increment % picParam->vop_time_increment_resolution;
|
|
// convert to micro-second
|
|
// TODO: unit of time stamp varies on different frame work
|
|
increment = increment * 1e6 / picParam->vop_time_increment_resolution;
|
|
mAcquiredBuffer->renderBuffer.timeStamp += increment;
|
|
if (useGraphicBuffer){
|
|
mPackedFrame.timestamp = mCurrentPTS;
|
|
mCurrentPTS = mAcquiredBuffer->renderBuffer.timeStamp;
|
|
}
|
|
}
|
|
} else {
|
|
// this indicates the start of a new frame in the packed frame. no B frame int the packet
|
|
// Update the timestamp according the increment
|
|
if (picParam->vop_time_increment_resolution){
|
|
int64_t increment = picData->vop_time_increment - mLastVOPTimeIncrement + picParam->vop_time_increment_resolution;
|
|
increment = increment % picParam->vop_time_increment_resolution;
|
|
//convert to micro-second
|
|
increment = increment * 1e6 / picParam->vop_time_increment_resolution;
|
|
if (useGraphicBuffer) {
|
|
mPackedFrame.timestamp = mCurrentPTS + increment;
|
|
}
|
|
else {
|
|
mCurrentPTS += increment;
|
|
}
|
|
|
|
} else {
|
|
if (useGraphicBuffer) {
|
|
mPackedFrame.timestamp = mCurrentPTS + 30000;
|
|
}
|
|
else {
|
|
mCurrentPTS += 30000;
|
|
}
|
|
}
|
|
}
|
|
endDecodingFrame(false);
|
|
mExpectingNVOP = true;
|
|
if (codingType != MP4_VOP_TYPE_B) {
|
|
mExpectingNVOP = false;
|
|
}
|
|
if (useGraphicBuffer) {
|
|
int32_t count = i - 1;
|
|
if (count < 0) {
|
|
WTRACE("Shuld not be here!");
|
|
return DECODE_SUCCESS;
|
|
}
|
|
vbp_picture_data_mp42 *lastpic = data->picture_data;
|
|
for(int k = 0; k < count; k++ ) {
|
|
lastpic = lastpic->next_picture_data;
|
|
}
|
|
mPackedFrame.offSet = lastpic->slice_data.slice_offset + lastpic->slice_data.slice_size;
|
|
VTRACE("Report OMX to handle for Multiple frame offset=%d time=%lld",mPackedFrame.offSet,mPackedFrame.timestamp);
|
|
return DECODE_MULTIPLE_FRAME;
|
|
}
|
|
}
|
|
|
|
// acquire a new surface buffer
|
|
status = acquireSurfaceBuffer();
|
|
CHECK_STATUS("acquireSurfaceBuffer");
|
|
|
|
// sprite is treated as P frame in the display order, so only B frame frame is not used as "reference"
|
|
mAcquiredBuffer->referenceFrame = (codingType != MP4_VOP_TYPE_B);
|
|
if (picData->picture_param.vol_fields.bits.interlaced) {
|
|
// only MPEG-4 studio profile can have field coding. All other profiles
|
|
// use frame coding only, i.e, there is no field VOP. (see vop_structure in MP4 spec)
|
|
mAcquiredBuffer->renderBuffer.scanFormat = VA_BOTTOM_FIELD | VA_TOP_FIELD;
|
|
} else {
|
|
mAcquiredBuffer->renderBuffer.scanFormat = VA_FRAME_PICTURE;
|
|
}
|
|
// TODO: set discontinuity flag
|
|
mAcquiredBuffer->renderBuffer.flag = 0;
|
|
mAcquiredBuffer->renderBuffer.timeStamp = mCurrentPTS;
|
|
if (mSizeChanged) {
|
|
mAcquiredBuffer->renderBuffer.flag |= IS_RESOLUTION_CHANGE;
|
|
mSizeChanged = false;
|
|
}
|
|
if (codingType != MP4_VOP_TYPE_B) {
|
|
mLastVOPCodingType = codingType;
|
|
mLastVOPTimeIncrement = picData->vop_time_increment;
|
|
}
|
|
|
|
// start decoding a frame
|
|
vaStatus = vaBeginPicture(mVADisplay, mVAContext, mAcquiredBuffer->renderBuffer.surface);
|
|
CHECK_VA_STATUS("vaBeginPicture");
|
|
|
|
mDecodingFrame = true;
|
|
mSendIQMatrixBuf = true;
|
|
}
|
|
|
|
status = decodeSlice(data, picData);
|
|
CHECK_STATUS("decodeSlice");
|
|
}
|
|
|
|
return DECODE_SUCCESS;
|
|
}
|
|
|
|
|
|
Decode_Status VideoDecoderMPEG4::decodeSlice(vbp_data_mp42 *data, vbp_picture_data_mp42 *picData) {
|
|
Decode_Status status;
|
|
VAStatus vaStatus;
|
|
uint32_t bufferIDCount = 0;
|
|
// maximum 4 buffers to render a slice: picture parameter, IQMatrix, slice parameter, slice data
|
|
VABufferID bufferIDs[4];
|
|
|
|
VAPictureParameterBufferMPEG4 *picParam = &(picData->picture_param);
|
|
vbp_slice_data_mp42 *sliceData = &(picData->slice_data);
|
|
VASliceParameterBufferMPEG4 *sliceParam = &(sliceData->slice_param);
|
|
|
|
// send picture parametre for each slice
|
|
status = setReference(picParam);
|
|
CHECK_STATUS("setReference");
|
|
|
|
vaStatus = vaCreateBuffer(
|
|
mVADisplay,
|
|
mVAContext,
|
|
VAPictureParameterBufferType,
|
|
sizeof(VAPictureParameterBufferMPEG4),
|
|
1,
|
|
picParam,
|
|
&bufferIDs[bufferIDCount]);
|
|
CHECK_VA_STATUS("vaCreatePictureParameterBuffer");
|
|
|
|
bufferIDCount++;
|
|
if (picParam->vol_fields.bits.quant_type && mSendIQMatrixBuf)
|
|
{
|
|
// only send IQ matrix for the first slice in the picture
|
|
vaStatus = vaCreateBuffer(
|
|
mVADisplay,
|
|
mVAContext,
|
|
VAIQMatrixBufferType,
|
|
sizeof(VAIQMatrixBufferMPEG4),
|
|
1,
|
|
&(data->iq_matrix_buffer),
|
|
&bufferIDs[bufferIDCount]);
|
|
CHECK_VA_STATUS("vaCreateIQMatrixBuffer");
|
|
|
|
mSendIQMatrixBuf = false;
|
|
bufferIDCount++;
|
|
}
|
|
|
|
vaStatus = vaCreateBuffer(
|
|
mVADisplay,
|
|
mVAContext,
|
|
VASliceParameterBufferType,
|
|
sizeof(VASliceParameterBufferMPEG4),
|
|
1,
|
|
sliceParam,
|
|
&bufferIDs[bufferIDCount]);
|
|
CHECK_VA_STATUS("vaCreateSliceParameterBuffer");
|
|
|
|
bufferIDCount++;
|
|
|
|
//slice data buffer pointer
|
|
//Note that this is the original data buffer ptr;
|
|
// offset to the actual slice data is provided in
|
|
// slice_data_offset in VASliceParameterBufferMP42
|
|
|
|
vaStatus = vaCreateBuffer(
|
|
mVADisplay,
|
|
mVAContext,
|
|
VASliceDataBufferType,
|
|
sliceData->slice_size, //size
|
|
1, //num_elements
|
|
sliceData->buffer_addr + sliceData->slice_offset,
|
|
&bufferIDs[bufferIDCount]);
|
|
CHECK_VA_STATUS("vaCreateSliceDataBuffer");
|
|
|
|
bufferIDCount++;
|
|
|
|
vaStatus = vaRenderPicture(
|
|
mVADisplay,
|
|
mVAContext,
|
|
bufferIDs,
|
|
bufferIDCount);
|
|
CHECK_VA_STATUS("vaRenderPicture");
|
|
|
|
|
|
return DECODE_SUCCESS;
|
|
}
|
|
|
|
Decode_Status VideoDecoderMPEG4::setReference(VAPictureParameterBufferMPEG4 *picParam) {
|
|
switch (picParam->vop_fields.bits.vop_coding_type) {
|
|
case MP4_VOP_TYPE_I:
|
|
picParam->forward_reference_picture = VA_INVALID_SURFACE;
|
|
picParam->backward_reference_picture = VA_INVALID_SURFACE;
|
|
break;
|
|
case MP4_VOP_TYPE_P:
|
|
if (mLastReference == NULL && mIsSyncFrame == false && !mIsShortHeader) {
|
|
return DECODE_NO_REFERENCE;
|
|
}
|
|
if (mLastReference != NULL) {
|
|
picParam->forward_reference_picture = mLastReference->renderBuffer.surface;
|
|
} else {
|
|
VTRACE("%s: no reference frame, but keep decoding", __FUNCTION__);
|
|
picParam->forward_reference_picture = VA_INVALID_SURFACE;
|
|
}
|
|
picParam->backward_reference_picture = VA_INVALID_SURFACE;
|
|
break;
|
|
case MP4_VOP_TYPE_B:
|
|
picParam->vop_fields.bits.backward_reference_vop_coding_type = mLastVOPCodingType;
|
|
// WEIRD, CHECK AGAIN !!!!!!!
|
|
if (mIsShortHeader) {
|
|
if (mLastReference != NULL) {
|
|
picParam->forward_reference_picture = mLastReference->renderBuffer.surface;
|
|
} else {
|
|
VTRACE("%s: no forward reference frame, but keep decoding", __FUNCTION__);
|
|
picParam->forward_reference_picture = VA_INVALID_SURFACE;
|
|
}
|
|
if (mForwardReference != NULL) {
|
|
picParam->backward_reference_picture = mForwardReference->renderBuffer.surface;
|
|
} else {
|
|
VTRACE("%s: no backward reference frame, but keep decoding", __FUNCTION__);
|
|
picParam->backward_reference_picture = VA_INVALID_SURFACE;
|
|
}
|
|
} else if (mLastReference == NULL || mForwardReference == NULL) {
|
|
return DECODE_NO_REFERENCE;
|
|
} else {
|
|
picParam->forward_reference_picture = mLastReference->renderBuffer.surface;
|
|
picParam->backward_reference_picture = mForwardReference->renderBuffer.surface;
|
|
}
|
|
break;
|
|
case MP4_VOP_TYPE_S:
|
|
// WEIRD, CHECK AGAIN!!!! WAS using mForwardReference
|
|
if (mLastReference == NULL) {
|
|
return DECODE_NO_REFERENCE;
|
|
}
|
|
picParam->forward_reference_picture = mLastReference->renderBuffer.surface;
|
|
picParam->backward_reference_picture = VA_INVALID_SURFACE;
|
|
break;
|
|
|
|
default:
|
|
// Will never reach here;
|
|
return DECODE_PARSER_FAIL;
|
|
}
|
|
return DECODE_SUCCESS;
|
|
}
|
|
|
|
Decode_Status VideoDecoderMPEG4::startVA(vbp_data_mp42 *data) {
|
|
updateFormatInfo(data);
|
|
|
|
VAProfile vaProfile;
|
|
|
|
if ((data->codec_data.profile_and_level_indication & 0xF8) == 0xF0) {
|
|
vaProfile = VAProfileMPEG4AdvancedSimple;
|
|
} else {
|
|
vaProfile = VAProfileMPEG4Simple;
|
|
}
|
|
|
|
mIsShortHeader = data->codec_data.short_video_header;
|
|
|
|
return VideoDecoderBase::setupVA(MP4_SURFACE_NUMBER, vaProfile);
|
|
}
|
|
|
|
void VideoDecoderMPEG4::updateFormatInfo(vbp_data_mp42 *data) {
|
|
ITRACE("updateFormatInfo: current size: %d x %d, new size: %d x %d",
|
|
mVideoFormatInfo.width, mVideoFormatInfo.height,
|
|
data->codec_data.video_object_layer_width,
|
|
data->codec_data.video_object_layer_height);
|
|
// error enhancement if vol is missing
|
|
if (!data->codec_data.got_vol && data->codec_data.got_vop) {
|
|
data->codec_data.video_object_layer_width = mVideoFormatInfo.width;
|
|
data->codec_data.video_object_layer_height = mVideoFormatInfo.height;
|
|
}
|
|
|
|
mVideoFormatInfo.cropBottom = data->codec_data.video_object_layer_height > mVideoFormatInfo.height ?
|
|
data->codec_data.video_object_layer_height - mVideoFormatInfo.height : 0;
|
|
mVideoFormatInfo.cropRight = data->codec_data.video_object_layer_width > mVideoFormatInfo.width ?
|
|
data->codec_data.video_object_layer_width - mVideoFormatInfo.width : 0;
|
|
|
|
if ((mVideoFormatInfo.width != (uint32_t)data->codec_data.video_object_layer_width ||
|
|
mVideoFormatInfo.height != (uint32_t)data->codec_data.video_object_layer_height) &&
|
|
data->codec_data.video_object_layer_width &&
|
|
data->codec_data.video_object_layer_height) {
|
|
// update encoded image size
|
|
mVideoFormatInfo.width = data->codec_data.video_object_layer_width;
|
|
mVideoFormatInfo.height = data->codec_data.video_object_layer_height;
|
|
mSizeChanged = true;
|
|
ITRACE("Video size is changed.");
|
|
}
|
|
|
|
// video_range has default value of 0. Y ranges from 16 to 235.
|
|
mVideoFormatInfo.videoRange = data->codec_data.video_range;
|
|
|
|
switch (data->codec_data.matrix_coefficients) {
|
|
case 1:
|
|
mVideoFormatInfo.colorMatrix = VA_SRC_BT709;
|
|
break;
|
|
|
|
// ITU-R Recommendation BT.470-6 System B, G (MP4), same as
|
|
// SMPTE 170M/BT601
|
|
case 5:
|
|
case 6:
|
|
mVideoFormatInfo.colorMatrix = VA_SRC_BT601;
|
|
break;
|
|
|
|
default:
|
|
// unknown color matrix, set to 0 so color space flag will not be set.
|
|
mVideoFormatInfo.colorMatrix = 0;
|
|
break;
|
|
}
|
|
|
|
mVideoFormatInfo.aspectX = data->codec_data.par_width;
|
|
mVideoFormatInfo.aspectY = data->codec_data.par_height;
|
|
//mVideoFormatInfo.bitrate = data->codec_data.bit_rate;
|
|
mVideoFormatInfo.valid = true;
|
|
|
|
setRenderRect();
|
|
setColorSpaceInfo(mVideoFormatInfo.colorMatrix, mVideoFormatInfo.videoRange);
|
|
}
|
|
|
|
Decode_Status VideoDecoderMPEG4::checkHardwareCapability() {
|
|
VAStatus vaStatus;
|
|
VAConfigAttrib cfgAttribs[2];
|
|
cfgAttribs[0].type = VAConfigAttribMaxPictureWidth;
|
|
cfgAttribs[1].type = VAConfigAttribMaxPictureHeight;
|
|
vaStatus = vaGetConfigAttributes(mVADisplay,
|
|
mIsShortHeader ? VAProfileH263Baseline : VAProfileMPEG4AdvancedSimple,
|
|
VAEntrypointVLD, cfgAttribs, 2);
|
|
CHECK_VA_STATUS("vaGetConfigAttributes");
|
|
if (cfgAttribs[0].value * cfgAttribs[1].value < (uint32_t)mVideoFormatInfo.width * (uint32_t)mVideoFormatInfo.height) {
|
|
ETRACE("hardware supports resolution %d * %d smaller than the clip resolution %d * %d",
|
|
cfgAttribs[0].value, cfgAttribs[1].value, mVideoFormatInfo.width, mVideoFormatInfo.height);
|
|
return DECODE_DRIVER_FAIL;
|
|
}
|
|
|
|
return DECODE_SUCCESS;
|
|
}
|