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