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 "VideoDecoderMPEG4.h"
18 #include "VideoDecoderTrace.h"
19 #include <string.h>
20
VideoDecoderMPEG4(const char * mimeType)21 VideoDecoderMPEG4::VideoDecoderMPEG4(const char *mimeType)
22 : VideoDecoderBase(mimeType, VBP_MPEG4),
23 mLastVOPTimeIncrement(0),
24 mExpectingNVOP(false),
25 mSendIQMatrixBuf(false),
26 mLastVOPCodingType(MP4_VOP_TYPE_I),
27 mIsShortHeader(false) {
28 }
29
~VideoDecoderMPEG4()30 VideoDecoderMPEG4::~VideoDecoderMPEG4() {
31 stop();
32 }
33
start(VideoConfigBuffer * buffer)34 Decode_Status VideoDecoderMPEG4::start(VideoConfigBuffer *buffer) {
35 Decode_Status status;
36
37 status = VideoDecoderBase::start(buffer);
38 CHECK_STATUS("VideoDecoderBase::start");
39
40 if (buffer->data == NULL || buffer->size == 0) {
41 WTRACE("No config data to start VA.");
42 return DECODE_SUCCESS;
43 }
44
45 vbp_data_mp42 *data = NULL;
46 status = VideoDecoderBase::parseBuffer(buffer->data, buffer->size, true, (void**)&data);
47 CHECK_STATUS("VideoDecoderBase::parseBuffer");
48
49 status = startVA(data);
50 return status;
51 }
52
stop(void)53 void VideoDecoderMPEG4::stop(void) {
54 // drop the last frame and ignore return value
55 endDecodingFrame(true);
56 VideoDecoderBase::stop();
57
58 mLastVOPTimeIncrement = 0;
59 mExpectingNVOP = false;
60 mLastVOPCodingType = MP4_VOP_TYPE_I;
61 }
62
decode(VideoDecodeBuffer * buffer)63 Decode_Status VideoDecoderMPEG4::decode(VideoDecodeBuffer *buffer) {
64 Decode_Status status;
65 vbp_data_mp42 *data = NULL;
66 bool useGraphicbuffer = mConfigBuffer.flag & USE_NATIVE_GRAPHIC_BUFFER;
67 if (buffer == NULL) {
68 return DECODE_INVALID_DATA;
69 }
70 if (buffer->flag & IS_SYNC_FRAME) {
71 mIsSyncFrame = true;
72 } else {
73 mIsSyncFrame = false;
74 }
75 buffer->ext = NULL;
76 status = VideoDecoderBase::parseBuffer(
77 buffer->data,
78 buffer->size,
79 false,
80 (void**)&data);
81 CHECK_STATUS("VideoDecoderBase::parseBuffer");
82
83 if (!mVAStarted) {
84 status = startVA(data);
85 CHECK_STATUS("startVA");
86 }
87
88 if (mSizeChanged && !useGraphicbuffer) {
89 // some container has the incorrect width/height.
90 // send the format change to OMX to update the crop info.
91 mSizeChanged = false;
92 ITRACE("Video size is changed during startVA");
93 return DECODE_FORMAT_CHANGE;
94 }
95
96 if ((mVideoFormatInfo.width != (uint32_t)data->codec_data.video_object_layer_width ||
97 mVideoFormatInfo.height != (uint32_t)data->codec_data.video_object_layer_height) &&
98 data->codec_data.video_object_layer_width &&
99 data->codec_data.video_object_layer_height) {
100 // update encoded image size
101 ITRACE("Video size is changed. from %dx%d to %dx%d\n", mVideoFormatInfo.width, mVideoFormatInfo.height,
102 data->codec_data.video_object_layer_width,data->codec_data.video_object_layer_height);
103
104 if (useGraphicbuffer && mStoreMetaData) {
105 pthread_mutex_lock(&mFormatLock);
106 }
107 mVideoFormatInfo.width = data->codec_data.video_object_layer_width;
108 mVideoFormatInfo.height = data->codec_data.video_object_layer_height;
109 bool needFlush = false;
110 if (useGraphicbuffer) {
111 if (mStoreMetaData) {
112 needFlush = true;
113
114 mVideoFormatInfo.valid = false;
115 pthread_mutex_unlock(&mFormatLock);
116 } else {
117 needFlush = (mVideoFormatInfo.width > mVideoFormatInfo.surfaceWidth)
118 || (mVideoFormatInfo.height > mVideoFormatInfo.surfaceHeight);
119 }
120 }
121 if (needFlush) {
122 if (mStoreMetaData) {
123 status = endDecodingFrame(false);
124 CHECK_STATUS("endDecodingFrame");
125 } else {
126 flushSurfaceBuffers();
127 }
128 mSizeChanged = false;
129 return DECODE_FORMAT_CHANGE;
130 } else {
131 mSizeChanged = true;
132 }
133
134 setRenderRect();
135 } else {
136 if (useGraphicbuffer && mStoreMetaData) {
137 mVideoFormatInfo.valid = true;
138 }
139 }
140
141 status = decodeFrame(buffer, data);
142 CHECK_STATUS("decodeFrame");
143
144 return status;
145 }
146
flush(void)147 void VideoDecoderMPEG4::flush(void) {
148 VideoDecoderBase::flush();
149
150 mExpectingNVOP = false;
151 mLastVOPTimeIncrement = 0;
152 mLastVOPCodingType = MP4_VOP_TYPE_I;
153 }
154
decodeFrame(VideoDecodeBuffer * buffer,vbp_data_mp42 * data)155 Decode_Status VideoDecoderMPEG4::decodeFrame(VideoDecodeBuffer *buffer, vbp_data_mp42 *data) {
156 Decode_Status status;
157 // check if any slice is parsed, we may just receive configuration data
158 if (data->number_picture_data == 0) {
159 WTRACE("number_picture_data == 0");
160 return DECODE_SUCCESS;
161 }
162 if (data->picture_data && (data->picture_data->picture_param.vop_width == 0 || data->picture_data->picture_param.vop_height == 0)) {
163 if (!data->codec_data.got_vol && data->codec_data.got_vop) {
164 // error enhancement if vol is missing
165 data->picture_data->picture_param.vop_width = mVideoFormatInfo.width;
166 data->picture_data->picture_param.vop_height = mVideoFormatInfo.height;
167 } else {
168 return DECODE_PARSER_FAIL;
169 }
170 }
171
172 uint64_t lastPTS = mCurrentPTS;
173 mCurrentPTS = buffer->timeStamp;
174
175 if (lastPTS != mCurrentPTS) {
176 // finish decoding the last frame
177 status = endDecodingFrame(false);
178 CHECK_STATUS("endDecodingFrame");
179
180 // start decoding a new frame
181 status = beginDecodingFrame(data);
182 if (status == DECODE_MULTIPLE_FRAME) {
183 buffer->ext = &mExtensionBuffer;
184 mExtensionBuffer.extType = PACKED_FRAME_TYPE;
185 mExtensionBuffer.extSize = sizeof(mPackedFrame);
186 mExtensionBuffer.extData = (uint8_t*)&mPackedFrame;
187 } else if (status != DECODE_SUCCESS) {
188 endDecodingFrame(true);
189 }
190 CHECK_STATUS("beginDecodingFrame");
191 } else {
192 status = continueDecodingFrame(data);
193 if (status == DECODE_MULTIPLE_FRAME) {
194 buffer->ext = &mExtensionBuffer;
195 mExtensionBuffer.extType = PACKED_FRAME_TYPE;
196 mExtensionBuffer.extSize = sizeof(mPackedFrame);
197 mExtensionBuffer.extData = (uint8_t*)&mPackedFrame;
198 } else if (status != DECODE_SUCCESS) {
199 endDecodingFrame(true);
200 }
201 CHECK_STATUS("continueDecodingFrame");
202 }
203
204 if (buffer->flag & HAS_COMPLETE_FRAME) {
205 // finish decoding current frame
206 status = endDecodingFrame(false);
207 CHECK_STATUS("endDecodingFrame");
208 }
209
210 return DECODE_SUCCESS;
211 }
212
beginDecodingFrame(vbp_data_mp42 * data)213 Decode_Status VideoDecoderMPEG4::beginDecodingFrame(vbp_data_mp42 *data) {
214
215 Decode_Status status = DECODE_SUCCESS;
216 vbp_picture_data_mp42 *picData = data->picture_data;
217 VAPictureParameterBufferMPEG4 *picParam = &(picData->picture_param);
218 int codingType = picParam->vop_fields.bits.vop_coding_type;
219
220 // start sanity checking
221 if (mExpectingNVOP) {
222 // if we are waiting for n-vop for packed frame, and the new frame is coded, the coding type
223 // of this frame must be B
224 // for example: {PB} B N P B B P...
225 if (picData->vop_coded == 1 && codingType != MP4_VOP_TYPE_B) {
226 WTRACE("Invalid coding type while waiting for n-vop for packed frame.");
227 mExpectingNVOP = false;
228 }
229 }
230
231 // handle N-VOP picuture, it could be a skipped frame or a simple placeholder of packed frame
232 if (picData->vop_coded == 0) {
233 if (mLastReference == NULL) {
234 WTRACE("The last reference is unavailable to construct skipped frame.");
235 flush();
236 mExpectingNVOP = false;
237 // TODO: handle this case
238 return DECODE_SUCCESS;
239 }
240
241 if (mExpectingNVOP) {
242 // P frame is already in queue, just need to update time stamp.
243 mLastReference->renderBuffer.timeStamp = mCurrentPTS;
244 mExpectingNVOP = false;
245 }
246 else {
247 // Do nothing for skip frame as the last frame will be rendered agian by natively
248 // No needs to handle reference frame neither
249 #if 0
250 // this is skipped frame, use the last reference frame as output
251 status = acquireSurfaceBuffer();
252 CHECK_STATUS("acquireSurfaceBuffer");
253 mAcquiredBuffer->renderBuffer.timeStamp = mCurrentPTS;
254 mAcquiredBuffer->renderBuffer.flag = 0;
255 mAcquiredBuffer->renderBuffer.scanFormat = mLastReference->renderBuffer.scanFormat;
256 mAcquiredBuffer->renderBuffer.surface = mLastReference->renderBuffer.surface;
257 // No need to update mappedData for HW decoding
258 //mAcquiredBuffer->mappedData.data = mLastReference->mappedData.data;
259 mAcquiredBuffer->referenceFrame = true;
260 status = outputSurfaceBuffer();
261 CHECK_STATUS("outputSurfaceBuffer");
262 #endif
263 }
264
265 if (data->number_picture_data > 1) {
266 WTRACE("Unexpected to have more picture data following a non-coded VOP.");
267 //picture data is thrown away. No issue if picture data is for N-VOP. if picture data is for
268 // coded picture, a frame is lost.
269 // TODO: handle this case
270 // return DECODE_FAIL;
271 }
272 return DECODE_SUCCESS;
273 }
274 else {
275 // Check if we have reference frame(s) for decoding
276 if (codingType == MP4_VOP_TYPE_B) {
277 if (mForwardReference == NULL ||
278 mLastReference == NULL) {
279 if (mIsShortHeader) {
280 status = DECODE_SUCCESS;
281 VTRACE("%s: No reference frame but keep decoding", __FUNCTION__);
282 } else
283 return DECODE_NO_REFERENCE;
284 }
285 } else if (codingType == MP4_VOP_TYPE_P || codingType == MP4_VOP_TYPE_S) {
286 if (mLastReference == NULL && mIsSyncFrame == false) {
287 if (mIsShortHeader) {
288 status = DECODE_SUCCESS;
289 VTRACE("%s: No reference frame but keep decoding", __FUNCTION__);
290 } else
291 return DECODE_NO_REFERENCE;
292 }
293 }
294 // all sanity checks pass, continue decoding through continueDecodingFrame
295 status = continueDecodingFrame(data);
296 }
297 return status;
298 }
299
continueDecodingFrame(vbp_data_mp42 * data)300 Decode_Status VideoDecoderMPEG4::continueDecodingFrame(vbp_data_mp42 *data) {
301 Decode_Status status = DECODE_SUCCESS;
302 VAStatus vaStatus = VA_STATUS_SUCCESS;
303 bool useGraphicBuffer = mConfigBuffer.flag & USE_NATIVE_GRAPHIC_BUFFER;
304
305 /*
306 Packed Frame Assumption:
307
308 1. In one packed frame, there's only one P or I frame and only one B frame.
309 2. In packed frame, there's no skipped frame (vop_coded = 0)
310 3. For one packed frame, there will be one N-VOP frame to follow the packed frame (may not immediately).
311 4. N-VOP frame is the frame with vop_coded = 0.
312 5. The timestamp of N-VOP frame will be used for P or I frame in the packed frame
313
314
315 I, P, {P, B}, B, N, P, N, I, ...
316 I, P, {P, B}, N, P, N, I, ...
317
318 The first N is placeholder for P frame in the packed frame
319 The second N is a skipped frame
320 */
321
322 vbp_picture_data_mp42 *picData = data->picture_data;
323 for (uint32_t i = 0; i < data->number_picture_data; i++, picData = picData->next_picture_data) {
324 // each slice has its own picture data, video_packet_header following resync_marker may reset picture header, see MP4 spec
325 VAPictureParameterBufferMPEG4 *picParam = &(picData->picture_param);
326 int codingType = picParam->vop_fields.bits.vop_coding_type;
327 if (codingType == MP4_VOP_TYPE_S && picParam->no_of_sprite_warping_points > 1) {
328 WTRACE("Hardware only supports up to one warping point (stationary or translation)");
329 }
330
331 if (picData->vop_coded == 0) {
332 ETRACE("Unexpected to have non-coded VOP.");
333 return DECODE_FAIL;
334 }
335 if (picData->new_picture_flag == 1 || mDecodingFrame == false) {
336 // either condition indicates start of a new frame
337 if (picData->new_picture_flag == 0) {
338 WTRACE("First slice of picture is lost!");
339 // TODO: handle this case
340 }
341 if (mDecodingFrame) {
342 if (codingType == MP4_VOP_TYPE_B){
343 // this indicates the start of a new frame in the packed frame
344 // Update timestamp for P frame in the packed frame as timestamp here is for the B frame!
345 if (picParam->vop_time_increment_resolution){
346 uint64_t increment = mLastVOPTimeIncrement - picData->vop_time_increment +
347 picParam->vop_time_increment_resolution;
348 increment = increment % picParam->vop_time_increment_resolution;
349 // convert to micro-second
350 // TODO: unit of time stamp varies on different frame work
351 increment = increment * 1e6 / picParam->vop_time_increment_resolution;
352 mAcquiredBuffer->renderBuffer.timeStamp += increment;
353 if (useGraphicBuffer){
354 mPackedFrame.timestamp = mCurrentPTS;
355 mCurrentPTS = mAcquiredBuffer->renderBuffer.timeStamp;
356 }
357 }
358 } else {
359 // this indicates the start of a new frame in the packed frame. no B frame int the packet
360 // Update the timestamp according the increment
361 if (picParam->vop_time_increment_resolution){
362 int64_t increment = picData->vop_time_increment - mLastVOPTimeIncrement + picParam->vop_time_increment_resolution;
363 increment = increment % picParam->vop_time_increment_resolution;
364 //convert to micro-second
365 increment = increment * 1e6 / picParam->vop_time_increment_resolution;
366 if (useGraphicBuffer) {
367 mPackedFrame.timestamp = mCurrentPTS + increment;
368 }
369 else {
370 mCurrentPTS += increment;
371 }
372
373 } else {
374 if (useGraphicBuffer) {
375 mPackedFrame.timestamp = mCurrentPTS + 30000;
376 }
377 else {
378 mCurrentPTS += 30000;
379 }
380 }
381 }
382 endDecodingFrame(false);
383 mExpectingNVOP = true;
384 if (codingType != MP4_VOP_TYPE_B) {
385 mExpectingNVOP = false;
386 }
387 if (useGraphicBuffer) {
388 int32_t count = i - 1;
389 if (count < 0) {
390 WTRACE("Shuld not be here!");
391 return DECODE_SUCCESS;
392 }
393 vbp_picture_data_mp42 *lastpic = data->picture_data;
394 for(int k = 0; k < count; k++ ) {
395 lastpic = lastpic->next_picture_data;
396 }
397 mPackedFrame.offSet = lastpic->slice_data.slice_offset + lastpic->slice_data.slice_size;
398 VTRACE("Report OMX to handle for Multiple frame offset=%d time=%lld",mPackedFrame.offSet,mPackedFrame.timestamp);
399 return DECODE_MULTIPLE_FRAME;
400 }
401 }
402
403 // acquire a new surface buffer
404 status = acquireSurfaceBuffer();
405 CHECK_STATUS("acquireSurfaceBuffer");
406
407 // sprite is treated as P frame in the display order, so only B frame frame is not used as "reference"
408 mAcquiredBuffer->referenceFrame = (codingType != MP4_VOP_TYPE_B);
409 if (picData->picture_param.vol_fields.bits.interlaced) {
410 // only MPEG-4 studio profile can have field coding. All other profiles
411 // use frame coding only, i.e, there is no field VOP. (see vop_structure in MP4 spec)
412 mAcquiredBuffer->renderBuffer.scanFormat = VA_BOTTOM_FIELD | VA_TOP_FIELD;
413 } else {
414 mAcquiredBuffer->renderBuffer.scanFormat = VA_FRAME_PICTURE;
415 }
416 // TODO: set discontinuity flag
417 mAcquiredBuffer->renderBuffer.flag = 0;
418 mAcquiredBuffer->renderBuffer.timeStamp = mCurrentPTS;
419 if (mSizeChanged) {
420 mAcquiredBuffer->renderBuffer.flag |= IS_RESOLUTION_CHANGE;
421 mSizeChanged = false;
422 }
423 if (codingType != MP4_VOP_TYPE_B) {
424 mLastVOPCodingType = codingType;
425 mLastVOPTimeIncrement = picData->vop_time_increment;
426 }
427
428 // start decoding a frame
429 vaStatus = vaBeginPicture(mVADisplay, mVAContext, mAcquiredBuffer->renderBuffer.surface);
430 CHECK_VA_STATUS("vaBeginPicture");
431
432 mDecodingFrame = true;
433 mSendIQMatrixBuf = true;
434 }
435
436 status = decodeSlice(data, picData);
437 CHECK_STATUS("decodeSlice");
438 }
439
440 return DECODE_SUCCESS;
441 }
442
443
decodeSlice(vbp_data_mp42 * data,vbp_picture_data_mp42 * picData)444 Decode_Status VideoDecoderMPEG4::decodeSlice(vbp_data_mp42 *data, vbp_picture_data_mp42 *picData) {
445 Decode_Status status;
446 VAStatus vaStatus;
447 uint32_t bufferIDCount = 0;
448 // maximum 4 buffers to render a slice: picture parameter, IQMatrix, slice parameter, slice data
449 VABufferID bufferIDs[4];
450
451 VAPictureParameterBufferMPEG4 *picParam = &(picData->picture_param);
452 vbp_slice_data_mp42 *sliceData = &(picData->slice_data);
453 VASliceParameterBufferMPEG4 *sliceParam = &(sliceData->slice_param);
454
455 // send picture parametre for each slice
456 status = setReference(picParam);
457 CHECK_STATUS("setReference");
458
459 vaStatus = vaCreateBuffer(
460 mVADisplay,
461 mVAContext,
462 VAPictureParameterBufferType,
463 sizeof(VAPictureParameterBufferMPEG4),
464 1,
465 picParam,
466 &bufferIDs[bufferIDCount]);
467 CHECK_VA_STATUS("vaCreatePictureParameterBuffer");
468
469 bufferIDCount++;
470 if (picParam->vol_fields.bits.quant_type && mSendIQMatrixBuf)
471 {
472 // only send IQ matrix for the first slice in the picture
473 vaStatus = vaCreateBuffer(
474 mVADisplay,
475 mVAContext,
476 VAIQMatrixBufferType,
477 sizeof(VAIQMatrixBufferMPEG4),
478 1,
479 &(data->iq_matrix_buffer),
480 &bufferIDs[bufferIDCount]);
481 CHECK_VA_STATUS("vaCreateIQMatrixBuffer");
482
483 mSendIQMatrixBuf = false;
484 bufferIDCount++;
485 }
486
487 vaStatus = vaCreateBuffer(
488 mVADisplay,
489 mVAContext,
490 VASliceParameterBufferType,
491 sizeof(VASliceParameterBufferMPEG4),
492 1,
493 sliceParam,
494 &bufferIDs[bufferIDCount]);
495 CHECK_VA_STATUS("vaCreateSliceParameterBuffer");
496
497 bufferIDCount++;
498
499 //slice data buffer pointer
500 //Note that this is the original data buffer ptr;
501 // offset to the actual slice data is provided in
502 // slice_data_offset in VASliceParameterBufferMP42
503
504 vaStatus = vaCreateBuffer(
505 mVADisplay,
506 mVAContext,
507 VASliceDataBufferType,
508 sliceData->slice_size, //size
509 1, //num_elements
510 sliceData->buffer_addr + sliceData->slice_offset,
511 &bufferIDs[bufferIDCount]);
512 CHECK_VA_STATUS("vaCreateSliceDataBuffer");
513
514 bufferIDCount++;
515
516 vaStatus = vaRenderPicture(
517 mVADisplay,
518 mVAContext,
519 bufferIDs,
520 bufferIDCount);
521 CHECK_VA_STATUS("vaRenderPicture");
522
523
524 return DECODE_SUCCESS;
525 }
526
setReference(VAPictureParameterBufferMPEG4 * picParam)527 Decode_Status VideoDecoderMPEG4::setReference(VAPictureParameterBufferMPEG4 *picParam) {
528 switch (picParam->vop_fields.bits.vop_coding_type) {
529 case MP4_VOP_TYPE_I:
530 picParam->forward_reference_picture = VA_INVALID_SURFACE;
531 picParam->backward_reference_picture = VA_INVALID_SURFACE;
532 break;
533 case MP4_VOP_TYPE_P:
534 if (mLastReference == NULL && mIsSyncFrame == false && !mIsShortHeader) {
535 return DECODE_NO_REFERENCE;
536 }
537 if (mLastReference != NULL) {
538 picParam->forward_reference_picture = mLastReference->renderBuffer.surface;
539 } else {
540 VTRACE("%s: no reference frame, but keep decoding", __FUNCTION__);
541 picParam->forward_reference_picture = VA_INVALID_SURFACE;
542 }
543 picParam->backward_reference_picture = VA_INVALID_SURFACE;
544 break;
545 case MP4_VOP_TYPE_B:
546 picParam->vop_fields.bits.backward_reference_vop_coding_type = mLastVOPCodingType;
547 // WEIRD, CHECK AGAIN !!!!!!!
548 if (mIsShortHeader) {
549 if (mLastReference != NULL) {
550 picParam->forward_reference_picture = mLastReference->renderBuffer.surface;
551 } else {
552 VTRACE("%s: no forward reference frame, but keep decoding", __FUNCTION__);
553 picParam->forward_reference_picture = VA_INVALID_SURFACE;
554 }
555 if (mForwardReference != NULL) {
556 picParam->backward_reference_picture = mForwardReference->renderBuffer.surface;
557 } else {
558 VTRACE("%s: no backward reference frame, but keep decoding", __FUNCTION__);
559 picParam->backward_reference_picture = VA_INVALID_SURFACE;
560 }
561 } else if (mLastReference == NULL || mForwardReference == NULL) {
562 return DECODE_NO_REFERENCE;
563 } else {
564 picParam->forward_reference_picture = mLastReference->renderBuffer.surface;
565 picParam->backward_reference_picture = mForwardReference->renderBuffer.surface;
566 }
567 break;
568 case MP4_VOP_TYPE_S:
569 // WEIRD, CHECK AGAIN!!!! WAS using mForwardReference
570 if (mLastReference == NULL) {
571 return DECODE_NO_REFERENCE;
572 }
573 picParam->forward_reference_picture = mLastReference->renderBuffer.surface;
574 picParam->backward_reference_picture = VA_INVALID_SURFACE;
575 break;
576
577 default:
578 // Will never reach here;
579 return DECODE_PARSER_FAIL;
580 }
581 return DECODE_SUCCESS;
582 }
583
startVA(vbp_data_mp42 * data)584 Decode_Status VideoDecoderMPEG4::startVA(vbp_data_mp42 *data) {
585 updateFormatInfo(data);
586
587 VAProfile vaProfile;
588
589 if ((data->codec_data.profile_and_level_indication & 0xF8) == 0xF0) {
590 vaProfile = VAProfileMPEG4AdvancedSimple;
591 } else {
592 vaProfile = VAProfileMPEG4Simple;
593 }
594
595 mIsShortHeader = data->codec_data.short_video_header;
596
597 return VideoDecoderBase::setupVA(MP4_SURFACE_NUMBER, vaProfile);
598 }
599
updateFormatInfo(vbp_data_mp42 * data)600 void VideoDecoderMPEG4::updateFormatInfo(vbp_data_mp42 *data) {
601 ITRACE("updateFormatInfo: current size: %d x %d, new size: %d x %d",
602 mVideoFormatInfo.width, mVideoFormatInfo.height,
603 data->codec_data.video_object_layer_width,
604 data->codec_data.video_object_layer_height);
605 // error enhancement if vol is missing
606 if (!data->codec_data.got_vol && data->codec_data.got_vop) {
607 data->codec_data.video_object_layer_width = mVideoFormatInfo.width;
608 data->codec_data.video_object_layer_height = mVideoFormatInfo.height;
609 }
610
611 mVideoFormatInfo.cropBottom = data->codec_data.video_object_layer_height > mVideoFormatInfo.height ?
612 data->codec_data.video_object_layer_height - mVideoFormatInfo.height : 0;
613 mVideoFormatInfo.cropRight = data->codec_data.video_object_layer_width > mVideoFormatInfo.width ?
614 data->codec_data.video_object_layer_width - mVideoFormatInfo.width : 0;
615
616 if ((mVideoFormatInfo.width != (uint32_t)data->codec_data.video_object_layer_width ||
617 mVideoFormatInfo.height != (uint32_t)data->codec_data.video_object_layer_height) &&
618 data->codec_data.video_object_layer_width &&
619 data->codec_data.video_object_layer_height) {
620 // update encoded image size
621 mVideoFormatInfo.width = data->codec_data.video_object_layer_width;
622 mVideoFormatInfo.height = data->codec_data.video_object_layer_height;
623 mSizeChanged = true;
624 ITRACE("Video size is changed.");
625 }
626
627 // video_range has default value of 0. Y ranges from 16 to 235.
628 mVideoFormatInfo.videoRange = data->codec_data.video_range;
629
630 switch (data->codec_data.matrix_coefficients) {
631 case 1:
632 mVideoFormatInfo.colorMatrix = VA_SRC_BT709;
633 break;
634
635 // ITU-R Recommendation BT.470-6 System B, G (MP4), same as
636 // SMPTE 170M/BT601
637 case 5:
638 case 6:
639 mVideoFormatInfo.colorMatrix = VA_SRC_BT601;
640 break;
641
642 default:
643 // unknown color matrix, set to 0 so color space flag will not be set.
644 mVideoFormatInfo.colorMatrix = 0;
645 break;
646 }
647
648 mVideoFormatInfo.aspectX = data->codec_data.par_width;
649 mVideoFormatInfo.aspectY = data->codec_data.par_height;
650 //mVideoFormatInfo.bitrate = data->codec_data.bit_rate;
651 mVideoFormatInfo.valid = true;
652
653 setRenderRect();
654 setColorSpaceInfo(mVideoFormatInfo.colorMatrix, mVideoFormatInfo.videoRange);
655 }
656
checkHardwareCapability()657 Decode_Status VideoDecoderMPEG4::checkHardwareCapability() {
658 VAStatus vaStatus;
659 VAConfigAttrib cfgAttribs[2];
660 cfgAttribs[0].type = VAConfigAttribMaxPictureWidth;
661 cfgAttribs[1].type = VAConfigAttribMaxPictureHeight;
662 vaStatus = vaGetConfigAttributes(mVADisplay,
663 mIsShortHeader ? VAProfileH263Baseline : VAProfileMPEG4AdvancedSimple,
664 VAEntrypointVLD, cfgAttribs, 2);
665 CHECK_VA_STATUS("vaGetConfigAttributes");
666 if (cfgAttribs[0].value * cfgAttribs[1].value < (uint32_t)mVideoFormatInfo.width * (uint32_t)mVideoFormatInfo.height) {
667 ETRACE("hardware supports resolution %d * %d smaller than the clip resolution %d * %d",
668 cfgAttribs[0].value, cfgAttribs[1].value, mVideoFormatInfo.width, mVideoFormatInfo.height);
669 return DECODE_DRIVER_FAIL;
670 }
671
672 return DECODE_SUCCESS;
673 }
674