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