1707 lines
56 KiB
C++
1707 lines
56 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 "VideoDecoderBase.h"
|
|
#include "VideoDecoderTrace.h"
|
|
#include <string.h>
|
|
#include <va/va_android.h>
|
|
#include <va/va_tpi.h>
|
|
#ifdef __SSE4_1__
|
|
#include "use_util_sse4.h"
|
|
#endif
|
|
|
|
#define INVALID_PTS ((uint64_t)-1)
|
|
#define MAXIMUM_POC 0x7FFFFFFF
|
|
#define MINIMUM_POC 0x80000000
|
|
#define ANDROID_DISPLAY_HANDLE 0x18C34078
|
|
|
|
VideoDecoderBase::VideoDecoderBase(const char *mimeType, _vbp_parser_type type)
|
|
: mInitialized(false),
|
|
mLowDelay(false),
|
|
mStoreMetaData(false),
|
|
mDisplay(NULL),
|
|
mVADisplay(NULL),
|
|
mVAContext(VA_INVALID_ID),
|
|
mVAConfig(VA_INVALID_ID),
|
|
mVAStarted(false),
|
|
mCurrentPTS(INVALID_PTS),
|
|
mAcquiredBuffer(NULL),
|
|
mLastReference(NULL),
|
|
mForwardReference(NULL),
|
|
mDecodingFrame(false),
|
|
mSizeChanged(false),
|
|
mShowFrame(true),
|
|
mOutputWindowSize(OUTPUT_WINDOW_SIZE),
|
|
mRotationDegrees(0),
|
|
mErrReportEnabled(false),
|
|
mWiDiOn(false),
|
|
mRawOutput(false),
|
|
mManageReference(true),
|
|
mOutputMethod(OUTPUT_BY_PCT),
|
|
mNumSurfaces(0),
|
|
mSurfaceBuffers(NULL),
|
|
mOutputHead(NULL),
|
|
mOutputTail(NULL),
|
|
mSurfaces(NULL),
|
|
mVASurfaceAttrib(NULL),
|
|
mSurfaceUserPtr(NULL),
|
|
mSurfaceAcquirePos(0),
|
|
mNextOutputPOC(MINIMUM_POC),
|
|
mParserType(type),
|
|
mParserHandle(NULL),
|
|
mSignalBufferSize(0) {
|
|
|
|
memset(&mVideoFormatInfo, 0, sizeof(VideoFormatInfo));
|
|
memset(&mConfigBuffer, 0, sizeof(mConfigBuffer));
|
|
for (int i = 0; i < MAX_GRAPHIC_BUFFER_NUM; i++) {
|
|
mSignalBufferPre[i] = NULL;
|
|
}
|
|
pthread_mutex_init(&mLock, NULL);
|
|
pthread_mutex_init(&mFormatLock, NULL);
|
|
mVideoFormatInfo.mimeType = strdup(mimeType);
|
|
mUseGEN = false;
|
|
mMetaDataBuffersNum = 0;
|
|
mLibHandle = NULL;
|
|
mParserOpen = NULL;
|
|
mParserClose = NULL;
|
|
mParserParse = NULL;
|
|
mParserQuery = NULL;
|
|
mParserFlush = NULL;
|
|
mParserUpdate = NULL;
|
|
}
|
|
|
|
VideoDecoderBase::~VideoDecoderBase() {
|
|
pthread_mutex_destroy(&mLock);
|
|
pthread_mutex_destroy(&mFormatLock);
|
|
stop();
|
|
free(mVideoFormatInfo.mimeType);
|
|
}
|
|
|
|
Decode_Status VideoDecoderBase::start(VideoConfigBuffer *buffer) {
|
|
if (buffer == NULL) {
|
|
return DECODE_INVALID_DATA;
|
|
}
|
|
|
|
if (mParserHandle != NULL) {
|
|
WTRACE("Decoder has already started.");
|
|
return DECODE_SUCCESS;
|
|
}
|
|
mLibHandle = dlopen("libmixvbp.so", RTLD_NOW);
|
|
if (mLibHandle == NULL) {
|
|
return DECODE_NO_PARSER;
|
|
}
|
|
mParserOpen = (OpenFunc)dlsym(mLibHandle, "vbp_open");
|
|
mParserClose = (CloseFunc)dlsym(mLibHandle, "vbp_close");
|
|
mParserParse = (ParseFunc)dlsym(mLibHandle, "vbp_parse");
|
|
mParserQuery = (QueryFunc)dlsym(mLibHandle, "vbp_query");
|
|
mParserFlush = (FlushFunc)dlsym(mLibHandle, "vbp_flush");
|
|
if (mParserOpen == NULL || mParserClose == NULL || mParserParse == NULL
|
|
|| mParserQuery == NULL || mParserFlush == NULL) {
|
|
return DECODE_NO_PARSER;
|
|
}
|
|
#if (defined USE_AVC_SHORT_FORMAT || defined USE_SLICE_HEADER_PARSING)
|
|
mParserUpdate = (UpdateFunc)dlsym(mLibHandle, "vbp_update");
|
|
if (mParserUpdate == NULL) {
|
|
return DECODE_NO_PARSER;
|
|
}
|
|
#endif
|
|
if ((int32_t)mParserType != VBP_INVALID) {
|
|
ITRACE("mParserType = %d", mParserType);
|
|
if (mParserOpen(mParserType, &mParserHandle) != VBP_OK) {
|
|
ETRACE("Failed to open VBP parser.");
|
|
return DECODE_NO_PARSER;
|
|
}
|
|
}
|
|
// keep a copy of configure buffer, meta data only. It can be used to override VA setup parameter.
|
|
mConfigBuffer = *buffer;
|
|
mConfigBuffer.data = NULL;
|
|
mConfigBuffer.size = 0;
|
|
|
|
mVideoFormatInfo.width = buffer->width;
|
|
mVideoFormatInfo.height = buffer->height;
|
|
if (buffer->flag & USE_NATIVE_GRAPHIC_BUFFER) {
|
|
mVideoFormatInfo.surfaceWidth = buffer->graphicBufferWidth;
|
|
mVideoFormatInfo.surfaceHeight = buffer->graphicBufferHeight;
|
|
}
|
|
mLowDelay = buffer->flag & WANT_LOW_DELAY;
|
|
mStoreMetaData = buffer->flag & WANT_STORE_META_DATA;
|
|
mRawOutput = buffer->flag & WANT_RAW_OUTPUT;
|
|
if (mRawOutput) {
|
|
WTRACE("Output is raw data.");
|
|
}
|
|
|
|
return DECODE_SUCCESS;
|
|
}
|
|
|
|
|
|
Decode_Status VideoDecoderBase::reset(VideoConfigBuffer *buffer) {
|
|
if (buffer == NULL) {
|
|
return DECODE_INVALID_DATA;
|
|
}
|
|
|
|
// if VA is already started, terminate VA as graphic buffers are reallocated by omxcodec
|
|
terminateVA();
|
|
|
|
// reset the mconfigBuffer to pass it for startVA.
|
|
mConfigBuffer = *buffer;
|
|
mConfigBuffer.data = NULL;
|
|
mConfigBuffer.size = 0;
|
|
|
|
mVideoFormatInfo.width = buffer->width;
|
|
mVideoFormatInfo.height = buffer->height;
|
|
if (buffer->flag & USE_NATIVE_GRAPHIC_BUFFER) {
|
|
mVideoFormatInfo.surfaceWidth = buffer->graphicBufferWidth;
|
|
mVideoFormatInfo.surfaceHeight = buffer->graphicBufferHeight;
|
|
}
|
|
mVideoFormatInfo.actualBufferNeeded = mConfigBuffer.surfaceNumber;
|
|
mLowDelay = buffer->flag & WANT_LOW_DELAY;
|
|
mStoreMetaData = buffer->flag & WANT_STORE_META_DATA;
|
|
mMetaDataBuffersNum = 0;
|
|
mRawOutput = buffer->flag & WANT_RAW_OUTPUT;
|
|
if (mRawOutput) {
|
|
WTRACE("Output is raw data.");
|
|
}
|
|
return DECODE_SUCCESS;
|
|
}
|
|
|
|
|
|
|
|
void VideoDecoderBase::stop(void) {
|
|
terminateVA();
|
|
|
|
mCurrentPTS = INVALID_PTS;
|
|
mAcquiredBuffer = NULL;
|
|
mLastReference = NULL;
|
|
mForwardReference = NULL;
|
|
mDecodingFrame = false;
|
|
mSizeChanged = false;
|
|
|
|
// private variables
|
|
mLowDelay = false;
|
|
mStoreMetaData = false;
|
|
mRawOutput = false;
|
|
mNumSurfaces = 0;
|
|
mSurfaceAcquirePos = 0;
|
|
mNextOutputPOC = MINIMUM_POC;
|
|
mVideoFormatInfo.valid = false;
|
|
if (mParserHandle){
|
|
mParserClose(mParserHandle);
|
|
mParserHandle = NULL;
|
|
}
|
|
if (mLibHandle) {
|
|
dlclose(mLibHandle);
|
|
mLibHandle = NULL;
|
|
}
|
|
}
|
|
|
|
void VideoDecoderBase::flush(void) {
|
|
if (mVAStarted == false) {
|
|
// nothing to flush at this stage
|
|
return;
|
|
}
|
|
|
|
endDecodingFrame(true);
|
|
|
|
VideoSurfaceBuffer *p = mOutputHead;
|
|
// check if there's buffer with DRC flag in the output queue
|
|
while (p) {
|
|
if (p->renderBuffer.flag & IS_RESOLUTION_CHANGE) {
|
|
mSizeChanged = true;
|
|
break;
|
|
}
|
|
p = p->next;
|
|
}
|
|
// avoid setting mSurfaceAcquirePos to 0 as it may cause tearing
|
|
// (surface is still being rendered)
|
|
mSurfaceAcquirePos = (mSurfaceAcquirePos + 1) % mNumSurfaces;
|
|
mNextOutputPOC = MINIMUM_POC;
|
|
mCurrentPTS = INVALID_PTS;
|
|
mAcquiredBuffer = NULL;
|
|
mLastReference = NULL;
|
|
mForwardReference = NULL;
|
|
mOutputHead = NULL;
|
|
mOutputTail = NULL;
|
|
mDecodingFrame = false;
|
|
|
|
// flush vbp parser
|
|
if (mParserHandle && (mParserFlush(mParserHandle) != VBP_OK)) {
|
|
WTRACE("Failed to flush parser. Continue");
|
|
}
|
|
|
|
// initialize surface buffer without resetting mapped/raw data
|
|
initSurfaceBuffer(false);
|
|
|
|
}
|
|
|
|
void VideoDecoderBase::freeSurfaceBuffers(void) {
|
|
if (mVAStarted == false) {
|
|
// nothing to free surface buffers at this stage
|
|
return;
|
|
}
|
|
|
|
pthread_mutex_lock(&mLock);
|
|
|
|
endDecodingFrame(true);
|
|
|
|
// if VA is already started, terminate VA as graphic buffers are reallocated by omxcodec
|
|
terminateVA();
|
|
|
|
pthread_mutex_unlock(&mLock);
|
|
}
|
|
|
|
const VideoFormatInfo* VideoDecoderBase::getFormatInfo(void) {
|
|
if ((mConfigBuffer.flag & USE_NATIVE_GRAPHIC_BUFFER) && mStoreMetaData) {
|
|
// Do nothing here, just to avoid thread
|
|
// contention in updateFormatInfo()
|
|
pthread_mutex_lock(&mFormatLock);
|
|
pthread_mutex_unlock(&mFormatLock);
|
|
}
|
|
|
|
return &mVideoFormatInfo;
|
|
}
|
|
|
|
int VideoDecoderBase::getOutputQueueLength(void) {
|
|
VideoSurfaceBuffer *p = mOutputHead;
|
|
|
|
int i = 0;
|
|
while (p) {
|
|
p = p->next;
|
|
i++;
|
|
}
|
|
|
|
return i;
|
|
}
|
|
|
|
const VideoRenderBuffer* VideoDecoderBase::getOutput(bool draining, VideoErrorBuffer *outErrBuf) {
|
|
if (mVAStarted == false) {
|
|
return NULL;
|
|
}
|
|
bool useGraphicBuffer = mConfigBuffer.flag & USE_NATIVE_GRAPHIC_BUFFER;
|
|
|
|
if (draining) {
|
|
// complete decoding the last frame and ignore return
|
|
endDecodingFrame(false);
|
|
}
|
|
|
|
if (mOutputHead == NULL) {
|
|
return NULL;
|
|
}
|
|
|
|
// output by position (the first buffer)
|
|
VideoSurfaceBuffer *outputByPos = mOutputHead;
|
|
|
|
if (mLowDelay) {
|
|
mOutputHead = mOutputHead->next;
|
|
if (mOutputHead == NULL) {
|
|
mOutputTail = NULL;
|
|
}
|
|
vaSetTimestampForSurface(mVADisplay, outputByPos->renderBuffer.surface, outputByPos->renderBuffer.timeStamp);
|
|
if (useGraphicBuffer && !mUseGEN) {
|
|
vaSyncSurface(mVADisplay, outputByPos->renderBuffer.surface);
|
|
fillDecodingErrors(&(outputByPos->renderBuffer));
|
|
}
|
|
if (draining && mOutputTail == NULL) {
|
|
outputByPos->renderBuffer.flag |= IS_EOS;
|
|
}
|
|
drainDecodingErrors(outErrBuf, &(outputByPos->renderBuffer));
|
|
|
|
return &(outputByPos->renderBuffer);
|
|
}
|
|
|
|
VideoSurfaceBuffer *output = NULL;
|
|
if (mOutputMethod == OUTPUT_BY_POC) {
|
|
output = findOutputByPoc(draining);
|
|
} else if (mOutputMethod == OUTPUT_BY_PCT) {
|
|
output = findOutputByPct(draining);
|
|
} else {
|
|
ETRACE("Invalid output method.");
|
|
return NULL;
|
|
}
|
|
|
|
if (output == NULL) {
|
|
return NULL;
|
|
}
|
|
|
|
if (output != outputByPos) {
|
|
// remove this output from middle or end of the list
|
|
VideoSurfaceBuffer *p = outputByPos;
|
|
while (p->next != output) {
|
|
p = p->next;
|
|
}
|
|
p->next = output->next;
|
|
if (mOutputTail == output) {
|
|
mOutputTail = p;
|
|
}
|
|
} else {
|
|
// remove this output from head of the list
|
|
mOutputHead = mOutputHead->next;
|
|
if (mOutputHead == NULL) {
|
|
mOutputTail = NULL;
|
|
}
|
|
}
|
|
//VTRACE("Output POC %d for display (pts = %.2f)", output->pictureOrder, output->renderBuffer.timeStamp/1E6);
|
|
vaSetTimestampForSurface(mVADisplay, output->renderBuffer.surface, output->renderBuffer.timeStamp);
|
|
|
|
if (useGraphicBuffer && !mUseGEN) {
|
|
vaSyncSurface(mVADisplay, output->renderBuffer.surface);
|
|
fillDecodingErrors(&(output->renderBuffer));
|
|
}
|
|
|
|
if (draining && mOutputTail == NULL) {
|
|
output->renderBuffer.flag |= IS_EOS;
|
|
}
|
|
|
|
drainDecodingErrors(outErrBuf, &(output->renderBuffer));
|
|
|
|
return &(output->renderBuffer);
|
|
}
|
|
|
|
VideoSurfaceBuffer* VideoDecoderBase::findOutputByPts() {
|
|
// output by presentation time stamp - buffer with the smallest time stamp is output
|
|
VideoSurfaceBuffer *p = mOutputHead;
|
|
VideoSurfaceBuffer *outputByPts = NULL;
|
|
uint64_t pts = INVALID_PTS;
|
|
do {
|
|
if ((uint64_t)(p->renderBuffer.timeStamp) <= pts) {
|
|
// find buffer with the smallest PTS
|
|
pts = p->renderBuffer.timeStamp;
|
|
outputByPts = p;
|
|
}
|
|
p = p->next;
|
|
} while (p != NULL);
|
|
|
|
return outputByPts;
|
|
}
|
|
|
|
VideoSurfaceBuffer* VideoDecoderBase::findOutputByPct(bool draining) {
|
|
// output by picture coding type (PCT)
|
|
// if there is more than one reference frame, the first reference frame is ouput, otherwise,
|
|
// output non-reference frame if there is any.
|
|
|
|
VideoSurfaceBuffer *p = mOutputHead;
|
|
VideoSurfaceBuffer *outputByPct = NULL;
|
|
int32_t reference = 0;
|
|
do {
|
|
if (p->referenceFrame) {
|
|
reference++;
|
|
if (reference > 1) {
|
|
// mOutputHead must be a reference frame
|
|
outputByPct = mOutputHead;
|
|
break;
|
|
}
|
|
} else {
|
|
// first non-reference frame
|
|
outputByPct = p;
|
|
break;
|
|
}
|
|
p = p->next;
|
|
} while (p != NULL);
|
|
|
|
if (outputByPct == NULL && draining) {
|
|
outputByPct = mOutputHead;
|
|
}
|
|
return outputByPct;
|
|
}
|
|
|
|
#if 0
|
|
VideoSurfaceBuffer* VideoDecoderBase::findOutputByPoc(bool draining) {
|
|
// output by picture order count (POC)
|
|
// Output criteria:
|
|
// if there is IDR frame (POC == 0), all the frames before IDR must be output;
|
|
// Otherwise, if draining flag is set or list is full, frame with the least POC is output;
|
|
// Otherwise, NOTHING is output
|
|
|
|
int32_t dpbFullness = 0;
|
|
for (int32_t i = 0; i < mNumSurfaces; i++) {
|
|
// count num of reference frames
|
|
if (mSurfaceBuffers[i].asReferernce) {
|
|
dpbFullness++;
|
|
}
|
|
}
|
|
|
|
if (mAcquiredBuffer && mAcquiredBuffer->asReferernce) {
|
|
// frame is being decoded and is not ready for output yet
|
|
dpbFullness--;
|
|
}
|
|
|
|
VideoSurfaceBuffer *p = mOutputHead;
|
|
while (p != NULL) {
|
|
// count dpbFullness with non-reference frame in the output queue
|
|
if (p->asReferernce == false) {
|
|
dpbFullness++;
|
|
}
|
|
p = p->next;
|
|
}
|
|
|
|
Retry:
|
|
p = mOutputHead;
|
|
VideoSurfaceBuffer *outputByPoc = NULL;
|
|
int32_t count = 0;
|
|
int32_t poc = MAXIMUM_POC;
|
|
|
|
do {
|
|
if (p->pictureOrder == 0) {
|
|
// output picture with the least POC before IDR
|
|
if (outputByPoc != NULL) {
|
|
mNextOutputPOC = outputByPoc->pictureOrder + 1;
|
|
return outputByPoc;
|
|
} else {
|
|
mNextOutputPOC = MINIMUM_POC;
|
|
}
|
|
}
|
|
|
|
// POC of the output candidate must not be less than mNextOutputPOC
|
|
if (p->pictureOrder < mNextOutputPOC) {
|
|
break;
|
|
}
|
|
|
|
if (p->pictureOrder < poc) {
|
|
// update the least POC.
|
|
poc = p->pictureOrder;
|
|
outputByPoc = p;
|
|
}
|
|
count++;
|
|
p = p->next;
|
|
} while (p != NULL && count < mOutputWindowSize);
|
|
|
|
if (draining == false && dpbFullness < mOutputWindowSize) {
|
|
// list is not full and we are not in draining state
|
|
// if DPB is already full, one frame must be output
|
|
return NULL;
|
|
}
|
|
|
|
if (outputByPoc == NULL) {
|
|
mNextOutputPOC = MINIMUM_POC;
|
|
goto Retry;
|
|
}
|
|
|
|
// for debugging purpose
|
|
if (outputByPoc->pictureOrder != 0 && outputByPoc->pictureOrder < mNextOutputPOC) {
|
|
ETRACE("Output POC is not incremental, expected %d, actual %d", mNextOutputPOC, outputByPoc->pictureOrder);
|
|
//gaps_in_frame_num_value_allowed_flag is not currently supported
|
|
}
|
|
|
|
mNextOutputPOC = outputByPoc->pictureOrder + 1;
|
|
|
|
return outputByPoc;
|
|
}
|
|
#else
|
|
VideoSurfaceBuffer* VideoDecoderBase::findOutputByPoc(bool draining) {
|
|
VideoSurfaceBuffer *output = NULL;
|
|
VideoSurfaceBuffer *p = mOutputHead;
|
|
int32_t count = 0;
|
|
int32_t poc = MAXIMUM_POC;
|
|
VideoSurfaceBuffer *outputleastpoc = mOutputHead;
|
|
do {
|
|
count++;
|
|
if (p->pictureOrder == 0) {
|
|
// any picture before this POC (new IDR) must be output
|
|
if (output == NULL) {
|
|
mNextOutputPOC = MINIMUM_POC;
|
|
// looking for any POC with negative value
|
|
} else {
|
|
mNextOutputPOC = output->pictureOrder + 1;
|
|
break;
|
|
}
|
|
}
|
|
if (p->pictureOrder < poc && p->pictureOrder >= mNextOutputPOC) {
|
|
// this POC meets ouput criteria.
|
|
poc = p->pictureOrder;
|
|
output = p;
|
|
outputleastpoc = p;
|
|
}
|
|
if (poc == mNextOutputPOC || count == mOutputWindowSize) {
|
|
if (output != NULL) {
|
|
// this indicates two cases:
|
|
// 1) the next output POC is found.
|
|
// 2) output queue is full and there is at least one buffer meeting the output criteria.
|
|
mNextOutputPOC = output->pictureOrder + 1;
|
|
break;
|
|
} else {
|
|
// this indicates output queue is full and no buffer in the queue meets the output criteria
|
|
// restart processing as queue is FULL and output criteria is changed. (next output POC is 0)
|
|
mNextOutputPOC = MINIMUM_POC;
|
|
count = 0;
|
|
poc = MAXIMUM_POC;
|
|
p = mOutputHead;
|
|
continue;
|
|
}
|
|
}
|
|
if (p->next == NULL) {
|
|
output = NULL;
|
|
}
|
|
|
|
p = p->next;
|
|
} while (p != NULL);
|
|
|
|
if (draining == true && output == NULL) {
|
|
output = outputleastpoc;
|
|
}
|
|
|
|
return output;
|
|
}
|
|
#endif
|
|
|
|
bool VideoDecoderBase::checkBufferAvail(void) {
|
|
if (!mInitialized) {
|
|
if ((mConfigBuffer.flag & USE_NATIVE_GRAPHIC_BUFFER) == 0) {
|
|
return true;
|
|
}
|
|
for (int i = 0; i < MAX_GRAPHIC_BUFFER_NUM; i++) {
|
|
if (mSignalBufferPre[i] != NULL) {
|
|
return true;
|
|
}
|
|
}
|
|
return false;
|
|
}
|
|
// check whether there is buffer available for decoding
|
|
// TODO: check frame being referenced for frame skipping
|
|
VideoSurfaceBuffer *buffer = NULL;
|
|
for (int32_t i = 0; i < mNumSurfaces; i++) {
|
|
buffer = mSurfaceBuffers + i;
|
|
|
|
if (buffer->asReferernce == false &&
|
|
buffer->renderBuffer.renderDone == true) {
|
|
querySurfaceRenderStatus(buffer);
|
|
if (buffer->renderBuffer.driverRenderDone == true)
|
|
return true;
|
|
}
|
|
}
|
|
return false;
|
|
}
|
|
|
|
Decode_Status VideoDecoderBase::acquireSurfaceBuffer(void) {
|
|
if (mVAStarted == false) {
|
|
return DECODE_FAIL;
|
|
}
|
|
|
|
if (mAcquiredBuffer != NULL) {
|
|
ETRACE("mAcquiredBuffer is not NULL. Implementation bug.");
|
|
return DECODE_FAIL;
|
|
}
|
|
|
|
int nextAcquire = mSurfaceAcquirePos;
|
|
VideoSurfaceBuffer *acquiredBuffer = NULL;
|
|
bool acquired = false;
|
|
|
|
while (acquired == false) {
|
|
acquiredBuffer = mSurfaceBuffers + nextAcquire;
|
|
|
|
querySurfaceRenderStatus(acquiredBuffer);
|
|
|
|
if (acquiredBuffer->asReferernce == false && acquiredBuffer->renderBuffer.renderDone == true && acquiredBuffer->renderBuffer.driverRenderDone == true) {
|
|
// this is potential buffer for acquisition. Check if it is referenced by other surface for frame skipping
|
|
VideoSurfaceBuffer *temp;
|
|
acquired = true;
|
|
for (int i = 0; i < mNumSurfaces; i++) {
|
|
if (i == nextAcquire) {
|
|
continue;
|
|
}
|
|
temp = mSurfaceBuffers + i;
|
|
// use mSurfaces[nextAcquire] instead of acquiredBuffer->renderBuffer.surface as its the actual surface to use.
|
|
if (temp->renderBuffer.surface == mSurfaces[nextAcquire] &&
|
|
temp->renderBuffer.renderDone == false) {
|
|
ITRACE("Surface is referenced by other surface buffer.");
|
|
acquired = false;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
if (acquired) {
|
|
break;
|
|
}
|
|
nextAcquire++;
|
|
if (nextAcquire == mNumSurfaces) {
|
|
nextAcquire = 0;
|
|
}
|
|
if (nextAcquire == mSurfaceAcquirePos) {
|
|
return DECODE_NO_SURFACE;
|
|
}
|
|
}
|
|
|
|
if (acquired == false) {
|
|
return DECODE_NO_SURFACE;
|
|
}
|
|
|
|
mAcquiredBuffer = acquiredBuffer;
|
|
mSurfaceAcquirePos = nextAcquire;
|
|
|
|
// set surface again as surface maybe reset by skipped frame.
|
|
// skipped frame is a "non-coded frame" and decoder needs to duplicate the previous reference frame as the output.
|
|
mAcquiredBuffer->renderBuffer.surface = mSurfaces[mSurfaceAcquirePos];
|
|
if (mSurfaceUserPtr && mAcquiredBuffer->mappedData) {
|
|
mAcquiredBuffer->mappedData->data = mSurfaceUserPtr[mSurfaceAcquirePos];
|
|
}
|
|
mAcquiredBuffer->renderBuffer.timeStamp = INVALID_PTS;
|
|
mAcquiredBuffer->renderBuffer.display = mVADisplay;
|
|
mAcquiredBuffer->renderBuffer.flag = 0;
|
|
mAcquiredBuffer->renderBuffer.renderDone = false;
|
|
mAcquiredBuffer->asReferernce = false;
|
|
mAcquiredBuffer->renderBuffer.errBuf.errorNumber = 0;
|
|
mAcquiredBuffer->renderBuffer.errBuf.timeStamp = INVALID_PTS;
|
|
|
|
return DECODE_SUCCESS;
|
|
}
|
|
|
|
Decode_Status VideoDecoderBase::outputSurfaceBuffer(void) {
|
|
Decode_Status status;
|
|
if (mAcquiredBuffer == NULL) {
|
|
ETRACE("mAcquiredBuffer is NULL. Implementation bug.");
|
|
return DECODE_FAIL;
|
|
}
|
|
|
|
if (mRawOutput) {
|
|
status = getRawDataFromSurface();
|
|
CHECK_STATUS();
|
|
}
|
|
|
|
// frame is successfly decoded to the current surface, it is ready for output
|
|
if (mShowFrame) {
|
|
mAcquiredBuffer->renderBuffer.renderDone = false;
|
|
} else {
|
|
mAcquiredBuffer->renderBuffer.renderDone = true;
|
|
}
|
|
|
|
// decoder must set "asReference and referenceFrame" flags properly
|
|
|
|
// update reference frames
|
|
if (mAcquiredBuffer->referenceFrame) {
|
|
if (mManageReference) {
|
|
// managing reference for MPEG4/H.263/WMV.
|
|
// AVC should manage reference frame in a different way
|
|
if (mForwardReference != NULL) {
|
|
// this foward reference is no longer needed
|
|
mForwardReference->asReferernce = false;
|
|
}
|
|
// Forware reference for either P or B frame prediction
|
|
mForwardReference = mLastReference;
|
|
mAcquiredBuffer->asReferernce = true;
|
|
}
|
|
|
|
// the last reference frame.
|
|
mLastReference = mAcquiredBuffer;
|
|
}
|
|
// add to the output list
|
|
if (mShowFrame) {
|
|
if (mOutputHead == NULL) {
|
|
mOutputHead = mAcquiredBuffer;
|
|
} else {
|
|
mOutputTail->next = mAcquiredBuffer;
|
|
}
|
|
mOutputTail = mAcquiredBuffer;
|
|
mOutputTail->next = NULL;
|
|
}
|
|
|
|
//VTRACE("Pushing POC %d to queue (pts = %.2f)", mAcquiredBuffer->pictureOrder, mAcquiredBuffer->renderBuffer.timeStamp/1E6);
|
|
|
|
mAcquiredBuffer = NULL;
|
|
mSurfaceAcquirePos = (mSurfaceAcquirePos + 1 ) % mNumSurfaces;
|
|
return DECODE_SUCCESS;
|
|
}
|
|
|
|
Decode_Status VideoDecoderBase::releaseSurfaceBuffer(void) {
|
|
if (mAcquiredBuffer == NULL) {
|
|
// this is harmless error
|
|
return DECODE_SUCCESS;
|
|
}
|
|
|
|
// frame is not decoded to the acquired buffer, current surface is invalid, and can't be output.
|
|
mAcquiredBuffer->asReferernce = false;
|
|
mAcquiredBuffer->renderBuffer.renderDone = true;
|
|
mAcquiredBuffer = NULL;
|
|
return DECODE_SUCCESS;
|
|
}
|
|
|
|
void VideoDecoderBase::flushSurfaceBuffers(void) {
|
|
endDecodingFrame(true);
|
|
VideoSurfaceBuffer *p = NULL;
|
|
while (mOutputHead) {
|
|
mOutputHead->renderBuffer.renderDone = true;
|
|
p = mOutputHead;
|
|
mOutputHead = mOutputHead->next;
|
|
p->next = NULL;
|
|
}
|
|
mOutputHead = NULL;
|
|
mOutputTail = NULL;
|
|
}
|
|
|
|
Decode_Status VideoDecoderBase::endDecodingFrame(bool dropFrame) {
|
|
Decode_Status status = DECODE_SUCCESS;
|
|
VAStatus vaStatus;
|
|
|
|
if (mDecodingFrame == false) {
|
|
if (mAcquiredBuffer != NULL) {
|
|
//ETRACE("mAcquiredBuffer is not NULL. Implementation bug.");
|
|
releaseSurfaceBuffer();
|
|
status = DECODE_FAIL;
|
|
}
|
|
return status;
|
|
}
|
|
// return through exit label to reset mDecodingFrame
|
|
if (mAcquiredBuffer == NULL) {
|
|
ETRACE("mAcquiredBuffer is NULL. Implementation bug.");
|
|
status = DECODE_FAIL;
|
|
goto exit;
|
|
}
|
|
|
|
vaStatus = vaEndPicture(mVADisplay, mVAContext);
|
|
if (vaStatus != VA_STATUS_SUCCESS) {
|
|
releaseSurfaceBuffer();
|
|
ETRACE("vaEndPicture failed. vaStatus = %d", vaStatus);
|
|
status = DECODE_DRIVER_FAIL;
|
|
goto exit;
|
|
}
|
|
|
|
if (dropFrame) {
|
|
// we are asked to drop this decoded picture
|
|
VTRACE("Frame dropped in endDecodingFrame");
|
|
vaStatus = vaSyncSurface(mVADisplay, mAcquiredBuffer->renderBuffer.surface);
|
|
releaseSurfaceBuffer();
|
|
goto exit;
|
|
}
|
|
status = outputSurfaceBuffer();
|
|
// fall through
|
|
exit:
|
|
mDecodingFrame = false;
|
|
return status;
|
|
}
|
|
|
|
|
|
Decode_Status VideoDecoderBase::setupVA(uint32_t numSurface, VAProfile profile, uint32_t numExtraSurface) {
|
|
VAStatus vaStatus = VA_STATUS_SUCCESS;
|
|
Decode_Status status;
|
|
|
|
if (mVAStarted) {
|
|
return DECODE_SUCCESS;
|
|
}
|
|
|
|
mRotationDegrees = 0;
|
|
if (mConfigBuffer.flag & USE_NATIVE_GRAPHIC_BUFFER){
|
|
#ifdef TARGET_HAS_ISV
|
|
if (mVideoFormatInfo.actualBufferNeeded > mConfigBuffer.surfaceNumber - mConfigBuffer.vppBufferNum)
|
|
#else
|
|
if (mVideoFormatInfo.actualBufferNeeded > mConfigBuffer.surfaceNumber)
|
|
#endif
|
|
return DECODE_FORMAT_CHANGE;
|
|
|
|
numSurface = mConfigBuffer.surfaceNumber;
|
|
// if format has been changed in USE_NATIVE_GRAPHIC_BUFFER mode,
|
|
// we can not setupVA here when the graphic buffer resolution is smaller than the resolution decoder really needs
|
|
if (mSizeChanged) {
|
|
if (mStoreMetaData || (!mStoreMetaData && (mVideoFormatInfo.surfaceWidth < mVideoFormatInfo.width || mVideoFormatInfo.surfaceHeight < mVideoFormatInfo.height))) {
|
|
mSizeChanged = false;
|
|
return DECODE_FORMAT_CHANGE;
|
|
}
|
|
}
|
|
}
|
|
|
|
// TODO: validate profile
|
|
if (numSurface == 0) {
|
|
return DECODE_FAIL;
|
|
}
|
|
|
|
if (mConfigBuffer.flag & HAS_MINIMUM_SURFACE_NUMBER) {
|
|
if (numSurface < mConfigBuffer.surfaceNumber) {
|
|
WTRACE("surface to allocated %d is less than minimum number required %d",
|
|
numSurface, mConfigBuffer.surfaceNumber);
|
|
numSurface = mConfigBuffer.surfaceNumber;
|
|
}
|
|
}
|
|
|
|
if (mVADisplay != NULL) {
|
|
ETRACE("VA is partially started.");
|
|
return DECODE_FAIL;
|
|
}
|
|
|
|
// Display is defined as "unsigned int"
|
|
#ifndef USE_HYBRID_DRIVER
|
|
mDisplay = new Display;
|
|
*mDisplay = ANDROID_DISPLAY_HANDLE;
|
|
#else
|
|
if (profile >= VAProfileH264Baseline && profile <= VAProfileVC1Advanced) {
|
|
ITRACE("Using GEN driver");
|
|
mDisplay = "libva_driver_name=i965";
|
|
mUseGEN = true;
|
|
} else {
|
|
ITRACE("Using PVR driver");
|
|
mDisplay = "libva_driver_name=pvr";
|
|
mUseGEN = false;
|
|
}
|
|
#endif
|
|
mVADisplay = vaGetDisplay(mDisplay);
|
|
if (mVADisplay == NULL) {
|
|
ETRACE("vaGetDisplay failed.");
|
|
return DECODE_DRIVER_FAIL;
|
|
}
|
|
|
|
int majorVersion, minorVersion;
|
|
vaStatus = vaInitialize(mVADisplay, &majorVersion, &minorVersion);
|
|
CHECK_VA_STATUS("vaInitialize");
|
|
|
|
if ((int32_t)profile != VAProfileSoftwareDecoding) {
|
|
|
|
status = checkHardwareCapability();
|
|
CHECK_STATUS("checkHardwareCapability");
|
|
|
|
#if (defined USE_AVC_SHORT_FORMAT || defined USE_SLICE_HEADER_PARSING)
|
|
status = getCodecSpecificConfigs(profile, &mVAConfig);
|
|
CHECK_STATUS("getCodecSpecificAttributes");
|
|
#else
|
|
VAConfigAttrib attrib;
|
|
//We are requesting RT attributes
|
|
attrib.type = VAConfigAttribRTFormat;
|
|
attrib.value = VA_RT_FORMAT_YUV420;
|
|
|
|
vaStatus = vaCreateConfig(
|
|
mVADisplay,
|
|
profile,
|
|
VAEntrypointVLD,
|
|
&attrib,
|
|
1,
|
|
&mVAConfig);
|
|
CHECK_VA_STATUS("vaCreateConfig");
|
|
#endif
|
|
}
|
|
|
|
mNumSurfaces = numSurface;
|
|
mNumExtraSurfaces = numExtraSurface;
|
|
mSurfaces = new VASurfaceID [mNumSurfaces + mNumExtraSurfaces];
|
|
mExtraSurfaces = mSurfaces + mNumSurfaces;
|
|
for (int i = 0; i < mNumSurfaces + mNumExtraSurfaces; ++i) {
|
|
mSurfaces[i] = VA_INVALID_SURFACE;
|
|
}
|
|
if (mSurfaces == NULL) {
|
|
return DECODE_MEMORY_FAIL;
|
|
}
|
|
|
|
setRenderRect();
|
|
setColorSpaceInfo(mVideoFormatInfo.colorMatrix, mVideoFormatInfo.videoRange);
|
|
|
|
int32_t format = VA_RT_FORMAT_YUV420;
|
|
if (mConfigBuffer.flag & WANT_SURFACE_PROTECTION) {
|
|
#ifndef USE_AVC_SHORT_FORMAT
|
|
format |= VA_RT_FORMAT_PROTECTED;
|
|
WTRACE("Surface is protected.");
|
|
#endif
|
|
}
|
|
if (mConfigBuffer.flag & USE_NATIVE_GRAPHIC_BUFFER) {
|
|
if (!mStoreMetaData) {
|
|
VASurfaceAttrib attribs[2];
|
|
mVASurfaceAttrib = new VASurfaceAttribExternalBuffers;
|
|
if (mVASurfaceAttrib == NULL) {
|
|
return DECODE_MEMORY_FAIL;
|
|
}
|
|
|
|
mVASurfaceAttrib->buffers= (unsigned long *)malloc(sizeof(unsigned long)*mNumSurfaces);
|
|
if (mVASurfaceAttrib->buffers == NULL) {
|
|
return DECODE_MEMORY_FAIL;
|
|
}
|
|
mVASurfaceAttrib->num_buffers = mNumSurfaces;
|
|
mVASurfaceAttrib->pixel_format = VA_FOURCC_NV12;
|
|
mVASurfaceAttrib->width = mVideoFormatInfo.surfaceWidth;
|
|
mVASurfaceAttrib->height = mVideoFormatInfo.surfaceHeight;
|
|
mVASurfaceAttrib->data_size = mConfigBuffer.graphicBufferHStride * mConfigBuffer.graphicBufferVStride * 1.5;
|
|
mVASurfaceAttrib->num_planes = 2;
|
|
mVASurfaceAttrib->pitches[0] = mConfigBuffer.graphicBufferHStride;
|
|
mVASurfaceAttrib->pitches[1] = mConfigBuffer.graphicBufferHStride;
|
|
mVASurfaceAttrib->pitches[2] = 0;
|
|
mVASurfaceAttrib->pitches[3] = 0;
|
|
mVASurfaceAttrib->offsets[0] = 0;
|
|
mVASurfaceAttrib->offsets[1] = mConfigBuffer.graphicBufferHStride * mConfigBuffer.graphicBufferVStride;
|
|
mVASurfaceAttrib->offsets[2] = 0;
|
|
mVASurfaceAttrib->offsets[3] = 0;
|
|
mVASurfaceAttrib->private_data = (void *)mConfigBuffer.nativeWindow;
|
|
mVASurfaceAttrib->flags = VA_SURFACE_ATTRIB_MEM_TYPE_ANDROID_GRALLOC;
|
|
if (mConfigBuffer.flag & USE_TILING_MEMORY)
|
|
mVASurfaceAttrib->flags |= VA_SURFACE_EXTBUF_DESC_ENABLE_TILING;
|
|
|
|
for (int i = 0; i < mNumSurfaces; i++) {
|
|
mVASurfaceAttrib->buffers[i] = (unsigned long)mConfigBuffer.graphicBufferHandler[i];
|
|
}
|
|
|
|
attribs[0].type = (VASurfaceAttribType)VASurfaceAttribMemoryType;
|
|
attribs[0].flags = VA_SURFACE_ATTRIB_SETTABLE;
|
|
attribs[0].value.type = VAGenericValueTypeInteger;
|
|
attribs[0].value.value.i = VA_SURFACE_ATTRIB_MEM_TYPE_ANDROID_GRALLOC;
|
|
|
|
attribs[1].type = (VASurfaceAttribType)VASurfaceAttribExternalBufferDescriptor;
|
|
attribs[1].flags = VA_SURFACE_ATTRIB_SETTABLE;
|
|
attribs[1].value.type = VAGenericValueTypePointer;
|
|
attribs[1].value.value.p = (void *)mVASurfaceAttrib;
|
|
|
|
vaStatus = vaCreateSurfaces(
|
|
mVADisplay,
|
|
format,
|
|
mVideoFormatInfo.surfaceWidth,
|
|
mVideoFormatInfo.surfaceHeight,
|
|
mSurfaces,
|
|
mNumSurfaces,
|
|
attribs,
|
|
2);
|
|
}
|
|
} else {
|
|
vaStatus = vaCreateSurfaces(
|
|
mVADisplay,
|
|
format,
|
|
mVideoFormatInfo.width,
|
|
mVideoFormatInfo.height,
|
|
mSurfaces,
|
|
mNumSurfaces,
|
|
NULL,
|
|
0);
|
|
mVideoFormatInfo.surfaceWidth = mVideoFormatInfo.width;
|
|
mVideoFormatInfo.surfaceHeight = mVideoFormatInfo.height;
|
|
}
|
|
CHECK_VA_STATUS("vaCreateSurfaces");
|
|
|
|
if (mNumExtraSurfaces != 0) {
|
|
vaStatus = vaCreateSurfaces(
|
|
mVADisplay,
|
|
format,
|
|
mVideoFormatInfo.surfaceWidth,
|
|
mVideoFormatInfo.surfaceHeight,
|
|
mExtraSurfaces,
|
|
mNumExtraSurfaces,
|
|
NULL,
|
|
0);
|
|
CHECK_VA_STATUS("vaCreateSurfaces");
|
|
}
|
|
|
|
mVideoFormatInfo.surfaceNumber = mNumSurfaces;
|
|
mVideoFormatInfo.ctxSurfaces = mSurfaces;
|
|
|
|
if ((int32_t)profile != VAProfileSoftwareDecoding) {
|
|
if (mStoreMetaData) {
|
|
if (mUseGEN) {
|
|
vaStatus = vaCreateContext(
|
|
mVADisplay,
|
|
mVAConfig,
|
|
mVideoFormatInfo.surfaceWidth,
|
|
mVideoFormatInfo.surfaceHeight,
|
|
0,
|
|
NULL,
|
|
0,
|
|
&mVAContext);
|
|
} else {
|
|
vaStatus = vaCreateContext(
|
|
mVADisplay,
|
|
mVAConfig,
|
|
mVideoFormatInfo.surfaceWidth,
|
|
mVideoFormatInfo.surfaceHeight,
|
|
0,
|
|
NULL,
|
|
mNumSurfaces + mNumExtraSurfaces,
|
|
&mVAContext);
|
|
}
|
|
} else {
|
|
vaStatus = vaCreateContext(
|
|
mVADisplay,
|
|
mVAConfig,
|
|
mVideoFormatInfo.surfaceWidth,
|
|
mVideoFormatInfo.surfaceHeight,
|
|
0,
|
|
mSurfaces,
|
|
mNumSurfaces + mNumExtraSurfaces,
|
|
&mVAContext);
|
|
}
|
|
CHECK_VA_STATUS("vaCreateContext");
|
|
}
|
|
|
|
mSurfaceBuffers = new VideoSurfaceBuffer [mNumSurfaces];
|
|
if (mSurfaceBuffers == NULL) {
|
|
return DECODE_MEMORY_FAIL;
|
|
}
|
|
initSurfaceBuffer(true);
|
|
|
|
if ((int32_t)profile == VAProfileSoftwareDecoding) {
|
|
// derive user pointer from surface for direct access
|
|
status = mapSurface();
|
|
CHECK_STATUS("mapSurface")
|
|
}
|
|
|
|
setRotationDegrees(mConfigBuffer.rotationDegrees);
|
|
|
|
mVAStarted = true;
|
|
|
|
pthread_mutex_lock(&mLock);
|
|
if (mStoreMetaData) {
|
|
for (uint32_t i = 0; i < mMetaDataBuffersNum; i++) {
|
|
status = createSurfaceFromHandle(i);
|
|
CHECK_STATUS("createSurfaceFromHandle");
|
|
mSurfaceBuffers[i].renderBuffer.graphicBufferIndex = i;
|
|
}
|
|
}
|
|
pthread_mutex_unlock(&mLock);
|
|
|
|
return DECODE_SUCCESS;
|
|
}
|
|
|
|
Decode_Status VideoDecoderBase::terminateVA(void) {
|
|
mSignalBufferSize = 0;
|
|
for (int i = 0; i < MAX_GRAPHIC_BUFFER_NUM; i++) {
|
|
mSignalBufferPre[i] = NULL;
|
|
}
|
|
|
|
if (mVAStarted == false) {
|
|
// VA hasn't been started yet
|
|
return DECODE_SUCCESS;
|
|
}
|
|
|
|
if (mSurfaceBuffers) {
|
|
for (int32_t i = 0; i < mNumSurfaces; i++) {
|
|
if (mSurfaceBuffers[i].renderBuffer.rawData) {
|
|
if (mSurfaceBuffers[i].renderBuffer.rawData->data) {
|
|
delete [] mSurfaceBuffers[i].renderBuffer.rawData->data;
|
|
}
|
|
delete mSurfaceBuffers[i].renderBuffer.rawData;
|
|
}
|
|
if (mSurfaceBuffers[i].mappedData) {
|
|
// don't delete data pointer as it is mapped from surface
|
|
delete mSurfaceBuffers[i].mappedData;
|
|
}
|
|
}
|
|
delete [] mSurfaceBuffers;
|
|
mSurfaceBuffers = NULL;
|
|
}
|
|
|
|
if (mVASurfaceAttrib) {
|
|
if (mVASurfaceAttrib->buffers) free(mVASurfaceAttrib->buffers);
|
|
delete mVASurfaceAttrib;
|
|
mVASurfaceAttrib = NULL;
|
|
}
|
|
|
|
|
|
if (mSurfaceUserPtr) {
|
|
delete [] mSurfaceUserPtr;
|
|
mSurfaceUserPtr = NULL;
|
|
}
|
|
|
|
if (mSurfaces) {
|
|
vaDestroySurfaces(mVADisplay, mSurfaces, mStoreMetaData ? mMetaDataBuffersNum : (mNumSurfaces + mNumExtraSurfaces));
|
|
delete [] mSurfaces;
|
|
mSurfaces = NULL;
|
|
}
|
|
|
|
if (mVAContext != VA_INVALID_ID) {
|
|
vaDestroyContext(mVADisplay, mVAContext);
|
|
mVAContext = VA_INVALID_ID;
|
|
}
|
|
|
|
if (mVAConfig != VA_INVALID_ID) {
|
|
vaDestroyConfig(mVADisplay, mVAConfig);
|
|
mVAConfig = VA_INVALID_ID;
|
|
}
|
|
|
|
if (mVADisplay) {
|
|
vaTerminate(mVADisplay);
|
|
mVADisplay = NULL;
|
|
}
|
|
|
|
if (mDisplay) {
|
|
#ifndef USE_HYBRID_DRIVER
|
|
delete mDisplay;
|
|
#endif
|
|
mDisplay = NULL;
|
|
}
|
|
|
|
mVAStarted = false;
|
|
mInitialized = false;
|
|
mErrReportEnabled = false;
|
|
if (mStoreMetaData) {
|
|
mMetaDataBuffersNum = 0;
|
|
mSurfaceAcquirePos = 0;
|
|
}
|
|
return DECODE_SUCCESS;
|
|
}
|
|
|
|
Decode_Status VideoDecoderBase::parseBuffer(uint8_t *buffer, int32_t size, bool config, void** vbpData) {
|
|
// DON'T check if mVAStarted == true
|
|
if (mParserHandle == NULL) {
|
|
return DECODE_NO_PARSER;
|
|
}
|
|
|
|
uint32_t vbpStatus;
|
|
if (buffer == NULL || size <= 0) {
|
|
return DECODE_INVALID_DATA;
|
|
}
|
|
|
|
uint8_t configFlag = config ? 1 : 0;
|
|
vbpStatus = mParserParse(mParserHandle, buffer, size, configFlag);
|
|
CHECK_VBP_STATUS("vbp_parse");
|
|
|
|
vbpStatus = mParserQuery(mParserHandle, vbpData);
|
|
CHECK_VBP_STATUS("vbp_query");
|
|
|
|
return DECODE_SUCCESS;
|
|
}
|
|
|
|
Decode_Status VideoDecoderBase::mapSurface(void) {
|
|
VAStatus vaStatus = VA_STATUS_SUCCESS;
|
|
VAImage image;
|
|
uint8_t *userPtr;
|
|
mSurfaceUserPtr = new uint8_t* [mNumSurfaces];
|
|
if (mSurfaceUserPtr == NULL) {
|
|
return DECODE_MEMORY_FAIL;
|
|
}
|
|
|
|
for (int32_t i = 0; i< mNumSurfaces; i++) {
|
|
vaStatus = vaDeriveImage(mVADisplay, mSurfaces[i], &image);
|
|
CHECK_VA_STATUS("vaDeriveImage");
|
|
vaStatus = vaMapBuffer(mVADisplay, image.buf, (void**)&userPtr);
|
|
CHECK_VA_STATUS("vaMapBuffer");
|
|
mSurfaceUserPtr[i] = userPtr;
|
|
mSurfaceBuffers[i].mappedData = new VideoFrameRawData;
|
|
if (mSurfaceBuffers[i].mappedData == NULL) {
|
|
return DECODE_MEMORY_FAIL;
|
|
}
|
|
mSurfaceBuffers[i].mappedData->own = false; // derived from surface so can't be released
|
|
mSurfaceBuffers[i].mappedData->data = NULL; // specified during acquireSurfaceBuffer
|
|
mSurfaceBuffers[i].mappedData->fourcc = image.format.fourcc;
|
|
mSurfaceBuffers[i].mappedData->width = mVideoFormatInfo.width;
|
|
mSurfaceBuffers[i].mappedData->height = mVideoFormatInfo.height;
|
|
mSurfaceBuffers[i].mappedData->size = image.data_size;
|
|
for (int pi = 0; pi < 3; pi++) {
|
|
mSurfaceBuffers[i].mappedData->pitch[pi] = image.pitches[pi];
|
|
mSurfaceBuffers[i].mappedData->offset[pi] = image.offsets[pi];
|
|
}
|
|
// debug information
|
|
if (image.pitches[0] != image.pitches[1] ||
|
|
image.width != mVideoFormatInfo.width ||
|
|
image.height != mVideoFormatInfo.height ||
|
|
image.offsets[0] != 0) {
|
|
WTRACE("Unexpected VAImage format, w = %d, h = %d, offset = %d", image.width, image.height, image.offsets[0]);
|
|
}
|
|
// TODO: do we need to unmap buffer?
|
|
//vaStatus = vaUnmapBuffer(mVADisplay, image.buf);
|
|
//CHECK_VA_STATUS("vaMapBuffer");
|
|
vaStatus = vaDestroyImage(mVADisplay,image.image_id);
|
|
CHECK_VA_STATUS("vaDestroyImage");
|
|
|
|
}
|
|
return DECODE_SUCCESS;
|
|
}
|
|
|
|
Decode_Status VideoDecoderBase::getRawDataFromSurface(VideoRenderBuffer *renderBuffer, uint8_t *pRawData, uint32_t *pSize, bool internal) {
|
|
if (internal) {
|
|
if (mAcquiredBuffer == NULL) {
|
|
return DECODE_FAIL;
|
|
}
|
|
renderBuffer = &(mAcquiredBuffer->renderBuffer);
|
|
}
|
|
|
|
VAStatus vaStatus;
|
|
VAImage vaImage;
|
|
vaStatus = vaSyncSurface(renderBuffer->display, renderBuffer->surface);
|
|
CHECK_VA_STATUS("vaSyncSurface");
|
|
|
|
vaStatus = vaDeriveImage(renderBuffer->display, renderBuffer->surface, &vaImage);
|
|
CHECK_VA_STATUS("vaDeriveImage");
|
|
|
|
void *pBuf = NULL;
|
|
vaStatus = vaMapBuffer(renderBuffer->display, vaImage.buf, &pBuf);
|
|
CHECK_VA_STATUS("vaMapBuffer");
|
|
|
|
|
|
// size in NV12 format
|
|
uint32_t cropWidth = mVideoFormatInfo.width - (mVideoFormatInfo.cropLeft + mVideoFormatInfo.cropRight);
|
|
uint32_t cropHeight = mVideoFormatInfo.height - (mVideoFormatInfo.cropBottom + mVideoFormatInfo.cropTop);
|
|
if (strcasecmp(mVideoFormatInfo.mimeType,"video/avc") == 0 ||
|
|
strcasecmp(mVideoFormatInfo.mimeType,"video/avc-secure") == 0 ||
|
|
strcasecmp(mVideoFormatInfo.mimeType,"video/h264") == 0) {
|
|
cropHeight = mVideoFormatInfo.height;
|
|
cropWidth = mVideoFormatInfo.width;
|
|
}
|
|
int32_t size = cropWidth * cropHeight * 3 / 2;
|
|
|
|
if (internal) {
|
|
VideoFrameRawData *rawData = NULL;
|
|
if (renderBuffer->rawData == NULL) {
|
|
rawData = new VideoFrameRawData;
|
|
if (rawData == NULL) {
|
|
return DECODE_MEMORY_FAIL;
|
|
}
|
|
memset(rawData, 0, sizeof(VideoFrameRawData));
|
|
renderBuffer->rawData = rawData;
|
|
} else {
|
|
rawData = renderBuffer->rawData;
|
|
}
|
|
|
|
if (rawData->data != NULL && rawData->size != size) {
|
|
delete [] rawData->data;
|
|
rawData->data = NULL;
|
|
rawData->size = 0;
|
|
}
|
|
if (rawData->data == NULL) {
|
|
rawData->data = new uint8_t [size];
|
|
if (rawData->data == NULL) {
|
|
return DECODE_MEMORY_FAIL;
|
|
}
|
|
}
|
|
|
|
rawData->own = true; // allocated by this library
|
|
rawData->width = cropWidth;
|
|
rawData->height = cropHeight;
|
|
rawData->pitch[0] = cropWidth;
|
|
rawData->pitch[1] = cropWidth;
|
|
rawData->pitch[2] = 0; // interleaved U/V, two planes
|
|
rawData->offset[0] = 0;
|
|
rawData->offset[1] = cropWidth * cropHeight;
|
|
rawData->offset[2] = cropWidth * cropHeight * 3 / 2;
|
|
rawData->size = size;
|
|
rawData->fourcc = 'NV12';
|
|
|
|
pRawData = rawData->data;
|
|
} else {
|
|
*pSize = size;
|
|
}
|
|
|
|
if (size == (int32_t)vaImage.data_size) {
|
|
#ifdef __SSE4_1__
|
|
stream_memcpy(pRawData, pBuf, size);
|
|
#else
|
|
memcpy(pRawData, pBuf, size);
|
|
#endif
|
|
} else {
|
|
// copy Y data
|
|
uint8_t *src = (uint8_t*)pBuf;
|
|
uint8_t *dst = pRawData;
|
|
uint32_t row = 0;
|
|
for (row = 0; row < cropHeight; row++) {
|
|
#ifdef __SSE4_1__
|
|
stream_memcpy(dst, src, cropWidth);
|
|
#else
|
|
memcpy(dst, src, cropWidth);
|
|
#endif
|
|
dst += cropWidth;
|
|
src += vaImage.pitches[0];
|
|
}
|
|
// copy interleaved V and U data
|
|
src = (uint8_t*)pBuf + vaImage.offsets[1];
|
|
for (row = 0; row < cropHeight / 2; row++) {
|
|
#ifdef __SSE4_1__
|
|
stream_memcpy(dst, src, cropWidth);
|
|
#else
|
|
memcpy(dst, src, cropWidth);
|
|
#endif
|
|
dst += cropWidth;
|
|
src += vaImage.pitches[1];
|
|
}
|
|
}
|
|
|
|
vaStatus = vaUnmapBuffer(renderBuffer->display, vaImage.buf);
|
|
CHECK_VA_STATUS("vaUnmapBuffer");
|
|
|
|
vaStatus = vaDestroyImage(renderBuffer->display, vaImage.image_id);
|
|
CHECK_VA_STATUS("vaDestroyImage");
|
|
|
|
return DECODE_SUCCESS;
|
|
}
|
|
|
|
Decode_Status VideoDecoderBase::createSurfaceFromHandle(int index) {
|
|
VAStatus vaStatus = VA_STATUS_SUCCESS;
|
|
Decode_Status status;
|
|
|
|
int32_t format = VA_RT_FORMAT_YUV420;
|
|
if (mConfigBuffer.flag & WANT_SURFACE_PROTECTION) {
|
|
#ifndef USE_AVC_SHORT_FORMAT
|
|
format |= VA_RT_FORMAT_PROTECTED;
|
|
WTRACE("Surface is protected.");
|
|
#endif
|
|
}
|
|
VASurfaceAttrib attribs[2];
|
|
VASurfaceAttribExternalBuffers surfExtBuf;
|
|
surfExtBuf.num_buffers = 1;
|
|
surfExtBuf.pixel_format = VA_FOURCC_NV12;
|
|
surfExtBuf.width = mVideoFormatInfo.surfaceWidth;
|
|
surfExtBuf.height = mVideoFormatInfo.surfaceHeight;
|
|
surfExtBuf.data_size = mConfigBuffer.graphicBufferHStride * mConfigBuffer.graphicBufferVStride * 1.5;
|
|
surfExtBuf.num_planes = 2;
|
|
surfExtBuf.pitches[0] = mConfigBuffer.graphicBufferHStride;
|
|
surfExtBuf.pitches[1] = mConfigBuffer.graphicBufferHStride;
|
|
surfExtBuf.pitches[2] = 0;
|
|
surfExtBuf.pitches[3] = 0;
|
|
surfExtBuf.offsets[0] = 0;
|
|
surfExtBuf.offsets[1] = mConfigBuffer.graphicBufferHStride * mConfigBuffer.graphicBufferVStride;
|
|
surfExtBuf.offsets[2] = 0;
|
|
surfExtBuf.offsets[3] = 0;
|
|
surfExtBuf.private_data = (void *)mConfigBuffer.nativeWindow;
|
|
surfExtBuf.flags = VA_SURFACE_ATTRIB_MEM_TYPE_ANDROID_GRALLOC;
|
|
if (mConfigBuffer.flag & USE_TILING_MEMORY) {
|
|
surfExtBuf.flags |= VA_SURFACE_EXTBUF_DESC_ENABLE_TILING;
|
|
}
|
|
|
|
surfExtBuf.buffers = (long unsigned int*)&(mConfigBuffer.graphicBufferHandler[index]);
|
|
|
|
attribs[0].type = (VASurfaceAttribType)VASurfaceAttribMemoryType;
|
|
attribs[0].flags = VA_SURFACE_ATTRIB_SETTABLE;
|
|
attribs[0].value.type = VAGenericValueTypeInteger;
|
|
attribs[0].value.value.i = VA_SURFACE_ATTRIB_MEM_TYPE_ANDROID_GRALLOC;
|
|
|
|
attribs[1].type = (VASurfaceAttribType)VASurfaceAttribExternalBufferDescriptor;
|
|
attribs[1].flags = VA_SURFACE_ATTRIB_SETTABLE;
|
|
attribs[1].value.type = VAGenericValueTypePointer;
|
|
attribs[1].value.value.p = (void *)&surfExtBuf;
|
|
|
|
vaStatus = vaCreateSurfaces(
|
|
mVADisplay,
|
|
format,
|
|
mVideoFormatInfo.surfaceWidth,
|
|
mVideoFormatInfo.surfaceHeight,
|
|
&(mSurfaces[index]),
|
|
1,
|
|
attribs,
|
|
2);
|
|
CHECK_VA_STATUS("vaCreateSurfaces");
|
|
|
|
return DECODE_SUCCESS;
|
|
}
|
|
|
|
void VideoDecoderBase::initSurfaceBuffer(bool reset) {
|
|
bool useGraphicBuffer = mConfigBuffer.flag & USE_NATIVE_GRAPHIC_BUFFER;
|
|
if (useGraphicBuffer && reset) {
|
|
pthread_mutex_lock(&mLock);
|
|
}
|
|
for (int32_t i = 0; i < mNumSurfaces; i++) {
|
|
mSurfaceBuffers[i].renderBuffer.display = mVADisplay;
|
|
mSurfaceBuffers[i].renderBuffer.surface = VA_INVALID_SURFACE; // set in acquireSurfaceBuffer
|
|
mSurfaceBuffers[i].renderBuffer.flag = 0;
|
|
mSurfaceBuffers[i].renderBuffer.scanFormat = VA_FRAME_PICTURE;
|
|
mSurfaceBuffers[i].renderBuffer.timeStamp = 0;
|
|
mSurfaceBuffers[i].referenceFrame = false;
|
|
mSurfaceBuffers[i].asReferernce= false;
|
|
mSurfaceBuffers[i].pictureOrder = 0;
|
|
mSurfaceBuffers[i].next = NULL;
|
|
if (reset == true) {
|
|
mSurfaceBuffers[i].renderBuffer.rawData = NULL;
|
|
mSurfaceBuffers[i].mappedData = NULL;
|
|
}
|
|
if (useGraphicBuffer) {
|
|
if (reset) {
|
|
mSurfaceBuffers[i].renderBuffer.graphicBufferHandle = mConfigBuffer.graphicBufferHandler[i];
|
|
mSurfaceBuffers[i].renderBuffer.renderDone = false; //default false
|
|
for (uint32_t j = 0; j < mSignalBufferSize; j++) {
|
|
if(mSignalBufferPre[j] != NULL && mSignalBufferPre[j] == mSurfaceBuffers[i].renderBuffer.graphicBufferHandle) {
|
|
mSurfaceBuffers[i].renderBuffer.renderDone = true;
|
|
VTRACE("initSurfaceBuffer set renderDone = true index = %d", i);
|
|
mSignalBufferPre[j] = NULL;
|
|
break;
|
|
}
|
|
}
|
|
} else {
|
|
mSurfaceBuffers[i].renderBuffer.renderDone = false;
|
|
}
|
|
} else {
|
|
mSurfaceBuffers[i].renderBuffer.graphicBufferHandle = NULL;
|
|
mSurfaceBuffers[i].renderBuffer.renderDone = true;
|
|
}
|
|
mSurfaceBuffers[i].renderBuffer.graphicBufferIndex = i;
|
|
}
|
|
|
|
if (useGraphicBuffer && reset) {
|
|
mInitialized = true;
|
|
mSignalBufferSize = 0;
|
|
pthread_mutex_unlock(&mLock);
|
|
}
|
|
}
|
|
|
|
Decode_Status VideoDecoderBase::signalRenderDone(void * graphichandler, bool isNew) {
|
|
Decode_Status status;
|
|
if (graphichandler == NULL) {
|
|
return DECODE_SUCCESS;
|
|
}
|
|
pthread_mutex_lock(&mLock);
|
|
bool graphicBufferMode = mConfigBuffer.flag & USE_NATIVE_GRAPHIC_BUFFER;
|
|
if (mStoreMetaData) {
|
|
if (!graphicBufferMode) {
|
|
pthread_mutex_unlock(&mLock);
|
|
return DECODE_SUCCESS;
|
|
}
|
|
|
|
if ((mMetaDataBuffersNum < mConfigBuffer.surfaceNumber) && isNew) {
|
|
mConfigBuffer.graphicBufferHandler[mMetaDataBuffersNum] = graphichandler;
|
|
if (mInitialized) {
|
|
mSurfaceBuffers[mMetaDataBuffersNum].renderBuffer.graphicBufferHandle = graphichandler;
|
|
mSurfaceBuffers[mMetaDataBuffersNum].renderBuffer.graphicBufferIndex = mMetaDataBuffersNum;
|
|
}
|
|
}
|
|
}
|
|
int i = 0;
|
|
if (!mInitialized) {
|
|
if (mSignalBufferSize >= MAX_GRAPHIC_BUFFER_NUM) {
|
|
pthread_mutex_unlock(&mLock);
|
|
return DECODE_INVALID_DATA;
|
|
}
|
|
mSignalBufferPre[mSignalBufferSize++] = graphichandler;
|
|
VTRACE("SignalRenderDoneFlag mInitialized = false graphichandler = %p, mSignalBufferSize = %d", graphichandler, mSignalBufferSize);
|
|
} else {
|
|
if (!graphicBufferMode) {
|
|
pthread_mutex_unlock(&mLock);
|
|
return DECODE_SUCCESS;
|
|
}
|
|
if (mStoreMetaData) {
|
|
if ((mMetaDataBuffersNum < mConfigBuffer.surfaceNumber) && isNew) {
|
|
if (mVAStarted) {
|
|
status = createSurfaceFromHandle(mMetaDataBuffersNum);
|
|
CHECK_STATUS("createSurfaceFromHandle")
|
|
}
|
|
}
|
|
}
|
|
for (i = 0; i < mNumSurfaces; i++) {
|
|
if (mSurfaceBuffers[i].renderBuffer.graphicBufferHandle == graphichandler) {
|
|
mSurfaceBuffers[i].renderBuffer.renderDone = true;
|
|
VTRACE("SignalRenderDoneFlag mInitialized = true index = %d", i);
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
if (mStoreMetaData) {
|
|
if ((mMetaDataBuffersNum < mConfigBuffer.surfaceNumber) && isNew) {
|
|
mMetaDataBuffersNum++;
|
|
}
|
|
}
|
|
|
|
pthread_mutex_unlock(&mLock);
|
|
|
|
return DECODE_SUCCESS;
|
|
|
|
}
|
|
|
|
void VideoDecoderBase::querySurfaceRenderStatus(VideoSurfaceBuffer* surface) {
|
|
VASurfaceStatus surfStat = VASurfaceReady;
|
|
VAStatus vaStat = VA_STATUS_SUCCESS;
|
|
|
|
if (!surface) {
|
|
LOGW("SurfaceBuffer not ready yet");
|
|
return;
|
|
}
|
|
surface->renderBuffer.driverRenderDone = true;
|
|
|
|
#ifndef USE_GEN_HW
|
|
if (surface->renderBuffer.surface != VA_INVALID_SURFACE &&
|
|
(mConfigBuffer.flag & USE_NATIVE_GRAPHIC_BUFFER)) {
|
|
|
|
vaStat = vaQuerySurfaceStatus(mVADisplay, surface->renderBuffer.surface, &surfStat);
|
|
|
|
if ((vaStat == VA_STATUS_SUCCESS) && (surfStat != VASurfaceReady))
|
|
surface->renderBuffer.driverRenderDone = false;
|
|
|
|
}
|
|
#endif
|
|
|
|
}
|
|
|
|
// This function should be called before start() to load different type of parsers
|
|
#if (defined USE_AVC_SHORT_FORMAT || defined USE_SLICE_HEADER_PARSING)
|
|
Decode_Status VideoDecoderBase::setParserType(_vbp_parser_type type) {
|
|
if ((int32_t)type != VBP_INVALID) {
|
|
ITRACE("Parser Type = %d", (int32_t)type);
|
|
mParserType = type;
|
|
return DECODE_SUCCESS;
|
|
} else {
|
|
ETRACE("Invalid parser type = %d", (int32_t)type);
|
|
return DECODE_NO_PARSER;
|
|
}
|
|
}
|
|
|
|
Decode_Status VideoDecoderBase::updateBuffer(uint8_t *buffer, int32_t size, void** vbpData) {
|
|
if (mParserHandle == NULL) {
|
|
return DECODE_NO_PARSER;
|
|
}
|
|
|
|
uint32_t vbpStatus;
|
|
if (buffer == NULL || size <= 0) {
|
|
return DECODE_INVALID_DATA;
|
|
}
|
|
|
|
vbpStatus = mParserUpdate(mParserHandle, buffer, size, vbpData);
|
|
CHECK_VBP_STATUS("vbp_update");
|
|
|
|
return DECODE_SUCCESS;
|
|
}
|
|
|
|
Decode_Status VideoDecoderBase::queryBuffer(void** vbpData) {
|
|
if (mParserHandle == NULL) {
|
|
return DECODE_NO_PARSER;
|
|
}
|
|
|
|
uint32_t vbpStatus;
|
|
vbpStatus = mParserQuery(mParserHandle, vbpData);
|
|
CHECK_VBP_STATUS("vbp_query");
|
|
|
|
return DECODE_SUCCESS;
|
|
}
|
|
|
|
Decode_Status VideoDecoderBase::getCodecSpecificConfigs(VAProfile profile, VAConfigID *config) {
|
|
VAStatus vaStatus;
|
|
VAConfigAttrib attrib;
|
|
attrib.type = VAConfigAttribRTFormat;
|
|
attrib.value = VA_RT_FORMAT_YUV420;
|
|
|
|
if (config == NULL) {
|
|
ETRACE("Invalid parameter!");
|
|
return DECODE_FAIL;
|
|
}
|
|
|
|
vaStatus = vaCreateConfig(
|
|
mVADisplay,
|
|
profile,
|
|
VAEntrypointVLD,
|
|
&attrib,
|
|
1,
|
|
config);
|
|
|
|
CHECK_VA_STATUS("vaCreateConfig");
|
|
|
|
return DECODE_SUCCESS;
|
|
}
|
|
#endif
|
|
Decode_Status VideoDecoderBase::checkHardwareCapability() {
|
|
return DECODE_SUCCESS;
|
|
}
|
|
|
|
void VideoDecoderBase::drainDecodingErrors(VideoErrorBuffer *outErrBuf, VideoRenderBuffer *currentSurface) {
|
|
if (mErrReportEnabled && outErrBuf && currentSurface) {
|
|
memcpy(outErrBuf, &(currentSurface->errBuf), sizeof(VideoErrorBuffer));
|
|
|
|
currentSurface->errBuf.errorNumber = 0;
|
|
currentSurface->errBuf.timeStamp = INVALID_PTS;
|
|
}
|
|
if (outErrBuf)
|
|
VTRACE("%s: error number is %d", __FUNCTION__, outErrBuf->errorNumber);
|
|
}
|
|
|
|
void VideoDecoderBase::fillDecodingErrors(VideoRenderBuffer *currentSurface) {
|
|
VAStatus ret;
|
|
|
|
if (mErrReportEnabled) {
|
|
currentSurface->errBuf.timeStamp = currentSurface->timeStamp;
|
|
// TODO: is 10 a suitable number?
|
|
VASurfaceDecodeMBErrors *err_drv_output = NULL;
|
|
ret = vaQuerySurfaceError(mVADisplay, currentSurface->surface, VA_STATUS_ERROR_DECODING_ERROR, (void **)&err_drv_output);
|
|
if (ret || !err_drv_output) {
|
|
WTRACE("vaQuerySurfaceError failed.");
|
|
return;
|
|
}
|
|
|
|
int offset = 0x1 & currentSurface->errBuf.errorNumber;// offset is either 0 or 1
|
|
for (int i = 0; i < MAX_ERR_NUM - offset; i++) {
|
|
if (err_drv_output[i].status != -1) {
|
|
currentSurface->errBuf.errorNumber++;
|
|
currentSurface->errBuf.errorArray[i + offset].type = DecodeMBError;
|
|
currentSurface->errBuf.errorArray[i + offset].error_data.mb_pos.start_mb = err_drv_output[i].start_mb;
|
|
currentSurface->errBuf.errorArray[i + offset].error_data.mb_pos.end_mb = err_drv_output[i].end_mb;
|
|
currentSurface->errBuf.errorArray[i + offset].num_mbs = err_drv_output[i].end_mb - err_drv_output[i].start_mb + 1;
|
|
ITRACE("Error Index[%d]: type = %d, start_mb = %d, end_mb = %d",
|
|
currentSurface->errBuf.errorNumber - 1,
|
|
currentSurface->errBuf.errorArray[i + offset].type,
|
|
currentSurface->errBuf.errorArray[i + offset].error_data.mb_pos.start_mb,
|
|
currentSurface->errBuf.errorArray[i + offset].error_data.mb_pos.end_mb);
|
|
} else break;
|
|
}
|
|
ITRACE("%s: error number of current surface is %d, timestamp @%llu",
|
|
__FUNCTION__, currentSurface->errBuf.errorNumber, currentSurface->timeStamp);
|
|
}
|
|
}
|
|
|
|
void VideoDecoderBase::setRotationDegrees(int32_t rotationDegrees) {
|
|
if (mRotationDegrees == rotationDegrees) {
|
|
return;
|
|
}
|
|
|
|
ITRACE("set new rotation degree: %d", rotationDegrees);
|
|
VADisplayAttribute rotate;
|
|
rotate.type = VADisplayAttribRotation;
|
|
rotate.value = VA_ROTATION_NONE;
|
|
if (rotationDegrees == 0)
|
|
rotate.value = VA_ROTATION_NONE;
|
|
else if (rotationDegrees == 90)
|
|
rotate.value = VA_ROTATION_90;
|
|
else if (rotationDegrees == 180)
|
|
rotate.value = VA_ROTATION_180;
|
|
else if (rotationDegrees == 270)
|
|
rotate.value = VA_ROTATION_270;
|
|
|
|
VAStatus ret = vaSetDisplayAttributes(mVADisplay, &rotate, 1);
|
|
if (ret) {
|
|
ETRACE("Failed to set rotation degree.");
|
|
}
|
|
mRotationDegrees = rotationDegrees;
|
|
}
|
|
|
|
void VideoDecoderBase::setRenderRect() {
|
|
|
|
if (!mVADisplay)
|
|
return;
|
|
|
|
VAStatus ret;
|
|
VARectangle rect;
|
|
rect.x = mVideoFormatInfo.cropLeft;
|
|
rect.y = mVideoFormatInfo.cropTop;
|
|
rect.width = mVideoFormatInfo.width - (mVideoFormatInfo.cropLeft + mVideoFormatInfo.cropRight);
|
|
rect.height = mVideoFormatInfo.height - (mVideoFormatInfo.cropBottom + mVideoFormatInfo.cropTop);
|
|
if (strcasecmp(mVideoFormatInfo.mimeType,"video/avc") == 0 ||
|
|
strcasecmp(mVideoFormatInfo.mimeType,"video/avc-secure") == 0 ||
|
|
strcasecmp(mVideoFormatInfo.mimeType,"video/h264") == 0) {
|
|
rect.height = mVideoFormatInfo.height;
|
|
rect.width = mVideoFormatInfo.width;
|
|
}
|
|
|
|
VADisplayAttribute render_rect;
|
|
render_rect.type = VADisplayAttribRenderRect;
|
|
render_rect.attrib_ptr = ▭
|
|
|
|
ret = vaSetDisplayAttributes(mVADisplay, &render_rect, 1);
|
|
if (ret) {
|
|
ETRACE("Failed to set rotation degree.");
|
|
}
|
|
}
|
|
|
|
void VideoDecoderBase::setColorSpaceInfo(int32_t colorMatrix, int32_t videoRange) {
|
|
ITRACE("set colorMatrix: 0x%x ", colorMatrix);
|
|
VADisplayAttribute cm;
|
|
cm.type = VADisplayAttribCSCMatrix;
|
|
if (colorMatrix == VA_SRC_BT601) {
|
|
cm.attrib_ptr = &s601;
|
|
} else if (colorMatrix == VA_SRC_BT709) {
|
|
cm.attrib_ptr = &s709;
|
|
} else {
|
|
// if we can't get the color matrix or it's not BT601 or BT709
|
|
// we decide the color matrix according to clip resolution
|
|
if (mVideoFormatInfo.width < 1280 && mVideoFormatInfo.height < 720)
|
|
cm.attrib_ptr = &s601;
|
|
else
|
|
cm.attrib_ptr = &s709;
|
|
}
|
|
|
|
VAStatus ret = vaSetDisplayAttributes(mVADisplay, &cm, 1);
|
|
|
|
if (ret) {
|
|
ETRACE("Failed to set colorMatrix.");
|
|
}
|
|
|
|
// 1: full range, 0: reduced range
|
|
ITRACE("set videoRange: %d ", videoRange);
|
|
VADisplayAttribute vr;
|
|
vr.type = VADisplayAttribColorRange;
|
|
vr.value = (videoRange == 1) ? VA_SOURCE_RANGE_FULL : VA_SOURCE_RANGE_REDUCED;
|
|
|
|
ret = vaSetDisplayAttributes(mVADisplay, &vr, 1);
|
|
|
|
if (ret) {
|
|
ETRACE("Failed to set videoRange.");
|
|
}
|
|
}
|