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