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;