Extend middleware to support secure video playback.

BZ: 29937

Change-Id: Ia8d59ff6285395efbfbd85d56b7fe70298aa6bb2
Signed-off-by: Andy Qiu <junhai.qiu@intel.com>
Reviewed-on: http://android.intel.com:8080/36931
Reviewed-by: buildbot <buildbot@intel.com>
Reviewed-by: Vehmanen, Kai <kai.vehmanen@intel.com>
Reviewed-by: Ding, Haitao <haitao.ding@intel.com>
Tested-by: Ding, Haitao <haitao.ding@intel.com>
diff --git a/videodecoder/Android.mk b/videodecoder/Android.mk
index b075586..26fa709 100644
--- a/videodecoder/Android.mk
+++ b/videodecoder/Android.mk
@@ -10,6 +10,7 @@
     VideoDecoderAVC.cpp \
     VideoDecoderVP8.cpp \
     VideoDecoderPAVC.cpp \
+    VideoDecoderAVCSecure.cpp \
     VideoDecoderTrace.cpp
 
 # LOCAL_CFLAGS :=
diff --git a/videodecoder/VideoDecoderAVC.cpp b/videodecoder/VideoDecoderAVC.cpp
index adc6b2a..243ca80 100644
--- a/videodecoder/VideoDecoderAVC.cpp
+++ b/videodecoder/VideoDecoderAVC.cpp
@@ -167,11 +167,13 @@
     }
 
     // HAS_COMPLETE_FRAME is not reliable as it may indicate end of a field
