| /* |
| * 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> |
| |
| 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"); |
| |
| 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 (!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; |
| } |