SoftVPXEncoder.cpp revision a5750e0dad9e90f2195ce36f2c4457fa04b2b83e
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/hardware/HardwareAPI.h>
24#include <media/hardware/MetadataBufferType.h>
25#include <media/stagefright/foundation/ADebug.h>
26#include <media/stagefright/MediaDefs.h>
27
28namespace android {
29
30template<class T>
31static void InitOMXParams(T *params) {
32    params->nSize = sizeof(T);
33    // OMX IL 1.1.2
34    params->nVersion.s.nVersionMajor = 1;
35    params->nVersion.s.nVersionMinor = 1;
36    params->nVersion.s.nRevision = 2;
37    params->nVersion.s.nStep = 0;
38}
39
40
41static int GetCPUCoreCount() {
42    int cpuCoreCount = 1;
43#if defined(_SC_NPROCESSORS_ONLN)
44    cpuCoreCount = sysconf(_SC_NPROCESSORS_ONLN);
45#else
46    // _SC_NPROC_ONLN must be defined...
47    cpuCoreCount = sysconf(_SC_NPROC_ONLN);
48#endif
49    CHECK_GE(cpuCoreCount, 1);
50    return cpuCoreCount;
51}
52
53
54// This color conversion utility is copied from SoftMPEG4Encoder.cpp
55inline static void ConvertSemiPlanarToPlanar(uint8_t *inyuv,
56                                             uint8_t* outyuv,
57                                             int32_t width,
58                                             int32_t height) {
59    int32_t outYsize = width * height;
60    uint32_t *outy =  (uint32_t *) outyuv;
61    uint16_t *outcb = (uint16_t *) (outyuv + outYsize);
62    uint16_t *outcr = (uint16_t *) (outyuv + outYsize + (outYsize >> 2));
63
64    /* Y copying */
65    memcpy(outy, inyuv, outYsize);
66
67    /* U & V copying */
68    uint32_t *inyuv_4 = (uint32_t *) (inyuv + outYsize);
69    for (int32_t i = height >> 1; i > 0; --i) {
70        for (int32_t j = width >> 2; j > 0; --j) {
71            uint32_t temp = *inyuv_4++;
72            uint32_t tempU = temp & 0xFF;
73            tempU = tempU | ((temp >> 8) & 0xFF00);
74
75            uint32_t tempV = (temp >> 8) & 0xFF;
76            tempV = tempV | ((temp >> 16) & 0xFF00);
77
78            // Flip U and V
79            *outcb++ = tempV;
80            *outcr++ = tempU;
81        }
82    }
83}
84
85static void ConvertRGB32ToPlanar(
86        const uint8_t *src, uint8_t *dstY, int32_t width, int32_t height) {
87    CHECK((width & 1) == 0);
88    CHECK((height & 1) == 0);
89
90    uint8_t *dstU = dstY + width * height;
91    uint8_t *dstV = dstU + (width / 2) * (height / 2);
92
93    for (int32_t y = 0; y < height; ++y) {
94        for (int32_t x = 0; x < width; ++x) {
95#ifdef SURFACE_IS_BGR32
96            unsigned blue = src[4 * x];
97            unsigned green = src[4 * x + 1];
98            unsigned red= src[4 * x + 2];
99#else
100            unsigned red= src[4 * x];
101            unsigned green = src[4 * x + 1];
102            unsigned blue = src[4 * x + 2];
103#endif
104
105            unsigned luma =
106                ((red * 66 + green * 129 + blue * 25) >> 8) + 16;
107
108            dstY[x] = luma;
109
110            if ((x & 1) == 0 && (y & 1) == 0) {
111                unsigned U =
112                    ((-red * 38 - green * 74 + blue * 112) >> 8) + 128;
113
114                unsigned V =
115                    ((red * 112 - green * 94 - blue * 18) >> 8) + 128;
116
117                dstU[x / 2] = U;
118                dstV[x / 2] = V;
119            }
120        }
121
122        if ((y & 1) == 0) {
123            dstU += width / 2;
124            dstV += width / 2;
125        }
126
127        src += 4 * width;
128        dstY += width;
129    }
130}
131
132SoftVPXEncoder::SoftVPXEncoder(const char *name,
133                               const OMX_CALLBACKTYPE *callbacks,
134                               OMX_PTR appData,
135                               OMX_COMPONENTTYPE **component)
136    : SimpleSoftOMXComponent(name, callbacks, appData, component),
137      mCodecContext(NULL),
138      mCodecConfiguration(NULL),
139      mCodecInterface(NULL),
140      mWidth(176),
141      mHeight(144),
142      mBitrate(192000),  // in bps
143      mFramerate(30 << 16), // in Q16 format
144      mBitrateUpdated(false),
145      mBitrateControlMode(VPX_VBR),  // variable bitrate
146      mDCTPartitions(0),
147      mErrorResilience(OMX_FALSE),
148      mColorFormat(OMX_COLOR_FormatYUV420Planar),
149      mLevel(OMX_VIDEO_VP8Level_Version0),
150      mKeyFrameInterval(0),
151      mMinQuantizer(0),
152      mMaxQuantizer(0),
153      mTemporalLayers(0),
154      mTemporalPatternType(OMX_VIDEO_VPXTemporalLayerPatternNone),
155      mTemporalPatternLength(0),
156      mTemporalPatternIdx(0),
157      mLastTimestamp(0x7FFFFFFFFFFFFFFFLL),
158      mConversionBuffer(NULL),
159      mInputDataIsMeta(false),
160      mGrallocModule(NULL),
161      mKeyFrameRequested(false) {
162    memset(mTemporalLayerBitrateRatio, 0, sizeof(mTemporalLayerBitrateRatio));
163    mTemporalLayerBitrateRatio[0] = 100;
164    initPorts();
165}
166
167
168SoftVPXEncoder::~SoftVPXEncoder() {
169    releaseEncoder();
170}
171
172
173void SoftVPXEncoder::initPorts() {
174    OMX_PARAM_PORTDEFINITIONTYPE inputPort;
175    OMX_PARAM_PORTDEFINITIONTYPE outputPort;
176
177    InitOMXParams(&inputPort);
178    InitOMXParams(&outputPort);
179
180    inputPort.nBufferCountMin = kNumBuffers;
181    inputPort.nBufferCountActual = inputPort.nBufferCountMin;
182    inputPort.bEnabled = OMX_TRUE;
183    inputPort.bPopulated = OMX_FALSE;
184    inputPort.eDomain = OMX_PortDomainVideo;
185    inputPort.bBuffersContiguous = OMX_FALSE;
186    inputPort.format.video.pNativeRender = NULL;
187    inputPort.format.video.nFrameWidth = mWidth;
188    inputPort.format.video.nFrameHeight = mHeight;
189    inputPort.format.video.nStride = inputPort.format.video.nFrameWidth;
190    inputPort.format.video.nSliceHeight = inputPort.format.video.nFrameHeight;
191    inputPort.format.video.nBitrate = 0;
192    // frameRate is in Q16 format.
193    inputPort.format.video.xFramerate = mFramerate;
194    inputPort.format.video.bFlagErrorConcealment = OMX_FALSE;
195    inputPort.nPortIndex = kInputPortIndex;
196    inputPort.eDir = OMX_DirInput;
197    inputPort.nBufferAlignment = kInputBufferAlignment;
198    inputPort.format.video.cMIMEType =
199        const_cast<char *>(MEDIA_MIMETYPE_VIDEO_RAW);
200    inputPort.format.video.eCompressionFormat = OMX_VIDEO_CodingUnused;
201    inputPort.format.video.eColorFormat = mColorFormat;
202    inputPort.format.video.pNativeWindow = NULL;
203    inputPort.nBufferSize =
204        (inputPort.format.video.nStride *
205        inputPort.format.video.nSliceHeight * 3) / 2;
206
207    addPort(inputPort);
208
209    outputPort.nBufferCountMin = kNumBuffers;
210    outputPort.nBufferCountActual = outputPort.nBufferCountMin;
211    outputPort.bEnabled = OMX_TRUE;
212    outputPort.bPopulated = OMX_FALSE;
213    outputPort.eDomain = OMX_PortDomainVideo;
214    outputPort.bBuffersContiguous = OMX_FALSE;
215    outputPort.format.video.pNativeRender = NULL;
216    outputPort.format.video.nFrameWidth = mWidth;
217    outputPort.format.video.nFrameHeight = mHeight;
218    outputPort.format.video.nStride = outputPort.format.video.nFrameWidth;
219    outputPort.format.video.nSliceHeight = outputPort.format.video.nFrameHeight;
220    outputPort.format.video.nBitrate = mBitrate;
221    outputPort.format.video.xFramerate = 0;
222    outputPort.format.video.bFlagErrorConcealment = OMX_FALSE;
223    outputPort.nPortIndex = kOutputPortIndex;
224    outputPort.eDir = OMX_DirOutput;
225    outputPort.nBufferAlignment = kOutputBufferAlignment;
226    outputPort.format.video.cMIMEType =
227        const_cast<char *>(MEDIA_MIMETYPE_VIDEO_VP8);
228    outputPort.format.video.eCompressionFormat = OMX_VIDEO_CodingVP8;
229    outputPort.format.video.eColorFormat = OMX_COLOR_FormatUnused;
230    outputPort.format.video.pNativeWindow = NULL;
231    outputPort.nBufferSize = 1024 * 1024; // arbitrary
232
233    addPort(outputPort);
234}
235
236
237status_t SoftVPXEncoder::initEncoder() {
238    vpx_codec_err_t codec_return;
239
240    mCodecContext = new vpx_codec_ctx_t;
241    mCodecConfiguration = new vpx_codec_enc_cfg_t;
242    mCodecInterface = vpx_codec_vp8_cx();
243
244    if (mCodecInterface == NULL) {
245        return UNKNOWN_ERROR;
246    }
247    ALOGD("VP8: initEncoder. BRMode: %u. TSLayers: %zu. KF: %u. QP: %u - %u",
248          (uint32_t)mBitrateControlMode, mTemporalLayers, mKeyFrameInterval,
249          mMinQuantizer, mMaxQuantizer);
250    codec_return = vpx_codec_enc_config_default(mCodecInterface,
251                                                mCodecConfiguration,
252                                                0);  // Codec specific flags
253
254    if (codec_return != VPX_CODEC_OK) {
255        ALOGE("Error populating default configuration for vpx encoder.");
256        return UNKNOWN_ERROR;
257    }
258
259    mCodecConfiguration->g_w = mWidth;
260    mCodecConfiguration->g_h = mHeight;
261    mCodecConfiguration->g_threads = GetCPUCoreCount();
262    mCodecConfiguration->g_error_resilient = mErrorResilience;
263
264    switch (mLevel) {
265        case OMX_VIDEO_VP8Level_Version0:
266            mCodecConfiguration->g_profile = 0;
267            break;
268
269        case OMX_VIDEO_VP8Level_Version1:
270            mCodecConfiguration->g_profile = 1;
271            break;
272
273        case OMX_VIDEO_VP8Level_Version2:
274            mCodecConfiguration->g_profile = 2;
275            break;
276
277        case OMX_VIDEO_VP8Level_Version3:
278            mCodecConfiguration->g_profile = 3;
279            break;
280
281        default:
282            mCodecConfiguration->g_profile = 0;
283    }
284
285    // OMX timebase unit is microsecond
286    // g_timebase is in seconds (i.e. 1/1000000 seconds)
287    mCodecConfiguration->g_timebase.num = 1;
288    mCodecConfiguration->g_timebase.den = 1000000;
289    // rc_target_bitrate is in kbps, mBitrate in bps
290    mCodecConfiguration->rc_target_bitrate = (mBitrate + 500) / 1000;
291    mCodecConfiguration->rc_end_usage = mBitrateControlMode;
292    // Disable frame drop - not allowed in MediaCodec now.
293    mCodecConfiguration->rc_dropframe_thresh = 0;
294    if (mBitrateControlMode == VPX_CBR) {
295        // Disable spatial resizing.
296        mCodecConfiguration->rc_resize_allowed = 0;
297        // Single-pass mode.
298        mCodecConfiguration->g_pass = VPX_RC_ONE_PASS;
299        // Maximum amount of bits that can be subtracted from the target
300        // bitrate - expressed as percentage of the target bitrate.
301        mCodecConfiguration->rc_undershoot_pct = 100;
302        // Maximum amount of bits that can be added to the target
303        // bitrate - expressed as percentage of the target bitrate.
304        mCodecConfiguration->rc_overshoot_pct = 15;
305        // Initial value of the buffer level in ms.
306        mCodecConfiguration->rc_buf_initial_sz = 500;
307        // Amount of data that the encoder should try to maintain in ms.
308        mCodecConfiguration->rc_buf_optimal_sz = 600;
309        // The amount of data that may be buffered by the decoding
310        // application in ms.
311        mCodecConfiguration->rc_buf_sz = 1000;
312        // Enable error resilience - needed for packet loss.
313        mCodecConfiguration->g_error_resilient = 1;
314        // Disable lagged encoding.
315        mCodecConfiguration->g_lag_in_frames = 0;
316        // Maximum key frame interval - for CBR boost to 3000
317        mCodecConfiguration->kf_max_dist = 3000;
318        // Encoder determines optimal key frame placement automatically.
319        mCodecConfiguration->kf_mode = VPX_KF_AUTO;
320    }
321
322    // Frames temporal pattern - for now WebRTC like pattern is only supported.
323    switch (mTemporalLayers) {
324        case 0:
325        {
326            mTemporalPatternLength = 0;
327            break;
328        }
329        case 1:
330        {
331            mCodecConfiguration->ts_number_layers = 1;
332            mCodecConfiguration->ts_rate_decimator[0] = 1;
333            mCodecConfiguration->ts_periodicity = 1;
334            mCodecConfiguration->ts_layer_id[0] = 0;
335            mTemporalPattern[0] = kTemporalUpdateLastRefAll;
336            mTemporalPatternLength = 1;
337            break;
338        }
339        case 2:
340        {
341            mCodecConfiguration->ts_number_layers = 2;
342            mCodecConfiguration->ts_rate_decimator[0] = 2;
343            mCodecConfiguration->ts_rate_decimator[1] = 1;
344            mCodecConfiguration->ts_periodicity = 2;
345            mCodecConfiguration->ts_layer_id[0] = 0;
346            mCodecConfiguration->ts_layer_id[1] = 1;
347            mTemporalPattern[0] = kTemporalUpdateLastAndGoldenRefAltRef;
348            mTemporalPattern[1] = kTemporalUpdateGoldenWithoutDependencyRefAltRef;
349            mTemporalPattern[2] = kTemporalUpdateLastRefAltRef;
350            mTemporalPattern[3] = kTemporalUpdateGoldenRefAltRef;
351            mTemporalPattern[4] = kTemporalUpdateLastRefAltRef;
352            mTemporalPattern[5] = kTemporalUpdateGoldenRefAltRef;
353            mTemporalPattern[6] = kTemporalUpdateLastRefAltRef;
354            mTemporalPattern[7] = kTemporalUpdateNone;
355            mTemporalPatternLength = 8;
356            break;
357        }
358        case 3:
359        {
360            mCodecConfiguration->ts_number_layers = 3;
361            mCodecConfiguration->ts_rate_decimator[0] = 4;
362            mCodecConfiguration->ts_rate_decimator[1] = 2;
363            mCodecConfiguration->ts_rate_decimator[2] = 1;
364            mCodecConfiguration->ts_periodicity = 4;
365            mCodecConfiguration->ts_layer_id[0] = 0;
366            mCodecConfiguration->ts_layer_id[1] = 2;
367            mCodecConfiguration->ts_layer_id[2] = 1;
368            mCodecConfiguration->ts_layer_id[3] = 2;
369            mTemporalPattern[0] = kTemporalUpdateLastAndGoldenRefAltRef;
370            mTemporalPattern[1] = kTemporalUpdateNoneNoRefGoldenRefAltRef;
371            mTemporalPattern[2] = kTemporalUpdateGoldenWithoutDependencyRefAltRef;
372            mTemporalPattern[3] = kTemporalUpdateNone;
373            mTemporalPattern[4] = kTemporalUpdateLastRefAltRef;
374            mTemporalPattern[5] = kTemporalUpdateNone;
375            mTemporalPattern[6] = kTemporalUpdateGoldenRefAltRef;
376            mTemporalPattern[7] = kTemporalUpdateNone;
377            mTemporalPatternLength = 8;
378            break;
379        }
380        default:
381        {
382            ALOGE("Wrong number of temporal layers %zu", mTemporalLayers);
383            return UNKNOWN_ERROR;
384        }
385    }
386
387    // Set bitrate values for each layer
388    for (size_t i = 0; i < mCodecConfiguration->ts_number_layers; i++) {
389        mCodecConfiguration->ts_target_bitrate[i] =
390            mCodecConfiguration->rc_target_bitrate *
391            mTemporalLayerBitrateRatio[i] / 100;
392    }
393    if (mKeyFrameInterval > 0) {
394        mCodecConfiguration->kf_max_dist = mKeyFrameInterval;
395        mCodecConfiguration->kf_min_dist = mKeyFrameInterval;
396        mCodecConfiguration->kf_mode = VPX_KF_AUTO;
397    }
398    if (mMinQuantizer > 0) {
399        mCodecConfiguration->rc_min_quantizer = mMinQuantizer;
400    }
401    if (mMaxQuantizer > 0) {
402        mCodecConfiguration->rc_max_quantizer = mMaxQuantizer;
403    }
404
405    codec_return = vpx_codec_enc_init(mCodecContext,
406                                      mCodecInterface,
407                                      mCodecConfiguration,
408                                      0);  // flags
409
410    if (codec_return != VPX_CODEC_OK) {
411        ALOGE("Error initializing vpx encoder");
412        return UNKNOWN_ERROR;
413    }
414
415    codec_return = vpx_codec_control(mCodecContext,
416                                     VP8E_SET_TOKEN_PARTITIONS,
417                                     mDCTPartitions);
418    if (codec_return != VPX_CODEC_OK) {
419        ALOGE("Error setting dct partitions for vpx encoder.");
420        return UNKNOWN_ERROR;
421    }
422
423    // Extra CBR settings
424    if (mBitrateControlMode == VPX_CBR) {
425        codec_return = vpx_codec_control(mCodecContext,
426                                         VP8E_SET_STATIC_THRESHOLD,
427                                         1);
428        if (codec_return == VPX_CODEC_OK) {
429            uint32_t rc_max_intra_target =
430                mCodecConfiguration->rc_buf_optimal_sz * (mFramerate >> 17) / 10;
431            // Don't go below 3 times per frame bandwidth.
432            if (rc_max_intra_target < 300) {
433                rc_max_intra_target = 300;
434            }
435            codec_return = vpx_codec_control(mCodecContext,
436                                             VP8E_SET_MAX_INTRA_BITRATE_PCT,
437                                             rc_max_intra_target);
438        }
439        if (codec_return == VPX_CODEC_OK) {
440            codec_return = vpx_codec_control(mCodecContext,
441                                             VP8E_SET_CPUUSED,
442                                             -8);
443        }
444        if (codec_return != VPX_CODEC_OK) {
445            ALOGE("Error setting cbr parameters for vpx encoder.");
446            return UNKNOWN_ERROR;
447        }
448    }
449
450    if (mColorFormat == OMX_COLOR_FormatYUV420SemiPlanar || mInputDataIsMeta) {
451        if (mConversionBuffer == NULL) {
452            mConversionBuffer = (uint8_t *)malloc(mWidth * mHeight * 3 / 2);
453            if (mConversionBuffer == NULL) {
454                ALOGE("Allocating conversion buffer failed.");
455                return UNKNOWN_ERROR;
456            }
457        }
458    }
459    return OK;
460}
461
462
463status_t SoftVPXEncoder::releaseEncoder() {
464    if (mCodecContext != NULL) {
465        vpx_codec_destroy(mCodecContext);
466        delete mCodecContext;
467        mCodecContext = NULL;
468    }
469
470    if (mCodecConfiguration != NULL) {
471        delete mCodecConfiguration;
472        mCodecConfiguration = NULL;
473    }
474
475    if (mConversionBuffer != NULL) {
476        delete mConversionBuffer;
477        mConversionBuffer = NULL;
478    }
479
480    // this one is not allocated by us
481    mCodecInterface = NULL;
482
483    return OK;
484}
485
486
487OMX_ERRORTYPE SoftVPXEncoder::internalGetParameter(OMX_INDEXTYPE index,
488                                                   OMX_PTR param) {
489    // can include extension index OMX_INDEXEXTTYPE
490    const int32_t indexFull = index;
491
492    switch (indexFull) {
493        case OMX_IndexParamVideoPortFormat: {
494            OMX_VIDEO_PARAM_PORTFORMATTYPE *formatParams =
495                (OMX_VIDEO_PARAM_PORTFORMATTYPE *)param;
496
497            if (formatParams->nPortIndex == kInputPortIndex) {
498                if (formatParams->nIndex >= kNumberOfSupportedColorFormats) {
499                    return OMX_ErrorNoMore;
500                }
501
502                // Color formats, in order of preference
503                if (formatParams->nIndex == 0) {
504                    formatParams->eColorFormat = OMX_COLOR_FormatYUV420Planar;
505                } else if (formatParams->nIndex == 1) {
506                    formatParams->eColorFormat =
507                        OMX_COLOR_FormatYUV420SemiPlanar;
508                } else {
509                    formatParams->eColorFormat = OMX_COLOR_FormatAndroidOpaque;
510                }
511
512                formatParams->eCompressionFormat = OMX_VIDEO_CodingUnused;
513                formatParams->xFramerate = mFramerate;
514                return OMX_ErrorNone;
515            } else if (formatParams->nPortIndex == kOutputPortIndex) {
516                formatParams->eCompressionFormat = OMX_VIDEO_CodingVP8;
517                formatParams->eColorFormat = OMX_COLOR_FormatUnused;
518                formatParams->xFramerate = 0;
519                return OMX_ErrorNone;
520            } else {
521                return OMX_ErrorBadPortIndex;
522            }
523        }
524
525        case OMX_IndexParamVideoBitrate: {
526            OMX_VIDEO_PARAM_BITRATETYPE *bitrate =
527                (OMX_VIDEO_PARAM_BITRATETYPE *)param;
528
529                if (bitrate->nPortIndex != kOutputPortIndex) {
530                    return OMX_ErrorUnsupportedIndex;
531                }
532
533                bitrate->nTargetBitrate = mBitrate;
534
535                if (mBitrateControlMode == VPX_VBR) {
536                    bitrate->eControlRate = OMX_Video_ControlRateVariable;
537                } else if (mBitrateControlMode == VPX_CBR) {
538                    bitrate->eControlRate = OMX_Video_ControlRateConstant;
539                } else {
540                    return OMX_ErrorUnsupportedSetting;
541                }
542                return OMX_ErrorNone;
543        }
544
545        // VP8 specific parameters that use extension headers
546        case OMX_IndexParamVideoVp8: {
547            OMX_VIDEO_PARAM_VP8TYPE *vp8Params =
548                (OMX_VIDEO_PARAM_VP8TYPE *)param;
549
550                if (vp8Params->nPortIndex != kOutputPortIndex) {
551                    return OMX_ErrorUnsupportedIndex;
552                }
553
554                vp8Params->eProfile = OMX_VIDEO_VP8ProfileMain;
555                vp8Params->eLevel = mLevel;
556                vp8Params->nDCTPartitions = mDCTPartitions;
557                vp8Params->bErrorResilientMode = mErrorResilience;
558                return OMX_ErrorNone;
559        }
560
561        case OMX_IndexParamVideoAndroidVp8Encoder: {
562            OMX_VIDEO_PARAM_ANDROID_VP8ENCODERTYPE *vp8AndroidParams =
563                (OMX_VIDEO_PARAM_ANDROID_VP8ENCODERTYPE *)param;
564
565                if (vp8AndroidParams->nPortIndex != kOutputPortIndex) {
566                    return OMX_ErrorUnsupportedIndex;
567                }
568
569                vp8AndroidParams->nKeyFrameInterval = mKeyFrameInterval;
570                vp8AndroidParams->eTemporalPattern = mTemporalPatternType;
571                vp8AndroidParams->nTemporalLayerCount = mTemporalLayers;
572                vp8AndroidParams->nMinQuantizer = mMinQuantizer;
573                vp8AndroidParams->nMaxQuantizer = mMaxQuantizer;
574                memcpy(vp8AndroidParams->nTemporalLayerBitrateRatio,
575                       mTemporalLayerBitrateRatio, sizeof(mTemporalLayerBitrateRatio));
576                return OMX_ErrorNone;
577        }
578
579        case OMX_IndexParamVideoProfileLevelQuerySupported: {
580            OMX_VIDEO_PARAM_PROFILELEVELTYPE *profileAndLevel =
581                (OMX_VIDEO_PARAM_PROFILELEVELTYPE *)param;
582
583            if (profileAndLevel->nPortIndex != kOutputPortIndex) {
584                return OMX_ErrorUnsupportedIndex;
585            }
586
587            switch (profileAndLevel->nProfileIndex) {
588                case 0:
589                    profileAndLevel->eLevel = OMX_VIDEO_VP8Level_Version0;
590                    break;
591
592                case 1:
593                    profileAndLevel->eLevel = OMX_VIDEO_VP8Level_Version1;
594                    break;
595
596                case 2:
597                    profileAndLevel->eLevel = OMX_VIDEO_VP8Level_Version2;
598                    break;
599
600                case 3:
601                    profileAndLevel->eLevel = OMX_VIDEO_VP8Level_Version3;
602                    break;
603
604                default:
605                    return OMX_ErrorNoMore;
606            }
607
608            profileAndLevel->eProfile = OMX_VIDEO_VP8ProfileMain;
609            return OMX_ErrorNone;
610        }
611
612        case OMX_IndexParamVideoProfileLevelCurrent: {
613            OMX_VIDEO_PARAM_PROFILELEVELTYPE *profileAndLevel =
614                (OMX_VIDEO_PARAM_PROFILELEVELTYPE *)param;
615
616            if (profileAndLevel->nPortIndex != kOutputPortIndex) {
617                return OMX_ErrorUnsupportedIndex;
618            }
619
620            profileAndLevel->eLevel = mLevel;
621            profileAndLevel->eProfile = OMX_VIDEO_VP8ProfileMain;
622            return OMX_ErrorNone;
623        }
624
625        default:
626            return SimpleSoftOMXComponent::internalGetParameter(index, param);
627    }
628}
629
630
631OMX_ERRORTYPE SoftVPXEncoder::internalSetParameter(OMX_INDEXTYPE index,
632                                                   const OMX_PTR param) {
633    // can include extension index OMX_INDEXEXTTYPE
634    const int32_t indexFull = index;
635
636    switch (indexFull) {
637        case OMX_IndexParamStandardComponentRole:
638            return internalSetRoleParams(
639                (const OMX_PARAM_COMPONENTROLETYPE *)param);
640
641        case OMX_IndexParamVideoBitrate:
642            return internalSetBitrateParams(
643                (const OMX_VIDEO_PARAM_BITRATETYPE *)param);
644
645        case OMX_IndexParamPortDefinition:
646        {
647            OMX_ERRORTYPE err = internalSetPortParams(
648                (const OMX_PARAM_PORTDEFINITIONTYPE *)param);
649
650            if (err != OMX_ErrorNone) {
651                return err;
652            }
653
654            return SimpleSoftOMXComponent::internalSetParameter(index, param);
655        }
656
657        case OMX_IndexParamVideoPortFormat:
658            return internalSetFormatParams(
659                (const OMX_VIDEO_PARAM_PORTFORMATTYPE *)param);
660
661        case OMX_IndexParamVideoVp8:
662            return internalSetVp8Params(
663                (const OMX_VIDEO_PARAM_VP8TYPE *)param);
664
665        case OMX_IndexParamVideoAndroidVp8Encoder:
666            return internalSetAndroidVp8Params(
667                (const OMX_VIDEO_PARAM_ANDROID_VP8ENCODERTYPE *)param);
668
669        case OMX_IndexParamVideoProfileLevelCurrent:
670            return internalSetProfileLevel(
671                (const OMX_VIDEO_PARAM_PROFILELEVELTYPE *)param);
672
673        case kStoreMetaDataExtensionIndex:
674        {
675            // storeMetaDataInBuffers
676            const StoreMetaDataInBuffersParams *storeParam =
677                (const StoreMetaDataInBuffersParams *)param;
678
679            if (storeParam->nPortIndex != kInputPortIndex) {
680                return OMX_ErrorBadPortIndex;
681            }
682
683            mInputDataIsMeta = (storeParam->bStoreMetaData == OMX_TRUE);
684
685            return OMX_ErrorNone;
686        }
687
688        default:
689            return SimpleSoftOMXComponent::internalSetParameter(index, param);
690    }
691}
692
693OMX_ERRORTYPE SoftVPXEncoder::setConfig(
694        OMX_INDEXTYPE index, const OMX_PTR _params) {
695    switch (index) {
696        case OMX_IndexConfigVideoIntraVOPRefresh:
697        {
698            OMX_CONFIG_INTRAREFRESHVOPTYPE *params =
699                (OMX_CONFIG_INTRAREFRESHVOPTYPE *)_params;
700
701            if (params->nPortIndex != kOutputPortIndex) {
702                return OMX_ErrorBadPortIndex;
703            }
704
705            mKeyFrameRequested = params->IntraRefreshVOP;
706            return OMX_ErrorNone;
707        }
708
709        case OMX_IndexConfigVideoBitrate:
710        {
711            OMX_VIDEO_CONFIG_BITRATETYPE *params =
712                (OMX_VIDEO_CONFIG_BITRATETYPE *)_params;
713
714            if (params->nPortIndex != kOutputPortIndex) {
715                return OMX_ErrorBadPortIndex;
716            }
717
718            if (mBitrate != params->nEncodeBitrate) {
719                mBitrate = params->nEncodeBitrate;
720                mBitrateUpdated = true;
721            }
722            return OMX_ErrorNone;
723        }
724
725        default:
726            return SimpleSoftOMXComponent::setConfig(index, _params);
727    }
728}
729
730OMX_ERRORTYPE SoftVPXEncoder::internalSetProfileLevel(
731        const OMX_VIDEO_PARAM_PROFILELEVELTYPE* profileAndLevel) {
732    if (profileAndLevel->nPortIndex != kOutputPortIndex) {
733        return OMX_ErrorUnsupportedIndex;
734    }
735
736    if (profileAndLevel->eProfile != OMX_VIDEO_VP8ProfileMain) {
737        return OMX_ErrorBadParameter;
738    }
739
740    if (profileAndLevel->eLevel == OMX_VIDEO_VP8Level_Version0 ||
741        profileAndLevel->eLevel == OMX_VIDEO_VP8Level_Version1 ||
742        profileAndLevel->eLevel == OMX_VIDEO_VP8Level_Version2 ||
743        profileAndLevel->eLevel == OMX_VIDEO_VP8Level_Version3) {
744        mLevel = (OMX_VIDEO_VP8LEVELTYPE)profileAndLevel->eLevel;
745    } else {
746        return OMX_ErrorBadParameter;
747    }
748
749    return OMX_ErrorNone;
750}
751
752
753OMX_ERRORTYPE SoftVPXEncoder::internalSetVp8Params(
754        const OMX_VIDEO_PARAM_VP8TYPE* vp8Params) {
755    if (vp8Params->nPortIndex != kOutputPortIndex) {
756        return OMX_ErrorUnsupportedIndex;
757    }
758
759    if (vp8Params->eProfile != OMX_VIDEO_VP8ProfileMain) {
760        return OMX_ErrorBadParameter;
761    }
762
763    if (vp8Params->eLevel == OMX_VIDEO_VP8Level_Version0 ||
764        vp8Params->eLevel == OMX_VIDEO_VP8Level_Version1 ||
765        vp8Params->eLevel == OMX_VIDEO_VP8Level_Version2 ||
766        vp8Params->eLevel == OMX_VIDEO_VP8Level_Version3) {
767        mLevel = vp8Params->eLevel;
768    } else {
769        return OMX_ErrorBadParameter;
770    }
771
772    if (vp8Params->nDCTPartitions <= kMaxDCTPartitions) {
773        mDCTPartitions = vp8Params->nDCTPartitions;
774    } else {
775        return OMX_ErrorBadParameter;
776    }
777
778    mErrorResilience = vp8Params->bErrorResilientMode;
779    return OMX_ErrorNone;
780}
781
782OMX_ERRORTYPE SoftVPXEncoder::internalSetAndroidVp8Params(
783        const OMX_VIDEO_PARAM_ANDROID_VP8ENCODERTYPE* vp8AndroidParams) {
784    if (vp8AndroidParams->nPortIndex != kOutputPortIndex) {
785        return OMX_ErrorUnsupportedIndex;
786    }
787    if (vp8AndroidParams->eTemporalPattern != OMX_VIDEO_VPXTemporalLayerPatternNone &&
788        vp8AndroidParams->eTemporalPattern != OMX_VIDEO_VPXTemporalLayerPatternWebRTC) {
789        return OMX_ErrorBadParameter;
790    }
791    if (vp8AndroidParams->nTemporalLayerCount > OMX_VIDEO_ANDROID_MAXVP8TEMPORALLAYERS) {
792        return OMX_ErrorBadParameter;
793    }
794    if (vp8AndroidParams->nMinQuantizer > vp8AndroidParams->nMaxQuantizer) {
795        return OMX_ErrorBadParameter;
796    }
797
798    mTemporalPatternType = vp8AndroidParams->eTemporalPattern;
799    if (vp8AndroidParams->eTemporalPattern == OMX_VIDEO_VPXTemporalLayerPatternWebRTC) {
800        mTemporalLayers = vp8AndroidParams->nTemporalLayerCount;
801    } else if (vp8AndroidParams->eTemporalPattern == OMX_VIDEO_VPXTemporalLayerPatternNone) {
802        mTemporalLayers = 0;
803    }
804    // Check the bitrate distribution between layers is in increasing order
805    if (mTemporalLayers > 1) {
806        for (size_t i = 0; i < mTemporalLayers - 1; i++) {
807            if (vp8AndroidParams->nTemporalLayerBitrateRatio[i + 1] <=
808                    vp8AndroidParams->nTemporalLayerBitrateRatio[i]) {
809                ALOGE("Wrong bitrate ratio - should be in increasing order.");
810                return OMX_ErrorBadParameter;
811            }
812        }
813    }
814    mKeyFrameInterval = vp8AndroidParams->nKeyFrameInterval;
815    mMinQuantizer = vp8AndroidParams->nMinQuantizer;
816    mMaxQuantizer = vp8AndroidParams->nMaxQuantizer;
817    memcpy(mTemporalLayerBitrateRatio, vp8AndroidParams->nTemporalLayerBitrateRatio,
818            sizeof(mTemporalLayerBitrateRatio));
819    ALOGD("VP8: internalSetAndroidVp8Params. BRMode: %u. TS: %zu. KF: %u."
820          " QP: %u - %u BR0: %u. BR1: %u. BR2: %u",
821          (uint32_t)mBitrateControlMode, mTemporalLayers, mKeyFrameInterval,
822          mMinQuantizer, mMaxQuantizer, mTemporalLayerBitrateRatio[0],
823          mTemporalLayerBitrateRatio[1], mTemporalLayerBitrateRatio[2]);
824    return OMX_ErrorNone;
825}
826
827OMX_ERRORTYPE SoftVPXEncoder::internalSetFormatParams(
828        const OMX_VIDEO_PARAM_PORTFORMATTYPE* format) {
829    if (format->nPortIndex == kInputPortIndex) {
830        if (format->eColorFormat == OMX_COLOR_FormatYUV420Planar ||
831            format->eColorFormat == OMX_COLOR_FormatYUV420SemiPlanar ||
832            format->eColorFormat == OMX_COLOR_FormatAndroidOpaque) {
833            mColorFormat = format->eColorFormat;
834
835            OMX_PARAM_PORTDEFINITIONTYPE *def = &editPortInfo(kInputPortIndex)->mDef;
836            def->format.video.eColorFormat = mColorFormat;
837
838            return OMX_ErrorNone;
839        } else {
840            ALOGE("Unsupported color format %i", format->eColorFormat);
841            return OMX_ErrorUnsupportedSetting;
842        }
843    } else if (format->nPortIndex == kOutputPortIndex) {
844        if (format->eCompressionFormat == OMX_VIDEO_CodingVP8) {
845            return OMX_ErrorNone;
846        } else {
847            return OMX_ErrorUnsupportedSetting;
848        }
849    } else {
850        return OMX_ErrorBadPortIndex;
851    }
852}
853
854
855OMX_ERRORTYPE SoftVPXEncoder::internalSetRoleParams(
856        const OMX_PARAM_COMPONENTROLETYPE* role) {
857    const char* roleText = (const char*)role->cRole;
858    const size_t roleTextMaxSize = OMX_MAX_STRINGNAME_SIZE - 1;
859
860    if (strncmp(roleText, "video_encoder.vp8", roleTextMaxSize)) {
861        ALOGE("Unsupported component role");
862        return OMX_ErrorBadParameter;
863    }
864
865    return OMX_ErrorNone;
866}
867
868
869OMX_ERRORTYPE SoftVPXEncoder::internalSetPortParams(
870        const OMX_PARAM_PORTDEFINITIONTYPE* port) {
871    if (port->nPortIndex == kInputPortIndex) {
872        mWidth = port->format.video.nFrameWidth;
873        mHeight = port->format.video.nFrameHeight;
874
875        // xFramerate comes in Q16 format, in frames per second unit
876        mFramerate = port->format.video.xFramerate;
877
878        if (port->format.video.eColorFormat == OMX_COLOR_FormatYUV420Planar ||
879            port->format.video.eColorFormat == OMX_COLOR_FormatYUV420SemiPlanar ||
880            port->format.video.eColorFormat == OMX_COLOR_FormatAndroidOpaque) {
881            mColorFormat = port->format.video.eColorFormat;
882        } else {
883            return OMX_ErrorUnsupportedSetting;
884        }
885
886        OMX_PARAM_PORTDEFINITIONTYPE *def = &editPortInfo(kInputPortIndex)->mDef;
887        def->format.video.nFrameWidth = mWidth;
888        def->format.video.nFrameHeight = mHeight;
889        def->format.video.xFramerate = mFramerate;
890        def->format.video.eColorFormat = mColorFormat;
891        def = &editPortInfo(kOutputPortIndex)->mDef;
892        def->format.video.nFrameWidth = mWidth;
893        def->format.video.nFrameHeight = mHeight;
894
895        return OMX_ErrorNone;
896    } else if (port->nPortIndex == kOutputPortIndex) {
897        mBitrate = port->format.video.nBitrate;
898        mWidth = port->format.video.nFrameWidth;
899        mHeight = port->format.video.nFrameHeight;
900
901        OMX_PARAM_PORTDEFINITIONTYPE *def = &editPortInfo(kOutputPortIndex)->mDef;
902        def->format.video.nFrameWidth = mWidth;
903        def->format.video.nFrameHeight = mHeight;
904        def->format.video.nBitrate = mBitrate;
905        return OMX_ErrorNone;
906    } else {
907        return OMX_ErrorBadPortIndex;
908    }
909}
910
911
912OMX_ERRORTYPE SoftVPXEncoder::internalSetBitrateParams(
913        const OMX_VIDEO_PARAM_BITRATETYPE* bitrate) {
914    if (bitrate->nPortIndex != kOutputPortIndex) {
915        return OMX_ErrorUnsupportedIndex;
916    }
917
918    mBitrate = bitrate->nTargetBitrate;
919
920    if (bitrate->eControlRate == OMX_Video_ControlRateVariable) {
921        mBitrateControlMode = VPX_VBR;
922    } else if (bitrate->eControlRate == OMX_Video_ControlRateConstant) {
923        mBitrateControlMode = VPX_CBR;
924    } else {
925        return OMX_ErrorUnsupportedSetting;
926    }
927
928    return OMX_ErrorNone;
929}
930
931vpx_enc_frame_flags_t SoftVPXEncoder::getEncodeFlags() {
932    vpx_enc_frame_flags_t flags = 0;
933    int patternIdx = mTemporalPatternIdx % mTemporalPatternLength;
934    mTemporalPatternIdx++;
935    switch (mTemporalPattern[patternIdx]) {
936        case kTemporalUpdateLast:
937            flags |= VP8_EFLAG_NO_UPD_GF;
938            flags |= VP8_EFLAG_NO_UPD_ARF;
939            flags |= VP8_EFLAG_NO_REF_GF;
940            flags |= VP8_EFLAG_NO_REF_ARF;
941            break;
942        case kTemporalUpdateGoldenWithoutDependency:
943            flags |= VP8_EFLAG_NO_REF_GF;
944            // Deliberately no break here.
945        case kTemporalUpdateGolden:
946            flags |= VP8_EFLAG_NO_REF_ARF;
947            flags |= VP8_EFLAG_NO_UPD_ARF;
948            flags |= VP8_EFLAG_NO_UPD_LAST;
949            break;
950        case kTemporalUpdateAltrefWithoutDependency:
951            flags |= VP8_EFLAG_NO_REF_ARF;
952            flags |= VP8_EFLAG_NO_REF_GF;
953            // Deliberately no break here.
954        case kTemporalUpdateAltref:
955            flags |= VP8_EFLAG_NO_UPD_GF;
956            flags |= VP8_EFLAG_NO_UPD_LAST;
957            break;
958        case kTemporalUpdateNoneNoRefAltref:
959            flags |= VP8_EFLAG_NO_REF_ARF;
960            // Deliberately no break here.
961        case kTemporalUpdateNone:
962            flags |= VP8_EFLAG_NO_UPD_GF;
963            flags |= VP8_EFLAG_NO_UPD_ARF;
964            flags |= VP8_EFLAG_NO_UPD_LAST;
965            flags |= VP8_EFLAG_NO_UPD_ENTROPY;
966            break;
967        case kTemporalUpdateNoneNoRefGoldenRefAltRef:
968            flags |= VP8_EFLAG_NO_REF_GF;
969            flags |= VP8_EFLAG_NO_UPD_GF;
970            flags |= VP8_EFLAG_NO_UPD_ARF;
971            flags |= VP8_EFLAG_NO_UPD_LAST;
972            flags |= VP8_EFLAG_NO_UPD_ENTROPY;
973            break;
974        case kTemporalUpdateGoldenWithoutDependencyRefAltRef:
975            flags |= VP8_EFLAG_NO_REF_GF;
976            flags |= VP8_EFLAG_NO_UPD_ARF;
977            flags |= VP8_EFLAG_NO_UPD_LAST;
978            break;
979        case kTemporalUpdateLastRefAltRef:
980            flags |= VP8_EFLAG_NO_UPD_GF;
981            flags |= VP8_EFLAG_NO_UPD_ARF;
982            flags |= VP8_EFLAG_NO_REF_GF;
983            break;
984        case kTemporalUpdateGoldenRefAltRef:
985            flags |= VP8_EFLAG_NO_UPD_ARF;
986            flags |= VP8_EFLAG_NO_UPD_LAST;
987            break;
988        case kTemporalUpdateLastAndGoldenRefAltRef:
989            flags |= VP8_EFLAG_NO_UPD_ARF;
990            flags |= VP8_EFLAG_NO_REF_GF;
991            break;
992        case kTemporalUpdateLastRefAll:
993            flags |= VP8_EFLAG_NO_UPD_ARF;
994            flags |= VP8_EFLAG_NO_UPD_GF;
995            break;
996    }
997    return flags;
998}
999
1000void SoftVPXEncoder::onQueueFilled(OMX_U32 portIndex) {
1001    // Initialize encoder if not already
1002    if (mCodecContext == NULL) {
1003        if (OK != initEncoder()) {
1004            ALOGE("Failed to initialize encoder");
1005            notify(OMX_EventError,
1006                   OMX_ErrorUndefined,
1007                   0,  // Extra notification data
1008                   NULL);  // Notification data pointer
1009            return;
1010        }
1011    }
1012
1013    vpx_codec_err_t codec_return;
1014    List<BufferInfo *> &inputBufferInfoQueue = getPortQueue(kInputPortIndex);
1015    List<BufferInfo *> &outputBufferInfoQueue = getPortQueue(kOutputPortIndex);
1016
1017    while (!inputBufferInfoQueue.empty() && !outputBufferInfoQueue.empty()) {
1018        BufferInfo *inputBufferInfo = *inputBufferInfoQueue.begin();
1019        OMX_BUFFERHEADERTYPE *inputBufferHeader = inputBufferInfo->mHeader;
1020
1021        BufferInfo *outputBufferInfo = *outputBufferInfoQueue.begin();
1022        OMX_BUFFERHEADERTYPE *outputBufferHeader = outputBufferInfo->mHeader;
1023
1024        if (inputBufferHeader->nFlags & OMX_BUFFERFLAG_EOS) {
1025            inputBufferInfoQueue.erase(inputBufferInfoQueue.begin());
1026            inputBufferInfo->mOwnedByUs = false;
1027            notifyEmptyBufferDone(inputBufferHeader);
1028
1029            outputBufferHeader->nFilledLen = 0;
1030            outputBufferHeader->nFlags = OMX_BUFFERFLAG_EOS;
1031
1032            outputBufferInfoQueue.erase(outputBufferInfoQueue.begin());
1033            outputBufferInfo->mOwnedByUs = false;
1034            notifyFillBufferDone(outputBufferHeader);
1035            return;
1036        }
1037
1038        uint8_t *source =
1039            inputBufferHeader->pBuffer + inputBufferHeader->nOffset;
1040
1041        if (mInputDataIsMeta) {
1042            CHECK_GE(inputBufferHeader->nFilledLen,
1043                     4 + sizeof(buffer_handle_t));
1044
1045            uint32_t bufferType = *(uint32_t *)source;
1046            CHECK_EQ(bufferType, kMetadataBufferTypeGrallocSource);
1047
1048            if (mGrallocModule == NULL) {
1049                CHECK_EQ(0, hw_get_module(
1050                            GRALLOC_HARDWARE_MODULE_ID, &mGrallocModule));
1051            }
1052
1053            const gralloc_module_t *grmodule =
1054                (const gralloc_module_t *)mGrallocModule;
1055
1056            buffer_handle_t handle = *(buffer_handle_t *)(source + 4);
1057
1058            void *bits;
1059            CHECK_EQ(0,
1060                     grmodule->lock(
1061                         grmodule, handle,
1062                         GRALLOC_USAGE_SW_READ_OFTEN
1063                            | GRALLOC_USAGE_SW_WRITE_NEVER,
1064                         0, 0, mWidth, mHeight, &bits));
1065
1066            ConvertRGB32ToPlanar(
1067                    (const uint8_t *)bits, mConversionBuffer, mWidth, mHeight);
1068
1069            source = mConversionBuffer;
1070
1071            CHECK_EQ(0, grmodule->unlock(grmodule, handle));
1072        } else if (mColorFormat == OMX_COLOR_FormatYUV420SemiPlanar) {
1073            ConvertSemiPlanarToPlanar(
1074                    source, mConversionBuffer, mWidth, mHeight);
1075
1076            source = mConversionBuffer;
1077        }
1078        vpx_image_t raw_frame;
1079        vpx_img_wrap(&raw_frame, VPX_IMG_FMT_I420, mWidth, mHeight,
1080                     kInputBufferAlignment, source);
1081
1082        vpx_enc_frame_flags_t flags = 0;
1083        if (mTemporalPatternLength > 0) {
1084            flags = getEncodeFlags();
1085        }
1086        if (mKeyFrameRequested) {
1087            flags |= VPX_EFLAG_FORCE_KF;
1088            mKeyFrameRequested = false;
1089        }
1090
1091        if (mBitrateUpdated) {
1092            mCodecConfiguration->rc_target_bitrate = mBitrate/1000;
1093            vpx_codec_err_t res = vpx_codec_enc_config_set(mCodecContext,
1094                                                           mCodecConfiguration);
1095            if (res != VPX_CODEC_OK) {
1096                ALOGE("vp8 encoder failed to update bitrate: %s",
1097                      vpx_codec_err_to_string(res));
1098                notify(OMX_EventError,
1099                       OMX_ErrorUndefined,
1100                       0, // Extra notification data
1101                       NULL); // Notification data pointer
1102            }
1103            mBitrateUpdated = false;
1104        }
1105
1106        uint32_t frameDuration;
1107        if (inputBufferHeader->nTimeStamp > mLastTimestamp) {
1108            frameDuration = (uint32_t)(inputBufferHeader->nTimeStamp - mLastTimestamp);
1109        } else {
1110            frameDuration = (uint32_t)(((uint64_t)1000000 << 16) / mFramerate);
1111        }
1112        mLastTimestamp = inputBufferHeader->nTimeStamp;
1113        codec_return = vpx_codec_encode(
1114                mCodecContext,
1115                &raw_frame,
1116                inputBufferHeader->nTimeStamp,  // in timebase units
1117                frameDuration,  // frame duration in timebase units
1118                flags,  // frame flags
1119                VPX_DL_REALTIME);  // encoding deadline
1120        if (codec_return != VPX_CODEC_OK) {
1121            ALOGE("vpx encoder failed to encode frame");
1122            notify(OMX_EventError,
1123                   OMX_ErrorUndefined,
1124                   0,  // Extra notification data
1125                   NULL);  // Notification data pointer
1126            return;
1127        }
1128
1129        vpx_codec_iter_t encoded_packet_iterator = NULL;
1130        const vpx_codec_cx_pkt_t* encoded_packet;
1131
1132        while ((encoded_packet = vpx_codec_get_cx_data(
1133                        mCodecContext, &encoded_packet_iterator))) {
1134            if (encoded_packet->kind == VPX_CODEC_CX_FRAME_PKT) {
1135                outputBufferHeader->nTimeStamp = encoded_packet->data.frame.pts;
1136                outputBufferHeader->nFlags = 0;
1137                if (encoded_packet->data.frame.flags & VPX_FRAME_IS_KEY)
1138                  outputBufferHeader->nFlags |= OMX_BUFFERFLAG_SYNCFRAME;
1139                outputBufferHeader->nOffset = 0;
1140                outputBufferHeader->nFilledLen = encoded_packet->data.frame.sz;
1141                memcpy(outputBufferHeader->pBuffer,
1142                       encoded_packet->data.frame.buf,
1143                       encoded_packet->data.frame.sz);
1144                outputBufferInfo->mOwnedByUs = false;
1145                outputBufferInfoQueue.erase(outputBufferInfoQueue.begin());
1146                notifyFillBufferDone(outputBufferHeader);
1147            }
1148        }
1149
1150        inputBufferInfo->mOwnedByUs = false;
1151        inputBufferInfoQueue.erase(inputBufferInfoQueue.begin());
1152        notifyEmptyBufferDone(inputBufferHeader);
1153    }
1154}
1155
1156OMX_ERRORTYPE SoftVPXEncoder::getExtensionIndex(
1157        const char *name, OMX_INDEXTYPE *index) {
1158    if (!strcmp(name, "OMX.google.android.index.storeMetaDataInBuffers")) {
1159        *(int32_t*)index = kStoreMetaDataExtensionIndex;
1160        return OMX_ErrorNone;
1161    }
1162    return SimpleSoftOMXComponent::getExtensionIndex(name, index);
1163}
1164
1165}  // namespace android
1166
1167
1168android::SoftOMXComponent *createSoftOMXComponent(
1169        const char *name, const OMX_CALLBACKTYPE *callbacks,
1170        OMX_PTR appData, OMX_COMPONENTTYPE **component) {
1171    return new android::SoftVPXEncoder(name, callbacks, appData, component);
1172}
1173