SoftMPEG4Encoder.cpp revision 2edda09a2ad1d112c52acd37d323f63f0a492d67
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 <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.xFramerate = def->format.video.xFramerate;
466                portDef->format.video.eColorFormat =
467                    (OMX_COLOR_FORMATTYPE) mVideoColorFormat;
468                portDef = &editPortInfo(1)->mDef;
469                portDef->format.video.nFrameWidth = mVideoWidth;
470                portDef->format.video.nFrameHeight = mVideoHeight;
471            } else {
472                mVideoBitRate = def->format.video.nBitrate;
473            }
474
475            return OMX_ErrorNone;
476        }
477
478        case OMX_IndexParamStandardComponentRole:
479        {
480            const OMX_PARAM_COMPONENTROLETYPE *roleParams =
481                (const OMX_PARAM_COMPONENTROLETYPE *)params;
482
483            if (strncmp((const char *)roleParams->cRole,
484                        (mEncodeMode == H263_MODE)
485                            ? "video_encoder.h263": "video_encoder.mpeg4",
486                        OMX_MAX_STRINGNAME_SIZE - 1)) {
487                return OMX_ErrorUndefined;
488            }
489
490            return OMX_ErrorNone;
491        }
492
493        case OMX_IndexParamVideoPortFormat:
494        {
495            const OMX_VIDEO_PARAM_PORTFORMATTYPE *formatParams =
496                (const OMX_VIDEO_PARAM_PORTFORMATTYPE *)params;
497
498            if (formatParams->nPortIndex > 1) {
499                return OMX_ErrorUndefined;
500            }
501
502            if (formatParams->nIndex > 2) {
503                return OMX_ErrorNoMore;
504            }
505
506            if (formatParams->nPortIndex == 0) {
507                if (formatParams->eCompressionFormat != OMX_VIDEO_CodingUnused ||
508                    ((formatParams->nIndex == 0 &&
509                      formatParams->eColorFormat != OMX_COLOR_FormatYUV420Planar) ||
510                    (formatParams->nIndex == 1 &&
511                     formatParams->eColorFormat != OMX_COLOR_FormatYUV420SemiPlanar) ||
512                    (formatParams->nIndex == 2 &&
513                     formatParams->eColorFormat != OMX_COLOR_FormatAndroidOpaque) )) {
514                    return OMX_ErrorUndefined;
515                }
516                mVideoColorFormat = formatParams->eColorFormat;
517            } else {
518                if ((mEncodeMode == H263_MODE &&
519                        formatParams->eCompressionFormat != OMX_VIDEO_CodingH263) ||
520                    (mEncodeMode == COMBINE_MODE_WITH_ERR_RES &&
521                        formatParams->eCompressionFormat != OMX_VIDEO_CodingMPEG4) ||
522                    formatParams->eColorFormat != OMX_COLOR_FormatUnused) {
523                    return OMX_ErrorUndefined;
524                }
525            }
526
527            return OMX_ErrorNone;
528        }
529
530        case OMX_IndexParamVideoH263:
531        {
532            OMX_VIDEO_PARAM_H263TYPE *h263type =
533                (OMX_VIDEO_PARAM_H263TYPE *)params;
534
535            if (h263type->nPortIndex != 1) {
536                return OMX_ErrorUndefined;
537            }
538
539            if (h263type->eProfile != OMX_VIDEO_H263ProfileBaseline ||
540                h263type->eLevel != OMX_VIDEO_H263Level45 ||
541                (h263type->nAllowedPictureTypes & OMX_VIDEO_PictureTypeB) ||
542                h263type->bPLUSPTYPEAllowed != OMX_FALSE ||
543                h263type->bForceRoundingTypeToZero != OMX_FALSE ||
544                h263type->nPictureHeaderRepetition != 0 ||
545                h263type->nGOBHeaderInterval != 0) {
546                return OMX_ErrorUndefined;
547            }
548
549            return OMX_ErrorNone;
550        }
551
552        case OMX_IndexParamVideoMpeg4:
553        {
554            OMX_VIDEO_PARAM_MPEG4TYPE *mpeg4type =
555                (OMX_VIDEO_PARAM_MPEG4TYPE *)params;
556
557            if (mpeg4type->nPortIndex != 1) {
558                return OMX_ErrorUndefined;
559            }
560
561            if (mpeg4type->eProfile != OMX_VIDEO_MPEG4ProfileCore ||
562                mpeg4type->eLevel != OMX_VIDEO_MPEG4Level2 ||
563                (mpeg4type->nAllowedPictureTypes & OMX_VIDEO_PictureTypeB) ||
564                mpeg4type->nBFrames != 0 ||
565                mpeg4type->nIDCVLCThreshold != 0 ||
566                mpeg4type->bACPred != OMX_TRUE ||
567                mpeg4type->nMaxPacketSize != 256 ||
568                mpeg4type->nTimeIncRes != 1000 ||
569                mpeg4type->nHeaderExtension != 0 ||
570                mpeg4type->bReversibleVLC != OMX_FALSE) {
571                return OMX_ErrorUndefined;
572            }
573
574            return OMX_ErrorNone;
575        }
576
577        case kStoreMetaDataExtensionIndex:
578        {
579            StoreMetaDataInBuffersParams *storeParams =
580                    (StoreMetaDataInBuffersParams*)params;
581            if (storeParams->nPortIndex != 0) {
582                ALOGE("%s: StoreMetadataInBuffersParams.nPortIndex not zero!",
583                        __FUNCTION__);
584                return OMX_ErrorUndefined;
585            }
586
587            mStoreMetaDataInBuffers = storeParams->bStoreMetaData;
588            ALOGV("StoreMetaDataInBuffers set to: %s",
589                    mStoreMetaDataInBuffers ? " true" : "false");
590
591            if (mStoreMetaDataInBuffers) {
592                mVideoColorFormat = OMX_COLOR_FormatAndroidOpaque;
593            }
594
595            return OMX_ErrorNone;
596        }
597
598        default:
599            return SimpleSoftOMXComponent::internalSetParameter(index, params);
600    }
601}
602
603void SoftMPEG4Encoder::onQueueFilled(OMX_U32 /* portIndex */) {
604    if (mSignalledError || mSawInputEOS) {
605        return;
606    }
607
608    if (!mStarted) {
609        if (OMX_ErrorNone != initEncoder()) {
610            return;
611        }
612    }
613
614    List<BufferInfo *> &inQueue = getPortQueue(0);
615    List<BufferInfo *> &outQueue = getPortQueue(1);
616
617    while (!mSawInputEOS && !inQueue.empty() && !outQueue.empty()) {
618        BufferInfo *inInfo = *inQueue.begin();
619        OMX_BUFFERHEADERTYPE *inHeader = inInfo->mHeader;
620        BufferInfo *outInfo = *outQueue.begin();
621        OMX_BUFFERHEADERTYPE *outHeader = outInfo->mHeader;
622
623        outHeader->nTimeStamp = 0;
624        outHeader->nFlags = 0;
625        outHeader->nOffset = 0;
626        outHeader->nFilledLen = 0;
627        outHeader->nOffset = 0;
628
629        uint8_t *outPtr = (uint8_t *) outHeader->pBuffer;
630        int32_t dataLength = outHeader->nAllocLen;
631
632        if (mNumInputFrames < 0) {
633            if (!PVGetVolHeader(mHandle, outPtr, &dataLength, 0)) {
634                ALOGE("Failed to get VOL header");
635                mSignalledError = true;
636                notify(OMX_EventError, OMX_ErrorUndefined, 0, 0);
637                return;
638            }
639            ALOGV("Output VOL header: %d bytes", dataLength);
640            ++mNumInputFrames;
641            outHeader->nFlags |= OMX_BUFFERFLAG_CODECCONFIG;
642            outHeader->nFilledLen = dataLength;
643            outQueue.erase(outQueue.begin());
644            outInfo->mOwnedByUs = false;
645            notifyFillBufferDone(outHeader);
646            return;
647        }
648
649        // Save the input buffer info so that it can be
650        // passed to an output buffer
651        InputBufferInfo info;
652        info.mTimeUs = inHeader->nTimeStamp;
653        info.mFlags = inHeader->nFlags;
654        mInputBufferInfoVec.push(info);
655
656        if (inHeader->nFlags & OMX_BUFFERFLAG_EOS) {
657            mSawInputEOS = true;
658        }
659
660        if (inHeader->nFilledLen > 0) {
661            const uint8_t *inputData = NULL;
662            if (mStoreMetaDataInBuffers) {
663                if (inHeader->nFilledLen != 8) {
664                    ALOGE("MetaData buffer is wrong size! "
665                            "(got %u bytes, expected 8)", inHeader->nFilledLen);
666                    mSignalledError = true;
667                    notify(OMX_EventError, OMX_ErrorUndefined, 0, 0);
668                    return;
669                }
670                inputData =
671                    extractGraphicBuffer(
672                            mInputFrameData, (mVideoWidth * mVideoHeight * 3) >> 1,
673                            inHeader->pBuffer + inHeader->nOffset, inHeader->nFilledLen,
674                            mVideoWidth, mVideoHeight);
675                if (inputData == NULL) {
676                    ALOGE("Unable to extract gralloc buffer in metadata mode");
677                    mSignalledError = true;
678                    notify(OMX_EventError, OMX_ErrorUndefined, 0, 0);
679                        return;
680                }
681            } else {
682                inputData = (const uint8_t *)inHeader->pBuffer + inHeader->nOffset;
683                if (mVideoColorFormat != OMX_COLOR_FormatYUV420Planar) {
684                    ConvertYUV420SemiPlanarToYUV420Planar(
685                        inputData, mInputFrameData, mVideoWidth, mVideoHeight);
686                    inputData = mInputFrameData;
687                }
688            }
689
690            CHECK(inputData != NULL);
691
692            VideoEncFrameIO vin, vout;
693            memset(&vin, 0, sizeof(vin));
694            memset(&vout, 0, sizeof(vout));
695            vin.height = ((mVideoHeight  + 15) >> 4) << 4;
696            vin.pitch = ((mVideoWidth + 15) >> 4) << 4;
697            vin.timestamp = (inHeader->nTimeStamp + 500) / 1000;  // in ms
698            vin.yChan = (uint8_t *)inputData;
699            vin.uChan = vin.yChan + vin.height * vin.pitch;
700            vin.vChan = vin.uChan + ((vin.height * vin.pitch) >> 2);
701
702            ULong modTimeMs = 0;
703            int32_t nLayer = 0;
704            MP4HintTrack hintTrack;
705            if (!PVEncodeVideoFrame(mHandle, &vin, &vout,
706                    &modTimeMs, outPtr, &dataLength, &nLayer) ||
707                !PVGetHintTrack(mHandle, &hintTrack)) {
708                ALOGE("Failed to encode frame or get hink track at frame %" PRId64,
709                    mNumInputFrames);
710                mSignalledError = true;
711                notify(OMX_EventError, OMX_ErrorUndefined, 0, 0);
712            }
713            CHECK(NULL == PVGetOverrunBuffer(mHandle));
714            if (hintTrack.CodeType == 0) {  // I-frame serves as sync frame
715                outHeader->nFlags |= OMX_BUFFERFLAG_SYNCFRAME;
716            }
717
718            ++mNumInputFrames;
719        } else {
720            dataLength = 0;
721        }
722
723        inQueue.erase(inQueue.begin());
724        inInfo->mOwnedByUs = false;
725        notifyEmptyBufferDone(inHeader);
726
727        outQueue.erase(outQueue.begin());
728        CHECK(!mInputBufferInfoVec.empty());
729        InputBufferInfo *inputBufInfo = mInputBufferInfoVec.begin();
730        outHeader->nTimeStamp = inputBufInfo->mTimeUs;
731        outHeader->nFlags |= (inputBufInfo->mFlags | OMX_BUFFERFLAG_ENDOFFRAME);
732        outHeader->nFilledLen = dataLength;
733        mInputBufferInfoVec.erase(mInputBufferInfoVec.begin());
734        outInfo->mOwnedByUs = false;
735        notifyFillBufferDone(outHeader);
736    }
737}
738
739}  // namespace android
740
741android::SoftOMXComponent *createSoftOMXComponent(
742        const char *name, const OMX_CALLBACKTYPE *callbacks,
743        OMX_PTR appData, OMX_COMPONENTTYPE **component) {
744    return new android::SoftMPEG4Encoder(name, callbacks, appData, component);
745}
746