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