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