Home | History | Annotate | Download | only in enc
      1 /*
      2  * Copyright (C) 2012 The Android Open Source Project
      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 //#define LOG_NDEBUG 0
     18 #define LOG_TAG "SoftMPEG4Encoder"
     19 #include <utils/Log.h>
     20 
     21 #include "mp4enc_api.h"
     22 #include "OMX_Video.h"
     23 
     24 #include <media/stagefright/foundation/ADebug.h>
     25 #include <media/stagefright/MediaDefs.h>
     26 #include <media/stagefright/MediaErrors.h>
     27 #include <media/stagefright/MetaData.h>
     28 #include <media/stagefright/Utils.h>
     29 
     30 #include "SoftMPEG4Encoder.h"
     31 
     32 namespace android {
     33 
     34 template<class T>
     35 static void InitOMXParams(T *params) {
     36     params->nSize = sizeof(T);
     37     params->nVersion.s.nVersionMajor = 1;
     38     params->nVersion.s.nVersionMinor = 0;
     39     params->nVersion.s.nRevision = 0;
     40     params->nVersion.s.nStep = 0;
     41 }
     42 
     43 inline static void ConvertYUV420SemiPlanarToYUV420Planar(
     44         uint8_t *inyuv, uint8_t* outyuv,
     45         int32_t width, int32_t height) {
     46 
     47     int32_t outYsize = width * height;
     48     uint32_t *outy =  (uint32_t *) outyuv;
     49     uint16_t *outcb = (uint16_t *) (outyuv + outYsize);
     50     uint16_t *outcr = (uint16_t *) (outyuv + outYsize + (outYsize >> 2));
     51 
     52     /* Y copying */
     53     memcpy(outy, inyuv, outYsize);
     54 
     55     /* U & V copying */
     56     uint32_t *inyuv_4 = (uint32_t *) (inyuv + outYsize);
     57     for (int32_t i = height >> 1; i > 0; --i) {
     58         for (int32_t j = width >> 2; j > 0; --j) {
     59             uint32_t temp = *inyuv_4++;
     60             uint32_t tempU = temp & 0xFF;
     61             tempU = tempU | ((temp >> 8) & 0xFF00);
     62 
     63             uint32_t tempV = (temp >> 8) & 0xFF;
     64             tempV = tempV | ((temp >> 16) & 0xFF00);
     65 
     66             // Flip U and V
     67             *outcb++ = tempV;
     68             *outcr++ = tempU;
     69         }
     70     }
     71 }
     72 
     73 SoftMPEG4Encoder::SoftMPEG4Encoder(
     74             const char *name,
     75             const OMX_CALLBACKTYPE *callbacks,
     76             OMX_PTR appData,
     77             OMX_COMPONENTTYPE **component)
     78     : SimpleSoftOMXComponent(name, callbacks, appData, component),
     79       mEncodeMode(COMBINE_MODE_WITH_ERR_RES),
     80       mVideoWidth(176),
     81       mVideoHeight(144),
     82       mVideoFrameRate(30),
     83       mVideoBitRate(192000),
     84       mVideoColorFormat(OMX_COLOR_FormatYUV420Planar),
     85       mIDRFrameRefreshIntervalInSec(1),
     86       mNumInputFrames(-1),
     87       mStarted(false),
     88       mSawInputEOS(false),
     89       mSignalledError(false),
     90       mHandle(new tagvideoEncControls),
     91       mEncParams(new tagvideoEncOptions),
     92       mInputFrameData(NULL) {
     93 
     94    if (!strcmp(name, "OMX.google.h263.encoder")) {
     95         mEncodeMode = H263_MODE;
     96     } else {
     97         CHECK(!strcmp(name, "OMX.google.mpeg4.encoder"));
     98     }
     99 
    100     initPorts();
    101     ALOGI("Construct SoftMPEG4Encoder");
    102 }
    103 
    104 SoftMPEG4Encoder::~SoftMPEG4Encoder() {
    105     ALOGV("Destruct SoftMPEG4Encoder");
    106     releaseEncoder();
    107     List<BufferInfo *> &outQueue = getPortQueue(1);
    108     List<BufferInfo *> &inQueue = getPortQueue(0);
    109     CHECK(outQueue.empty());
    110     CHECK(inQueue.empty());
    111 }
    112 
    113 OMX_ERRORTYPE SoftMPEG4Encoder::initEncParams() {
    114     CHECK(mHandle != NULL);
    115     memset(mHandle, 0, sizeof(tagvideoEncControls));
    116 
    117     CHECK(mEncParams != NULL);
    118     memset(mEncParams, 0, sizeof(tagvideoEncOptions));
    119     if (!PVGetDefaultEncOption(mEncParams, 0)) {
    120         ALOGE("Failed to get default encoding parameters");
    121         return OMX_ErrorUndefined;
    122     }
    123     mEncParams->encMode = mEncodeMode;
    124     mEncParams->encWidth[0] = mVideoWidth;
    125     mEncParams->encHeight[0] = mVideoHeight;
    126     mEncParams->encFrameRate[0] = mVideoFrameRate;
    127     mEncParams->rcType = VBR_1;
    128     mEncParams->vbvDelay = 5.0f;
    129 
    130     // FIXME:
    131     // Add more profile and level support for MPEG4 encoder
    132     mEncParams->profile_level = CORE_PROFILE_LEVEL2;
    133     mEncParams->packetSize = 32;
    134     mEncParams->rvlcEnable = PV_OFF;
    135     mEncParams->numLayers = 1;
    136     mEncParams->timeIncRes = 1000;
    137     mEncParams->tickPerSrc = mEncParams->timeIncRes / mVideoFrameRate;
    138 
    139     mEncParams->bitRate[0] = mVideoBitRate;
    140     mEncParams->iQuant[0] = 15;
    141     mEncParams->pQuant[0] = 12;
    142     mEncParams->quantType[0] = 0;
    143     mEncParams->noFrameSkipped = PV_OFF;
    144 
    145     if (mVideoColorFormat == OMX_COLOR_FormatYUV420SemiPlanar) {
    146         // Color conversion is needed.
    147         CHECK(mInputFrameData == NULL);
    148         mInputFrameData =
    149             (uint8_t *) malloc((mVideoWidth * mVideoHeight * 3 ) >> 1);
    150         CHECK(mInputFrameData != NULL);
    151     }
    152 
    153     // PV's MPEG4 encoder requires the video dimension of multiple
    154     if (mVideoWidth % 16 != 0 || mVideoHeight % 16 != 0) {
    155         ALOGE("Video frame size %dx%d must be a multiple of 16",
    156             mVideoWidth, mVideoHeight);
    157         return OMX_ErrorBadParameter;
    158     }
    159 
    160     // Set IDR frame refresh interval
    161     if (mIDRFrameRefreshIntervalInSec < 0) {
    162         mEncParams->intraPeriod = -1;
    163     } else if (mIDRFrameRefreshIntervalInSec == 0) {
    164         mEncParams->intraPeriod = 1;  // All I frames
    165     } else {
    166         mEncParams->intraPeriod =
    167             (mIDRFrameRefreshIntervalInSec * mVideoFrameRate);
    168     }
    169 
    170     mEncParams->numIntraMB = 0;
    171     mEncParams->sceneDetect = PV_ON;
    172     mEncParams->searchRange = 16;
    173     mEncParams->mv8x8Enable = PV_OFF;
    174     mEncParams->gobHeaderInterval = 0;
    175     mEncParams->useACPred = PV_ON;
    176     mEncParams->intraDCVlcTh = 0;
    177 
    178     return OMX_ErrorNone;
    179 }
    180 
    181 OMX_ERRORTYPE SoftMPEG4Encoder::initEncoder() {
    182     CHECK(!mStarted);
    183 
    184     OMX_ERRORTYPE errType = OMX_ErrorNone;
    185     if (OMX_ErrorNone != (errType = initEncParams())) {
    186         ALOGE("Failed to initialized encoder params");
    187         mSignalledError = true;
    188         notify(OMX_EventError, OMX_ErrorUndefined, 0, 0);
    189         return errType;
    190     }
    191 
    192     if (!PVInitVideoEncoder(mHandle, mEncParams)) {
    193         ALOGE("Failed to initialize the encoder");
    194         mSignalledError = true;
    195         notify(OMX_EventError, OMX_ErrorUndefined, 0, 0);
    196         return OMX_ErrorUndefined;
    197     }
    198 
    199     mNumInputFrames = -1;  // 1st buffer for codec specific data
    200     mStarted = true;
    201 
    202     return OMX_ErrorNone;
    203 }
    204 
    205 OMX_ERRORTYPE SoftMPEG4Encoder::releaseEncoder() {
    206     if (!mStarted) {
    207         return OMX_ErrorNone;
    208     }
    209 
    210     PVCleanUpVideoEncoder(mHandle);
    211 
    212     delete mInputFrameData;
    213     mInputFrameData = NULL;
    214 
    215     delete mEncParams;
    216     mEncParams = NULL;
    217 
    218     delete mHandle;
    219     mHandle = NULL;
    220 
    221     mStarted = false;
    222 
    223     return OMX_ErrorNone;
    224 }
    225 
    226 void SoftMPEG4Encoder::initPorts() {
    227     OMX_PARAM_PORTDEFINITIONTYPE def;
    228     InitOMXParams(&def);
    229 
    230     const size_t kInputBufferSize = (mVideoWidth * mVideoHeight * 3) >> 1;
    231 
    232     // 256 * 1024 is a magic number for PV's encoder, not sure why
    233     const size_t kOutputBufferSize =
    234         (kInputBufferSize > 256 * 1024)
    235             ? kInputBufferSize: 256 * 1024;
    236 
    237     def.nPortIndex = 0;
    238     def.eDir = OMX_DirInput;
    239     def.nBufferCountMin = kNumBuffers;
    240     def.nBufferCountActual = def.nBufferCountMin;
    241     def.nBufferSize = kInputBufferSize;
    242     def.bEnabled = OMX_TRUE;
    243     def.bPopulated = OMX_FALSE;
    244     def.eDomain = OMX_PortDomainVideo;
    245     def.bBuffersContiguous = OMX_FALSE;
    246     def.nBufferAlignment = 1;
    247 
    248     def.format.video.cMIMEType = const_cast<char *>("video/raw");
    249 
    250     def.format.video.eCompressionFormat = OMX_VIDEO_CodingUnused;
    251     def.format.video.eColorFormat = OMX_COLOR_FormatYUV420Planar;
    252     def.format.video.xFramerate = (mVideoFrameRate << 16);  // Q16 format
    253     def.format.video.nBitrate = mVideoBitRate;
    254     def.format.video.nFrameWidth = mVideoWidth;
    255     def.format.video.nFrameHeight = mVideoHeight;
    256     def.format.video.nStride = mVideoWidth;
    257     def.format.video.nSliceHeight = mVideoHeight;
    258 
    259     addPort(def);
    260 
    261     def.nPortIndex = 1;
    262     def.eDir = OMX_DirOutput;
    263     def.nBufferCountMin = kNumBuffers;
    264     def.nBufferCountActual = def.nBufferCountMin;
    265     def.nBufferSize = kOutputBufferSize;
    266     def.bEnabled = OMX_TRUE;
    267     def.bPopulated = OMX_FALSE;
    268     def.eDomain = OMX_PortDomainVideo;
    269     def.bBuffersContiguous = OMX_FALSE;
    270     def.nBufferAlignment = 2;
    271 
    272     def.format.video.cMIMEType =
    273         (mEncodeMode == COMBINE_MODE_WITH_ERR_RES)
    274             ? const_cast<char *>(MEDIA_MIMETYPE_VIDEO_MPEG4)
    275             : const_cast<char *>(MEDIA_MIMETYPE_VIDEO_H263);
    276 
    277     def.format.video.eCompressionFormat =
    278         (mEncodeMode == COMBINE_MODE_WITH_ERR_RES)
    279             ? OMX_VIDEO_CodingMPEG4
    280             : OMX_VIDEO_CodingH263;
    281 
    282     def.format.video.eColorFormat = OMX_COLOR_FormatUnused;
    283     def.format.video.xFramerate = (0 << 16);  // Q16 format
    284     def.format.video.nBitrate = mVideoBitRate;
    285     def.format.video.nFrameWidth = mVideoWidth;
    286     def.format.video.nFrameHeight = mVideoHeight;
    287     def.format.video.nStride = mVideoWidth;
    288     def.format.video.nSliceHeight = mVideoHeight;
    289 
    290     addPort(def);
    291 }
    292 
    293 OMX_ERRORTYPE SoftMPEG4Encoder::internalGetParameter(
    294         OMX_INDEXTYPE index, OMX_PTR params) {
    295     switch (index) {
    296         case OMX_IndexParamVideoErrorCorrection:
    297         {
    298             return OMX_ErrorNotImplemented;
    299         }
    300 
    301         case OMX_IndexParamVideoBitrate:
    302         {
    303             OMX_VIDEO_PARAM_BITRATETYPE *bitRate =
    304                 (OMX_VIDEO_PARAM_BITRATETYPE *) params;
    305 
    306             if (bitRate->nPortIndex != 1) {
    307                 return OMX_ErrorUndefined;
    308             }
    309 
    310             bitRate->eControlRate = OMX_Video_ControlRateVariable;
    311             bitRate->nTargetBitrate = mVideoBitRate;
    312             return OMX_ErrorNone;
    313         }
    314 
    315         case OMX_IndexParamVideoPortFormat:
    316         {
    317             OMX_VIDEO_PARAM_PORTFORMATTYPE *formatParams =
    318                 (OMX_VIDEO_PARAM_PORTFORMATTYPE *)params;
    319 
    320             if (formatParams->nPortIndex > 1) {
    321                 return OMX_ErrorUndefined;
    322             }
    323 
    324             if (formatParams->nIndex > 1) {
    325                 return OMX_ErrorNoMore;
    326             }
    327 
    328             if (formatParams->nPortIndex == 0) {
    329                 formatParams->eCompressionFormat = OMX_VIDEO_CodingUnused;
    330                 if (formatParams->nIndex == 0) {
    331                     formatParams->eColorFormat = OMX_COLOR_FormatYUV420Planar;
    332                 } else {
    333                     formatParams->eColorFormat = OMX_COLOR_FormatYUV420SemiPlanar;
    334                 }
    335             } else {
    336                 formatParams->eCompressionFormat =
    337                     (mEncodeMode == COMBINE_MODE_WITH_ERR_RES)
    338                         ? OMX_VIDEO_CodingMPEG4
    339                         : OMX_VIDEO_CodingH263;
    340 
    341                 formatParams->eColorFormat = OMX_COLOR_FormatUnused;
    342             }
    343 
    344             return OMX_ErrorNone;
    345         }
    346 
    347         case OMX_IndexParamVideoH263:
    348         {
    349             OMX_VIDEO_PARAM_H263TYPE *h263type =
    350                 (OMX_VIDEO_PARAM_H263TYPE *)params;
    351 
    352             if (h263type->nPortIndex != 1) {
    353                 return OMX_ErrorUndefined;
    354             }
    355 
    356             h263type->nAllowedPictureTypes =
    357                 (OMX_VIDEO_PictureTypeI | OMX_VIDEO_PictureTypeP);
    358             h263type->eProfile = OMX_VIDEO_H263ProfileBaseline;
    359             h263type->eLevel = OMX_VIDEO_H263Level45;
    360             h263type->bPLUSPTYPEAllowed = OMX_FALSE;
    361             h263type->bForceRoundingTypeToZero = OMX_FALSE;
    362             h263type->nPictureHeaderRepetition = 0;
    363             h263type->nGOBHeaderInterval = 0;
    364 
    365             return OMX_ErrorNone;
    366         }
    367 
    368         case OMX_IndexParamVideoMpeg4:
    369         {
    370             OMX_VIDEO_PARAM_MPEG4TYPE *mpeg4type =
    371                 (OMX_VIDEO_PARAM_MPEG4TYPE *)params;
    372 
    373             if (mpeg4type->nPortIndex != 1) {
    374                 return OMX_ErrorUndefined;
    375             }
    376 
    377             mpeg4type->eProfile = OMX_VIDEO_MPEG4ProfileCore;
    378             mpeg4type->eLevel = OMX_VIDEO_MPEG4Level2;
    379             mpeg4type->nAllowedPictureTypes =
    380                 (OMX_VIDEO_PictureTypeI | OMX_VIDEO_PictureTypeP);
    381             mpeg4type->nBFrames = 0;
    382             mpeg4type->nIDCVLCThreshold = 0;
    383             mpeg4type->bACPred = OMX_TRUE;
    384             mpeg4type->nMaxPacketSize = 256;
    385             mpeg4type->nTimeIncRes = 1000;
    386             mpeg4type->nHeaderExtension = 0;
    387             mpeg4type->bReversibleVLC = OMX_FALSE;
    388 
    389             return OMX_ErrorNone;
    390         }
    391 
    392         case OMX_IndexParamVideoProfileLevelQuerySupported:
    393         {
    394             OMX_VIDEO_PARAM_PROFILELEVELTYPE *profileLevel =
    395                 (OMX_VIDEO_PARAM_PROFILELEVELTYPE *)params;
    396 
    397             if (profileLevel->nPortIndex != 1) {
    398                 return OMX_ErrorUndefined;
    399             }
    400 
    401             if (profileLevel->nProfileIndex > 0) {
    402                 return OMX_ErrorNoMore;
    403             }
    404 
    405             if (mEncodeMode == H263_MODE) {
    406                 profileLevel->eProfile = OMX_VIDEO_H263ProfileBaseline;
    407                 profileLevel->eLevel = OMX_VIDEO_H263Level45;
    408             } else {
    409                 profileLevel->eProfile = OMX_VIDEO_MPEG4ProfileCore;
    410                 profileLevel->eLevel = OMX_VIDEO_MPEG4Level2;
    411             }
    412 
    413             return OMX_ErrorNone;
    414         }
    415 
    416         default:
    417             return SimpleSoftOMXComponent::internalGetParameter(index, params);
    418     }
    419 }
    420 
    421 OMX_ERRORTYPE SoftMPEG4Encoder::internalSetParameter(
    422         OMX_INDEXTYPE index, const OMX_PTR params) {
    423     switch (index) {
    424         case OMX_IndexParamVideoErrorCorrection:
    425         {
    426             return OMX_ErrorNotImplemented;
    427         }
    428 
    429         case OMX_IndexParamVideoBitrate:
    430         {
    431             OMX_VIDEO_PARAM_BITRATETYPE *bitRate =
    432                 (OMX_VIDEO_PARAM_BITRATETYPE *) params;
    433 
    434             if (bitRate->nPortIndex != 1 ||
    435                 bitRate->eControlRate != OMX_Video_ControlRateVariable) {
    436                 return OMX_ErrorUndefined;
    437             }
    438 
    439             mVideoBitRate = bitRate->nTargetBitrate;
    440             return OMX_ErrorNone;
    441         }
    442 
    443         case OMX_IndexParamPortDefinition:
    444         {
    445             OMX_PARAM_PORTDEFINITIONTYPE *def =
    446                 (OMX_PARAM_PORTDEFINITIONTYPE *)params;
    447             if (def->nPortIndex > 1) {
    448                 return OMX_ErrorUndefined;
    449             }
    450 
    451             if (def->nPortIndex == 0) {
    452                 if (def->format.video.eCompressionFormat != OMX_VIDEO_CodingUnused ||
    453                     (def->format.video.eColorFormat != OMX_COLOR_FormatYUV420Planar &&
    454                      def->format.video.eColorFormat != OMX_COLOR_FormatYUV420SemiPlanar)) {
    455                     return OMX_ErrorUndefined;
    456                 }
    457             } else {
    458                 if ((mEncodeMode == COMBINE_MODE_WITH_ERR_RES &&
    459                         def->format.video.eCompressionFormat != OMX_VIDEO_CodingMPEG4) ||
    460                     (mEncodeMode == H263_MODE &&
    461                         def->format.video.eCompressionFormat != OMX_VIDEO_CodingH263) ||
    462                     (def->format.video.eColorFormat != OMX_COLOR_FormatUnused)) {
    463                     return OMX_ErrorUndefined;
    464                 }
    465             }
    466 
    467             OMX_ERRORTYPE err = SimpleSoftOMXComponent::internalSetParameter(index, params);
    468             if (OMX_ErrorNone != err) {
    469                 return err;
    470             }
    471 
    472             if (def->nPortIndex == 0) {
    473                 mVideoWidth = def->format.video.nFrameWidth;
    474                 mVideoHeight = def->format.video.nFrameHeight;
    475                 mVideoFrameRate = def->format.video.xFramerate >> 16;
    476                 mVideoColorFormat = def->format.video.eColorFormat;
    477             } else {
    478                 mVideoBitRate = def->format.video.nBitrate;
    479             }
    480 
    481             return OMX_ErrorNone;
    482         }
    483 
    484         case OMX_IndexParamStandardComponentRole:
    485         {
    486             const OMX_PARAM_COMPONENTROLETYPE *roleParams =
    487                 (const OMX_PARAM_COMPONENTROLETYPE *)params;
    488 
    489             if (strncmp((const char *)roleParams->cRole,
    490                         (mEncodeMode == H263_MODE)
    491                             ? "video_encoder.h263": "video_encoder.mpeg4",
    492                         OMX_MAX_STRINGNAME_SIZE - 1)) {
    493                 return OMX_ErrorUndefined;
    494             }
    495 
    496             return OMX_ErrorNone;
    497         }
    498 
    499         case OMX_IndexParamVideoPortFormat:
    500         {
    501             const OMX_VIDEO_PARAM_PORTFORMATTYPE *formatParams =
    502                 (const OMX_VIDEO_PARAM_PORTFORMATTYPE *)params;
    503 
    504             if (formatParams->nPortIndex > 1) {
    505                 return OMX_ErrorUndefined;
    506             }
    507 
    508             if (formatParams->nIndex > 1) {
    509                 return OMX_ErrorNoMore;
    510             }
    511 
    512             if (formatParams->nPortIndex == 0) {
    513                 if (formatParams->eCompressionFormat != OMX_VIDEO_CodingUnused ||
    514                     ((formatParams->nIndex == 0 &&
    515                       formatParams->eColorFormat != OMX_COLOR_FormatYUV420Planar) ||
    516                     (formatParams->nIndex == 1 &&
    517                      formatParams->eColorFormat != OMX_COLOR_FormatYUV420SemiPlanar))) {
    518                     return OMX_ErrorUndefined;
    519                 }
    520                 mVideoColorFormat = formatParams->eColorFormat;
    521             } else {
    522                 if ((mEncodeMode == H263_MODE &&
    523                         formatParams->eCompressionFormat != OMX_VIDEO_CodingH263) ||
    524                     (mEncodeMode == COMBINE_MODE_WITH_ERR_RES &&
    525                         formatParams->eCompressionFormat != OMX_VIDEO_CodingMPEG4) ||
    526                     formatParams->eColorFormat != OMX_COLOR_FormatUnused) {
    527                     return OMX_ErrorUndefined;
    528                 }
    529             }
    530 
    531             return OMX_ErrorNone;
    532         }
    533 
    534         case OMX_IndexParamVideoH263:
    535         {
    536             OMX_VIDEO_PARAM_H263TYPE *h263type =
    537                 (OMX_VIDEO_PARAM_H263TYPE *)params;
    538 
    539             if (h263type->nPortIndex != 1) {
    540                 return OMX_ErrorUndefined;
    541             }
    542 
    543             if (h263type->eProfile != OMX_VIDEO_H263ProfileBaseline ||
    544                 h263type->eLevel != OMX_VIDEO_H263Level45 ||
    545                 (h263type->nAllowedPictureTypes & OMX_VIDEO_PictureTypeB) ||
    546                 h263type->bPLUSPTYPEAllowed != OMX_FALSE ||
    547                 h263type->bForceRoundingTypeToZero != OMX_FALSE ||
    548                 h263type->nPictureHeaderRepetition != 0 ||
    549                 h263type->nGOBHeaderInterval != 0) {
    550                 return OMX_ErrorUndefined;
    551             }
    552 
    553             return OMX_ErrorNone;
    554         }
    555 
    556         case OMX_IndexParamVideoMpeg4:
    557         {
    558             OMX_VIDEO_PARAM_MPEG4TYPE *mpeg4type =
    559                 (OMX_VIDEO_PARAM_MPEG4TYPE *)params;
    560 
    561             if (mpeg4type->nPortIndex != 1) {
    562                 return OMX_ErrorUndefined;
    563             }
    564 
    565             if (mpeg4type->eProfile != OMX_VIDEO_MPEG4ProfileCore ||
    566                 mpeg4type->eLevel != OMX_VIDEO_MPEG4Level2 ||
    567                 (mpeg4type->nAllowedPictureTypes & OMX_VIDEO_PictureTypeB) ||
    568                 mpeg4type->nBFrames != 0 ||
    569                 mpeg4type->nIDCVLCThreshold != 0 ||
    570                 mpeg4type->bACPred != OMX_TRUE ||
    571                 mpeg4type->nMaxPacketSize != 256 ||
    572                 mpeg4type->nTimeIncRes != 1000 ||
    573                 mpeg4type->nHeaderExtension != 0 ||
    574                 mpeg4type->bReversibleVLC != OMX_FALSE) {
    575                 return OMX_ErrorUndefined;
    576             }
    577 
    578             return OMX_ErrorNone;
    579         }
    580 
    581         default:
    582             return SimpleSoftOMXComponent::internalSetParameter(index, params);
    583     }
    584 }
    585 
    586 void SoftMPEG4Encoder::onQueueFilled(OMX_U32 portIndex) {
    587     if (mSignalledError || mSawInputEOS) {
    588         return;
    589     }
    590 
    591     if (!mStarted) {
    592         if (OMX_ErrorNone != initEncoder()) {
    593             return;
    594         }
    595     }
    596 
    597     List<BufferInfo *> &inQueue = getPortQueue(0);
    598     List<BufferInfo *> &outQueue = getPortQueue(1);
    599 
    600     while (!mSawInputEOS && !inQueue.empty() && !outQueue.empty()) {
    601         BufferInfo *inInfo = *inQueue.begin();
    602         OMX_BUFFERHEADERTYPE *inHeader = inInfo->mHeader;
    603         BufferInfo *outInfo = *outQueue.begin();
    604         OMX_BUFFERHEADERTYPE *outHeader = outInfo->mHeader;
    605 
    606         outHeader->nTimeStamp = 0;
    607         outHeader->nFlags = 0;
    608         outHeader->nOffset = 0;
    609         outHeader->nFilledLen = 0;
    610         outHeader->nOffset = 0;
    611 
    612         uint8_t *outPtr = (uint8_t *) outHeader->pBuffer;
    613         int32_t dataLength = outHeader->nAllocLen;
    614 
    615         if (mNumInputFrames < 0) {
    616             if (!PVGetVolHeader(mHandle, outPtr, &dataLength, 0)) {
    617                 ALOGE("Failed to get VOL header");
    618                 mSignalledError = true;
    619                 notify(OMX_EventError, OMX_ErrorUndefined, 0, 0);
    620                 return;
    621             }
    622             ALOGV("Output VOL header: %d bytes", dataLength);
    623             ++mNumInputFrames;
    624             outHeader->nFlags |= OMX_BUFFERFLAG_CODECCONFIG;
    625             outHeader->nFilledLen = dataLength;
    626             outQueue.erase(outQueue.begin());
    627             outInfo->mOwnedByUs = false;
    628             notifyFillBufferDone(outHeader);
    629             return;
    630         }
    631 
    632         // Save the input buffer info so that it can be
    633         // passed to an output buffer
    634         InputBufferInfo info;
    635         info.mTimeUs = inHeader->nTimeStamp;
    636         info.mFlags = inHeader->nFlags;
    637         mInputBufferInfoVec.push(info);
    638 
    639         if (inHeader->nFlags & OMX_BUFFERFLAG_EOS) {
    640             mSawInputEOS = true;
    641         }
    642 
    643         if (inHeader->nFilledLen > 0) {
    644             const void *inData = inHeader->pBuffer + inHeader->nOffset;
    645             uint8_t *inputData = (uint8_t *) inData;
    646             if (mVideoColorFormat != OMX_COLOR_FormatYUV420Planar) {
    647                 ConvertYUV420SemiPlanarToYUV420Planar(
    648                     inputData, mInputFrameData, mVideoWidth, mVideoHeight);
    649                 inputData = mInputFrameData;
    650             }
    651             CHECK(inputData != NULL);
    652 
    653             VideoEncFrameIO vin, vout;
    654             memset(&vin, 0, sizeof(vin));
    655             memset(&vout, 0, sizeof(vout));
    656             vin.height = ((mVideoHeight  + 15) >> 4) << 4;
    657             vin.pitch = ((mVideoWidth + 15) >> 4) << 4;
    658             vin.timestamp = (inHeader->nTimeStamp + 500) / 1000;  // in ms
    659             vin.yChan = inputData;
    660             vin.uChan = vin.yChan + vin.height * vin.pitch;
    661             vin.vChan = vin.uChan + ((vin.height * vin.pitch) >> 2);
    662 
    663             unsigned long modTimeMs = 0;
    664             int32_t nLayer = 0;
    665             MP4HintTrack hintTrack;
    666             if (!PVEncodeVideoFrame(mHandle, &vin, &vout,
    667                     &modTimeMs, outPtr, &dataLength, &nLayer) ||
    668                 !PVGetHintTrack(mHandle, &hintTrack)) {
    669                 ALOGE("Failed to encode frame or get hink track at frame %lld",
    670                     mNumInputFrames);
    671                 mSignalledError = true;
    672                 notify(OMX_EventError, OMX_ErrorUndefined, 0, 0);
    673             }
    674             CHECK(NULL == PVGetOverrunBuffer(mHandle));
    675             if (hintTrack.CodeType == 0) {  // I-frame serves as sync frame
    676                 outHeader->nFlags |= OMX_BUFFERFLAG_SYNCFRAME;
    677             }
    678 
    679             ++mNumInputFrames;
    680         } else {
    681             dataLength = 0;
    682         }
    683 
    684         inQueue.erase(inQueue.begin());
    685         inInfo->mOwnedByUs = false;
    686         notifyEmptyBufferDone(inHeader);
    687 
    688         outQueue.erase(outQueue.begin());
    689         CHECK(!mInputBufferInfoVec.empty());
    690         InputBufferInfo *inputBufInfo = mInputBufferInfoVec.begin();
    691         mInputBufferInfoVec.erase(mInputBufferInfoVec.begin());
    692         outHeader->nTimeStamp = inputBufInfo->mTimeUs;
    693         outHeader->nFlags |= (inputBufInfo->mFlags | OMX_BUFFERFLAG_ENDOFFRAME);
    694         outHeader->nFilledLen = dataLength;
    695         outInfo->mOwnedByUs = false;
    696         notifyFillBufferDone(outHeader);
    697     }
    698 }
    699 
    700 }  // namespace android
    701 
    702 android::SoftOMXComponent *createSoftOMXComponent(
    703         const char *name, const OMX_CALLBACKTYPE *callbacks,
    704         OMX_PTR appData, OMX_COMPONENTTYPE **component) {
    705     return new android::SoftMPEG4Encoder(name, callbacks, appData, component);
    706 }
    707