libmix: add support for Error Reporting needed by WebRTC
BZ: 147912
The error will be reported when the frame is removed from output
queue for rendering.
Change-Id: Ibcf9dc0dcaf31c62b76a8f51acb13157b71403e1
Signed-off-by: Dan Liang <dan.liang@intel.com>
diff --git a/videodecoder/VideoDecoderAVC.cpp b/videodecoder/VideoDecoderAVC.cpp
index 221db27..e88b150 100644
--- a/videodecoder/VideoDecoderAVC.cpp
+++ b/videodecoder/VideoDecoderAVC.cpp
@@ -401,6 +401,10 @@
if (!(ref->flags & VA_PICTURE_H264_INVALID)) {
ref->picture_id = findSurface(ref);
if (ref->picture_id == VA_INVALID_SURFACE) {
+ // Error DecodeRefMissing is counted once even there're multiple
+ mAcquiredBuffer->renderBuffer.errBuf.errorNumber = 1;
+ mAcquiredBuffer->renderBuffer.errBuf.errorArray[0].type = DecodeRefMissing;
+
if (mLastReference) {
WTRACE("Reference frame %d is missing. Use last reference", getPOC(ref));
ref->picture_id = mLastReference->renderBuffer.surface;
diff --git a/videodecoder/VideoDecoderBase.cpp b/videodecoder/VideoDecoderBase.cpp
old mode 100755
new mode 100644
index ec429a1..5ec182f
--- a/videodecoder/VideoDecoderBase.cpp
+++ b/videodecoder/VideoDecoderBase.cpp
@@ -207,7 +207,7 @@
return &mVideoFormatInfo;
}
-const VideoRenderBuffer* VideoDecoderBase::getOutput(bool draining) {
+const VideoRenderBuffer* VideoDecoderBase::getOutput(bool draining, VideoErrorBuffer *outErrBuf) {
VAStatus vaStatus;
if (mVAStarted == false) {
return NULL;
@@ -232,11 +232,16 @@
mOutputTail = NULL;
}
vaStatus = vaSetTimestampForSurface(mVADisplay, outputByPos->renderBuffer.surface, outputByPos->renderBuffer.timeStamp);
- if (useGraphicBuffer)
- vaSyncSurface(mVADisplay, outputByPos->renderBuffer.surface);
+ if (useGraphicBuffer) {
+ if (vaSyncSurface(mVADisplay, outputByPos->renderBuffer.surface) == VA_STATUS_ERROR_DECODING_ERROR) {
+ fillDecodingErrors(&(outputByPos->renderBuffer));
+ }
+ }
if (draining && mOutputTail == NULL) {
outputByPos->renderBuffer.flag |= IS_EOS;
}
+ drainDecodingErrors(outErrBuf, &(outputByPos->renderBuffer));
+
return &(outputByPos->renderBuffer);
}
@@ -284,12 +289,18 @@
//VTRACE("Output POC %d for display (pts = %.2f)", output->pictureOrder, output->renderBuffer.timeStamp/1E6);
vaStatus = vaSetTimestampForSurface(mVADisplay, output->renderBuffer.surface, output->renderBuffer.timeStamp);
- if (useGraphicBuffer)
- vaSyncSurface(mVADisplay, output->renderBuffer.surface);
+ if (useGraphicBuffer) {
+ if (vaSyncSurface(mVADisplay, output->renderBuffer.surface) == VA_STATUS_ERROR_DECODING_ERROR) {
+ fillDecodingErrors(&(output->renderBuffer));
+ }
+ }
if (draining && mOutputTail == NULL) {
output->renderBuffer.flag |= IS_EOS;
}
+
+ drainDecodingErrors(outErrBuf, &(output->renderBuffer));
+
return &(output->renderBuffer);
}
@@ -574,6 +585,8 @@
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;
}
@@ -912,6 +925,10 @@
return DECODE_MEMORY_FAIL;
}
+ if (mConfigBuffer.flag & WANT_ERROR_REPORT) {
+ mErrReportEnabled = true;
+ }
+
initSurfaceBuffer(true);
if ((int32_t)profile == VAProfileSoftwareDecoding) {
@@ -998,6 +1015,7 @@
mVAStarted = false;
mInitialized = false;
+ mErrReportEnabled = false;
mSignalBufferSize = 0;
for (int i = 0; i < MAX_GRAPHIC_BUFFER_NUM; i++) {
mSignalBufferPre[i] = NULL;
@@ -1334,3 +1352,28 @@
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;
+ }
+}
+
+void VideoDecoderBase::fillDecodingErrors(VideoRenderBuffer *CurrentSurface) {
+ VAStatus ret;
+
+ if (mErrReportEnabled) {
+ CurrentSurface->errBuf.timeStamp = CurrentSurface->timeStamp;
+ // TODO: is 10 a suitable number?
+ VASurfaceDecodeMBErrors err_drv_output[MAX_ERR_NUM - 1];
+ ret = vaQuerySurfaceError(mVADisplay, CurrentSurface->surface, VA_STATUS_ERROR_DECODING_ERROR, (void **)&err_drv_output);
+ for (int i = CurrentSurface->errBuf.errorNumber; i < MAX_ERR_NUM - 1; i++) {
+ if (err_drv_output[i].status != -1) {
+ CurrentSurface->errBuf.errorNumber++;
+ CurrentSurface->errBuf.errorArray[i].type = (VideoDecodeErrorType)err_drv_output[i].decode_error_type;
+ }
+ }
+ }
+}
diff --git a/videodecoder/VideoDecoderBase.h b/videodecoder/VideoDecoderBase.h
index f2e5dee..6527be6 100644
--- a/videodecoder/VideoDecoderBase.h
+++ b/videodecoder/VideoDecoderBase.h
@@ -60,7 +60,7 @@
virtual void stop(void);
//virtual Decode_Status decode(VideoDecodeBuffer *buffer);
virtual void flush(void);
- virtual const VideoRenderBuffer* getOutput(bool draining = false);
+ virtual const VideoRenderBuffer* getOutput(bool draining = false, VideoErrorBuffer *output_buf = NULL);
virtual Decode_Status signalRenderDone(void * graphichandler);
virtual const VideoFormatInfo* getFormatInfo(void);
virtual bool checkBufferAvail();
@@ -98,11 +98,12 @@
private:
Decode_Status mapSurface(void);
void initSurfaceBuffer(bool reset);
+ void drainDecodingErrors(VideoErrorBuffer *outErrBuf, VideoRenderBuffer *CurrentSurface);
+ void fillDecodingErrors(VideoRenderBuffer *CurrentSurface);
bool mInitialized;
pthread_mutex_t mLock;
-
protected:
VideoFormatInfo mVideoFormatInfo;
Display *mDisplay;
@@ -125,6 +126,8 @@
int32_t mOutputWindowSize; // indicate limit of number of outstanding frames for output
+ bool mErrReportEnabled;
+
enum {
// TODO: move this to vbp_loader.h
VBP_INVALID = 0xFF,
diff --git a/videodecoder/VideoDecoderDefs.h b/videodecoder/VideoDecoderDefs.h
index d3deb56..7a903c4 100644
--- a/videodecoder/VideoDecoderDefs.h
+++ b/videodecoder/VideoDecoderDefs.h
@@ -105,8 +105,20 @@
// indicate it's the last output frame of the sequence
IS_EOS = 0x10000,
+ // indicate whether error reporting is needed
+ WANT_ERROR_REPORT = 0x20000,
+
} VIDEO_BUFFER_FLAG;
+typedef enum
+{
+ DecodeSliceMissing = 0,
+ DecodeMBError = 1,
+ DecodeRefMissing = 2,
+} VideoDecodeErrorType;
+
+#define MAX_ERR_NUM 10
+
struct VideoDecodeBuffer {
uint8_t *data;
int32_t size;
@@ -140,6 +152,19 @@
#endif
};
+struct VideoErrorInfo {
+ VideoDecodeErrorType type;
+ union {
+ typedef struct {uint32_t start_mb; uint32_t end_mb;} mb_pos;
+ } error_data;
+};
+
+struct VideoErrorBuffer {
+ uint32_t errorNumber; // Error number should be no more than MAX_ERR_NUM
+ int64_t timeStamp; // presentation time stamp
+ VideoErrorInfo errorArray[MAX_ERR_NUM];
+};
+
struct VideoRenderBuffer {
VASurfaceID surface;
VADisplay display;
@@ -152,8 +177,9 @@
uint32_t flag;
mutable volatile bool driverRenderDone;
VideoFrameRawData *rawData;
-};
+ VideoErrorBuffer errBuf;
+};
struct VideoSurfaceBuffer {
VideoRenderBuffer renderBuffer;
diff --git a/videodecoder/VideoDecoderInterface.h b/videodecoder/VideoDecoderInterface.h
index 4373ad5..79399c9 100644
--- a/videodecoder/VideoDecoderInterface.h
+++ b/videodecoder/VideoDecoderInterface.h
@@ -36,7 +36,7 @@
virtual void stop(void) = 0;
virtual void flush() = 0;
virtual Decode_Status decode(VideoDecodeBuffer *buffer) = 0;
- virtual const VideoRenderBuffer* getOutput(bool draining = false) = 0;
+ virtual const VideoRenderBuffer* getOutput(bool draining = false, VideoErrorBuffer *output_buf = NULL) = 0;
virtual const VideoFormatInfo* getFormatInfo(void) = 0;
virtual Decode_Status signalRenderDone(void * graphichandler) = 0;
virtual bool checkBufferAvail() = 0;
diff --git a/videodecoder/VideoDecoderVP8.cpp b/videodecoder/VideoDecoderVP8.cpp
index 24b7315..145c7b6 100644
--- a/videodecoder/VideoDecoderVP8.cpp
+++ b/videodecoder/VideoDecoderVP8.cpp
@@ -311,6 +311,8 @@
if (mRFBs[0][VP8_LAST_REF_PIC].surfaceBuffer == NULL ||
mRFBs[0][VP8_ALT_REF_PIC].surfaceBuffer == NULL ||
mRFBs[0][VP8_GOLDEN_REF_PIC].surfaceBuffer == NULL) {
+ mAcquiredBuffer->renderBuffer.errBuf.errorNumber = 1;
+ mAcquiredBuffer->renderBuffer.errBuf.errorArray[0].type = DecodeRefMissing;
return DECODE_NO_REFERENCE;
}
//mRFBs[0][VP8_LAST_REF_PIC].surfaceBuffer = mLastReference;