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