142ef0c715da879a9878b7bf4eb9c90b21e4ab8aeJames Dong/*
242ef0c715da879a9878b7bf4eb9c90b21e4ab8aeJames Dong * Copyright (C) 2010 The Android Open Source Project
342ef0c715da879a9878b7bf4eb9c90b21e4ab8aeJames Dong *
442ef0c715da879a9878b7bf4eb9c90b21e4ab8aeJames Dong * Licensed under the Apache License, Version 2.0 (the "License");
542ef0c715da879a9878b7bf4eb9c90b21e4ab8aeJames Dong * you may not use this file except in compliance with the License.
642ef0c715da879a9878b7bf4eb9c90b21e4ab8aeJames Dong * You may obtain a copy of the License at
742ef0c715da879a9878b7bf4eb9c90b21e4ab8aeJames Dong *
842ef0c715da879a9878b7bf4eb9c90b21e4ab8aeJames Dong *      http://www.apache.org/licenses/LICENSE-2.0
942ef0c715da879a9878b7bf4eb9c90b21e4ab8aeJames Dong *
1042ef0c715da879a9878b7bf4eb9c90b21e4ab8aeJames Dong * Unless required by applicable law or agreed to in writing, software
1142ef0c715da879a9878b7bf4eb9c90b21e4ab8aeJames Dong * distributed under the License is distributed on an "AS IS" BASIS,
1242ef0c715da879a9878b7bf4eb9c90b21e4ab8aeJames Dong * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
1342ef0c715da879a9878b7bf4eb9c90b21e4ab8aeJames Dong * See the License for the specific language governing permissions and
1442ef0c715da879a9878b7bf4eb9c90b21e4ab8aeJames Dong * limitations under the License.
1542ef0c715da879a9878b7bf4eb9c90b21e4ab8aeJames Dong */
1642ef0c715da879a9878b7bf4eb9c90b21e4ab8aeJames Dong
1742ef0c715da879a9878b7bf4eb9c90b21e4ab8aeJames Dong//#define LOG_NDEBUG 0
1842ef0c715da879a9878b7bf4eb9c90b21e4ab8aeJames Dong#define LOG_TAG "M4vH263Encoder"
1942ef0c715da879a9878b7bf4eb9c90b21e4ab8aeJames Dong#include <utils/Log.h>
2042ef0c715da879a9878b7bf4eb9c90b21e4ab8aeJames Dong
2142ef0c715da879a9878b7bf4eb9c90b21e4ab8aeJames Dong#include "M4vH263Encoder.h"
2242ef0c715da879a9878b7bf4eb9c90b21e4ab8aeJames Dong
2342ef0c715da879a9878b7bf4eb9c90b21e4ab8aeJames Dong#include "mp4enc_api.h"
2442ef0c715da879a9878b7bf4eb9c90b21e4ab8aeJames Dong#include "OMX_Video.h"
2542ef0c715da879a9878b7bf4eb9c90b21e4ab8aeJames Dong
2642ef0c715da879a9878b7bf4eb9c90b21e4ab8aeJames Dong#include <media/stagefright/MediaBufferGroup.h>
2742ef0c715da879a9878b7bf4eb9c90b21e4ab8aeJames Dong#include <media/stagefright/MediaDebug.h>
2842ef0c715da879a9878b7bf4eb9c90b21e4ab8aeJames Dong#include <media/stagefright/MediaDefs.h>
2942ef0c715da879a9878b7bf4eb9c90b21e4ab8aeJames Dong#include <media/stagefright/MediaErrors.h>
3042ef0c715da879a9878b7bf4eb9c90b21e4ab8aeJames Dong#include <media/stagefright/MetaData.h>
3142ef0c715da879a9878b7bf4eb9c90b21e4ab8aeJames Dong#include <media/stagefright/Utils.h>
3242ef0c715da879a9878b7bf4eb9c90b21e4ab8aeJames Dong
3342ef0c715da879a9878b7bf4eb9c90b21e4ab8aeJames Dongnamespace android {
3442ef0c715da879a9878b7bf4eb9c90b21e4ab8aeJames Dong
3542ef0c715da879a9878b7bf4eb9c90b21e4ab8aeJames Donginline static void ConvertYUV420SemiPlanarToYUV420Planar(
3642ef0c715da879a9878b7bf4eb9c90b21e4ab8aeJames Dong        uint8_t *inyuv, uint8_t* outyuv,
3742ef0c715da879a9878b7bf4eb9c90b21e4ab8aeJames Dong        int32_t width, int32_t height) {
3842ef0c715da879a9878b7bf4eb9c90b21e4ab8aeJames Dong
3942ef0c715da879a9878b7bf4eb9c90b21e4ab8aeJames Dong    int32_t outYsize = width * height;
4042ef0c715da879a9878b7bf4eb9c90b21e4ab8aeJames Dong    uint32_t *outy = (uint32_t *)  outyuv;
4142ef0c715da879a9878b7bf4eb9c90b21e4ab8aeJames Dong    uint16_t *outcb = (uint16_t *) (outyuv + outYsize);
4242ef0c715da879a9878b7bf4eb9c90b21e4ab8aeJames Dong    uint16_t *outcr = (uint16_t *) (outyuv + outYsize + (outYsize >> 2));
4342ef0c715da879a9878b7bf4eb9c90b21e4ab8aeJames Dong
4442ef0c715da879a9878b7bf4eb9c90b21e4ab8aeJames Dong    /* Y copying */
4542ef0c715da879a9878b7bf4eb9c90b21e4ab8aeJames Dong    memcpy(outy, inyuv, outYsize);
4642ef0c715da879a9878b7bf4eb9c90b21e4ab8aeJames Dong
4742ef0c715da879a9878b7bf4eb9c90b21e4ab8aeJames Dong    /* U & V copying */
4842ef0c715da879a9878b7bf4eb9c90b21e4ab8aeJames Dong    uint32_t *inyuv_4 = (uint32_t *) (inyuv + outYsize);
4942ef0c715da879a9878b7bf4eb9c90b21e4ab8aeJames Dong    for (int32_t i = height >> 1; i > 0; --i) {
5042ef0c715da879a9878b7bf4eb9c90b21e4ab8aeJames Dong        for (int32_t j = width >> 2; j > 0; --j) {
5142ef0c715da879a9878b7bf4eb9c90b21e4ab8aeJames Dong            uint32_t temp = *inyuv_4++;
5242ef0c715da879a9878b7bf4eb9c90b21e4ab8aeJames Dong            uint32_t tempU = temp & 0xFF;
5342ef0c715da879a9878b7bf4eb9c90b21e4ab8aeJames Dong            tempU = tempU | ((temp >> 8) & 0xFF00);
5442ef0c715da879a9878b7bf4eb9c90b21e4ab8aeJames Dong
5542ef0c715da879a9878b7bf4eb9c90b21e4ab8aeJames Dong            uint32_t tempV = (temp >> 8) & 0xFF;
5642ef0c715da879a9878b7bf4eb9c90b21e4ab8aeJames Dong            tempV = tempV | ((temp >> 16) & 0xFF00);
5742ef0c715da879a9878b7bf4eb9c90b21e4ab8aeJames Dong
5842ef0c715da879a9878b7bf4eb9c90b21e4ab8aeJames Dong            // Flip U and V
5942ef0c715da879a9878b7bf4eb9c90b21e4ab8aeJames Dong            *outcb++ = tempV;
6042ef0c715da879a9878b7bf4eb9c90b21e4ab8aeJames Dong            *outcr++ = tempU;
6142ef0c715da879a9878b7bf4eb9c90b21e4ab8aeJames Dong        }
6242ef0c715da879a9878b7bf4eb9c90b21e4ab8aeJames Dong    }
6342ef0c715da879a9878b7bf4eb9c90b21e4ab8aeJames Dong}
6442ef0c715da879a9878b7bf4eb9c90b21e4ab8aeJames Dong
6542ef0c715da879a9878b7bf4eb9c90b21e4ab8aeJames DongM4vH263Encoder::M4vH263Encoder(
6642ef0c715da879a9878b7bf4eb9c90b21e4ab8aeJames Dong        const sp<MediaSource>& source,
6742ef0c715da879a9878b7bf4eb9c90b21e4ab8aeJames Dong        const sp<MetaData>& meta)
6842ef0c715da879a9878b7bf4eb9c90b21e4ab8aeJames Dong    : mSource(source),
6942ef0c715da879a9878b7bf4eb9c90b21e4ab8aeJames Dong      mMeta(meta),
7042ef0c715da879a9878b7bf4eb9c90b21e4ab8aeJames Dong      mNumInputFrames(-1),
7142ef0c715da879a9878b7bf4eb9c90b21e4ab8aeJames Dong      mNextModTimeUs(0),
72e95d192fae5a80ed821c53bfea214a85ea395e90James Dong      mPrevTimestampUs(-1),
7342ef0c715da879a9878b7bf4eb9c90b21e4ab8aeJames Dong      mStarted(false),
7442ef0c715da879a9878b7bf4eb9c90b21e4ab8aeJames Dong      mInputBuffer(NULL),
7542ef0c715da879a9878b7bf4eb9c90b21e4ab8aeJames Dong      mInputFrameData(NULL),
7642ef0c715da879a9878b7bf4eb9c90b21e4ab8aeJames Dong      mGroup(NULL) {
7742ef0c715da879a9878b7bf4eb9c90b21e4ab8aeJames Dong
7842ef0c715da879a9878b7bf4eb9c90b21e4ab8aeJames Dong    LOGV("Construct software M4vH263Encoder");
7942ef0c715da879a9878b7bf4eb9c90b21e4ab8aeJames Dong
8042ef0c715da879a9878b7bf4eb9c90b21e4ab8aeJames Dong    mHandle = new tagvideoEncControls;
8142ef0c715da879a9878b7bf4eb9c90b21e4ab8aeJames Dong    memset(mHandle, 0, sizeof(tagvideoEncControls));
8242ef0c715da879a9878b7bf4eb9c90b21e4ab8aeJames Dong
8342ef0c715da879a9878b7bf4eb9c90b21e4ab8aeJames Dong    mInitCheck = initCheck(meta);
8442ef0c715da879a9878b7bf4eb9c90b21e4ab8aeJames Dong}
8542ef0c715da879a9878b7bf4eb9c90b21e4ab8aeJames Dong
8642ef0c715da879a9878b7bf4eb9c90b21e4ab8aeJames DongM4vH263Encoder::~M4vH263Encoder() {
8742ef0c715da879a9878b7bf4eb9c90b21e4ab8aeJames Dong    LOGV("Destruct software M4vH263Encoder");
8842ef0c715da879a9878b7bf4eb9c90b21e4ab8aeJames Dong    if (mStarted) {
8942ef0c715da879a9878b7bf4eb9c90b21e4ab8aeJames Dong        stop();
9042ef0c715da879a9878b7bf4eb9c90b21e4ab8aeJames Dong    }
9142ef0c715da879a9878b7bf4eb9c90b21e4ab8aeJames Dong
9242ef0c715da879a9878b7bf4eb9c90b21e4ab8aeJames Dong    delete mEncParams;
9342ef0c715da879a9878b7bf4eb9c90b21e4ab8aeJames Dong    delete mHandle;
9442ef0c715da879a9878b7bf4eb9c90b21e4ab8aeJames Dong}
9542ef0c715da879a9878b7bf4eb9c90b21e4ab8aeJames Dong
9642ef0c715da879a9878b7bf4eb9c90b21e4ab8aeJames Dongstatus_t M4vH263Encoder::initCheck(const sp<MetaData>& meta) {
9742ef0c715da879a9878b7bf4eb9c90b21e4ab8aeJames Dong    LOGV("initCheck");
9842ef0c715da879a9878b7bf4eb9c90b21e4ab8aeJames Dong    CHECK(meta->findInt32(kKeyWidth, &mVideoWidth));
9942ef0c715da879a9878b7bf4eb9c90b21e4ab8aeJames Dong    CHECK(meta->findInt32(kKeyHeight, &mVideoHeight));
10042ef0c715da879a9878b7bf4eb9c90b21e4ab8aeJames Dong    CHECK(meta->findInt32(kKeySampleRate, &mVideoFrameRate));
10142ef0c715da879a9878b7bf4eb9c90b21e4ab8aeJames Dong    CHECK(meta->findInt32(kKeyBitRate, &mVideoBitRate));
10242ef0c715da879a9878b7bf4eb9c90b21e4ab8aeJames Dong
10342ef0c715da879a9878b7bf4eb9c90b21e4ab8aeJames Dong    // XXX: Add more color format support
10442ef0c715da879a9878b7bf4eb9c90b21e4ab8aeJames Dong    CHECK(meta->findInt32(kKeyColorFormat, &mVideoColorFormat));
10542ef0c715da879a9878b7bf4eb9c90b21e4ab8aeJames Dong    if (mVideoColorFormat != OMX_COLOR_FormatYUV420Planar) {
10642ef0c715da879a9878b7bf4eb9c90b21e4ab8aeJames Dong        if (mVideoColorFormat != OMX_COLOR_FormatYUV420SemiPlanar) {
10742ef0c715da879a9878b7bf4eb9c90b21e4ab8aeJames Dong            LOGE("Color format %d is not supported", mVideoColorFormat);
10842ef0c715da879a9878b7bf4eb9c90b21e4ab8aeJames Dong            return BAD_VALUE;
10942ef0c715da879a9878b7bf4eb9c90b21e4ab8aeJames Dong        }
11042ef0c715da879a9878b7bf4eb9c90b21e4ab8aeJames Dong        // Allocate spare buffer only when color conversion is needed.
11142ef0c715da879a9878b7bf4eb9c90b21e4ab8aeJames Dong        // Assume the color format is OMX_COLOR_FormatYUV420SemiPlanar.
11242ef0c715da879a9878b7bf4eb9c90b21e4ab8aeJames Dong        mInputFrameData =
11342ef0c715da879a9878b7bf4eb9c90b21e4ab8aeJames Dong            (uint8_t *) malloc((mVideoWidth * mVideoHeight * 3 ) >> 1);
11442ef0c715da879a9878b7bf4eb9c90b21e4ab8aeJames Dong        CHECK(mInputFrameData);
11542ef0c715da879a9878b7bf4eb9c90b21e4ab8aeJames Dong    }
11642ef0c715da879a9878b7bf4eb9c90b21e4ab8aeJames Dong
11742ef0c715da879a9878b7bf4eb9c90b21e4ab8aeJames Dong    // XXX: Remove this restriction
11842ef0c715da879a9878b7bf4eb9c90b21e4ab8aeJames Dong    if (mVideoWidth % 16 != 0 || mVideoHeight % 16 != 0) {
11942ef0c715da879a9878b7bf4eb9c90b21e4ab8aeJames Dong        LOGE("Video frame size %dx%d must be a multiple of 16",
12042ef0c715da879a9878b7bf4eb9c90b21e4ab8aeJames Dong            mVideoWidth, mVideoHeight);
12142ef0c715da879a9878b7bf4eb9c90b21e4ab8aeJames Dong        return BAD_VALUE;
12242ef0c715da879a9878b7bf4eb9c90b21e4ab8aeJames Dong    }
12342ef0c715da879a9878b7bf4eb9c90b21e4ab8aeJames Dong
12442ef0c715da879a9878b7bf4eb9c90b21e4ab8aeJames Dong    mEncParams = new tagvideoEncOptions;
12542ef0c715da879a9878b7bf4eb9c90b21e4ab8aeJames Dong    memset(mEncParams, 0, sizeof(tagvideoEncOptions));
12642ef0c715da879a9878b7bf4eb9c90b21e4ab8aeJames Dong    if (!PVGetDefaultEncOption(mEncParams, 0)) {
12742ef0c715da879a9878b7bf4eb9c90b21e4ab8aeJames Dong        LOGE("Failed to get default encoding parameters");
12842ef0c715da879a9878b7bf4eb9c90b21e4ab8aeJames Dong        return BAD_VALUE;
12942ef0c715da879a9878b7bf4eb9c90b21e4ab8aeJames Dong    }
13042ef0c715da879a9878b7bf4eb9c90b21e4ab8aeJames Dong
13142ef0c715da879a9878b7bf4eb9c90b21e4ab8aeJames Dong    // Need to know which role the encoder is in.
13242ef0c715da879a9878b7bf4eb9c90b21e4ab8aeJames Dong    // XXX: Set the mode proper for other types of applications
13342ef0c715da879a9878b7bf4eb9c90b21e4ab8aeJames Dong    //      like streaming or video conference
13442ef0c715da879a9878b7bf4eb9c90b21e4ab8aeJames Dong    const char *mime;
13542ef0c715da879a9878b7bf4eb9c90b21e4ab8aeJames Dong    CHECK(meta->findCString(kKeyMIMEType, &mime));
13642ef0c715da879a9878b7bf4eb9c90b21e4ab8aeJames Dong    CHECK(!strcmp(mime, MEDIA_MIMETYPE_VIDEO_MPEG4) ||
13742ef0c715da879a9878b7bf4eb9c90b21e4ab8aeJames Dong          !strcmp(mime, MEDIA_MIMETYPE_VIDEO_H263));
13842ef0c715da879a9878b7bf4eb9c90b21e4ab8aeJames Dong    if (!strcmp(mime, MEDIA_MIMETYPE_VIDEO_MPEG4)) {
13942ef0c715da879a9878b7bf4eb9c90b21e4ab8aeJames Dong        mEncParams->encMode = COMBINE_MODE_WITH_ERR_RES;
14042ef0c715da879a9878b7bf4eb9c90b21e4ab8aeJames Dong    } else {
14142ef0c715da879a9878b7bf4eb9c90b21e4ab8aeJames Dong        mEncParams->encMode = H263_MODE;
14242ef0c715da879a9878b7bf4eb9c90b21e4ab8aeJames Dong    }
14342ef0c715da879a9878b7bf4eb9c90b21e4ab8aeJames Dong    mEncParams->encWidth[0] = mVideoWidth;
14442ef0c715da879a9878b7bf4eb9c90b21e4ab8aeJames Dong    mEncParams->encHeight[0] = mVideoHeight;
14542ef0c715da879a9878b7bf4eb9c90b21e4ab8aeJames Dong    mEncParams->encFrameRate[0] = mVideoFrameRate;
14642ef0c715da879a9878b7bf4eb9c90b21e4ab8aeJames Dong    mEncParams->rcType = VBR_1;
14742ef0c715da879a9878b7bf4eb9c90b21e4ab8aeJames Dong    mEncParams->vbvDelay = (float)5.0;
14842ef0c715da879a9878b7bf4eb9c90b21e4ab8aeJames Dong
14942ef0c715da879a9878b7bf4eb9c90b21e4ab8aeJames Dong    // Set profile and level
15042ef0c715da879a9878b7bf4eb9c90b21e4ab8aeJames Dong    // If profile and level setting is not correct, failure
15142ef0c715da879a9878b7bf4eb9c90b21e4ab8aeJames Dong    // is reported when the encoder is initialized.
15242ef0c715da879a9878b7bf4eb9c90b21e4ab8aeJames Dong    mEncParams->profile_level = CORE_PROFILE_LEVEL2;
15342ef0c715da879a9878b7bf4eb9c90b21e4ab8aeJames Dong    int32_t profileLevel;
15442ef0c715da879a9878b7bf4eb9c90b21e4ab8aeJames Dong    if (meta->findInt32(kKeyVideoLevel, &profileLevel)) {
15542ef0c715da879a9878b7bf4eb9c90b21e4ab8aeJames Dong        mEncParams->profile_level = (ProfileLevelType)profileLevel;
15642ef0c715da879a9878b7bf4eb9c90b21e4ab8aeJames Dong    }
15742ef0c715da879a9878b7bf4eb9c90b21e4ab8aeJames Dong
15842ef0c715da879a9878b7bf4eb9c90b21e4ab8aeJames Dong    mEncParams->packetSize = 32;
15942ef0c715da879a9878b7bf4eb9c90b21e4ab8aeJames Dong    mEncParams->rvlcEnable = PV_OFF;
16042ef0c715da879a9878b7bf4eb9c90b21e4ab8aeJames Dong    mEncParams->numLayers = 1;
16142ef0c715da879a9878b7bf4eb9c90b21e4ab8aeJames Dong    mEncParams->timeIncRes = 1000;
16242ef0c715da879a9878b7bf4eb9c90b21e4ab8aeJames Dong    mEncParams->tickPerSrc = mEncParams->timeIncRes / mVideoFrameRate;
16342ef0c715da879a9878b7bf4eb9c90b21e4ab8aeJames Dong
16442ef0c715da879a9878b7bf4eb9c90b21e4ab8aeJames Dong    mEncParams->bitRate[0] = mVideoBitRate;
16542ef0c715da879a9878b7bf4eb9c90b21e4ab8aeJames Dong    mEncParams->iQuant[0] = 15;
16642ef0c715da879a9878b7bf4eb9c90b21e4ab8aeJames Dong    mEncParams->pQuant[0] = 12;
16742ef0c715da879a9878b7bf4eb9c90b21e4ab8aeJames Dong    mEncParams->quantType[0] = 0;
16842ef0c715da879a9878b7bf4eb9c90b21e4ab8aeJames Dong    mEncParams->noFrameSkipped = PV_OFF;
16942ef0c715da879a9878b7bf4eb9c90b21e4ab8aeJames Dong
17042ef0c715da879a9878b7bf4eb9c90b21e4ab8aeJames Dong    // Set IDR frame refresh interval
17142ef0c715da879a9878b7bf4eb9c90b21e4ab8aeJames Dong    int32_t iFramesIntervalSec;
17242ef0c715da879a9878b7bf4eb9c90b21e4ab8aeJames Dong    CHECK(meta->findInt32(kKeyIFramesInterval, &iFramesIntervalSec));
17342ef0c715da879a9878b7bf4eb9c90b21e4ab8aeJames Dong    if (iFramesIntervalSec < 0) {
17442ef0c715da879a9878b7bf4eb9c90b21e4ab8aeJames Dong        mEncParams->intraPeriod = -1;
17542ef0c715da879a9878b7bf4eb9c90b21e4ab8aeJames Dong    } else if (iFramesIntervalSec == 0) {
17642ef0c715da879a9878b7bf4eb9c90b21e4ab8aeJames Dong        mEncParams->intraPeriod = 1;  // All I frames
17742ef0c715da879a9878b7bf4eb9c90b21e4ab8aeJames Dong    } else {
17842ef0c715da879a9878b7bf4eb9c90b21e4ab8aeJames Dong        mEncParams->intraPeriod =
17942ef0c715da879a9878b7bf4eb9c90b21e4ab8aeJames Dong            (iFramesIntervalSec * mVideoFrameRate);
18042ef0c715da879a9878b7bf4eb9c90b21e4ab8aeJames Dong    }
18142ef0c715da879a9878b7bf4eb9c90b21e4ab8aeJames Dong
18242ef0c715da879a9878b7bf4eb9c90b21e4ab8aeJames Dong    mEncParams->numIntraMB = 0;
18342ef0c715da879a9878b7bf4eb9c90b21e4ab8aeJames Dong    mEncParams->sceneDetect = PV_ON;
18442ef0c715da879a9878b7bf4eb9c90b21e4ab8aeJames Dong    mEncParams->searchRange = 16;
18542ef0c715da879a9878b7bf4eb9c90b21e4ab8aeJames Dong    mEncParams->mv8x8Enable = PV_OFF;
18642ef0c715da879a9878b7bf4eb9c90b21e4ab8aeJames Dong    mEncParams->gobHeaderInterval = 0;
18742ef0c715da879a9878b7bf4eb9c90b21e4ab8aeJames Dong    mEncParams->useACPred = PV_ON;
18842ef0c715da879a9878b7bf4eb9c90b21e4ab8aeJames Dong    mEncParams->intraDCVlcTh = 0;
18942ef0c715da879a9878b7bf4eb9c90b21e4ab8aeJames Dong
19042ef0c715da879a9878b7bf4eb9c90b21e4ab8aeJames Dong    mFormat = new MetaData;
19142ef0c715da879a9878b7bf4eb9c90b21e4ab8aeJames Dong    mFormat->setInt32(kKeyWidth, mVideoWidth);
19242ef0c715da879a9878b7bf4eb9c90b21e4ab8aeJames Dong    mFormat->setInt32(kKeyHeight, mVideoHeight);
19342ef0c715da879a9878b7bf4eb9c90b21e4ab8aeJames Dong    mFormat->setInt32(kKeyBitRate, mVideoBitRate);
19442ef0c715da879a9878b7bf4eb9c90b21e4ab8aeJames Dong    mFormat->setInt32(kKeySampleRate, mVideoFrameRate);
19542ef0c715da879a9878b7bf4eb9c90b21e4ab8aeJames Dong    mFormat->setInt32(kKeyColorFormat, mVideoColorFormat);
19642ef0c715da879a9878b7bf4eb9c90b21e4ab8aeJames Dong
19742ef0c715da879a9878b7bf4eb9c90b21e4ab8aeJames Dong    mFormat->setCString(kKeyMIMEType, mime);
19842ef0c715da879a9878b7bf4eb9c90b21e4ab8aeJames Dong    mFormat->setCString(kKeyDecoderComponent, "M4vH263Encoder");
19942ef0c715da879a9878b7bf4eb9c90b21e4ab8aeJames Dong    return OK;
20042ef0c715da879a9878b7bf4eb9c90b21e4ab8aeJames Dong}
20142ef0c715da879a9878b7bf4eb9c90b21e4ab8aeJames Dong
20242ef0c715da879a9878b7bf4eb9c90b21e4ab8aeJames Dongstatus_t M4vH263Encoder::start(MetaData *params) {
20342ef0c715da879a9878b7bf4eb9c90b21e4ab8aeJames Dong    LOGV("start");
20442ef0c715da879a9878b7bf4eb9c90b21e4ab8aeJames Dong    if (mInitCheck != OK) {
20542ef0c715da879a9878b7bf4eb9c90b21e4ab8aeJames Dong        return mInitCheck;
20642ef0c715da879a9878b7bf4eb9c90b21e4ab8aeJames Dong    }
20742ef0c715da879a9878b7bf4eb9c90b21e4ab8aeJames Dong
20842ef0c715da879a9878b7bf4eb9c90b21e4ab8aeJames Dong    if (mStarted) {
20942ef0c715da879a9878b7bf4eb9c90b21e4ab8aeJames Dong        LOGW("Call start() when encoder already started");
21042ef0c715da879a9878b7bf4eb9c90b21e4ab8aeJames Dong        return OK;
21142ef0c715da879a9878b7bf4eb9c90b21e4ab8aeJames Dong    }
21242ef0c715da879a9878b7bf4eb9c90b21e4ab8aeJames Dong
21342ef0c715da879a9878b7bf4eb9c90b21e4ab8aeJames Dong    if (!PVInitVideoEncoder(mHandle, mEncParams)) {
21442ef0c715da879a9878b7bf4eb9c90b21e4ab8aeJames Dong        LOGE("Failed to initialize the encoder");
21542ef0c715da879a9878b7bf4eb9c90b21e4ab8aeJames Dong        return UNKNOWN_ERROR;
21642ef0c715da879a9878b7bf4eb9c90b21e4ab8aeJames Dong    }
21742ef0c715da879a9878b7bf4eb9c90b21e4ab8aeJames Dong
21842ef0c715da879a9878b7bf4eb9c90b21e4ab8aeJames Dong    mGroup = new MediaBufferGroup();
21942ef0c715da879a9878b7bf4eb9c90b21e4ab8aeJames Dong    int32_t maxSize;
22042ef0c715da879a9878b7bf4eb9c90b21e4ab8aeJames Dong    if (!PVGetMaxVideoFrameSize(mHandle, &maxSize)) {
22142ef0c715da879a9878b7bf4eb9c90b21e4ab8aeJames Dong        maxSize = 256 * 1024;  // Magic #
22242ef0c715da879a9878b7bf4eb9c90b21e4ab8aeJames Dong    }
22342ef0c715da879a9878b7bf4eb9c90b21e4ab8aeJames Dong    LOGV("Max output buffer size: %d", maxSize);
22442ef0c715da879a9878b7bf4eb9c90b21e4ab8aeJames Dong    mGroup->add_buffer(new MediaBuffer(maxSize));
22542ef0c715da879a9878b7bf4eb9c90b21e4ab8aeJames Dong
22642ef0c715da879a9878b7bf4eb9c90b21e4ab8aeJames Dong    mSource->start(params);
22742ef0c715da879a9878b7bf4eb9c90b21e4ab8aeJames Dong    mNumInputFrames = -1;  // 1st frame contains codec specific data
22842ef0c715da879a9878b7bf4eb9c90b21e4ab8aeJames Dong    mStarted = true;
22942ef0c715da879a9878b7bf4eb9c90b21e4ab8aeJames Dong
23042ef0c715da879a9878b7bf4eb9c90b21e4ab8aeJames Dong    return OK;
23142ef0c715da879a9878b7bf4eb9c90b21e4ab8aeJames Dong}
23242ef0c715da879a9878b7bf4eb9c90b21e4ab8aeJames Dong
23342ef0c715da879a9878b7bf4eb9c90b21e4ab8aeJames Dongstatus_t M4vH263Encoder::stop() {
23442ef0c715da879a9878b7bf4eb9c90b21e4ab8aeJames Dong    LOGV("stop");
23542ef0c715da879a9878b7bf4eb9c90b21e4ab8aeJames Dong    if (!mStarted) {
23642ef0c715da879a9878b7bf4eb9c90b21e4ab8aeJames Dong        LOGW("Call stop() when encoder has not started");
23742ef0c715da879a9878b7bf4eb9c90b21e4ab8aeJames Dong        return OK;
23842ef0c715da879a9878b7bf4eb9c90b21e4ab8aeJames Dong    }
23942ef0c715da879a9878b7bf4eb9c90b21e4ab8aeJames Dong
24042ef0c715da879a9878b7bf4eb9c90b21e4ab8aeJames Dong    if (mInputBuffer) {
24142ef0c715da879a9878b7bf4eb9c90b21e4ab8aeJames Dong        mInputBuffer->release();
24242ef0c715da879a9878b7bf4eb9c90b21e4ab8aeJames Dong        mInputBuffer = NULL;
24342ef0c715da879a9878b7bf4eb9c90b21e4ab8aeJames Dong    }
24442ef0c715da879a9878b7bf4eb9c90b21e4ab8aeJames Dong
24542ef0c715da879a9878b7bf4eb9c90b21e4ab8aeJames Dong    if (mGroup) {
24642ef0c715da879a9878b7bf4eb9c90b21e4ab8aeJames Dong        delete mGroup;
24742ef0c715da879a9878b7bf4eb9c90b21e4ab8aeJames Dong        mGroup = NULL;
24842ef0c715da879a9878b7bf4eb9c90b21e4ab8aeJames Dong    }
24942ef0c715da879a9878b7bf4eb9c90b21e4ab8aeJames Dong
25042ef0c715da879a9878b7bf4eb9c90b21e4ab8aeJames Dong    if (mInputFrameData) {
25142ef0c715da879a9878b7bf4eb9c90b21e4ab8aeJames Dong        delete mInputFrameData;
25242ef0c715da879a9878b7bf4eb9c90b21e4ab8aeJames Dong        mInputFrameData = NULL;
25342ef0c715da879a9878b7bf4eb9c90b21e4ab8aeJames Dong    }
25442ef0c715da879a9878b7bf4eb9c90b21e4ab8aeJames Dong
25542ef0c715da879a9878b7bf4eb9c90b21e4ab8aeJames Dong    CHECK(PVCleanUpVideoEncoder(mHandle));
25642ef0c715da879a9878b7bf4eb9c90b21e4ab8aeJames Dong
25742ef0c715da879a9878b7bf4eb9c90b21e4ab8aeJames Dong    mSource->stop();
25842ef0c715da879a9878b7bf4eb9c90b21e4ab8aeJames Dong    mStarted = false;
25942ef0c715da879a9878b7bf4eb9c90b21e4ab8aeJames Dong
26042ef0c715da879a9878b7bf4eb9c90b21e4ab8aeJames Dong    return OK;
26142ef0c715da879a9878b7bf4eb9c90b21e4ab8aeJames Dong}
26242ef0c715da879a9878b7bf4eb9c90b21e4ab8aeJames Dong
26342ef0c715da879a9878b7bf4eb9c90b21e4ab8aeJames Dongsp<MetaData> M4vH263Encoder::getFormat() {
26442ef0c715da879a9878b7bf4eb9c90b21e4ab8aeJames Dong    LOGV("getFormat");
26542ef0c715da879a9878b7bf4eb9c90b21e4ab8aeJames Dong    return mFormat;
26642ef0c715da879a9878b7bf4eb9c90b21e4ab8aeJames Dong}
26742ef0c715da879a9878b7bf4eb9c90b21e4ab8aeJames Dong
26842ef0c715da879a9878b7bf4eb9c90b21e4ab8aeJames Dongstatus_t M4vH263Encoder::read(
26942ef0c715da879a9878b7bf4eb9c90b21e4ab8aeJames Dong        MediaBuffer **out, const ReadOptions *options) {
27042ef0c715da879a9878b7bf4eb9c90b21e4ab8aeJames Dong
27142ef0c715da879a9878b7bf4eb9c90b21e4ab8aeJames Dong    *out = NULL;
27242ef0c715da879a9878b7bf4eb9c90b21e4ab8aeJames Dong
27342ef0c715da879a9878b7bf4eb9c90b21e4ab8aeJames Dong    MediaBuffer *outputBuffer;
27442ef0c715da879a9878b7bf4eb9c90b21e4ab8aeJames Dong    CHECK_EQ(OK, mGroup->acquire_buffer(&outputBuffer));
27542ef0c715da879a9878b7bf4eb9c90b21e4ab8aeJames Dong    uint8_t *outPtr = (uint8_t *) outputBuffer->data();
27642ef0c715da879a9878b7bf4eb9c90b21e4ab8aeJames Dong    int32_t dataLength = outputBuffer->size();
27742ef0c715da879a9878b7bf4eb9c90b21e4ab8aeJames Dong
27842ef0c715da879a9878b7bf4eb9c90b21e4ab8aeJames Dong    // Output codec specific data
27942ef0c715da879a9878b7bf4eb9c90b21e4ab8aeJames Dong    if (mNumInputFrames < 0) {
28042ef0c715da879a9878b7bf4eb9c90b21e4ab8aeJames Dong        if (!PVGetVolHeader(mHandle, outPtr, &dataLength, 0)) {
28142ef0c715da879a9878b7bf4eb9c90b21e4ab8aeJames Dong            LOGE("Failed to get VOL header");
28242ef0c715da879a9878b7bf4eb9c90b21e4ab8aeJames Dong            return UNKNOWN_ERROR;
28342ef0c715da879a9878b7bf4eb9c90b21e4ab8aeJames Dong        }
28442ef0c715da879a9878b7bf4eb9c90b21e4ab8aeJames Dong        LOGV("Output VOL header: %d bytes", dataLength);
28542ef0c715da879a9878b7bf4eb9c90b21e4ab8aeJames Dong        outputBuffer->meta_data()->setInt32(kKeyIsCodecConfig, 1);
28642ef0c715da879a9878b7bf4eb9c90b21e4ab8aeJames Dong        outputBuffer->set_range(0, dataLength);
28742ef0c715da879a9878b7bf4eb9c90b21e4ab8aeJames Dong        *out = outputBuffer;
28842ef0c715da879a9878b7bf4eb9c90b21e4ab8aeJames Dong        ++mNumInputFrames;
28942ef0c715da879a9878b7bf4eb9c90b21e4ab8aeJames Dong        return OK;
29042ef0c715da879a9878b7bf4eb9c90b21e4ab8aeJames Dong    }
29142ef0c715da879a9878b7bf4eb9c90b21e4ab8aeJames Dong
29242ef0c715da879a9878b7bf4eb9c90b21e4ab8aeJames Dong    // Ready for accepting an input video frame
29342ef0c715da879a9878b7bf4eb9c90b21e4ab8aeJames Dong    if (OK != mSource->read(&mInputBuffer, options)) {
29442ef0c715da879a9878b7bf4eb9c90b21e4ab8aeJames Dong        LOGE("Failed to read from data source");
29542ef0c715da879a9878b7bf4eb9c90b21e4ab8aeJames Dong        outputBuffer->release();
29642ef0c715da879a9878b7bf4eb9c90b21e4ab8aeJames Dong        return UNKNOWN_ERROR;
29742ef0c715da879a9878b7bf4eb9c90b21e4ab8aeJames Dong    }
298e6daea5940c38267d24a39fc32bffa119132e852James Dong
299e6daea5940c38267d24a39fc32bffa119132e852James Dong    if (mInputBuffer->size() - ((mVideoWidth * mVideoHeight * 3) >> 1) != 0) {
300e6daea5940c38267d24a39fc32bffa119132e852James Dong        outputBuffer->release();
301e6daea5940c38267d24a39fc32bffa119132e852James Dong        mInputBuffer->release();
302e6daea5940c38267d24a39fc32bffa119132e852James Dong        mInputBuffer = NULL;
303e6daea5940c38267d24a39fc32bffa119132e852James Dong        return UNKNOWN_ERROR;
304e6daea5940c38267d24a39fc32bffa119132e852James Dong    }
305e6daea5940c38267d24a39fc32bffa119132e852James Dong
30642ef0c715da879a9878b7bf4eb9c90b21e4ab8aeJames Dong    int64_t timeUs;
30742ef0c715da879a9878b7bf4eb9c90b21e4ab8aeJames Dong    CHECK(mInputBuffer->meta_data()->findInt64(kKeyTime, &timeUs));
308708ec39c21568e0c2aa3d20c681f0e14ee6134adJames Dong
309708ec39c21568e0c2aa3d20c681f0e14ee6134adJames Dong    // When the timestamp of the current sample is the same as that
310708ec39c21568e0c2aa3d20c681f0e14ee6134adJames Dong    // of the previous sample, encoding of the current sample is
311708ec39c21568e0c2aa3d20c681f0e14ee6134adJames Dong    // bypassed, and the output length of the sample is set to 0
312708ec39c21568e0c2aa3d20c681f0e14ee6134adJames Dong    if (mNumInputFrames >= 1 &&
313708ec39c21568e0c2aa3d20c681f0e14ee6134adJames Dong        (mNextModTimeUs > timeUs || mPrevTimestampUs == timeUs)) {
314708ec39c21568e0c2aa3d20c681f0e14ee6134adJames Dong        // Frame arrives too late
31542ef0c715da879a9878b7bf4eb9c90b21e4ab8aeJames Dong        outputBuffer->set_range(0, 0);
31642ef0c715da879a9878b7bf4eb9c90b21e4ab8aeJames Dong        *out = outputBuffer;
31742ef0c715da879a9878b7bf4eb9c90b21e4ab8aeJames Dong        mInputBuffer->release();
31842ef0c715da879a9878b7bf4eb9c90b21e4ab8aeJames Dong        mInputBuffer = NULL;
31942ef0c715da879a9878b7bf4eb9c90b21e4ab8aeJames Dong        return OK;
32042ef0c715da879a9878b7bf4eb9c90b21e4ab8aeJames Dong    }
32142ef0c715da879a9878b7bf4eb9c90b21e4ab8aeJames Dong
322708ec39c21568e0c2aa3d20c681f0e14ee6134adJames Dong    // Don't accept out-of-order samples
323708ec39c21568e0c2aa3d20c681f0e14ee6134adJames Dong    CHECK(mPrevTimestampUs < timeUs);
324708ec39c21568e0c2aa3d20c681f0e14ee6134adJames Dong    mPrevTimestampUs = timeUs;
325708ec39c21568e0c2aa3d20c681f0e14ee6134adJames Dong
32642ef0c715da879a9878b7bf4eb9c90b21e4ab8aeJames Dong    // Color convert to OMX_COLOR_FormatYUV420Planar if necessary
32742ef0c715da879a9878b7bf4eb9c90b21e4ab8aeJames Dong    outputBuffer->meta_data()->setInt64(kKeyTime, timeUs);
32842ef0c715da879a9878b7bf4eb9c90b21e4ab8aeJames Dong    uint8_t *inPtr = (uint8_t *) mInputBuffer->data();
32942ef0c715da879a9878b7bf4eb9c90b21e4ab8aeJames Dong    if (mVideoColorFormat != OMX_COLOR_FormatYUV420Planar) {
33042ef0c715da879a9878b7bf4eb9c90b21e4ab8aeJames Dong        CHECK(mInputFrameData);
33142ef0c715da879a9878b7bf4eb9c90b21e4ab8aeJames Dong        CHECK(mVideoColorFormat == OMX_COLOR_FormatYUV420SemiPlanar);
33242ef0c715da879a9878b7bf4eb9c90b21e4ab8aeJames Dong        ConvertYUV420SemiPlanarToYUV420Planar(
33342ef0c715da879a9878b7bf4eb9c90b21e4ab8aeJames Dong            inPtr, mInputFrameData, mVideoWidth, mVideoHeight);
33442ef0c715da879a9878b7bf4eb9c90b21e4ab8aeJames Dong        inPtr = mInputFrameData;
33542ef0c715da879a9878b7bf4eb9c90b21e4ab8aeJames Dong    }
33642ef0c715da879a9878b7bf4eb9c90b21e4ab8aeJames Dong    CHECK(inPtr != NULL);
33742ef0c715da879a9878b7bf4eb9c90b21e4ab8aeJames Dong
33842ef0c715da879a9878b7bf4eb9c90b21e4ab8aeJames Dong    // Ready for encoding a video frame
33942ef0c715da879a9878b7bf4eb9c90b21e4ab8aeJames Dong    VideoEncFrameIO vin, vout;
34042ef0c715da879a9878b7bf4eb9c90b21e4ab8aeJames Dong    vin.height = ((mVideoHeight + 15) >> 4) << 4;
34142ef0c715da879a9878b7bf4eb9c90b21e4ab8aeJames Dong    vin.pitch  = ((mVideoWidth  + 15) >> 4) << 4;
34242ef0c715da879a9878b7bf4eb9c90b21e4ab8aeJames Dong    vin.timestamp = (timeUs + 500) / 1000; // in ms
34342ef0c715da879a9878b7bf4eb9c90b21e4ab8aeJames Dong    vin.yChan = inPtr;
34442ef0c715da879a9878b7bf4eb9c90b21e4ab8aeJames Dong    vin.uChan = vin.yChan + vin.height * vin.pitch;
34542ef0c715da879a9878b7bf4eb9c90b21e4ab8aeJames Dong    vin.vChan = vin.uChan + ((vin.height * vin.pitch) >> 2);
34642ef0c715da879a9878b7bf4eb9c90b21e4ab8aeJames Dong    unsigned long modTimeMs = 0;
34742ef0c715da879a9878b7bf4eb9c90b21e4ab8aeJames Dong    int32_t nLayer = 0;
34842ef0c715da879a9878b7bf4eb9c90b21e4ab8aeJames Dong    MP4HintTrack hintTrack;
34942ef0c715da879a9878b7bf4eb9c90b21e4ab8aeJames Dong    if (!PVEncodeVideoFrame(mHandle, &vin, &vout,
35042ef0c715da879a9878b7bf4eb9c90b21e4ab8aeJames Dong            &modTimeMs, outPtr, &dataLength, &nLayer) ||
35142ef0c715da879a9878b7bf4eb9c90b21e4ab8aeJames Dong        !PVGetHintTrack(mHandle, &hintTrack)) {
35242ef0c715da879a9878b7bf4eb9c90b21e4ab8aeJames Dong        LOGE("Failed to encode frame or get hink track at frame %lld",
35342ef0c715da879a9878b7bf4eb9c90b21e4ab8aeJames Dong            mNumInputFrames);
35442ef0c715da879a9878b7bf4eb9c90b21e4ab8aeJames Dong        outputBuffer->release();
35542ef0c715da879a9878b7bf4eb9c90b21e4ab8aeJames Dong        mInputBuffer->release();
35642ef0c715da879a9878b7bf4eb9c90b21e4ab8aeJames Dong        mInputBuffer = NULL;
35742ef0c715da879a9878b7bf4eb9c90b21e4ab8aeJames Dong        return UNKNOWN_ERROR;
35842ef0c715da879a9878b7bf4eb9c90b21e4ab8aeJames Dong    }
35942ef0c715da879a9878b7bf4eb9c90b21e4ab8aeJames Dong    CHECK_EQ(NULL, PVGetOverrunBuffer(mHandle));
36042ef0c715da879a9878b7bf4eb9c90b21e4ab8aeJames Dong    if (hintTrack.CodeType == 0) {  // I-frame serves as sync frame
36142ef0c715da879a9878b7bf4eb9c90b21e4ab8aeJames Dong        outputBuffer->meta_data()->setInt32(kKeyIsSyncFrame, 1);
36242ef0c715da879a9878b7bf4eb9c90b21e4ab8aeJames Dong    }
36342ef0c715da879a9878b7bf4eb9c90b21e4ab8aeJames Dong
36442ef0c715da879a9878b7bf4eb9c90b21e4ab8aeJames Dong    ++mNumInputFrames;
36542ef0c715da879a9878b7bf4eb9c90b21e4ab8aeJames Dong    mNextModTimeUs = modTimeMs * 1000LL;
36642ef0c715da879a9878b7bf4eb9c90b21e4ab8aeJames Dong    outputBuffer->set_range(0, dataLength);
36742ef0c715da879a9878b7bf4eb9c90b21e4ab8aeJames Dong    *out = outputBuffer;
36842ef0c715da879a9878b7bf4eb9c90b21e4ab8aeJames Dong    mInputBuffer->release();
36942ef0c715da879a9878b7bf4eb9c90b21e4ab8aeJames Dong    mInputBuffer = NULL;
37042ef0c715da879a9878b7bf4eb9c90b21e4ab8aeJames Dong    return OK;
37142ef0c715da879a9878b7bf4eb9c90b21e4ab8aeJames Dong}
37242ef0c715da879a9878b7bf4eb9c90b21e4ab8aeJames Dong
37342ef0c715da879a9878b7bf4eb9c90b21e4ab8aeJames Dongvoid M4vH263Encoder::signalBufferReturned(MediaBuffer *buffer) {
37442ef0c715da879a9878b7bf4eb9c90b21e4ab8aeJames Dong}
37542ef0c715da879a9878b7bf4eb9c90b21e4ab8aeJames Dong
37642ef0c715da879a9878b7bf4eb9c90b21e4ab8aeJames Dong}  // namespace android
377