SoftVPXEncoder.cpp revision b4698f79230bbee15936641d951d49655f9e6da5
1/*
2 * Copyright (C) 2013 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 "SoftVPXEncoder"
19#include "SoftVPXEncoder.h"
20
21#include <utils/Log.h>
22
23#include <media/stagefright/foundation/ADebug.h>
24#include <media/stagefright/MediaDefs.h>
25
26namespace android {
27
28
29template<class T>
30static void InitOMXParams(T *params) {
31    params->nSize = sizeof(T);
32    // OMX IL 1.1.2
33    params->nVersion.s.nVersionMajor = 1;
34    params->nVersion.s.nVersionMinor = 1;
35    params->nVersion.s.nRevision = 2;
36    params->nVersion.s.nStep = 0;
37}
38
39
40static int GetCPUCoreCount() {
41    int cpuCoreCount = 1;
42#if defined(_SC_NPROCESSORS_ONLN)
43    cpuCoreCount = sysconf(_SC_NPROCESSORS_ONLN);
44#else
45    // _SC_NPROC_ONLN must be defined...
46    cpuCoreCount = sysconf(_SC_NPROC_ONLN);
47#endif
48    CHECK_GE(cpuCoreCount, 1);
49    return cpuCoreCount;
50}
51
52
53// This color conversion utility is copied from SoftMPEG4Encoder.cpp
54inline static void ConvertSemiPlanarToPlanar(uint8_t *inyuv,
55                                             uint8_t* outyuv,
56                                             int32_t width,
57                                             int32_t height) {
58    int32_t outYsize = width * height;
59    uint32_t *outy =  (uint32_t *) outyuv;
60    uint16_t *outcb = (uint16_t *) (outyuv + outYsize);
61    uint16_t *outcr = (uint16_t *) (outyuv + outYsize + (outYsize >> 2));
62
63    /* Y copying */
64    memcpy(outy, inyuv, outYsize);
65
66    /* U & V copying */
67    uint32_t *inyuv_4 = (uint32_t *) (inyuv + outYsize);
68    for (int32_t i = height >> 1; i > 0; --i) {
69        for (int32_t j = width >> 2; j > 0; --j) {
70            uint32_t temp = *inyuv_4++;
71            uint32_t tempU = temp & 0xFF;
72            tempU = tempU | ((temp >> 8) & 0xFF00);
73
74            uint32_t tempV = (temp >> 8) & 0xFF;
75            tempV = tempV | ((temp >> 16) & 0xFF00);
76
77            // Flip U and V
78            *outcb++ = tempV;
79            *outcr++ = tempU;
80        }
81    }
82}
83
84
85SoftVPXEncoder::SoftVPXEncoder(const char *name,
86                               const OMX_CALLBACKTYPE *callbacks,
87                               OMX_PTR appData,
88                               OMX_COMPONENTTYPE **component)
89    : SimpleSoftOMXComponent(name, callbacks, appData, component),
90      mCodecContext(NULL),
91      mCodecConfiguration(NULL),
92      mCodecInterface(NULL),
93      mWidth(176),
94      mHeight(144),
95      mBitrate(192000),  // in bps
96      mBitrateControlMode(VPX_VBR),  // variable bitrate
97      mFrameDurationUs(33333),  // Defaults to 30 fps
98      mDCTPartitions(0),
99      mErrorResilience(OMX_FALSE),
100      mColorFormat(OMX_COLOR_FormatYUV420Planar),
101      mLevel(OMX_VIDEO_VP8Level_Version0),
102      mConversionBuffer(NULL) {
103
104    initPorts();
105}
106
107
108SoftVPXEncoder::~SoftVPXEncoder() {
109    releaseEncoder();
110}
111
112
113void SoftVPXEncoder::initPorts() {
114    OMX_PARAM_PORTDEFINITIONTYPE inputPort;
115    OMX_PARAM_PORTDEFINITIONTYPE outputPort;
116
117    InitOMXParams(&inputPort);
118    InitOMXParams(&outputPort);
119
120    inputPort.nBufferCountMin = kNumBuffers;
121    inputPort.nBufferCountActual = inputPort.nBufferCountMin;
122    inputPort.bEnabled = OMX_TRUE;
123    inputPort.bPopulated = OMX_FALSE;
124    inputPort.eDomain = OMX_PortDomainVideo;
125    inputPort.bBuffersContiguous = OMX_FALSE;
126    inputPort.format.video.pNativeRender = NULL;
127    inputPort.format.video.nFrameWidth = mWidth;
128    inputPort.format.video.nFrameHeight = mHeight;
129    inputPort.format.video.nStride = inputPort.format.video.nFrameWidth;
130    inputPort.format.video.nSliceHeight = inputPort.format.video.nFrameHeight;
131    inputPort.format.video.nBitrate = 0;
132    // frameRate is reciprocal of frameDuration, which is
133    // in microseconds. It is also in Q16 format.
134    inputPort.format.video.xFramerate = (1000000/mFrameDurationUs) << 16;
135    inputPort.format.video.bFlagErrorConcealment = OMX_FALSE;
136    inputPort.nPortIndex = kInputPortIndex;
137    inputPort.eDir = OMX_DirInput;
138    inputPort.nBufferAlignment = kInputBufferAlignment;
139    inputPort.format.video.cMIMEType =
140        const_cast<char *>(MEDIA_MIMETYPE_VIDEO_RAW);
141    inputPort.format.video.eCompressionFormat = OMX_VIDEO_CodingUnused;
142    inputPort.format.video.eColorFormat = mColorFormat;
143    inputPort.format.video.pNativeWindow = NULL;
144    inputPort.nBufferSize =
145        (inputPort.format.video.nStride *
146        inputPort.format.video.nSliceHeight * 3) / 2;
147
148    addPort(inputPort);
149
150    outputPort.nBufferCountMin = kNumBuffers;
151    outputPort.nBufferCountActual = outputPort.nBufferCountMin;
152    outputPort.bEnabled = OMX_TRUE;
153    outputPort.bPopulated = OMX_FALSE;
154    outputPort.eDomain = OMX_PortDomainVideo;
155    outputPort.bBuffersContiguous = OMX_FALSE;
156    outputPort.format.video.pNativeRender = NULL;
157    outputPort.format.video.nFrameWidth = mWidth;
158    outputPort.format.video.nFrameHeight = mHeight;
159    outputPort.format.video.nStride = outputPort.format.video.nFrameWidth;
160    outputPort.format.video.nSliceHeight = outputPort.format.video.nFrameHeight;
161    outputPort.format.video.nBitrate = mBitrate;
162    outputPort.format.video.xFramerate = 0;
163    outputPort.format.video.bFlagErrorConcealment = OMX_FALSE;
164    outputPort.nPortIndex = kOutputPortIndex;
165    outputPort.eDir = OMX_DirOutput;
166    outputPort.nBufferAlignment = kOutputBufferAlignment;
167    outputPort.format.video.cMIMEType =
168        const_cast<char *>(MEDIA_MIMETYPE_VIDEO_VPX);
169    outputPort.format.video.eCompressionFormat = OMX_VIDEO_CodingVPX;
170    outputPort.format.video.eColorFormat = OMX_COLOR_FormatUnused;
171    outputPort.format.video.pNativeWindow = NULL;
172    outputPort.nBufferSize = 256 * 1024;  // arbitrary
173
174    addPort(outputPort);
175}
176
177
178status_t SoftVPXEncoder::initEncoder() {
179    vpx_codec_err_t codec_return;
180
181    mCodecContext = new vpx_codec_ctx_t;
182    mCodecConfiguration = new vpx_codec_enc_cfg_t;
183    mCodecInterface = vpx_codec_vp8_cx();
184
185    if (mCodecInterface == NULL) {
186        return UNKNOWN_ERROR;
187    }
188
189    codec_return = vpx_codec_enc_config_default(mCodecInterface,
190                                                mCodecConfiguration,
191                                                0);  // Codec specific flags
192
193    if (codec_return != VPX_CODEC_OK) {
194        ALOGE("Error populating default configuration for vpx encoder.");
195        return UNKNOWN_ERROR;
196    }
197
198    mCodecConfiguration->g_w = mWidth;
199    mCodecConfiguration->g_h = mHeight;
200    mCodecConfiguration->g_threads = GetCPUCoreCount();
201    mCodecConfiguration->g_error_resilient = mErrorResilience;
202
203    switch (mLevel) {
204        case OMX_VIDEO_VP8Level_Version0:
205            mCodecConfiguration->g_profile = 0;
206            break;
207
208        case OMX_VIDEO_VP8Level_Version1:
209            mCodecConfiguration->g_profile = 1;
210            break;
211
212        case OMX_VIDEO_VP8Level_Version2:
213            mCodecConfiguration->g_profile = 2;
214            break;
215
216        case OMX_VIDEO_VP8Level_Version3:
217            mCodecConfiguration->g_profile = 3;
218            break;
219
220        default:
221            mCodecConfiguration->g_profile = 0;
222    }
223
224    // OMX timebase unit is microsecond
225    // g_timebase is in seconds (i.e. 1/1000000 seconds)
226    mCodecConfiguration->g_timebase.num = 1;
227    mCodecConfiguration->g_timebase.den = 1000000;
228    // rc_target_bitrate is in kbps, mBitrate in bps
229    mCodecConfiguration->rc_target_bitrate = mBitrate/1000;
230    mCodecConfiguration->rc_end_usage = mBitrateControlMode;
231
232    codec_return = vpx_codec_enc_init(mCodecContext,
233                                      mCodecInterface,
234                                      mCodecConfiguration,
235                                      0);  // flags
236
237    if (codec_return != VPX_CODEC_OK) {
238        ALOGE("Error initializing vpx encoder");
239        return UNKNOWN_ERROR;
240    }
241
242    codec_return = vpx_codec_control(mCodecContext,
243                                     VP8E_SET_TOKEN_PARTITIONS,
244                                     mDCTPartitions);
245    if (codec_return != VPX_CODEC_OK) {
246        ALOGE("Error setting dct partitions for vpx encoder.");
247        return UNKNOWN_ERROR;
248    }
249
250    if (mColorFormat == OMX_COLOR_FormatYUV420SemiPlanar) {
251        if (mConversionBuffer == NULL) {
252            mConversionBuffer = (uint8_t *)malloc(mWidth * mHeight * 3 / 2);
253            if (mConversionBuffer == NULL) {
254                ALOGE("Allocating conversion buffer failed.");
255                return UNKNOWN_ERROR;
256            }
257        }
258    }
259    return OK;
260}
261
262
263status_t SoftVPXEncoder::releaseEncoder() {
264    if (mCodecContext != NULL) {
265        vpx_codec_destroy(mCodecContext);
266        delete mCodecContext;
267        mCodecContext = NULL;
268    }
269
270    if (mCodecConfiguration != NULL) {
271        delete mCodecConfiguration;
272        mCodecConfiguration = NULL;
273    }
274
275    if (mConversionBuffer != NULL) {
276        delete mConversionBuffer;
277        mConversionBuffer = NULL;
278    }
279
280    // this one is not allocated by us
281    mCodecInterface = NULL;
282
283    return OK;
284}
285
286
287OMX_ERRORTYPE SoftVPXEncoder::internalGetParameter(OMX_INDEXTYPE index,
288                                                   OMX_PTR param) {
289    // can include extension index OMX_INDEXEXTTYPE
290    const int32_t indexFull = index;
291
292    switch (indexFull) {
293        case OMX_IndexParamVideoPortFormat: {
294            OMX_VIDEO_PARAM_PORTFORMATTYPE *formatParams =
295                (OMX_VIDEO_PARAM_PORTFORMATTYPE *)param;
296
297            if (formatParams->nPortIndex == kInputPortIndex) {
298                if (formatParams->nIndex >= kNumberOfSupportedColorFormats) {
299                    return OMX_ErrorNoMore;
300                }
301
302                // Color formats, in order of preference
303                if (formatParams->nIndex == 0) {
304                    formatParams->eColorFormat = OMX_COLOR_FormatYUV420Planar;
305                } else if (formatParams->nIndex == 1) {
306                    formatParams->eColorFormat =
307                        OMX_COLOR_FormatYUV420SemiPlanar;
308                } else {
309                    formatParams->eColorFormat = OMX_COLOR_FormatAndroidOpaque;
310                }
311
312                formatParams->eCompressionFormat = OMX_VIDEO_CodingUnused;
313                // Converting from microseconds
314                // Also converting to Q16 format
315                formatParams->xFramerate = (1000000/mFrameDurationUs) << 16;
316                return OMX_ErrorNone;
317            } else if (formatParams->nPortIndex == kOutputPortIndex) {
318                formatParams->eCompressionFormat = OMX_VIDEO_CodingVPX;
319                formatParams->eColorFormat = OMX_COLOR_FormatUnused;
320                formatParams->xFramerate = 0;
321                return OMX_ErrorNone;
322            } else {
323                return OMX_ErrorBadPortIndex;
324            }
325        }
326
327        case OMX_IndexParamVideoBitrate: {
328            OMX_VIDEO_PARAM_BITRATETYPE *bitrate =
329                (OMX_VIDEO_PARAM_BITRATETYPE *)param;
330
331                if (bitrate->nPortIndex != kOutputPortIndex) {
332                    return OMX_ErrorUnsupportedIndex;
333                }
334
335                bitrate->nTargetBitrate = mBitrate;
336
337                if (mBitrateControlMode == VPX_VBR) {
338                    bitrate->eControlRate = OMX_Video_ControlRateVariable;
339                } else if (mBitrateControlMode == VPX_CBR) {
340                    bitrate->eControlRate = OMX_Video_ControlRateConstant;
341                } else {
342                    return OMX_ErrorUnsupportedSetting;
343                }
344                return OMX_ErrorNone;
345        }
346
347        // VP8 specific parameters that use extension headers
348        case OMX_IndexParamVideoVp8: {
349            OMX_VIDEO_PARAM_VP8TYPE *vp8Params =
350                (OMX_VIDEO_PARAM_VP8TYPE *)param;
351
352                if (vp8Params->nPortIndex != kOutputPortIndex) {
353                    return OMX_ErrorUnsupportedIndex;
354                }
355
356                vp8Params->eProfile = OMX_VIDEO_VP8ProfileMain;
357                vp8Params->eLevel = mLevel;
358                vp8Params->nDCTPartitions = mDCTPartitions;
359                vp8Params->bErrorResilientMode = mErrorResilience;
360                return OMX_ErrorNone;
361        }
362
363        case OMX_IndexParamVideoProfileLevelQuerySupported: {
364            OMX_VIDEO_PARAM_PROFILELEVELTYPE *profileAndLevel =
365                (OMX_VIDEO_PARAM_PROFILELEVELTYPE *)param;
366
367            if (profileAndLevel->nPortIndex != kOutputPortIndex) {
368                return OMX_ErrorUnsupportedIndex;
369            }
370
371            switch (profileAndLevel->nProfileIndex) {
372                case 0:
373                    profileAndLevel->eLevel = OMX_VIDEO_VP8Level_Version0;
374                    break;
375
376                case 1:
377                    profileAndLevel->eLevel = OMX_VIDEO_VP8Level_Version1;
378                    break;
379
380                case 2:
381                    profileAndLevel->eLevel = OMX_VIDEO_VP8Level_Version2;
382                    break;
383
384                case 3:
385                    profileAndLevel->eLevel = OMX_VIDEO_VP8Level_Version3;
386                    break;
387
388                default:
389                    return OMX_ErrorNoMore;
390            }
391
392            profileAndLevel->eProfile = OMX_VIDEO_VP8ProfileMain;
393            return OMX_ErrorNone;
394        }
395
396        case OMX_IndexParamVideoProfileLevelCurrent: {
397            OMX_VIDEO_PARAM_PROFILELEVELTYPE *profileAndLevel =
398                (OMX_VIDEO_PARAM_PROFILELEVELTYPE *)param;
399
400            if (profileAndLevel->nPortIndex != kOutputPortIndex) {
401                return OMX_ErrorUnsupportedIndex;
402            }
403
404            profileAndLevel->eLevel = mLevel;
405            profileAndLevel->eProfile = OMX_VIDEO_VP8ProfileMain;
406            return OMX_ErrorNone;
407        }
408
409        default:
410            return SimpleSoftOMXComponent::internalGetParameter(index, param);
411    }
412}
413
414
415OMX_ERRORTYPE SoftVPXEncoder::internalSetParameter(OMX_INDEXTYPE index,
416                                                   const OMX_PTR param) {
417    // can include extension index OMX_INDEXEXTTYPE
418    const int32_t indexFull = index;
419
420    switch (indexFull) {
421        case OMX_IndexParamStandardComponentRole:
422            return internalSetRoleParams(
423                (const OMX_PARAM_COMPONENTROLETYPE *)param);
424
425        case OMX_IndexParamVideoBitrate:
426            return internalSetBitrateParams(
427                (const OMX_VIDEO_PARAM_BITRATETYPE *)param);
428
429        case OMX_IndexParamPortDefinition:
430            return internalSetPortParams(
431                (const OMX_PARAM_PORTDEFINITIONTYPE *)param);
432
433        case OMX_IndexParamVideoPortFormat:
434            return internalSetFormatParams(
435                (const OMX_VIDEO_PARAM_PORTFORMATTYPE *)param);
436
437        case OMX_IndexParamVideoVp8:
438            return internalSetVp8Params(
439                (const OMX_VIDEO_PARAM_VP8TYPE *)param);
440
441        case OMX_IndexParamVideoProfileLevelCurrent:
442            return internalSetProfileLevel(
443                (const OMX_VIDEO_PARAM_PROFILELEVELTYPE *)param);
444
445        default:
446            return SimpleSoftOMXComponent::internalSetParameter(index, param);
447    }
448}
449
450OMX_ERRORTYPE SoftVPXEncoder::internalSetProfileLevel(
451        const OMX_VIDEO_PARAM_PROFILELEVELTYPE* profileAndLevel) {
452    if (profileAndLevel->nPortIndex != kOutputPortIndex) {
453        return OMX_ErrorUnsupportedIndex;
454    }
455
456    if (profileAndLevel->eProfile != OMX_VIDEO_VP8ProfileMain) {
457        return OMX_ErrorBadParameter;
458    }
459
460    if (profileAndLevel->eLevel == OMX_VIDEO_VP8Level_Version0 ||
461        profileAndLevel->eLevel == OMX_VIDEO_VP8Level_Version1 ||
462        profileAndLevel->eLevel == OMX_VIDEO_VP8Level_Version2 ||
463        profileAndLevel->eLevel == OMX_VIDEO_VP8Level_Version3) {
464        mLevel = (OMX_VIDEO_VP8LEVELTYPE)profileAndLevel->eLevel;
465    } else {
466        return OMX_ErrorBadParameter;
467    }
468
469    return OMX_ErrorNone;
470}
471
472
473OMX_ERRORTYPE SoftVPXEncoder::internalSetVp8Params(
474        const OMX_VIDEO_PARAM_VP8TYPE* vp8Params) {
475    if (vp8Params->nPortIndex != kOutputPortIndex) {
476        return OMX_ErrorUnsupportedIndex;
477    }
478
479    if (vp8Params->eProfile != OMX_VIDEO_VP8ProfileMain) {
480        return OMX_ErrorBadParameter;
481    }
482
483    if (vp8Params->eLevel == OMX_VIDEO_VP8Level_Version0 ||
484        vp8Params->eLevel == OMX_VIDEO_VP8Level_Version1 ||
485        vp8Params->eLevel == OMX_VIDEO_VP8Level_Version2 ||
486        vp8Params->eLevel == OMX_VIDEO_VP8Level_Version3) {
487        mLevel = vp8Params->eLevel;
488    } else {
489        return OMX_ErrorBadParameter;
490    }
491
492    if (vp8Params->nDCTPartitions <= kMaxDCTPartitions) {
493        mDCTPartitions = vp8Params->nDCTPartitions;
494    } else {
495        return OMX_ErrorBadParameter;
496    }
497
498    mErrorResilience = vp8Params->bErrorResilientMode;
499    return OMX_ErrorNone;
500}
501
502
503OMX_ERRORTYPE SoftVPXEncoder::internalSetFormatParams(
504        const OMX_VIDEO_PARAM_PORTFORMATTYPE* format) {
505    if (format->nPortIndex == kInputPortIndex) {
506        if (format->eColorFormat == OMX_COLOR_FormatYUV420Planar ||
507            format->eColorFormat == OMX_COLOR_FormatYUV420SemiPlanar ||
508            format->eColorFormat == OMX_COLOR_FormatAndroidOpaque) {
509            mColorFormat = format->eColorFormat;
510            return OMX_ErrorNone;
511        } else {
512            ALOGE("Unsupported color format %i", format->eColorFormat);
513            return OMX_ErrorUnsupportedSetting;
514        }
515    } else if (format->nPortIndex == kOutputPortIndex) {
516        if (format->eCompressionFormat == OMX_VIDEO_CodingVPX) {
517            return OMX_ErrorNone;
518        } else {
519            return OMX_ErrorUnsupportedSetting;
520        }
521    } else {
522        return OMX_ErrorBadPortIndex;
523    }
524}
525
526
527OMX_ERRORTYPE SoftVPXEncoder::internalSetRoleParams(
528        const OMX_PARAM_COMPONENTROLETYPE* role) {
529    const char* roleText = (const char*)role->cRole;
530    const size_t roleTextMaxSize = OMX_MAX_STRINGNAME_SIZE - 1;
531
532    if (strncmp(roleText, "video_encoder.vpx", roleTextMaxSize)) {
533        ALOGE("Unsupported component role");
534        return OMX_ErrorBadParameter;
535    }
536
537    return OMX_ErrorNone;
538}
539
540
541OMX_ERRORTYPE SoftVPXEncoder::internalSetPortParams(
542        const OMX_PARAM_PORTDEFINITIONTYPE* port) {
543    if (port->nPortIndex == kInputPortIndex) {
544        mWidth = port->format.video.nFrameWidth;
545        mHeight = port->format.video.nFrameHeight;
546
547        // xFramerate comes in Q16 format, in frames per second unit
548        const uint32_t framerate = port->format.video.xFramerate >> 16;
549        // frame duration is in microseconds
550        mFrameDurationUs = (1000000/framerate);
551
552        if (port->format.video.eColorFormat == OMX_COLOR_FormatYUV420Planar ||
553            port->format.video.eColorFormat == OMX_COLOR_FormatYUV420SemiPlanar ||
554            port->format.video.eColorFormat == OMX_COLOR_FormatAndroidOpaque) {
555                mColorFormat = port->format.video.eColorFormat;
556        } else {
557            return OMX_ErrorUnsupportedSetting;
558        }
559
560        return OMX_ErrorNone;
561    } else if (port->nPortIndex == kOutputPortIndex) {
562        mBitrate = port->format.video.nBitrate;
563        return OMX_ErrorNone;
564    } else {
565        return OMX_ErrorBadPortIndex;
566    }
567}
568
569
570OMX_ERRORTYPE SoftVPXEncoder::internalSetBitrateParams(
571        const OMX_VIDEO_PARAM_BITRATETYPE* bitrate) {
572    if (bitrate->nPortIndex != kOutputPortIndex) {
573        return OMX_ErrorUnsupportedIndex;
574    }
575
576    mBitrate = bitrate->nTargetBitrate;
577
578    if (bitrate->eControlRate == OMX_Video_ControlRateVariable) {
579        mBitrateControlMode = VPX_VBR;
580    } else if (bitrate->eControlRate == OMX_Video_ControlRateConstant) {
581        mBitrateControlMode = VPX_CBR;
582    } else {
583        return OMX_ErrorUnsupportedSetting;
584    }
585
586    return OMX_ErrorNone;
587}
588
589
590void SoftVPXEncoder::onQueueFilled(OMX_U32 portIndex) {
591    // Initialize encoder if not already
592    if (mCodecContext == NULL) {
593        if (OK != initEncoder()) {
594            ALOGE("Failed to initialize encoder");
595            notify(OMX_EventError,
596                   OMX_ErrorUndefined,
597                   0,  // Extra notification data
598                   NULL);  // Notification data pointer
599            return;
600        }
601    }
602
603    vpx_codec_err_t codec_return;
604    List<BufferInfo *> &inputBufferInfoQueue = getPortQueue(kInputPortIndex);
605    List<BufferInfo *> &outputBufferInfoQueue = getPortQueue(kOutputPortIndex);
606
607    while (!inputBufferInfoQueue.empty() && !outputBufferInfoQueue.empty()) {
608        BufferInfo *inputBufferInfo = *inputBufferInfoQueue.begin();
609        OMX_BUFFERHEADERTYPE *inputBufferHeader = inputBufferInfo->mHeader;
610
611        BufferInfo *outputBufferInfo = *outputBufferInfoQueue.begin();
612        OMX_BUFFERHEADERTYPE *outputBufferHeader = outputBufferInfo->mHeader;
613
614        if (inputBufferHeader->nFlags & OMX_BUFFERFLAG_EOS) {
615            inputBufferInfoQueue.erase(inputBufferInfoQueue.begin());
616            inputBufferInfo->mOwnedByUs = false;
617            notifyEmptyBufferDone(inputBufferHeader);
618
619            outputBufferHeader->nFilledLen = 0;
620            outputBufferHeader->nFlags = OMX_BUFFERFLAG_EOS;
621
622            outputBufferInfoQueue.erase(outputBufferInfoQueue.begin());
623            outputBufferInfo->mOwnedByUs = false;
624            notifyFillBufferDone(outputBufferHeader);
625            return;
626        }
627
628        uint8_t* source = inputBufferHeader->pBuffer + inputBufferHeader->nOffset;
629
630        // NOTE: As much as nothing is known about color format
631        // when it is denoted as AndroidOpaque, it is at least
632        // assumed to be planar.
633        if (mColorFormat == OMX_COLOR_FormatYUV420SemiPlanar) {
634            ConvertSemiPlanarToPlanar(source, mConversionBuffer, mWidth, mHeight);
635            source = mConversionBuffer;
636        }
637        vpx_image_t raw_frame;
638        vpx_img_wrap(&raw_frame, VPX_IMG_FMT_I420, mWidth, mHeight,
639                     kInputBufferAlignment, source);
640        codec_return = vpx_codec_encode(mCodecContext,
641                                        &raw_frame,
642                                        inputBufferHeader->nTimeStamp,  // in timebase units
643                                        mFrameDurationUs,  // frame duration in timebase units
644                                        0,  // frame flags
645                                        VPX_DL_REALTIME);  // encoding deadline
646        if (codec_return != VPX_CODEC_OK) {
647            ALOGE("vpx encoder failed to encode frame");
648            notify(OMX_EventError,
649                   OMX_ErrorUndefined,
650                   0,  // Extra notification data
651                   NULL);  // Notification data pointer
652            return;
653        }
654
655        vpx_codec_iter_t encoded_packet_iterator = NULL;
656        const vpx_codec_cx_pkt_t* encoded_packet;
657
658        while (encoded_packet = vpx_codec_get_cx_data(mCodecContext, &encoded_packet_iterator)) {
659            if (encoded_packet->kind == VPX_CODEC_CX_FRAME_PKT) {
660                outputBufferHeader->nTimeStamp = encoded_packet->data.frame.pts;
661                outputBufferHeader->nFlags = 0;
662                outputBufferHeader->nOffset = 0;
663                outputBufferHeader->nFilledLen = encoded_packet->data.frame.sz;
664                memcpy(outputBufferHeader->pBuffer,
665                       encoded_packet->data.frame.buf,
666                       encoded_packet->data.frame.sz);
667                outputBufferInfo->mOwnedByUs = false;
668                outputBufferInfoQueue.erase(outputBufferInfoQueue.begin());
669                notifyFillBufferDone(outputBufferHeader);
670            }
671        }
672
673        inputBufferInfo->mOwnedByUs = false;
674        inputBufferInfoQueue.erase(inputBufferInfoQueue.begin());
675        notifyEmptyBufferDone(inputBufferHeader);
676    }
677}
678}  // namespace android
679
680
681android::SoftOMXComponent *createSoftOMXComponent(
682        const char *name, const OMX_CALLBACKTYPE *callbacks,
683        OMX_PTR appData, OMX_COMPONENTTYPE **component) {
684    return new android::SoftVPXEncoder(name, callbacks, appData, component);
685}
686