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