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 "VideoDecoderVP8.h"
18#include "VideoDecoderTrace.h"
19#include <string.h>
20
21VideoDecoderVP8::VideoDecoderVP8(const char *mimeType)
22    : VideoDecoderBase(mimeType, VBP_VP8) {
23    invalidateReferenceFrames(0);
24    invalidateReferenceFrames(1);
25}
26
27VideoDecoderVP8::~VideoDecoderVP8() {
28    stop();
29}
30
31void VideoDecoderVP8::invalidateReferenceFrames(int toggle) {
32    ReferenceFrameBuffer *p = mRFBs[toggle];
33    for (int i = 0; i < VP8_REF_SIZE; i++) {
34        p->index = (uint32_t) -1;
35        p->surfaceBuffer = NULL;
36        p++;
37    }
38}
39
40void VideoDecoderVP8::clearAsReference(int toggle, int ref_type) {
41    ReferenceFrameBuffer ref = mRFBs[toggle][ref_type];
42    if (ref.surfaceBuffer) {
43        ref.surfaceBuffer->asReferernce = false;
44    }
45}
46
47void VideoDecoderVP8::updateFormatInfo(vbp_data_vp8 *data) {
48    uint32_t width = data->codec_data->frame_width;
49    uint32_t height = data->codec_data->frame_height;
50    ITRACE("updateFormatInfo: current size: %d x %d, new size: %d x %d",
51            mVideoFormatInfo.width, mVideoFormatInfo.height, width, height);
52
53    if ((mConfigBuffer.flag & USE_NATIVE_GRAPHIC_BUFFER) && mStoreMetaData) {
54        pthread_mutex_lock(&mFormatLock);
55    }
56
57    if ((mVideoFormatInfo.width != width ||
58            mVideoFormatInfo.height != height) &&
59            width && height) {
60        if ((VideoDecoderBase::alignMB(mVideoFormatInfo.width) != width) ||
61            (VideoDecoderBase::alignMB(mVideoFormatInfo.height) != height)) {
62            mSizeChanged = true;
63            ITRACE("Video size is changed.");
64        }
65        mVideoFormatInfo.width = width;
66        mVideoFormatInfo.height = height;
67    }
68
69    // video_range has default value of 0. Y ranges from 16 to 235.
70    mVideoFormatInfo.videoRange = 0;
71
72    switch (data->codec_data->clr_type) {
73        case 0:
74            mVideoFormatInfo.colorMatrix = VA_SRC_BT601;
75            break;
76        case 1:
77        default:
78            mVideoFormatInfo.colorMatrix = 0;
79            break;
80    }
81
82    mVideoFormatInfo.cropLeft = data->codec_data->crop_left;
83    mVideoFormatInfo.cropRight = data->codec_data->crop_right;
84    mVideoFormatInfo.cropTop = data->codec_data->crop_top;
85    mVideoFormatInfo.cropBottom = data->codec_data->crop_bottom;
86    ITRACE("Cropping: left = %d, top = %d, right = %d, bottom = %d", data->codec_data->crop_left, data->codec_data->crop_top, data->codec_data->crop_right, data->codec_data->crop_bottom);
87
88    if ((mConfigBuffer.flag & USE_NATIVE_GRAPHIC_BUFFER) && mStoreMetaData) {
89        if (mSizeChanged) {
90            mVideoFormatInfo.valid = false;
91        } else {
92            mVideoFormatInfo.valid = true;
93        }
94
95        pthread_mutex_unlock(&mFormatLock);
96    } else {
97        mVideoFormatInfo.valid = true;
98    }
99
100    setRenderRect();
101    setColorSpaceInfo(mVideoFormatInfo.colorMatrix, mVideoFormatInfo.videoRange);
102}
103
104Decode_Status VideoDecoderVP8::startVA(vbp_data_vp8 *data) {
105    updateFormatInfo(data);
106
107    VAProfile vaProfile = VAProfileVP8Version0_3;
108    if (data->codec_data->version_num > 3) {
109        return DECODE_PARSER_FAIL;
110    }
111
112    enableLowDelayMode(true);
113
114    return VideoDecoderBase::setupVA(VP8_SURFACE_NUMBER + VP8_REF_SIZE, vaProfile);
115}
116
117Decode_Status VideoDecoderVP8::start(VideoConfigBuffer *buffer) {
118    Decode_Status status;
119
120    status = VideoDecoderBase::start(buffer);
121    CHECK_STATUS("VideoDecoderBase::start");
122
123    // We don't want base class to manage reference.
124    VideoDecoderBase::ManageReference(false);
125
126    if (buffer->data == NULL || buffer->size == 0) {
127        WTRACE("No config data to start VA.");
128        return DECODE_SUCCESS;
129    }
130
131    vbp_data_vp8 *data = NULL;
132    status = VideoDecoderBase::parseBuffer(buffer->data, buffer->size, true, (void**)&data);
133    CHECK_STATUS("VideoDecoderBase::parseBuffer");
134
135    status = startVA(data);
136    return status;
137}
138
139void VideoDecoderVP8::stop(void) {
140    VideoDecoderBase::stop();
141
142    invalidateReferenceFrames(0);
143    invalidateReferenceFrames(1);
144}
145
146void VideoDecoderVP8::flush(void) {
147    VideoDecoderBase::flush();
148
149    invalidateReferenceFrames(0);
150    invalidateReferenceFrames(1);
151}
152
153Decode_Status VideoDecoderVP8::decode(VideoDecodeBuffer *buffer) {
154    Decode_Status status;
155    vbp_data_vp8 *data = NULL;
156    if (buffer == NULL) {
157        ETRACE("VideoDecodeBuffer is NULL.");
158        return DECODE_INVALID_DATA;
159    }
160
161    status = VideoDecoderBase::parseBuffer(
162                 buffer->data,
163                 buffer->size,
164                 false,
165                 (void**)&data);
166    CHECK_STATUS("VideoDecoderBase::parseBuffer");
167
168    mShowFrame = data->codec_data->show_frame;
169
170    if (!mVAStarted) {
171        status = startVA(data);
172        CHECK_STATUS("startVA");
173    }
174
175    VideoDecoderBase::setRotationDegrees(buffer->rotationDegrees);
176
177    status = decodeFrame(buffer, data);
178
179    return status;
180}
181
182Decode_Status VideoDecoderVP8::decodeFrame(VideoDecodeBuffer* buffer, vbp_data_vp8 *data) {
183    Decode_Status status;
184    bool useGraphicbuffer = mConfigBuffer.flag & USE_NATIVE_GRAPHIC_BUFFER;
185    mCurrentPTS = buffer->timeStamp;
186    if (0 == data->num_pictures || NULL == data->pic_data) {
187        WTRACE("Number of pictures is 0.");
188        return DECODE_SUCCESS;
189    }
190
191    if (VP8_KEY_FRAME == data->codec_data->frame_type) {
192        updateFormatInfo(data);
193        if (mSizeChanged && !(mConfigBuffer.flag & USE_NATIVE_GRAPHIC_BUFFER)) {
194            mSizeChanged = false;
195            return DECODE_FORMAT_CHANGE;
196        }
197
198        bool needFlush = false;
199        if (useGraphicbuffer) {
200            // For VP8 in adaptive playback legacy mode,
201            // force buffer reallocation.
202            needFlush = mSizeChanged;
203        }
204        if (needFlush) {
205            if (mStoreMetaData) {
206                status = endDecodingFrame(false);
207                CHECK_STATUS("endDecodingFrame");
208            } else {
209                flushSurfaceBuffers();
210            }
211            mSizeChanged = false;
212            return DECODE_FORMAT_CHANGE;
213        }
214    }
215
216    if (data->codec_data->frame_type == VP8_SKIPPED_FRAME) {
217        // Do nothing for skip frame as the last frame will be rendered agian by natively
218        return DECODE_SUCCESS;
219    }
220
221    status = acquireSurfaceBuffer();
222    CHECK_STATUS("acquireSurfaceBuffer");
223
224    // set referenceFrame to true if frame decoded is I/P frame, false otherwise.
225    int frameType = data->codec_data->frame_type;
226    mAcquiredBuffer->referenceFrame = (frameType == VP8_KEY_FRAME || frameType == VP8_INTER_FRAME);
227    // assume it is frame picture.
228    mAcquiredBuffer->renderBuffer.scanFormat = VA_FRAME_PICTURE;
229    mAcquiredBuffer->renderBuffer.timeStamp = buffer->timeStamp;
230    mAcquiredBuffer->renderBuffer.flag = 0;
231    if (buffer->flag & WANT_DECODE_ONLY) {
232        mAcquiredBuffer->renderBuffer.flag |= WANT_DECODE_ONLY;
233    }
234    if (mSizeChanged) {
235        mSizeChanged = false;
236        mAcquiredBuffer->renderBuffer.flag |= IS_RESOLUTION_CHANGE;
237    }
238
239    // Here data->num_pictures is always equal to 1
240    for (uint32_t index = 0; index < data->num_pictures; index++) {
241        status = decodePicture(data, index);
242        if (status != DECODE_SUCCESS) {
243            endDecodingFrame(true);
244            return status;
245        }
246    }
247
248    if (frameType != VP8_SKIPPED_FRAME) {
249        updateReferenceFrames(data);
250    }
251
252    // if sample is successfully decoded, call outputSurfaceBuffer(); otherwise
253    // call releaseSurfacebuffer();
254    status = outputSurfaceBuffer();
255    return status;
256}
257
258Decode_Status VideoDecoderVP8::decodePicture(vbp_data_vp8 *data, int32_t picIndex) {
259    VAStatus vaStatus = VA_STATUS_SUCCESS;
260    Decode_Status status;
261    uint32_t bufferIDCount = 0;
262    VABufferID bufferIDs[5];
263
264    vbp_picture_data_vp8 *picData = &(data->pic_data[picIndex]);
265    VAPictureParameterBufferVP8 *picParams = picData->pic_parms;
266
267    status = setReference(picParams);
268    CHECK_STATUS("setReference");
269
270    vaStatus = vaBeginPicture(mVADisplay, mVAContext, mAcquiredBuffer->renderBuffer.surface);
271    CHECK_VA_STATUS("vaBeginPicture");
272    // setting mDecodingFrame to true so vaEndPicture will be invoked to end the picture decoding.
273    mDecodingFrame = true;
274
275    vaStatus = vaCreateBuffer(
276                   mVADisplay,
277                   mVAContext,
278                   VAPictureParameterBufferType,
279                   sizeof(VAPictureParameterBufferVP8),
280                   1,
281                   picParams,
282                   &bufferIDs[bufferIDCount]);
283    CHECK_VA_STATUS("vaCreatePictureParameterBuffer");
284    bufferIDCount++;
285
286    vaStatus = vaCreateBuffer(
287                   mVADisplay,
288                   mVAContext,
289                   VAProbabilityBufferType,
290                   sizeof(VAProbabilityDataBufferVP8),
291                   1,
292                   data->prob_data,
293                   &bufferIDs[bufferIDCount]);
294    CHECK_VA_STATUS("vaCreateProbabilityBuffer");
295    bufferIDCount++;
296
297    vaStatus = vaCreateBuffer(
298                   mVADisplay,
299                   mVAContext,
300                   VAIQMatrixBufferType,
301                   sizeof(VAIQMatrixBufferVP8),
302                   1,
303                   data->IQ_matrix_buf,
304                   &bufferIDs[bufferIDCount]);
305    CHECK_VA_STATUS("vaCreateIQMatrixBuffer");
306    bufferIDCount++;
307
308    /* Here picData->num_slices is always equal to 1 */
309    for (uint32_t i = 0; i < picData->num_slices; i++) {
310        vaStatus = vaCreateBuffer(
311                       mVADisplay,
312                       mVAContext,
313                       VASliceParameterBufferType,
314                       sizeof(VASliceParameterBufferVP8),
315                       1,
316                       &(picData->slc_data[i].slc_parms),
317                       &bufferIDs[bufferIDCount]);
318        CHECK_VA_STATUS("vaCreateSliceParameterBuffer");
319        bufferIDCount++;
320
321        vaStatus = vaCreateBuffer(
322                       mVADisplay,
323                       mVAContext,
324                       VASliceDataBufferType,
325                       picData->slc_data[i].slice_size, //size
326                       1,        //num_elements
327                       picData->slc_data[i].buffer_addr + picData->slc_data[i].slice_offset,
328                       &bufferIDs[bufferIDCount]);
329        CHECK_VA_STATUS("vaCreateSliceDataBuffer");
330        bufferIDCount++;
331    }
332
333    vaStatus = vaRenderPicture(
334                   mVADisplay,
335                   mVAContext,
336                   bufferIDs,
337                   bufferIDCount);
338    CHECK_VA_STATUS("vaRenderPicture");
339
340    vaStatus = vaEndPicture(mVADisplay, mVAContext);
341    mDecodingFrame = false;
342    CHECK_VA_STATUS("vaEndPicture");
343
344    return DECODE_SUCCESS;
345}
346
347Decode_Status VideoDecoderVP8::setReference(VAPictureParameterBufferVP8 *picParam) {
348    int frameType = picParam->pic_fields.bits.key_frame;
349    switch (frameType) {
350    case VP8_KEY_FRAME:
351        picParam->last_ref_frame = VA_INVALID_SURFACE;
352        picParam->alt_ref_frame = VA_INVALID_SURFACE;
353        picParam->golden_ref_frame = VA_INVALID_SURFACE;
354        break;
355    case VP8_INTER_FRAME:
356        if (mRFBs[0][VP8_LAST_REF_PIC].surfaceBuffer   == NULL ||
357                mRFBs[0][VP8_ALT_REF_PIC].surfaceBuffer    == NULL ||
358                mRFBs[0][VP8_GOLDEN_REF_PIC].surfaceBuffer == NULL) {
359            mAcquiredBuffer->renderBuffer.errBuf.errorNumber = 1;
360            mAcquiredBuffer->renderBuffer.errBuf.errorArray[0].type = DecodeRefMissing;
361            return DECODE_NO_REFERENCE;
362        }
363        //mRFBs[0][VP8_LAST_REF_PIC].surfaceBuffer = mLastReference;
364        picParam->last_ref_frame = mRFBs[0][VP8_LAST_REF_PIC].surfaceBuffer->renderBuffer.surface;
365        picParam->alt_ref_frame = mRFBs[0][VP8_ALT_REF_PIC].surfaceBuffer->renderBuffer.surface;
366        picParam->golden_ref_frame = mRFBs[0][VP8_GOLDEN_REF_PIC].surfaceBuffer->renderBuffer.surface;
367        break;
368    case VP8_SKIPPED_FRAME:
369        // will never happen here
370        break;
371    default:
372        return DECODE_PARSER_FAIL;
373    }
374
375    return DECODE_SUCCESS;
376}
377
378void VideoDecoderVP8::updateReferenceFrames(vbp_data_vp8 *data) {
379    /* Refresh last frame reference buffer using the currently reconstructed frame */
380    refreshLastReference(data);
381
382    /* Refresh golden frame reference buffer using the currently reconstructed frame */
383    refreshGoldenReference(data);
384
385    /* Refresh alternative frame reference buffer using the currently reconstructed frame */
386    refreshAltReference(data);
387
388    /* Update reference frames */
389    for (int i = 0; i < VP8_REF_SIZE; i++) {
390        VideoSurfaceBuffer *p = mRFBs[1][i].surfaceBuffer;
391        int j;
392        for (j = 0; j < VP8_REF_SIZE; j++) {
393            if (p == mRFBs[0][j].surfaceBuffer) {
394                break;
395            }
396        }
397        if (j == VP8_REF_SIZE) {
398            clearAsReference(1, i);
399        }
400    }
401}
402
403void VideoDecoderVP8::refreshLastReference(vbp_data_vp8 *data) {
404    /* Save previous last reference */
405    mRFBs[1][VP8_LAST_REF_PIC].surfaceBuffer = mRFBs[0][VP8_LAST_REF_PIC].surfaceBuffer;
406    mRFBs[1][VP8_LAST_REF_PIC].index = mRFBs[0][VP8_LAST_REF_PIC].index;
407
408    /* For key frame, this is always true */
409    if (data->codec_data->refresh_last_frame) {
410        mRFBs[0][VP8_LAST_REF_PIC].surfaceBuffer = mAcquiredBuffer;
411        mRFBs[0][VP8_LAST_REF_PIC].index = mAcquiredBuffer->renderBuffer.surface;
412        mRFBs[0][VP8_LAST_REF_PIC].surfaceBuffer->asReferernce = true;
413    }
414}
415
416void VideoDecoderVP8::refreshGoldenReference(vbp_data_vp8 *data) {
417    /* Save previous golden reference */
418    mRFBs[1][VP8_GOLDEN_REF_PIC].surfaceBuffer = mRFBs[0][VP8_GOLDEN_REF_PIC].surfaceBuffer;
419    mRFBs[1][VP8_GOLDEN_REF_PIC].index = mRFBs[0][VP8_GOLDEN_REF_PIC].index;
420
421    if (data->codec_data->golden_copied != BufferCopied_NoneToGolden) {
422        if (data->codec_data->golden_copied == BufferCopied_LastToGolden) {
423            /* LastFrame is copied to GoldenFrame */
424            mRFBs[0][VP8_GOLDEN_REF_PIC].surfaceBuffer = mRFBs[1][VP8_LAST_REF_PIC].surfaceBuffer;
425            mRFBs[0][VP8_GOLDEN_REF_PIC].index = mRFBs[1][VP8_LAST_REF_PIC].index;
426        } else if (data->codec_data->golden_copied == BufferCopied_AltRefToGolden) {
427            /* AltRefFrame is copied to GoldenFrame */
428            mRFBs[0][VP8_GOLDEN_REF_PIC].surfaceBuffer = mRFBs[0][VP8_ALT_REF_PIC].surfaceBuffer;
429            mRFBs[0][VP8_GOLDEN_REF_PIC].index = mRFBs[0][VP8_ALT_REF_PIC].index;
430        }
431    }
432
433    /* For key frame, this is always true */
434    if (data->codec_data->refresh_golden_frame) {
435        mRFBs[0][VP8_GOLDEN_REF_PIC].surfaceBuffer = mAcquiredBuffer;
436        mRFBs[0][VP8_GOLDEN_REF_PIC].index = mAcquiredBuffer->renderBuffer.surface;
437        mRFBs[0][VP8_GOLDEN_REF_PIC].surfaceBuffer->asReferernce = true;
438    }
439}
440
441void VideoDecoderVP8::refreshAltReference(vbp_data_vp8 *data) {
442    /* Save previous alternative reference */
443    mRFBs[1][VP8_ALT_REF_PIC].surfaceBuffer = mRFBs[0][VP8_ALT_REF_PIC].surfaceBuffer;
444    mRFBs[1][VP8_ALT_REF_PIC].index = mRFBs[0][VP8_ALT_REF_PIC].index;
445
446    if (data->codec_data->altref_copied != BufferCopied_NoneToAltRef) {
447        if (data->codec_data->altref_copied == BufferCopied_LastToAltRef) {
448            /* LastFrame is copied to AltRefFrame */
449            mRFBs[0][VP8_ALT_REF_PIC].surfaceBuffer = mRFBs[1][VP8_LAST_REF_PIC].surfaceBuffer;
450            mRFBs[0][VP8_ALT_REF_PIC].index = mRFBs[1][VP8_LAST_REF_PIC].index;
451        } else if (data->codec_data->altref_copied == BufferCopied_GoldenToAltRef) {
452            /* GoldenFrame is copied to AltRefFrame */
453            mRFBs[0][VP8_ALT_REF_PIC].surfaceBuffer = mRFBs[1][VP8_GOLDEN_REF_PIC].surfaceBuffer;
454            mRFBs[0][VP8_ALT_REF_PIC].index = mRFBs[1][VP8_GOLDEN_REF_PIC].index;
455        }
456    }
457
458    /* For key frame, this is always true */
459    if (data->codec_data->refresh_alt_frame) {
460        mRFBs[0][VP8_ALT_REF_PIC].surfaceBuffer = mAcquiredBuffer;
461        mRFBs[0][VP8_ALT_REF_PIC].index = mAcquiredBuffer->renderBuffer.surface;
462        mRFBs[0][VP8_ALT_REF_PIC].surfaceBuffer->asReferernce = true;
463    }
464}
465
466
467Decode_Status VideoDecoderVP8::checkHardwareCapability() {
468    VAStatus vaStatus;
469    VAConfigAttrib cfgAttribs[2];
470    cfgAttribs[0].type = VAConfigAttribMaxPictureWidth;
471    cfgAttribs[1].type = VAConfigAttribMaxPictureHeight;
472    vaStatus = vaGetConfigAttributes(mVADisplay, VAProfileVP8Version0_3,
473            VAEntrypointVLD, cfgAttribs, 2);
474    CHECK_VA_STATUS("vaGetConfigAttributes");
475    if (cfgAttribs[0].value * cfgAttribs[1].value < (uint32_t)mVideoFormatInfo.width * (uint32_t)mVideoFormatInfo.height) {
476        ETRACE("hardware supports resolution %d * %d smaller than the clip resolution %d * %d",
477                cfgAttribs[0].value, cfgAttribs[1].value, mVideoFormatInfo.width, mVideoFormatInfo.height);
478        return DECODE_DRIVER_FAIL;
479    }
480
481    return DECODE_SUCCESS;
482}
483
484