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