Home | History | Annotate | Download | only in videodecoder
      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 "VideoDecoderWMV.h"
     18 #include "VideoDecoderTrace.h"
     19 #include <string.h>
     20 
     21 #define MAX_PICTURE_WIDTH_VC1   1920
     22 #define MAX_PICTURE_HEIGHT_VC1  1088
     23 
     24 VideoDecoderWMV::VideoDecoderWMV(const char *mimeType)
     25     : VideoDecoderBase(mimeType, VBP_VC1),
     26       mBufferIDs(NULL),
     27       mNumBufferIDs(0),
     28       mConfigDataParsed(false),
     29       mRangeMapped(false),
     30       mDeblockedCurrPicIndex(0),
     31       mDeblockedLastPicIndex(1),
     32       mDeblockedForwardPicIndex(2) {
     33 }
     34 
     35 
     36 VideoDecoderWMV::~VideoDecoderWMV() {
     37     stop();
     38 }
     39 
     40 Decode_Status VideoDecoderWMV::start(VideoConfigBuffer *buffer) {
     41     Decode_Status status;
     42 
     43     status = VideoDecoderBase::start(buffer);
     44     CHECK_STATUS("VideoDecoderBase::start");
     45 
     46     if (buffer->data == NULL || buffer->size == 0) {
     47         WTRACE("No config data to start VA.");
     48         return DECODE_SUCCESS;
     49     }
     50 
     51     vbp_data_vc1 *data = NULL;
     52     status = parseBuffer(buffer->data, buffer->size, &data);
     53     CHECK_STATUS("parseBuffer");
     54 
     55     if (data->se_data->CODED_WIDTH > MAX_PICTURE_WIDTH_VC1 ||
     56             data->se_data->CODED_HEIGHT > MAX_PICTURE_HEIGHT_VC1) {
     57         return DECODE_INVALID_DATA;
     58     }
     59 
     60     status = startVA(data);
     61     return status;
     62 }
     63 
     64 void VideoDecoderWMV::stop(void) {
     65     if (mBufferIDs) {
     66         delete [] mBufferIDs;
     67         mBufferIDs = NULL;
     68     }
     69     mNumBufferIDs = 0;
     70     mConfigDataParsed = false;
     71     mRangeMapped = false;
     72 
     73     mDeblockedCurrPicIndex = 0;
     74     mDeblockedLastPicIndex = 1;
     75     mDeblockedForwardPicIndex = 2;
     76 
     77     VideoDecoderBase::stop();
     78 }
     79 
     80 void VideoDecoderWMV::flush(void) {
     81     VideoDecoderBase::flush();
     82 
     83     mRangeMapped = false;
     84     mDeblockedCurrPicIndex = 0;
     85     mDeblockedLastPicIndex = 1;
     86     mDeblockedForwardPicIndex = 2;
     87 }
     88 
     89 Decode_Status VideoDecoderWMV::decode(VideoDecodeBuffer *buffer) {
     90     Decode_Status status;
     91     vbp_data_vc1 *data = NULL;
     92     bool useGraphicbuffer = mConfigBuffer.flag & USE_NATIVE_GRAPHIC_BUFFER;
     93     if (buffer == NULL) {
     94         return DECODE_INVALID_DATA;
     95     }
     96 
     97     status = parseBuffer(buffer->data, buffer->size, &data);
     98     CHECK_STATUS("parseBuffer");
     99 
    100     if (data->se_data->CODED_WIDTH > MAX_PICTURE_WIDTH_VC1 ||
    101             data->se_data->CODED_HEIGHT > MAX_PICTURE_HEIGHT_VC1) {
    102         return DECODE_INVALID_DATA;
    103     }
    104 
    105     if (!mVAStarted) {
    106         status = startVA(data);
    107         CHECK_STATUS("startVA");
    108     }
    109 
    110     if (mSizeChanged && !useGraphicbuffer) {
    111         mSizeChanged = false;
    112         return DECODE_FORMAT_CHANGE;
    113     }
    114 
    115     if ((mVideoFormatInfo.width != data->se_data->CODED_WIDTH ||
    116         mVideoFormatInfo.height != data->se_data->CODED_HEIGHT) &&
    117         data->se_data->CODED_WIDTH &&
    118         data->se_data->CODED_HEIGHT) {
    119         ITRACE("video size is changed from %dx%d to %dx%d", mVideoFormatInfo.width, mVideoFormatInfo.height,
    120         data->se_data->CODED_WIDTH, data->se_data->CODED_HEIGHT);
    121         if (useGraphicbuffer && mStoreMetaData) {
    122             pthread_mutex_lock(&mFormatLock);
    123         }
    124         mVideoFormatInfo.width = data->se_data->CODED_WIDTH;
    125         mVideoFormatInfo.height = data->se_data->CODED_HEIGHT;
    126         bool needFlush = false;
    127         if (useGraphicbuffer) {
    128             if (mStoreMetaData) {
    129                 needFlush = true;
    130 
    131                 mVideoFormatInfo.valid = false;
    132                 pthread_mutex_unlock(&mFormatLock);
    133             } else {
    134                 needFlush = (mVideoFormatInfo.width > mVideoFormatInfo.surfaceWidth)
    135                          || (mVideoFormatInfo.height > mVideoFormatInfo.surfaceHeight);
    136             }
    137         }
    138 
    139         setRenderRect();
    140 
    141         if (needFlush) {
    142             if (mStoreMetaData) {
    143                 status = endDecodingFrame(false);
    144                 CHECK_STATUS("endDecodingFrame");
    145             } else {
    146                 flushSurfaceBuffers();
    147             }
    148             mSizeChanged = false;
    149             return DECODE_FORMAT_CHANGE;
    150         } else {
    151             mSizeChanged = true;
    152         }
    153     } else {
    154         if (useGraphicbuffer && mStoreMetaData) {
    155             mVideoFormatInfo.valid = true;
    156         }
    157     }
    158 
    159     status = decodeFrame(buffer, data);
    160     CHECK_STATUS("decodeFrame");
    161     return status;
    162 }
    163 
    164 Decode_Status VideoDecoderWMV::decodeFrame(VideoDecodeBuffer* buffer, vbp_data_vc1 *data) {
    165     Decode_Status status;
    166     mCurrentPTS = buffer->timeStamp;
    167     if (0 == data->num_pictures || NULL == data->pic_data) {
    168         WTRACE("Number of pictures is 0, buffer contains configuration data only?");
    169         return DECODE_SUCCESS;
    170     }
    171 
    172     if (data->pic_data[0].picture_is_skipped == VC1_PTYPE_SKIPPED) {
    173 
    174         // Do nothing for skip frame as the last frame will be rendered agian by natively
    175         // No needs to handle reference frame neither
    176         return DECODE_SUCCESS;
    177 #if 0
    178         //use the last P or I frame surface for skipped frame and treat it as P frame
    179         if (mLastReference == NULL) {
    180             // TODO: handle this case
    181             WTRACE("The last reference is unavailable to construct skipped frame.");
    182             return DECODE_SUCCESS;
    183         }
    184 
    185         status = acquireSurfaceBuffer();
    186         CHECK_STATUS("acquireSurfaceBuffer");
    187         mAcquiredBuffer->renderBuffer.timeStamp = mCurrentPTS;
    188         mAcquiredBuffer->renderBuffer.flag = 0;
    189         mAcquiredBuffer->renderBuffer.scanFormat = mLastReference->renderBuffer.scanFormat;
    190         mAcquiredBuffer->renderBuffer.surface = mLastReference->renderBuffer.surface;
    191         // No need to update mappedData for HW decoding
    192         //mAcquiredBuffer->mappedData.data = mLastReference->mappedData.data;
    193         mAcquiredBuffer->referenceFrame = true;
    194         // let outputSurfaceBuffer handle "asReference" for VC1
    195         status = outputSurfaceBuffer();
    196         return status;
    197 #endif
    198     }
    199 
    200     status = acquireSurfaceBuffer();
    201     CHECK_STATUS("acquireSurfaceBuffer");
    202 
    203     mAcquiredBuffer->renderBuffer.timeStamp = buffer->timeStamp;
    204     if (buffer->flag & HAS_DISCONTINUITY) {
    205         mAcquiredBuffer->renderBuffer.flag |= HAS_DISCONTINUITY;
    206     }
    207     if (buffer->flag & WANT_DECODE_ONLY) {
    208         mAcquiredBuffer->renderBuffer.flag |= WANT_DECODE_ONLY;
    209     }
    210     if (mSizeChanged) {
    211         mSizeChanged = false;
    212         mAcquiredBuffer->renderBuffer.flag |= IS_RESOLUTION_CHANGE;
    213     }
    214 
    215     if (data->num_pictures > 1) {
    216         if (data->pic_data[0].pic_parms->picture_fields.bits.is_first_field) {
    217             mAcquiredBuffer->renderBuffer.scanFormat = VA_TOP_FIELD;
    218         } else {
    219             mAcquiredBuffer->renderBuffer.scanFormat = VA_BOTTOM_FIELD;
    220         }
    221     } else {
    222         mAcquiredBuffer->renderBuffer.scanFormat = VA_FRAME_PICTURE;
    223     }
    224 
    225     mRangeMapped = (data->se_data->RANGE_MAPY_FLAG || data->se_data->RANGE_MAPUV_FLAG || data->se_data->RANGERED);
    226 
    227     int frameType = data->pic_data[0].pic_parms->picture_fields.bits.picture_type;
    228     mAcquiredBuffer->referenceFrame = (frameType == VC1_PTYPE_I || frameType == VC1_PTYPE_P);
    229 
    230     // TODO: handle multiple frames parsed from a sample buffer
    231     int numPictures = (data->num_pictures > 1) ? 2 : 1;
    232 
    233     for (int index = 0; index < numPictures; index++) {
    234         status = decodePicture(data, index);
    235         if (status != DECODE_SUCCESS) {
    236             endDecodingFrame(true);
    237             return status;
    238         }
    239     }
    240 
    241     if (mRangeMapped) {
    242         updateDeblockedPicIndexes(frameType);
    243     }
    244 
    245     // let outputSurfaceBuffer handle "asReference" for VC1
    246     status = outputSurfaceBuffer();
    247     return status;
    248 }
    249 
    250 
    251 Decode_Status VideoDecoderWMV::decodePicture(vbp_data_vc1 *data, int32_t picIndex) {
    252     VAStatus vaStatus = VA_STATUS_SUCCESS;
    253     Decode_Status status;
    254     int32_t bufferIDCount = 0;
    255     vbp_picture_data_vc1 *picData = &(data->pic_data[picIndex]);
    256     VAPictureParameterBufferVC1 *picParams = picData->pic_parms;
    257 
    258     if (picParams == NULL) {
    259         return DECODE_PARSER_FAIL;
    260     }
    261 
    262     status = allocateVABufferIDs(picData->num_slices * 2 + 2);
    263     CHECK_STATUS("allocateVABufferIDs");
    264 
    265     status = setReference(picParams, picIndex, mAcquiredBuffer->renderBuffer.surface);
    266     CHECK_STATUS("setReference");
    267 
    268     if (mRangeMapped) {
    269         // keep the destination surface for the picture after decoding and in-loop filtering
    270         picParams->inloop_decoded_picture = mExtraSurfaces[mDeblockedCurrPicIndex];
    271     } else {
    272         picParams->inloop_decoded_picture = VA_INVALID_SURFACE;
    273     }
    274 
    275     vaStatus = vaBeginPicture(mVADisplay, mVAContext, mAcquiredBuffer->renderBuffer.surface);
    276     CHECK_VA_STATUS("vaBeginPicture");
    277     // setting mDecodingFrame to true so vaEndPicture will be invoked to end the picture decoding.
    278     mDecodingFrame = true;
    279 
    280     vaStatus = vaCreateBuffer(
    281             mVADisplay,
    282             mVAContext,
    283             VAPictureParameterBufferType,
    284             sizeof(VAPictureParameterBufferVC1),
    285             1,
    286             picParams,
    287             &mBufferIDs[bufferIDCount]);
    288     CHECK_VA_STATUS("vaCreatePictureParameterBuffer");
    289     bufferIDCount++;
    290 
    291     if (picParams->bitplane_present.value) {
    292         vaStatus = vaCreateBuffer(
    293                 mVADisplay,
    294                 mVAContext,
    295                 VABitPlaneBufferType,
    296                 picData->size_bitplanes,
    297                 1,
    298                 picData->packed_bitplanes,
    299                 &mBufferIDs[bufferIDCount]);
    300         CHECK_VA_STATUS("vaCreateBitPlaneBuffer");
    301         bufferIDCount++;
    302     }
    303 
    304     for (uint32_t i = 0; i < picData->num_slices; i++) {
    305         vaStatus = vaCreateBuffer(
    306                 mVADisplay,
    307                 mVAContext,
    308                 VASliceParameterBufferType,
    309                 sizeof(VASliceParameterBufferVC1),
    310                 1,
    311                 &(picData->slc_data[i].slc_parms),
    312                 &mBufferIDs[bufferIDCount]);
    313         CHECK_VA_STATUS("vaCreateSliceParameterBuffer");
    314         bufferIDCount++;
    315 
    316         vaStatus = vaCreateBuffer(
    317                 mVADisplay,
    318                 mVAContext,
    319                 VASliceDataBufferType,
    320                 //size
    321                 picData->slc_data[i].slice_size,
    322                 //num_elements
    323                 1,
    324                 //slice data buffer pointer
    325                 //Note that this is the original data buffer ptr;
    326                 // offset to the actual slice data is provided in
    327                 // slice_data_offset in VASliceParameterBufferVC1
    328                 picData->slc_data[i].buffer_addr + picData->slc_data[i].slice_offset,
    329                 &mBufferIDs[bufferIDCount]);
    330         CHECK_VA_STATUS("vaCreateSliceDataBuffer");
    331         bufferIDCount++;
    332     }
    333 
    334     vaStatus = vaRenderPicture(
    335             mVADisplay,
    336             mVAContext,
    337             mBufferIDs,
    338             bufferIDCount);
    339     CHECK_VA_STATUS("vaRenderPicture");
    340 
    341     vaStatus = vaEndPicture(mVADisplay, mVAContext);
    342     mDecodingFrame = false;
    343     CHECK_VA_STATUS("vaRenderPicture");
    344 
    345     return DECODE_SUCCESS;
    346 }
    347 
    348 
    349 Decode_Status VideoDecoderWMV::setReference(
    350         VAPictureParameterBufferVC1 *params,
    351         int32_t picIndex,
    352         VASurfaceID current) {
    353     int frameType = params->picture_fields.bits.picture_type;
    354     switch (frameType) {
    355         case VC1_PTYPE_I:
    356             params->forward_reference_picture = current;
    357             params->backward_reference_picture = current;
    358             break;
    359         case VC1_PTYPE_P:
    360             // check REFDIST in the picture parameter buffer
    361             if (0 != params->reference_fields.bits.reference_distance_flag &&
    362                 0 != params->reference_fields.bits.reference_distance) {
    363                 /* The previous decoded frame (distance is up to 16 but not 0) is used
    364                             for reference. Not supported here.
    365                             */
    366                 return DECODE_NO_REFERENCE;
    367             }
    368             if (1 == picIndex) {
    369                 // handle interlace field coding case
    370                 if (1 == params->reference_fields.bits.num_reference_pictures ||
    371                     1 == params->reference_fields.bits.reference_field_pic_indicator) {
    372                     /*
    373                                     two reference fields or the second closest I/P field is used for
    374                                     prediction. Set forward reference picture to INVALID so it will be
    375                                     updated to a valid previous reconstructed reference frame later.
    376                                     */
    377                     params->forward_reference_picture = VA_INVALID_SURFACE;
    378                 } else {
    379                    /* the closest I/P is used for reference so it must be the
    380                                   complementary field in the same surface.
    381                                  */
    382                     params->forward_reference_picture = current;
    383                 }
    384             }
    385             if (VA_INVALID_SURFACE == params->forward_reference_picture) {
    386                 if (mLastReference == NULL) {
    387                     return DECODE_NO_REFERENCE;
    388                 }
    389                 params->forward_reference_picture = mLastReference->renderBuffer.surface;
    390             }
    391             params->backward_reference_picture = VA_INVALID_SURFACE;
    392             break;
    393         case VC1_PTYPE_B:
    394             if (mForwardReference == NULL || mLastReference == NULL) {
    395                 return DECODE_NO_REFERENCE;
    396             }
    397             params->forward_reference_picture = mForwardReference->renderBuffer.surface;
    398             params->backward_reference_picture = mLastReference->renderBuffer.surface;
    399             break;
    400         case VC1_PTYPE_BI:
    401             params->forward_reference_picture = VA_INVALID_SURFACE;
    402             params->backward_reference_picture = VA_INVALID_SURFACE;
    403             break;
    404         case VC1_PTYPE_SKIPPED:
    405             //Will never happen here
    406             break;
    407         default:
    408             break;
    409     }
    410     return DECODE_SUCCESS;
    411 }
    412 
    413 void VideoDecoderWMV::updateDeblockedPicIndexes(int frameType) {
    414     int32_t curPicIndex = mDeblockedCurrPicIndex;
    415 
    416     /* Out Loop (range map) buffers */
    417     if (frameType != VC1_PTYPE_SKIPPED) {
    418         if ((frameType == VC1_PTYPE_I) || (frameType == VC1_PTYPE_P)) {
    419             mDeblockedCurrPicIndex = mDeblockedLastPicIndex;
    420             mDeblockedLastPicIndex = curPicIndex;
    421         } else {
    422             mDeblockedCurrPicIndex = mDeblockedForwardPicIndex;
    423             mDeblockedForwardPicIndex = curPicIndex;
    424         }
    425     }
    426 }
    427 
    428 Decode_Status VideoDecoderWMV::updateConfigData(
    429         uint8_t *configData,
    430         int32_t configDataLen,
    431         uint8_t **newConfigData,
    432         int32_t* newConfigDataLen) {
    433     int32_t i = 0;
    434     uint8_t *p = configData;
    435 
    436     /* Check for start codes.  If one exist, then this is VC-1 and not WMV. */
    437     while (i < configDataLen - 2) {
    438         if ((p[i] == 0) &&
    439             (p[i + 1] == 0) &&
    440             (p[i + 2] == 1)) {
    441             *newConfigData = NULL;
    442             *newConfigDataLen = 0;
    443             return DECODE_SUCCESS;
    444         }
    445         i++;
    446     }
    447 
    448     *newConfigDataLen = configDataLen + 9;
    449     p = *newConfigData = new uint8_t [*newConfigDataLen];
    450     if (!p) {
    451        return DECODE_MEMORY_FAIL;
    452     }
    453 
    454     /* If we get here we have 4+ bytes of codec data that must be formatted */
    455     /* to pass through as an RCV sequence header. */
    456     p[0] = 0;
    457     p[1] = 0;
    458     p[2] = 1;
    459     p[3] = 0x0f;  /* Start code. */
    460     p[4] = (mVideoFormatInfo.width >> 8) & 0x0ff;
    461     p[5] = mVideoFormatInfo.width & 0x0ff;
    462     p[6] = (mVideoFormatInfo.height >> 8) & 0x0ff;
    463     p[7] = mVideoFormatInfo.height & 0x0ff;
    464 
    465     memcpy(p + 8, configData, configDataLen);
    466     *(p + configDataLen + 8) = 0x80;
    467 
    468     return DECODE_SUCCESS;
    469 }
    470 
    471 Decode_Status VideoDecoderWMV::startVA(vbp_data_vc1 *data) {
    472     updateFormatInfo(data);
    473 
    474     VAProfile vaProfile;
    475     switch (data->se_data->PROFILE) {
    476         case 0:
    477         vaProfile = VAProfileVC1Simple;
    478         break;
    479         case 1:
    480         vaProfile = VAProfileVC1Main;
    481         break;
    482         default:
    483         vaProfile = VAProfileVC1Advanced;
    484         break;
    485     }
    486 
    487     return VideoDecoderBase::setupVA(VC1_SURFACE_NUMBER, vaProfile, VC1_EXTRA_SURFACE_NUMBER);
    488 }
    489 
    490 void VideoDecoderWMV::updateFormatInfo(vbp_data_vc1 *data) {
    491     ITRACE("updateFormatInfo: current size: %d x %d, new size: %d x %d",
    492         mVideoFormatInfo.width, mVideoFormatInfo.height,
    493         data->se_data->CODED_WIDTH, data->se_data->CODED_HEIGHT);
    494 
    495     mVideoFormatInfo.cropBottom = data->se_data->CODED_HEIGHT > mVideoFormatInfo.height ?
    496                                                                            data->se_data->CODED_HEIGHT - mVideoFormatInfo.height : 0;
    497     mVideoFormatInfo.cropRight = data->se_data->CODED_WIDTH > mVideoFormatInfo.width ?
    498                                                                       data->se_data->CODED_WIDTH - mVideoFormatInfo.width : 0;
    499 
    500      if ((mVideoFormatInfo.width != data->se_data->CODED_WIDTH ||
    501         mVideoFormatInfo.height != data->se_data->CODED_HEIGHT) &&
    502         data->se_data->CODED_WIDTH &&
    503         data->se_data->CODED_HEIGHT) {
    504         // encoded image size
    505         mVideoFormatInfo.width = data->se_data->CODED_WIDTH;
    506         mVideoFormatInfo.height = data->se_data->CODED_HEIGHT;
    507         mSizeChanged = true;
    508         ITRACE("Video size is changed.");
    509     }
    510 
    511     // video_range has default value of 0. Y ranges from 16 to 235.
    512     mVideoFormatInfo.videoRange = 0;
    513 
    514     switch (data->se_data->MATRIX_COEF) {
    515         case 1:
    516             mVideoFormatInfo.colorMatrix = VA_SRC_BT709;
    517             break;
    518         // ITU-R BT.1700, ITU-R BT.601-5, and SMPTE 293M-1996.
    519         case 6:
    520             mVideoFormatInfo.colorMatrix = VA_SRC_BT601;
    521             break;
    522         default:
    523             // unknown color matrix, set to 0 so color space flag will not be set.
    524             mVideoFormatInfo.colorMatrix = 0;
    525             break;
    526     }
    527 
    528     mVideoFormatInfo.aspectX = data->se_data->ASPECT_HORIZ_SIZE;
    529     mVideoFormatInfo.aspectY = data->se_data->ASPECT_VERT_SIZE;
    530     mVideoFormatInfo.bitrate = 0; //data->se_data->bitrate;
    531     mVideoFormatInfo.valid = true;
    532 
    533     setRenderRect();
    534     setColorSpaceInfo(mVideoFormatInfo.colorMatrix, mVideoFormatInfo.videoRange);
    535 }
    536 
    537 Decode_Status VideoDecoderWMV::allocateVABufferIDs(int32_t number) {
    538     if (mNumBufferIDs > number) {
    539         return DECODE_SUCCESS;
    540     }
    541     if (mBufferIDs) {
    542         delete [] mBufferIDs;
    543     }
    544     mBufferIDs = NULL;
    545     mNumBufferIDs = 0;
    546     mBufferIDs = new VABufferID [number];
    547     if (mBufferIDs == NULL) {
    548         return DECODE_MEMORY_FAIL;
    549     }
    550     mNumBufferIDs = number;
    551     return DECODE_SUCCESS;
    552 }
    553 
    554 Decode_Status VideoDecoderWMV::parseBuffer(uint8_t *data, int32_t size, vbp_data_vc1 **vbpData) {
    555     Decode_Status status;
    556 
    557     if (data == NULL || size == 0) {
    558         return DECODE_INVALID_DATA;
    559     }
    560 
    561     if (mConfigDataParsed) {
    562         status = VideoDecoderBase::parseBuffer(data, size, false, (void**)vbpData);
    563         CHECK_STATUS("VideoDecoderBase::parseBuffer");
    564     } else {
    565         uint8_t *newData = NULL;
    566         int32_t newSize = 0;
    567         status = updateConfigData(data, size, &newData, &newSize);
    568         CHECK_STATUS("updateConfigData");
    569 
    570         if (newSize) {
    571             status = VideoDecoderBase::parseBuffer(newData, newSize, true, (void**)vbpData);
    572             delete [] newData;
    573         } else {
    574             status = VideoDecoderBase::parseBuffer(data, size, true, (void**)vbpData);
    575         }
    576         CHECK_STATUS("VideoDecoderBase::parseBuffer");
    577         mConfigDataParsed = true;
    578     }
    579     return DECODE_SUCCESS;
    580 }
    581 
    582 
    583 Decode_Status VideoDecoderWMV::checkHardwareCapability() {
    584 #ifndef USE_GEN_HW
    585     VAStatus vaStatus;
    586     VAConfigAttrib cfgAttribs[2];
    587     cfgAttribs[0].type = VAConfigAttribMaxPictureWidth;
    588     cfgAttribs[1].type = VAConfigAttribMaxPictureHeight;
    589     vaStatus = vaGetConfigAttributes(mVADisplay, VAProfileVC1Advanced,
    590             VAEntrypointVLD, cfgAttribs, 2);
    591     CHECK_VA_STATUS("vaGetConfigAttributes");
    592     if (cfgAttribs[0].value * cfgAttribs[1].value < (uint32_t)mVideoFormatInfo.width * (uint32_t)mVideoFormatInfo.height) {
    593         ETRACE("hardware supports resolution %d * %d smaller than the clip resolution %d * %d",
    594                 cfgAttribs[0].value, cfgAttribs[1].value, mVideoFormatInfo.width, mVideoFormatInfo.height);
    595         return DECODE_DRIVER_FAIL;
    596     }
    597 #endif
    598     return DECODE_SUCCESS;
    599 }
    600 
    601 
    602