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