C++程序  |  368行  |  11.94 KB

/*
* 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 "va_private.h"
#include "VideoDecoderAVCSecure.h"
#include "VideoDecoderTrace.h"
#include <string.h>

#define STARTCODE_PREFIX_LEN        3
#define NALU_TYPE_MASK              0x1F
#define MAX_NALU_HEADER_BUFFER      8192
static const uint8_t startcodePrefix[STARTCODE_PREFIX_LEN] = {0x00, 0x00, 0x01};

VideoDecoderAVCSecure::VideoDecoderAVCSecure(const char *mimeType)
    : VideoDecoderAVC(mimeType),
      mNaluHeaderBuffer(NULL),
      mSliceHeaderBuffer(NULL) {
    setParserType(VBP_H264SECURE);
}

VideoDecoderAVCSecure::~VideoDecoderAVCSecure() {
}

Decode_Status VideoDecoderAVCSecure::start(VideoConfigBuffer *buffer) {
    Decode_Status status = VideoDecoderAVC::start(buffer);
    if (status != DECODE_SUCCESS) {
        return status;
    }

    mNaluHeaderBuffer = new uint8_t [MAX_NALU_HEADER_BUFFER];

    if (mNaluHeaderBuffer == NULL) {
        ETRACE("Failed to allocate memory for mNaluHeaderBuffer");
        return DECODE_MEMORY_FAIL;
    }

    mSliceHeaderBuffer = new uint8_t [MAX_NALU_HEADER_BUFFER];
    if (mSliceHeaderBuffer == NULL) {
        ETRACE("Failed to allocate memory for mSliceHeaderBuffer");
        if (mNaluHeaderBuffer) {
            delete [] mNaluHeaderBuffer;
            mNaluHeaderBuffer = NULL;
        }
        return DECODE_MEMORY_FAIL;
    }

    return status;
}

void VideoDecoderAVCSecure::stop(void) {
    VideoDecoderAVC::stop();

    if (mNaluHeaderBuffer) {
        delete [] mNaluHeaderBuffer;
        mNaluHeaderBuffer = NULL;
    }

    if (mSliceHeaderBuffer) {
        delete [] mSliceHeaderBuffer;
        mSliceHeaderBuffer = NULL;
    }

}

Decode_Status VideoDecoderAVCSecure::decode(VideoDecodeBuffer *buffer) {
    Decode_Status status;
    int32_t sizeAccumulated = 0;
    int32_t sliceHeaderSize = 0;
    int32_t sizeLeft = 0;
    int32_t sliceIdx = 0;
    uint8_t naluType;
    frame_info_t* pFrameInfo;

    mFrameSize = 0;
    if (buffer->flag & IS_SECURE_DATA) {
        VTRACE("Decoding protected video ...");
        mIsEncryptData = 1;
    } else {
        VTRACE("Decoding clear video ...");
        mIsEncryptData = 0;
        return VideoDecoderAVC::decode(buffer);
    }

    if (buffer->size != sizeof(frame_info_t)) {
        ETRACE("Not enough data to read frame_info_t!");
        return DECODE_INVALID_DATA;
    }
    pFrameInfo = (frame_info_t*) buffer->data;

    mFrameSize = pFrameInfo->length;
    VTRACE("mFrameSize = %d", mFrameSize);

    memcpy(&mEncParam, pFrameInfo->pavp, sizeof(pavp_info_t));
    for (int32_t i = 0; i < pFrameInfo->num_nalus; i++) {
        naluType = pFrameInfo->nalus[i].type & NALU_TYPE_MASK;
        if (naluType >= h264_NAL_UNIT_TYPE_SLICE && naluType <= h264_NAL_UNIT_TYPE_IDR) {
            memcpy(mSliceHeaderBuffer + sliceHeaderSize,
                &sliceIdx,
                sizeof(int32_t));
            sliceHeaderSize += 4;

            memcpy(mSliceHeaderBuffer + sliceHeaderSize,
                &pFrameInfo->data,
                sizeof(uint8_t*));
            sliceHeaderSize += sizeof(uint8_t*);

            memcpy(mSliceHeaderBuffer + sliceHeaderSize,
                &pFrameInfo->nalus[i].offset,
                sizeof(uint32_t));
            sliceHeaderSize += sizeof(uint32_t);

            memcpy(mSliceHeaderBuffer + sliceHeaderSize,
                &pFrameInfo->nalus[i].length,
                sizeof(uint32_t));
            sliceHeaderSize += sizeof(uint32_t);

            memcpy(mSliceHeaderBuffer + sliceHeaderSize,
                pFrameInfo->nalus[i].slice_header,
                sizeof(slice_header_t));
            sliceHeaderSize += sizeof(slice_header_t);
            if (pFrameInfo->nalus[i].type & 0x60) {
                memcpy(mSliceHeaderBuffer+sliceHeaderSize, pFrameInfo->dec_ref_pic_marking, sizeof(dec_ref_pic_marking_t));
            } else {
                memset(mSliceHeaderBuffer+sliceHeaderSize, 0, sizeof(dec_ref_pic_marking_t));
            }
            sliceHeaderSize += sizeof(dec_ref_pic_marking_t);
            sliceIdx++;
        } else if (naluType >= h264_NAL_UNIT_TYPE_SEI && naluType <= h264_NAL_UNIT_TYPE_PPS) {
            memcpy(mNaluHeaderBuffer + sizeAccumulated,
                startcodePrefix,
                STARTCODE_PREFIX_LEN);
            sizeAccumulated += STARTCODE_PREFIX_LEN;
            memcpy(mNaluHeaderBuffer + sizeAccumulated,
                pFrameInfo->nalus[i].data,
                pFrameInfo->nalus[i].length);
            sizeAccumulated += pFrameInfo->nalus[i].length;
        } else {
            WTRACE("Failure: DECODE_FRAME_DROPPED");
            return DECODE_FRAME_DROPPED;
        }
    }

    vbp_data_h264 *data = NULL;
    int new_sequence_to_handle = 0;

    if (sizeAccumulated > 0) {
        status =  VideoDecoderBase::parseBuffer(
                mNaluHeaderBuffer,
                sizeAccumulated,
                false,
                (void**)&data);
        CHECK_STATUS("VideoDecoderBase::parseBuffer");

        // [FIX DRC zoom issue] if one buffer contains more than one nalu
        // for example SPS+PPS+IDR, new_sps/new_pps flags set in parseBuffer
        // will be flushed in the following updateBuffer.
        // So that handleNewSequence will not be handled in decodeFrame()
        if (data->new_sps || data->new_pps) {
            new_sequence_to_handle = 1;
        }
    }

    if (sliceHeaderSize > 0) {
        memset(mSliceHeaderBuffer + sliceHeaderSize, 0xFF, 4);
        sliceHeaderSize += 4;
        status =  VideoDecoderBase::updateBuffer(
                mSliceHeaderBuffer,
                sliceHeaderSize,
                (void**)&data);
        CHECK_STATUS("VideoDecoderBase::updateBuffer");

        // in case the flags were flushed but indeed new sequence needed to be handled.
        if ((1 == new_sequence_to_handle) &&
            ((data->new_sps == 0) || (data->new_pps == 0))) {
            data->new_sps = 1;
            data->new_pps = 1;
        }
    }

    if (data == NULL) {
        ETRACE("Invalid data returned by parser!");
        return DECODE_MEMORY_FAIL;
    }

    if (!mVAStarted) {
         if (data->has_sps && data->has_pps) {
            status = startVA(data);
            CHECK_STATUS("startVA");
        } else {
            WTRACE("Can't start VA as either SPS or PPS is still not available.");
            return DECODE_SUCCESS;
        }
    }
    status = decodeFrame(buffer, data);
    return status;
}

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[5];

    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);
    VAEncryptionParameterBuffer encryptParam;

    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;
        }

        // Update  the reference frames and surface IDs for DPB and current frame
        status = updateDPB(picParam);
        CHECK_STATUS("updateDPB");

        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++;

        if (mIsEncryptData) {
            memset(&encryptParam, 0, sizeof(VAEncryptionParameterBuffer));
            encryptParam.pavpCounterMode = 4;
            encryptParam.pavpEncryptionType = 2;
            encryptParam.hostEncryptMode = 2;
            encryptParam.pavpHasBeenEnabled = 1;
            encryptParam.app_id = 0;
            memcpy(encryptParam.pavpAesCounter, mEncParam.iv, 16);

            vaStatus = vaCreateBuffer(
                mVADisplay,
                mVAContext,
                (VABufferType)VAEncryptionParameterBufferType,
                sizeof(VAEncryptionParameterBuffer),
                1,
                &encryptParam,
                &bufferIDs[bufferIDCount]);
            CHECK_VA_STATUS("vaCreateEncryptionParameterBuffer");
            bufferIDCount++;
        }

        vaStatus = vaCreateBuffer(
            mVADisplay,
            mVAContext,
            VASliceDataBufferType,
            mFrameSize, //size
            1,        //num_elements
            sliceData->buffer_addr + sliceData->slice_offset,
            &bufferIDs[bufferIDCount]);
        CHECK_VA_STATUS("vaCreateSliceDataBuffer");
        bufferIDCount++;

    }

    vaStatus = vaCreateBuffer(
        mVADisplay,
        mVAContext,
        VASliceParameterBufferType,
        sizeof(VASliceParameterBufferH264Base),
        1,
        sliceParam,
        &bufferIDs[bufferIDCount]);

    CHECK_VA_STATUS("vaCreateSliceParameterBuffer");
    bufferIDCount++;

    vaStatus = vaRenderPicture(
        mVADisplay,
        mVAContext,
        bufferIDs,
        bufferIDCount);
    CHECK_VA_STATUS("vaRenderPicture");

    return DECODE_SUCCESS;
}

Decode_Status VideoDecoderAVCSecure::getCodecSpecificConfigs(
    VAProfile profile, VAConfigID *config)
{
    VAStatus vaStatus;
    VAConfigAttrib attrib[2];

    if (config == NULL) {
        ETRACE("Invalid parameter!");
        return DECODE_FAIL;
    }

    attrib[0].type = VAConfigAttribRTFormat;
    attrib[0].value = VA_RT_FORMAT_YUV420;
    attrib[1].type = VAConfigAttribDecSliceMode;
    attrib[1].value = VA_DEC_SLICE_MODE_NORMAL;

    vaStatus = vaGetConfigAttributes(mVADisplay,profile,VAEntrypointVLD, &attrib[1], 1);

    if (attrib[1].value & VA_DEC_SLICE_MODE_BASE)
    {
        ITRACE("AVC short format used");
        attrib[1].value = VA_DEC_SLICE_MODE_BASE;
    } else if (attrib[1].value & VA_DEC_SLICE_MODE_NORMAL) {
        ITRACE("AVC long format ssed");
        attrib[1].value = VA_DEC_SLICE_MODE_NORMAL;
    } else {
        ETRACE("Unsupported Decode Slice Mode!");
        return DECODE_FAIL;
    }

    vaStatus = vaCreateConfig(
            mVADisplay,
            profile,
            VAEntrypointVLD,
            &attrib[0],
            2,
            config);
    CHECK_VA_STATUS("vaCreateConfig");

    return DECODE_SUCCESS;
}