-  /*  if (buffer->flag & HAS_COMPLETE_FRAME) {
+#if 0
+    if (buffer->flag & HAS_COMPLETE_FRAME) {
         // finish decoding current frame
         status = endDecodingFrame(false);
         CHECK_STATUS("endDecodingFrame");
-    }*/
+    }
+#endif
 
     if (mSizeChanged) {
         mSizeChanged = false;
diff --git a/videodecoder/VideoDecoderAVCSecure.cpp b/videodecoder/VideoDecoderAVCSecure.cpp
new file mode 100644
index 0000000..3bcfd70
--- /dev/null
+++ b/videodecoder/VideoDecoderAVCSecure.cpp
@@ -0,0 +1,515 @@
+/* INTEL CONFIDENTIAL
+* Copyright (c) 2009-2011 Intel Corporation.  All rights reserved.
+*
+* The source code contained or described herein and all documents
+* related to the source code ("Material") are owned by Intel
+* Corporation or its suppliers or licensors.  Title to the
+* Material remains with Intel Corporation or its suppliers and
+* licensors.  The Material contains trade secrets and proprietary
+* and confidential information of Intel or its suppliers and
+* licensors. The Material is protected by worldwide copyright and
+* trade secret laws and treaty provisions.  No part of the Material
+* may be used, copied, reproduced, modified, published, uploaded,
+* posted, transmitted, distributed, or disclosed in any way without
+* Intel's prior express written permission.
+*
+* No license under any patent, copyright, trade secret or other
+* intellectual property right is granted to or conferred upon you
+* by disclosure or delivery of the Materials, either expressly, by
+* implication, inducement, estoppel or otherwise. Any license
+* under such intellectual property rights must be express and
+* approved by Intel in writing.
+*
+*/
+
+#include "VideoDecoderAVCSecure.h"
+#include "VideoDecoderTrace.h"
+#include <string.h>
+
+
+#define STARTCODE_00                0x00
+#define STARTCODE_01                0x01
+#define STARTCODE_PREFIX_LEN        3
+#define NALU_TYPE_MASK              0x1F
+
+
+// mask for little endian, to mast the second and fourth bytes in the byte stream
+#define STARTCODE_MASK0             0xFF000000 //0x00FF0000
+#define STARTCODE_MASK1             0x0000FF00  //0x000000FF
+
+
+typedef enum {
+    NAL_UNIT_TYPE_unspecified0 = 0,
+    NAL_UNIT_TYPE_SLICE,
+    NAL_UNIT_TYPE_DPA,
+    NAL_UNIT_TYPE_DPB,
+    NAL_UNIT_TYPE_DPC,
+    NAL_UNIT_TYPE_IDR,
+    NAL_UNIT_TYPE_SEI,
+    NAL_UNIT_TYPE_SPS,
+    NAL_UNIT_TYPE_PPS,
+    NAL_UNIT_TYPE_Acc_unit_delimiter,
+    NAL_UNIT_TYPE_EOSeq,
+    NAL_UNIT_TYPE_EOstream,
+    NAL_UNIT_TYPE_filler_data,
+    NAL_UNIT_TYPE_SPS_extension,
+    NAL_UNIT_TYPE_Reserved14,
+    NAL_UNIT_TYPE_Reserved15,
+    NAL_UNIT_TYPE_Reserved16,
+    NAL_UNIT_TYPE_Reserved17,
+    NAL_UNIT_TYPE_Reserved18,
+    NAL_UNIT_TYPE_ACP,
+    NAL_UNIT_TYPE_Reserved20,
+    NAL_UNIT_TYPE_Reserved21,
+    NAL_UNIT_TYPE_Reserved22,
+    NAL_UNIT_TYPE_Reserved23,
+    NAL_UNIT_TYPE_unspecified24,
+} NAL_UNIT_TYPE;
+
+#ifndef min
+#define min(X, Y)  ((X) <(Y) ? (X) : (Y))
+#endif
+
+
+static const uint8_t startcodePrefix[STARTCODE_PREFIX_LEN] = {0x00, 0x00, 0x01};
+
+
+VideoDecoderAVCSecure::VideoDecoderAVCSecure(const char *mimeType)
+    : VideoDecoderAVC(mimeType),
+      mNaluHeaderBuffer(NULL),
+      mInputBuffer(NULL) {
+
+    memset(&mMetadata, 0, sizeof(NaluMetadata));
+    memset(&mByteStream, 0, sizeof(NaluByteStream));
+}
+
+VideoDecoderAVCSecure::~VideoDecoderAVCSecure() {
+}
+
+Decode_Status VideoDecoderAVCSecure::start(VideoConfigBuffer *buffer) {
+    Decode_Status status = VideoDecoderAVC::start(buffer);
+    if (status != DECODE_SUCCESS) {
+        return status;
+    }
+
+    mMetadata.naluInfo = new NaluInfo [MAX_NALU_NUMBER];
+    mByteStream.byteStream = new uint8_t [MAX_NALU_HEADER_BUFFER];
+    mNaluHeaderBuffer = new uint8_t [MAX_NALU_HEADER_BUFFER];
+
+    if (mMetadata.naluInfo == NULL ||
+        mByteStream.byteStream == NULL ||
+        mNaluHeaderBuffer == NULL) {
+        ETRACE("Failed to allocate memory.");
+        // TODO: release all allocated memory
+        return DECODE_MEMORY_FAIL;
+    }
+    return status;
+}
+
+void VideoDecoderAVCSecure::stop(void) {
+    VideoDecoderAVC::stop();
+
+    if (mMetadata.naluInfo) {
+        delete [] mMetadata.naluInfo;
+        mMetadata.naluInfo = NULL;
+    }
+
+    if (mByteStream.byteStream) {
+        delete [] mByteStream.byteStream;
+        mByteStream.byteStream = NULL;
+    }
+
+    if (mNaluHeaderBuffer) {
+        delete [] mNaluHeaderBuffer;
+        mNaluHeaderBuffer = NULL;
+    }
+}
+
+Decode_Status VideoDecoderAVCSecure::decode(VideoDecodeBuffer *buffer) {
+    Decode_Status status;
+    int32_t sizeAccumulated = 0;
+    int32_t sizeLeft = 0;
+    uint8_t *pByteStream = NULL;
+    NaluInfo *pNaluInfo = mMetadata.naluInfo;
+
+    if (buffer->flag & IS_SECURE_DATA) {
+        pByteStream = buffer->data;
+        sizeLeft = buffer->size;
+        mInputBuffer = NULL;
+    } else {
+        status = parseAnnexBStream(buffer->data, buffer->size, &mByteStream);
+        CHECK_STATUS("parseAnnexBStream");
+        pByteStream = mByteStream.byteStream;
+        sizeLeft = mByteStream.streamPos;
+        mInputBuffer = buffer->data;
+    }
+    if (sizeLeft < 4) {
+        ETRACE("Not enough data to read number of NALU.");
+        return DECODE_INVALID_DATA;
+    }
+
+    // read number of NALU
+    memcpy(&(mMetadata.naluNumber), pByteStream, sizeof(int32_t));
+    pByteStream += 4;
+    sizeLeft -= 4;
+
+    if (mMetadata.naluNumber == 0) {
+        WTRACE("Number of NALU is ZERO!");
+        return DECODE_SUCCESS;
+    }
+
+    for (int32_t i = 0; i < mMetadata.naluNumber; i++) {
+        if (sizeLeft < 12) {
+            ETRACE("Not enough data to parse NALU offset, size, header length for NALU %d, left = %d", i, sizeLeft);
+            return DECODE_INVALID_DATA;
+        }
+        sizeLeft -= 12;
+        // read NALU offset
+        memcpy(&(pNaluInfo->naluOffset), pByteStream, sizeof(int32_t));
+        pByteStream += 4;
+
+        // read NALU size
+        memcpy(&(pNaluInfo->naluLen), pByteStream, sizeof(int32_t));
+        pByteStream += 4;
+
+        // read NALU header length
+        memcpy(&(pNaluInfo->naluHeaderLen), pByteStream, sizeof(int32_t));
+        pByteStream += 4;
+
+        if (sizeLeft < pNaluInfo->naluHeaderLen) {
+            ETRACE("Not enough data to copy NALU header for %d, left = %d, header len = %d", i, sizeLeft, pNaluInfo->naluHeaderLen);
+            return DECODE_INVALID_DATA;
+        }
+
+        sizeLeft -=  pNaluInfo->naluHeaderLen;
+
+        if (pNaluInfo->naluHeaderLen) {
+            // copy start code prefix to buffer
+            memcpy(mNaluHeaderBuffer + sizeAccumulated,
+                startcodePrefix,
+                STARTCODE_PREFIX_LEN);
+            sizeAccumulated += STARTCODE_PREFIX_LEN;
+
+            // copy NALU header
+            memcpy(mNaluHeaderBuffer + sizeAccumulated, pByteStream, pNaluInfo->naluHeaderLen);
+            pByteStream += pNaluInfo->naluHeaderLen;
+
+            sizeAccumulated += pNaluInfo->naluHeaderLen;
+        } else {
+            WTRACE("header len is zero for NALU %d", i);
+        }
+
+        // for next NALU
+        pNaluInfo++;
+    }
+
+    buffer->data = mNaluHeaderBuffer;
+    buffer->size = sizeAccumulated;
+
+    return VideoDecoderAVC::decode(buffer);
+}
+
+
+Decode_Status VideoDecoderAVCSecure::decodeSlice(vbp_data_h264 *data, uint32_t picIndex, uint32_t sliceIndex) {
+
+    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];
+
+    vbp_picture_data_h264 *picData = &(data->pic_data[picIndex]);
+    vbp_slice_data_h264 *sliceData = &(picData->slc_data[sliceIndex]);
+    VAPictureParameterBufferH264 *picParam = picData->pic_parms;
+    VASliceParameterBufferH264 *sliceParam = &(sliceData->slc_parms);
+
+    if (sliceParam->first_mb_in_slice == 0 || mDecodingFrame == false) {
+        // either condition indicates start of a new frame
+        if (sliceParam->first_mb_in_slice != 0) {
+            WTRACE("The first slice is lost.");
+            // TODO: handle the first slice lost
+        }
+        if (mDecodingFrame) {
+            // interlace content, complete decoding the first field
+            vaStatus = vaEndPicture(mVADisplay, mVAContext);
+            CHECK_VA_STATUS("vaEndPicture");
+
+            // for interlace content, top field may be valid only after the second field is parsed
+            mAcquiredBuffer->pictureOrder= picParam->CurrPic.TopFieldOrderCnt;
+        }
+
+        // Check there is no reference frame loss before decoding a frame
+
+        // Update  the reference frames and surface IDs for DPB and current frame
+        status = updateDPB(picParam);
+        CHECK_STATUS("updateDPB");
+
+        //We have to provide a hacked DPB rather than complete DPB for libva as workaround
+        status = updateReferenceFrames(picData);
+        CHECK_STATUS("updateReferenceFrames");
+
+        vaStatus = vaBeginPicture(mVADisplay, mVAContext, mAcquiredBuffer->renderBuffer.surface);
+        CHECK_VA_STATUS("vaBeginPicture");
+
+        // start decoding a frame
+        mDecodingFrame = true;
+
+        vaStatus = vaCreateBuffer(
+            mVADisplay,
+            mVAContext,
+            VAPictureParameterBufferType,
+            sizeof(VAPictureParameterBufferH264),
+            1,
+            picParam,
+            &bufferIDs[bufferIDCount]);
+        CHECK_VA_STATUS("vaCreatePictureParameterBuffer");
+        bufferIDCount++;
+
+        vaStatus = vaCreateBuffer(
+            mVADisplay,
+            mVAContext,
+            VAIQMatrixBufferType,
+            sizeof(VAIQMatrixBufferH264),
+            1,
+            data->IQ_matrix_buf,
+            &bufferIDs[bufferIDCount]);
+        CHECK_VA_STATUS("vaCreateIQMatrixBuffer");
+        bufferIDCount++;
+    }
+
+    status = setReference(sliceParam);
+    CHECK_STATUS("setReference");
+
+    // find which naluinfo is correlated to current slice
+    int naluIndex = 0;
+    uint32_t accumulatedHeaderLen = 0;
+    uint32_t headerLen = 0;
+    for (; naluIndex < mMetadata.naluNumber; naluIndex++)  {
+        headerLen = mMetadata.naluInfo[naluIndex].naluHeaderLen;
+        if (headerLen == 0) {
+            WTRACE("lenght of current NAL unit is 0.");
+            continue;
+        }
+        accumulatedHeaderLen += STARTCODE_PREFIX_LEN;
+        if (accumulatedHeaderLen + headerLen > sliceData->slice_offset) {
+            break;
+        }
+        accumulatedHeaderLen += headerLen;
+    }
+
+    if (sliceData->slice_offset != accumulatedHeaderLen) {
+        WTRACE("unexpected slice offset %d, accumulatedHeaderLen = %d", sliceData->slice_offset, accumulatedHeaderLen);
+    }
+
+    sliceParam->slice_data_size = mMetadata.naluInfo[naluIndex].naluLen;
+    sliceData->slice_size = sliceParam->slice_data_size;
+
+    // no need to update:
+    // sliceParam->slice_data_offset - 0 always
+    // sliceParam->slice_data_bit_offset - relative to  sliceData->slice_offset
+
+    vaStatus = vaCreateBuffer(
+        mVADisplay,
+        mVAContext,
+        VASliceParameterBufferType,
+        sizeof(VASliceParameterBufferH264),
+        1,
+        sliceParam,
+        &bufferIDs[bufferIDCount]);
+    CHECK_VA_STATUS("vaCreateSliceParameterBuffer");
+    bufferIDCount++;
+
+    // sliceData->slice_offset - accumulatedHeaderLen is the absolute offset to start codes of current NAL unit
+    // offset points to first byte of NAL unit
+    uint32_t sliceOffset = mMetadata.naluInfo[naluIndex].naluOffset;
+    if (mInputBuffer != NULL) {
+        vaStatus = vaCreateBuffer(
+            mVADisplay,
+            mVAContext,
+            VASliceDataBufferType,
+            sliceData->slice_size, //size
+            1,        //num_elements
+            mInputBuffer  + sliceOffset,
+            &bufferIDs[bufferIDCount]);
+    } else {
+        vaStatus = vaCreateBuffer(
+            mVADisplay,
+            mVAContext,
+            VAProtectedSliceDataBufferType,
+            sliceData->slice_size, //size
+            1,        //num_elements
+            (uint8_t*)sliceOffset, // IMR offset
+            &bufferIDs[bufferIDCount]);
+    }
+    CHECK_VA_STATUS("vaCreateSliceDataBuffer");
+    bufferIDCount++;
+
+    vaStatus = vaRenderPicture(
+        mVADisplay,
+        mVAContext,
+        bufferIDs,
+        bufferIDCount);
+    CHECK_VA_STATUS("vaRenderPicture");
+
+    return DECODE_SUCCESS;
+}
+
+
+// Parse byte string pattern "0x000001" (3 bytes)  in the current buffer.
+// Returns offset of position following  the pattern in the buffer if pattern is found or -1 if not found.
+int32_t VideoDecoderAVCSecure::findNalUnitOffset(uint8_t *stream, int32_t offset, int32_t length) {
+    uint8_t *ptr;
+    uint32_t left = 0, data = 0, phase = 0;
+    uint8_t mask1 = 0, mask2 = 0;
+
+    /* Meaning of phase:
+        0: initial status, "0x000001" bytes are not found so far;
+        1: one "0x00" byte is found;
+        2: two or more consecutive "0x00" bytes" are found;
+        3: "0x000001" patten is found ;
+        4: if there is one more byte after "0x000001";
+       */
+
+    left = length;
+    ptr = (uint8_t *) (stream + offset);
+    phase = 0;
+
+    // parse until there is more data and start code not found
+    while ((left > 0) && (phase < 3)) {
+        // Check if the address is 32-bit aligned & phase=0, if thats the case we can check 4 bytes instead of one byte at a time.
+        if (((((uint32_t)ptr) & 0x3) == 0) && (phase == 0)) {
+            while (left > 3) {
+                data = *((uint32_t *)ptr);
+                mask1 = (STARTCODE_00 != (data & STARTCODE_MASK0));
+                mask2 = (STARTCODE_00 != (data & STARTCODE_MASK1));
+                // If second byte and fourth byte are not zero's then we cannot have a start code here,
+                //  as we need two consecutive zero bytes for a start code pattern.
+                if (mask1 && mask2) {
+                    // skip 4 bytes and start over
+                    ptr += 4;
+                    left -=4;
+                    continue;
+                } else {
+                    break;
+                }
+            }
+        }
+
+        // At this point either data is not on a 32-bit boundary or phase > 0 so we look at one byte at a time
+        if (left > 0) {
+            if (*ptr == STARTCODE_00) {
+                phase++;
+                if (phase > 2) {
+                    // more than 2 consecutive '0x00' bytes is found
+                    phase = 2;
+                }
+            } else if ((*ptr == STARTCODE_01) && (phase == 2)) {
+                // start code is found
+                phase = 3;
+            } else {
+                // reset lookup
+                phase = 0;
+            }
+            ptr++;
+            left--;
+        }
+    }
+
+    if ((left > 0) && (phase == 3)) {
+        phase = 4;
+        // return offset of position following the pattern in the buffer which matches "0x000001" byte string
+        return (int32_t)(ptr - stream);
+    }
+    return -1;
+}
+
+
+Decode_Status VideoDecoderAVCSecure::copyNaluHeader(uint8_t *stream, NaluByteStream *naluStream) {
+    uint8_t naluType;
+    int32_t naluHeaderLen;
+
+    naluType = *(uint8_t *)(stream + naluStream->naluOffset);
+    naluType &= NALU_TYPE_MASK;
+    // first update nalu header length based on nalu type
+    if (naluType >= NAL_UNIT_TYPE_SLICE && naluType <= NAL_UNIT_TYPE_IDR) {
+        // coded slice, return only up to MAX_SLICE_HEADER_SIZE bytes
+        naluHeaderLen = min(naluStream->naluLen, MAX_SLICE_HEADER_SIZE);
+    } else if (naluType >= NAL_UNIT_TYPE_SEI && naluType <= NAL_UNIT_TYPE_PPS) {
+        //sps, pps, sei, etc, return the entire NAL unit in clear
+        naluHeaderLen = naluStream->naluLen;
+    } else {
+        return DECODE_FRAME_DROPPED;
+    }
+
+    memcpy(naluStream->byteStream + naluStream->streamPos, &(naluStream->naluOffset), sizeof(int32_t));
+    naluStream->streamPos += 4;
+
+    memcpy(naluStream->byteStream + naluStream->streamPos, &(naluStream->naluLen), sizeof(int32_t));
+    naluStream->streamPos += 4;
+
+    memcpy(naluStream->byteStream + naluStream->streamPos, &naluHeaderLen, sizeof(int32_t));
+    naluStream->streamPos += 4;
+
+    if (naluHeaderLen) {
+        memcpy(naluStream->byteStream + naluStream->streamPos, (uint8_t*)(stream + naluStream->naluOffset), naluHeaderLen);
+        naluStream->streamPos += naluHeaderLen;
+    }
+    return DECODE_SUCCESS;
+}
+
+
+// parse start-code prefixed stream, also knowns as Annex B byte stream, commonly used in AVI, ES, MPEG2 TS container
+Decode_Status VideoDecoderAVCSecure::parseAnnexBStream(uint8_t *stream, int32_t length, NaluByteStream *naluStream) {
+    int32_t naluOffset, offset, left;
+    NaluInfo *info;
+    uint32_t ret = DECODE_SUCCESS;
+
+    naluOffset = 0;
+    offset = 0;
+    left = length;
+
+    // leave 4 bytes to copy nalu count
+    naluStream->streamPos = 4;
+    naluStream->naluCount = 0;
+    memset(naluStream->byteStream, 0, MAX_NALU_HEADER_BUFFER);
+
+    for (; ;) {
+        naluOffset = findNalUnitOffset(stream, offset, left);
+        if (naluOffset == -1) {
+            break;
+        }
+
+        if (naluStream->naluCount == 0) {
+            naluStream->naluOffset = naluOffset;
+        } else {
+            naluStream->naluLen = naluOffset - naluStream->naluOffset - STARTCODE_PREFIX_LEN;
+            ret = copyNaluHeader(stream, naluStream);
+            if (ret != DECODE_SUCCESS && ret != DECODE_FRAME_DROPPED) {
+                LOGW("copyNaluHeader returned %d", ret);
+                return ret;
+            }
+            // starting position for next NALU
+            naluStream->naluOffset = naluOffset;
+        }
+
+        if (ret == DECODE_SUCCESS) {
+            naluStream->naluCount++;
+        }
+
+        // update next lookup position and length
+        offset = naluOffset + 1; // skip one byte of NAL unit type
+        left = length - offset;
+    }
+
+    if (naluStream->naluCount > 0) {
+        naluStream->naluLen = length - naluStream->naluOffset;
+        memcpy(naluStream->byteStream, &(naluStream->naluCount), sizeof(int32_t));
+        // ignore return value, either DECODE_SUCCESS or DECODE_FRAME_DROPPED
+        copyNaluHeader(stream, naluStream);
+        return DECODE_SUCCESS;
+    }
+
+    LOGW("number of valid NALU is 0!");
+    return DECODE_SUCCESS;
+}
+
diff --git a/videodecoder/VideoDecoderAVCSecure.h b/videodecoder/VideoDecoderAVCSecure.h
new file mode 100644
index 0000000..af5ae44
--- /dev/null
+++ b/videodecoder/VideoDecoderAVCSecure.h
@@ -0,0 +1,83 @@
+/* INTEL CONFIDENTIAL
+* Copyright (c) 2009-2011 Intel Corporation.  All rights reserved.
+*
+* The source code contained or described herein and all documents
+* related to the source code ("Material") are owned by Intel
+* Corporation or its suppliers or licensors.  Title to the
+* Material remains with Intel Corporation or its suppliers and
+* licensors.  The Material contains trade secrets and proprietary
+* and confidential information of Intel or its suppliers and
+* licensors. The Material is protected by worldwide copyright and
+* trade secret laws and treaty provisions.  No part of the Material
+* may be used, copied, reproduced, modified, published, uploaded,
+* posted, transmitted, distributed, or disclosed in any way without
+* Intel's prior express written permission.
+*
+* No license under any patent, copyright, trade secret or other
+* intellectual property right is granted to or conferred upon you
+* by disclosure or delivery of the Materials, either expressly, by
+* implication, inducement, estoppel or otherwise. Any license
+* under such intellectual property rights must be express and
+* approved by Intel in writing.
+*
+*/
+
+#ifndef VIDEO_DECODER_AVC_SECURE_H_
+#define VIDEO_DECODER_AVC_SECURE_H_
+
+#include "VideoDecoderAVC.h"
+
+
+class VideoDecoderAVCSecure : public VideoDecoderAVC {
+public:
+    VideoDecoderAVCSecure(const char *mimeType);
+    virtual ~VideoDecoderAVCSecure();
+
+    virtual Decode_Status start(VideoConfigBuffer *buffer);
+    virtual void stop(void);
+
+    // data in the decoded buffer is all encrypted.
+    virtual Decode_Status decode(VideoDecodeBuffer *buffer);
+
+private:
+    enum {
+        MAX_SLICE_HEADER_SIZE  = 30,
+        MAX_NALU_HEADER_BUFFER = 8192,
+        MAX_NALU_NUMBER = 400,  // > 4096/12
+    };
+
+    // Information of Network Abstraction Layer Unit
+    struct NaluInfo {
+        int32_t naluOffset;                        // offset of NAL unit in the firewalled buffer
+        int32_t naluLen;                           // length of NAL unit
+        int32_t naluHeaderLen;                     // length of NAL unit header
+    };
+
+    struct NaluMetadata {
+        NaluInfo *naluInfo;
+        int32_t naluNumber;  // number of NAL units
+    };
+
+    struct NaluByteStream {
+        int32_t naluOffset;
+        int32_t naluLen;
+        int32_t streamPos;
+        uint8_t *byteStream;   // 4 bytes of naluCount, 4 bytes of naluOffset, 4 bytes of naulLen, 4 bytes of naluHeaderLen, followed by naluHeaderData
+        int32_t naluCount;
+    };
+
+    virtual Decode_Status decodeSlice(vbp_data_h264 *data, uint32_t picIndex, uint32_t sliceIndex);
+    int32_t findNalUnitOffset(uint8_t *stream, int32_t offset, int32_t length);
+    Decode_Status copyNaluHeader(uint8_t *stream, NaluByteStream *naluStream);
+    Decode_Status parseAnnexBStream(uint8_t *stream, int32_t length, NaluByteStream *naluStream);
+
+private:
+    NaluMetadata mMetadata;
+    NaluByteStream mByteStream;
+    uint8_t *mNaluHeaderBuffer;
+    uint8_t *mInputBuffer;
+};
+
+
+
+#endif /* VIDEO_DECODER_AVC_SECURE_H_ */
diff --git a/videodecoder/VideoDecoderBase.cpp b/videodecoder/VideoDecoderBase.cpp
index 3e816b8..29c7cec 100644
--- a/videodecoder/VideoDecoderBase.cpp
+++ b/videodecoder/VideoDecoderBase.cpp
@@ -78,7 +78,7 @@
 
     memset(&mVideoFormatInfo, 0, sizeof(VideoFormatInfo));
     memset(&mConfigBuffer, 0, sizeof(mConfigBuffer));
