1/*
2* Copyright (c) 2009-2011 Intel Corporation.  All rights reserved.
3*
4* Licensed under the Apache License, Version 2.0 (the "License");
5* you may not use this file except in compliance with the License.
6* You may obtain a copy of the License at
7*
8* http://www.apache.org/licenses/LICENSE-2.0
9*
10* Unless required by applicable law or agreed to in writing, software
11* distributed under the License is distributed on an "AS IS" BASIS,
12* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13* See the License for the specific language governing permissions and
14* limitations under the License.
15*/
16
17#include "va_private.h"
18#include "VideoDecoderAVCSecure.h"
19#include "VideoDecoderTrace.h"
20#include <string.h>
21
22#define STARTCODE_PREFIX_LEN        3
23#define NALU_TYPE_MASK              0x1F
24#define MAX_NALU_HEADER_BUFFER      8192
25static const uint8_t startcodePrefix[STARTCODE_PREFIX_LEN] = {0x00, 0x00, 0x01};
26
27VideoDecoderAVCSecure::VideoDecoderAVCSecure(const char *mimeType)
28    : VideoDecoderAVC(mimeType),
29      mNaluHeaderBuffer(NULL),
30      mSliceHeaderBuffer(NULL) {
31    setParserType(VBP_H264SECURE);
32}
33
34VideoDecoderAVCSecure::~VideoDecoderAVCSecure() {
35}
36
37Decode_Status VideoDecoderAVCSecure::start(VideoConfigBuffer *buffer) {
38    Decode_Status status = VideoDecoderAVC::start(buffer);
39    if (status != DECODE_SUCCESS) {
40        return status;
41    }
42
43    mNaluHeaderBuffer = new uint8_t [MAX_NALU_HEADER_BUFFER];
44
45    if (mNaluHeaderBuffer == NULL) {
46        ETRACE("Failed to allocate memory for mNaluHeaderBuffer");
47        return DECODE_MEMORY_FAIL;
48    }
49
50    mSliceHeaderBuffer = new uint8_t [MAX_NALU_HEADER_BUFFER];
51    if (mSliceHeaderBuffer == NULL) {
52        ETRACE("Failed to allocate memory for mSliceHeaderBuffer");
53        if (mNaluHeaderBuffer) {
54            delete [] mNaluHeaderBuffer;
55            mNaluHeaderBuffer = NULL;
56        }
57        return DECODE_MEMORY_FAIL;
58    }
59
60    return status;
61}
62
63void VideoDecoderAVCSecure::stop(void) {
64    VideoDecoderAVC::stop();
65
66    if (mNaluHeaderBuffer) {
67        delete [] mNaluHeaderBuffer;
68        mNaluHeaderBuffer = NULL;
69    }
70
71    if (mSliceHeaderBuffer) {
72        delete [] mSliceHeaderBuffer;
73        mSliceHeaderBuffer = NULL;
74    }
75
76}
77
78Decode_Status VideoDecoderAVCSecure::decode(VideoDecodeBuffer *buffer) {
79    Decode_Status status;
80    int32_t sizeAccumulated = 0;
81    int32_t sliceHeaderSize = 0;
82    int32_t sizeLeft = 0;
83    int32_t sliceIdx = 0;
84    uint8_t naluType;
85    frame_info_t* pFrameInfo;
86
87    mFrameSize = 0;
88    if (buffer->flag & IS_SECURE_DATA) {
89        VTRACE("Decoding protected video ...");
90        mIsEncryptData = 1;
91    } else {
92        VTRACE("Decoding clear video ...");
93        mIsEncryptData = 0;
94        return VideoDecoderAVC::decode(buffer);
95    }
96
97    if (buffer->size != sizeof(frame_info_t)) {
98        ETRACE("Not enough data to read frame_info_t!");
99        return DECODE_INVALID_DATA;
100    }
101    pFrameInfo = (frame_info_t*) buffer->data;
102
103    mFrameSize = pFrameInfo->length;
104    VTRACE("mFrameSize = %d", mFrameSize);
105
106    memcpy(&mEncParam, pFrameInfo->pavp, sizeof(pavp_info_t));
107    for (int32_t i = 0; i < pFrameInfo->num_nalus; i++) {
108        naluType = pFrameInfo->nalus[i].type & NALU_TYPE_MASK;
109        if (naluType >= h264_NAL_UNIT_TYPE_SLICE && naluType <= h264_NAL_UNIT_TYPE_IDR) {
110            memcpy(mSliceHeaderBuffer + sliceHeaderSize,
111                &sliceIdx,
112                sizeof(int32_t));
113            sliceHeaderSize += 4;
114
115            memcpy(mSliceHeaderBuffer + sliceHeaderSize,
116                &pFrameInfo->data,
117                sizeof(uint8_t*));
118            sliceHeaderSize += sizeof(uint8_t*);
119
120            memcpy(mSliceHeaderBuffer + sliceHeaderSize,
121                &pFrameInfo->nalus[i].offset,
122                sizeof(uint32_t));
123            sliceHeaderSize += sizeof(uint32_t);
124
125            memcpy(mSliceHeaderBuffer + sliceHeaderSize,
126                &pFrameInfo->nalus[i].length,
127                sizeof(uint32_t));
128            sliceHeaderSize += sizeof(uint32_t);
129
130            memcpy(mSliceHeaderBuffer + sliceHeaderSize,
131                pFrameInfo->nalus[i].slice_header,
132                sizeof(slice_header_t));
133            sliceHeaderSize += sizeof(slice_header_t);
134            if (pFrameInfo->nalus[i].type & 0x60) {
135                memcpy(mSliceHeaderBuffer+sliceHeaderSize, pFrameInfo->dec_ref_pic_marking, sizeof(dec_ref_pic_marking_t));
136            } else {
137                memset(mSliceHeaderBuffer+sliceHeaderSize, 0, sizeof(dec_ref_pic_marking_t));
138            }
139            sliceHeaderSize += sizeof(dec_ref_pic_marking_t);
140            sliceIdx++;
141        } else if (naluType >= h264_NAL_UNIT_TYPE_SEI && naluType <= h264_NAL_UNIT_TYPE_PPS) {
142            memcpy(mNaluHeaderBuffer + sizeAccumulated,
143                startcodePrefix,
144                STARTCODE_PREFIX_LEN);
145            sizeAccumulated += STARTCODE_PREFIX_LEN;
146            memcpy(mNaluHeaderBuffer + sizeAccumulated,
147                pFrameInfo->nalus[i].data,
148                pFrameInfo->nalus[i].length);
149            sizeAccumulated += pFrameInfo->nalus[i].length;
150        } else {
151            WTRACE("Failure: DECODE_FRAME_DROPPED");
152            return DECODE_FRAME_DROPPED;
153        }
154    }
155
156    vbp_data_h264 *data = NULL;
157
158    if (sizeAccumulated > 0) {
159        status =  VideoDecoderBase::parseBuffer(
160                mNaluHeaderBuffer,
161                sizeAccumulated,
162                false,
163                (void**)&data);
164        CHECK_STATUS("VideoDecoderBase::parseBuffer");
165    }
166
167    if (sliceHeaderSize > 0) {
168        memset(mSliceHeaderBuffer + sliceHeaderSize, 0xFF, 4);
169        sliceHeaderSize += 4;
170        status =  VideoDecoderBase::updateBuffer(
171                mSliceHeaderBuffer,
172                sliceHeaderSize,
173                (void**)&data);
174        CHECK_STATUS("VideoDecoderBase::updateBuffer");
175    }
176
177    if (data == NULL) {
178        ETRACE("Invalid data returned by parser!");
179        return DECODE_MEMORY_FAIL;
180    }
181
182    if (!mVAStarted) {
183         if (data->has_sps && data->has_pps) {
184            status = startVA(data);
185            CHECK_STATUS("startVA");
186        } else {
187            WTRACE("Can't start VA as either SPS or PPS is still not available.");
188            return DECODE_SUCCESS;
189        }
190    }
191    status = decodeFrame(buffer, data);
192    return status;
193}
194
195Decode_Status VideoDecoderAVCSecure::decodeSlice(vbp_data_h264 *data, uint32_t picIndex, uint32_t sliceIndex) {
196    Decode_Status status;
197    VAStatus vaStatus;
198    uint32_t bufferIDCount = 0;
199    // maximum 4 buffers to render a slice: picture parameter, IQMatrix, slice parameter, slice data
200    VABufferID bufferIDs[5];
201
202    vbp_picture_data_h264 *picData = &(data->pic_data[picIndex]);
203    vbp_slice_data_h264 *sliceData = &(picData->slc_data[sliceIndex]);
204    VAPictureParameterBufferH264 *picParam = picData->pic_parms;
205    VASliceParameterBufferH264 *sliceParam = &(sliceData->slc_parms);
206    VAEncryptionParameterBuffer encryptParam;
207
208    if (sliceParam->first_mb_in_slice == 0 || mDecodingFrame == false) {
209        // either condition indicates start of a new frame
210        if (sliceParam->first_mb_in_slice != 0) {
211            WTRACE("The first slice is lost.");
212            // TODO: handle the first slice lost
213        }
214        if (mDecodingFrame) {
215            // interlace content, complete decoding the first field
216            vaStatus = vaEndPicture(mVADisplay, mVAContext);
217            CHECK_VA_STATUS("vaEndPicture");
218
219            // for interlace content, top field may be valid only after the second field is parsed
220            mAcquiredBuffer->pictureOrder= picParam->CurrPic.TopFieldOrderCnt;
221        }
222
223        // Update  the reference frames and surface IDs for DPB and current frame
224        status = updateDPB(picParam);
225        CHECK_STATUS("updateDPB");
226
227        vaStatus = vaBeginPicture(mVADisplay, mVAContext, mAcquiredBuffer->renderBuffer.surface);
228        CHECK_VA_STATUS("vaBeginPicture");
229
230        // start decoding a frame
231        mDecodingFrame = true;
232
233        vaStatus = vaCreateBuffer(
234            mVADisplay,
235            mVAContext,
236            VAPictureParameterBufferType,
237            sizeof(VAPictureParameterBufferH264),
238            1,
239            picParam,
240            &bufferIDs[bufferIDCount]);
241        CHECK_VA_STATUS("vaCreatePictureParameterBuffer");
242        bufferIDCount++;
243
244        vaStatus = vaCreateBuffer(
245            mVADisplay,
246            mVAContext,
247            VAIQMatrixBufferType,
248            sizeof(VAIQMatrixBufferH264),
249            1,
250            data->IQ_matrix_buf,
251            &bufferIDs[bufferIDCount]);
252        CHECK_VA_STATUS("vaCreateIQMatrixBuffer");
253        bufferIDCount++;
254
255        if (mIsEncryptData) {
256            memset(&encryptParam, 0, sizeof(VAEncryptionParameterBuffer));
257            encryptParam.pavpCounterMode = 4;
258            encryptParam.pavpEncryptionType = 2;
259            encryptParam.hostEncryptMode = 2;
260            encryptParam.pavpHasBeenEnabled = 1;
261            encryptParam.app_id = 0;
262            memcpy(encryptParam.pavpAesCounter, mEncParam.iv, 16);
263
264            vaStatus = vaCreateBuffer(
265                mVADisplay,
266                mVAContext,
267                (VABufferType)VAEncryptionParameterBufferType,
268                sizeof(VAEncryptionParameterBuffer),
269                1,
270                &encryptParam,
271                &bufferIDs[bufferIDCount]);
272            CHECK_VA_STATUS("vaCreateEncryptionParameterBuffer");
273            bufferIDCount++;
274        }
275
276        vaStatus = vaCreateBuffer(
277            mVADisplay,
278            mVAContext,
279            VASliceDataBufferType,
280            mFrameSize, //size
281            1,        //num_elements
282            sliceData->buffer_addr + sliceData->slice_offset,
283            &bufferIDs[bufferIDCount]);
284        CHECK_VA_STATUS("vaCreateSliceDataBuffer");
285        bufferIDCount++;
286
287    }
288
289    vaStatus = vaCreateBuffer(
290        mVADisplay,
291        mVAContext,
292        VASliceParameterBufferType,
293        sizeof(VASliceParameterBufferH264Base),
294        1,
295        sliceParam,
296        &bufferIDs[bufferIDCount]);
297
298    CHECK_VA_STATUS("vaCreateSliceParameterBuffer");
299    bufferIDCount++;
300
301    vaStatus = vaRenderPicture(
302        mVADisplay,
303        mVAContext,
304        bufferIDs,
305        bufferIDCount);
306    CHECK_VA_STATUS("vaRenderPicture");
307
308    return DECODE_SUCCESS;
309}
310
311Decode_Status VideoDecoderAVCSecure::getCodecSpecificConfigs(
312    VAProfile profile, VAConfigID *config)
313{
314    VAStatus vaStatus;
315    VAConfigAttrib attrib[2];
316
317    if (config == NULL) {
318        ETRACE("Invalid parameter!");
319        return DECODE_FAIL;
320    }
321
322    attrib[0].type = VAConfigAttribRTFormat;
323    attrib[0].value = VA_RT_FORMAT_YUV420;
324    attrib[1].type = VAConfigAttribDecSliceMode;
325    attrib[1].value = VA_DEC_SLICE_MODE_NORMAL;
326
327    vaStatus = vaGetConfigAttributes(mVADisplay,profile,VAEntrypointVLD, &attrib[1], 1);
328
329    if (attrib[1].value & VA_DEC_SLICE_MODE_BASE)
330    {
331        ITRACE("AVC short format used");
332        attrib[1].value = VA_DEC_SLICE_MODE_BASE;
333    } else if (attrib[1].value & VA_DEC_SLICE_MODE_NORMAL) {
334        ITRACE("AVC long format ssed");
335        attrib[1].value = VA_DEC_SLICE_MODE_NORMAL;
336    } else {
337        ETRACE("Unsupported Decode Slice Mode!");
338        return DECODE_FAIL;
339    }
340
341    vaStatus = vaCreateConfig(
342            mVADisplay,
343            profile,
344            VAEntrypointVLD,
345            &attrib[0],
346            2,
347            config);
348    CHECK_VA_STATUS("vaCreateConfig");
349
350    return DECODE_SUCCESS;
351}
352