-    for (int i =0; i < MAX_GRAPHIC_NUM; i++) {
+    for (int i = 0; i < MAX_GRAPHIC_BUFFER_NUM; i++) {
          mSignalBufferPre[i] = NULL;
     }
     pthread_mutex_init(&mLock, NULL);
@@ -471,7 +471,7 @@
         if ((mConfigBuffer.flag & USE_NATIVE_GRAPHIC_BUFFER) == 0) {
             return true;
         }
-        for (int i = 0; i < MAX_GRAPHIC_NUM; i++) {
+        for (int i = 0; i < MAX_GRAPHIC_BUFFER_NUM; i++) {
             if (mSignalBufferPre[i] != NULL) {
                 return true;
             }
@@ -1153,7 +1153,7 @@
             mSurfaceBuffers[i].renderBuffer.graphicBufferHandle = NULL;
             mSurfaceBuffers[i].renderBuffer.renderDone = true;
         }
-        mSurfaceBuffers[i].renderBuffer.acquirePos = i;
+        mSurfaceBuffers[i].renderBuffer.graphicBufferIndex = i;
     }
 
     if (useGraphicBuffer && reset) {
@@ -1172,7 +1172,7 @@
     if (!mInitialized) {
         mSignalBufferPre[mSignalBufferSize++] = graphichandler;
         VTRACE("SignalRenderDoneFlag mInitialized = false graphichandler = %p, mSignalBufferSize = %d", graphichandler, mSignalBufferSize);
-        if (mSignalBufferSize > MAX_GRAPHIC_NUM)
+        if (mSignalBufferSize > MAX_GRAPHIC_BUFFER_NUM)
             return DECODE_INVALID_DATA;
     } else {
         if (!(mConfigBuffer.flag & USE_NATIVE_GRAPHIC_BUFFER)) {
diff --git a/videodecoder/VideoDecoderBase.h b/videodecoder/VideoDecoderBase.h
index c80367a..ece3a44 100644
--- a/videodecoder/VideoDecoderBase.h
+++ b/videodecoder/VideoDecoderBase.h
@@ -138,7 +138,7 @@
     int32_t mNextOutputPOC; // Picture order count of next output
     _vbp_parser_type mParserType;
     void *mParserHandle;
-    void *mSignalBufferPre[MAX_GRAPHIC_NUM];
+    void *mSignalBufferPre[MAX_GRAPHIC_BUFFER_NUM];
     uint32 mSignalBufferSize;
 
 protected:
diff --git a/videodecoder/VideoDecoderDefs.h b/videodecoder/VideoDecoderDefs.h
index dc72a6f..54ce618 100644
--- a/videodecoder/VideoDecoderDefs.h
+++ b/videodecoder/VideoDecoderDefs.h
@@ -28,7 +28,6 @@
 #include <va/va.h>
 #include <stdint.h>
 
-
 // format specific data, for future extension.
 struct VideoExtensionBuffer {
     int32_t extType;
@@ -100,6 +99,9 @@
     // indicate whether it is a sync frame in container
     IS_SYNC_FRAME = 0x4000,
 
+    // indicate whether video decoder buffer contains secure data
+    IS_SECURE_DATA = 0x8000,
+
 } VIDEO_BUFFER_FLAG;
 
 struct VideoDecodeBuffer {
@@ -111,7 +113,7 @@
 };
 
 
-#define MAX_GRAPHIC_NUM 16 + 1 + 11 // max DPB + 1 + AVC_EXTRA_NUM
+#define MAX_GRAPHIC_BUFFER_NUM  (16 + 1 + 11)  // max DPB + 1 + AVC_EXTRA_NUM
 
 struct VideoConfigBuffer {
     uint8_t *data;
@@ -122,7 +124,7 @@
     int32_t surfaceNumber;
     VAProfile profile;
     uint32_t flag;
-    void *graphicBufferHandler[ MAX_GRAPHIC_NUM ];
+    void *graphicBufferHandler[MAX_GRAPHIC_BUFFER_NUM];
     uint32_t graphicBufferStride;
     uint32_t graphicBufferColorFormat;
     uint32_t graphicBufferWidth;
@@ -140,7 +142,7 @@
     mutable volatile bool renderDone;  // indicated whether frame is rendered, this must be set to false by the client of this library once
                                         // surface is rendered. Not setting this flag will lead to DECODE_NO_SURFACE error.
     void * graphicBufferHandle;
-    int32_t acquirePos;  //the acquirepos in graphichandle array
+    int32_t graphicBufferIndex;  //the index in graphichandle array
     uint32_t flag;
     mutable volatile bool driverRenderDone;
     VideoFrameRawData *rawData;
diff --git a/videodecoder/VideoDecoderHost.cpp b/videodecoder/VideoDecoderHost.cpp
index b3e3039..4e6b1b4 100644
--- a/videodecoder/VideoDecoderHost.cpp
+++ b/videodecoder/VideoDecoderHost.cpp
@@ -26,6 +26,7 @@
 #include "VideoDecoderMPEG4.h"
 #include "VideoDecoderAVC.h"
 #include "VideoDecoderPAVC.h"
+#include "VideoDecoderAVCSecure.h"
 #include "VideoDecoderHost.h"
 #include "VideoDecoderTrace.h"
 #include <string.h>
@@ -53,6 +54,9 @@
     } else if (strcasecmp(mimeType, "video/pavc") == 0) {
         VideoDecoderAVC *p = new VideoDecoderPAVC(mimeType);
         return (IVideoDecoder *)p;
+    } else if (strcasecmp(mimeType, "video/avc-secure") == 0) {
+        VideoDecoderAVC *p = new VideoDecoderAVCSecure(mimeType);
+        return (IVideoDecoder *)p;
     } else {
         ETRACE("Unknown mime type: %s", mimeType);
     }