Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 10f8baa4 authored by James Dong's avatar James Dong Committed by Android Git Automerger
Browse files

am 42ef0c71: Initial check-in for software m4v_h263 encoder

Merge commit '42ef0c71' into gingerbread-plus-aosp

* commit '42ef0c71':
  Initial check-in for software m4v_h263 encoder
parents 203ec9fa 42ef0c71
Loading
Loading
Loading
Loading
+1 −0
Original line number Diff line number Diff line
@@ -68,6 +68,7 @@ LOCAL_STATIC_LIBRARIES := \
        libstagefright_avcdec \
        libstagefright_avcenc \
        libstagefright_m4vh263dec \
        libstagefright_m4vh263enc \
        libstagefright_mp3dec \
        libstagefright_vorbisdec \
        libstagefright_matroska \
+5 −0
Original line number Diff line number Diff line
@@ -27,6 +27,7 @@
#include "include/AVCDecoder.h"
#include "include/AVCEncoder.h"
#include "include/M4vH263Decoder.h"
#include "include/M4vH263Encoder.h"
#include "include/MP3Decoder.h"
#include "include/VorbisDecoder.h"
#include "include/VPXDecoder.h"
@@ -83,6 +84,7 @@ FACTORY_CREATE_ENCODER(AMRNBEncoder)
FACTORY_CREATE_ENCODER(AMRWBEncoder)
FACTORY_CREATE_ENCODER(AACEncoder)
FACTORY_CREATE_ENCODER(AVCEncoder)
FACTORY_CREATE_ENCODER(M4vH263Encoder)

static sp<MediaSource> InstantiateSoftwareEncoder(
        const char *name, const sp<MediaSource> &source,
@@ -97,6 +99,7 @@ static sp<MediaSource> InstantiateSoftwareEncoder(
        FACTORY_REF(AMRWBEncoder)
        FACTORY_REF(AACEncoder)
        FACTORY_REF(AVCEncoder)
        FACTORY_REF(M4vH263Encoder)
    };
    for (size_t i = 0;
         i < sizeof(kFactoryInfo) / sizeof(kFactoryInfo[0]); ++i) {
@@ -181,10 +184,12 @@ static const CodecInfo kEncoderInfo[] = {
    { MEDIA_MIMETYPE_VIDEO_MPEG4, "OMX.qcom.7x30.video.encoder.mpeg4" },
    { MEDIA_MIMETYPE_VIDEO_MPEG4, "OMX.qcom.video.encoder.mpeg4" },
    { MEDIA_MIMETYPE_VIDEO_MPEG4, "OMX.TI.Video.encoder" },
    { MEDIA_MIMETYPE_VIDEO_MPEG4, "M4vH263Encoder" },
//    { MEDIA_MIMETYPE_VIDEO_MPEG4, "OMX.PV.mpeg4enc" },
    { MEDIA_MIMETYPE_VIDEO_H263, "OMX.qcom.7x30.video.encoder.h263" },
    { MEDIA_MIMETYPE_VIDEO_H263, "OMX.qcom.video.encoder.h263" },
    { MEDIA_MIMETYPE_VIDEO_H263, "OMX.TI.Video.encoder" },
    { MEDIA_MIMETYPE_VIDEO_H263, "M4vH263Encoder" },
//    { MEDIA_MIMETYPE_VIDEO_H263, "OMX.PV.h263enc" },
    { MEDIA_MIMETYPE_VIDEO_AVC, "OMX.qcom.7x30.video.encoder.avc" },
    { MEDIA_MIMETYPE_VIDEO_AVC, "OMX.qcom.video.encoder.avc" },
+37 −0
Original line number Diff line number Diff line
LOCAL_PATH := $(call my-dir)
include $(CLEAR_VARS)

LOCAL_SRC_FILES := \
    M4vH263Encoder.cpp \
    src/bitstream_io.cpp \
    src/combined_encode.cpp \
    src/datapart_encode.cpp \
    src/dct.cpp \
    src/findhalfpel.cpp \
    src/fastcodemb.cpp \
    src/fastidct.cpp \
    src/fastquant.cpp \
    src/me_utils.cpp \
    src/mp4enc_api.cpp \
    src/rate_control.cpp \
    src/motion_est.cpp \
    src/motion_comp.cpp \
    src/sad.cpp \
    src/sad_halfpel.cpp \
    src/vlc_encode.cpp \
    src/vop.cpp


LOCAL_MODULE := libstagefright_m4vh263enc

LOCAL_CFLAGS := \
    -DBX_RC \
    -DOSCL_IMPORT_REF= -DOSCL_UNUSED_ARG= -DOSCL_EXPORT_REF=

LOCAL_C_INCLUDES := \
    $(LOCAL_PATH)/src \
    $(LOCAL_PATH)/include \
    $(TOP)/external/opencore/extern_libs_v2/khronos/openmax/include \
    $(TOP)/frameworks/base/media/libstagefright/include

include $(BUILD_STATIC_LIBRARY)
+359 −0
Original line number Diff line number Diff line
/*
 * Copyright (C) 2010 The Android Open Source Project
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

//#define LOG_NDEBUG 0
#define LOG_TAG "M4vH263Encoder"
#include <utils/Log.h>

#include "M4vH263Encoder.h"

#include "mp4enc_api.h"
#include "OMX_Video.h"

#include <media/stagefright/MediaBufferGroup.h>
#include <media/stagefright/MediaDebug.h>
#include <media/stagefright/MediaDefs.h>
#include <media/stagefright/MediaErrors.h>
#include <media/stagefright/MetaData.h>
#include <media/stagefright/Utils.h>

namespace android {

inline static void ConvertYUV420SemiPlanarToYUV420Planar(
        uint8_t *inyuv, uint8_t* outyuv,
        int32_t width, int32_t height) {

    int32_t outYsize = width * height;
    uint32_t *outy = (uint32_t *)  outyuv;
    uint16_t *outcb = (uint16_t *) (outyuv + outYsize);
    uint16_t *outcr = (uint16_t *) (outyuv + outYsize + (outYsize >> 2));

    /* Y copying */
    memcpy(outy, inyuv, outYsize);

    /* U & V copying */
    uint32_t *inyuv_4 = (uint32_t *) (inyuv + outYsize);
    for (int32_t i = height >> 1; i > 0; --i) {
        for (int32_t j = width >> 2; j > 0; --j) {
            uint32_t temp = *inyuv_4++;
            uint32_t tempU = temp & 0xFF;
            tempU = tempU | ((temp >> 8) & 0xFF00);

            uint32_t tempV = (temp >> 8) & 0xFF;
            tempV = tempV | ((temp >> 16) & 0xFF00);

            // Flip U and V
            *outcb++ = tempV;
            *outcr++ = tempU;
        }
    }
}

M4vH263Encoder::M4vH263Encoder(
        const sp<MediaSource>& source,
        const sp<MetaData>& meta)
    : mSource(source),
      mMeta(meta),
      mNumInputFrames(-1),
      mNextModTimeUs(0),
      mStarted(false),
      mInputBuffer(NULL),
      mInputFrameData(NULL),
      mGroup(NULL) {

    LOGV("Construct software M4vH263Encoder");

    mHandle = new tagvideoEncControls;
    memset(mHandle, 0, sizeof(tagvideoEncControls));

    mInitCheck = initCheck(meta);
}

M4vH263Encoder::~M4vH263Encoder() {
    LOGV("Destruct software M4vH263Encoder");
    if (mStarted) {
        stop();
    }

    delete mEncParams;
    delete mHandle;
}

status_t M4vH263Encoder::initCheck(const sp<MetaData>& meta) {
    LOGV("initCheck");
    CHECK(meta->findInt32(kKeyWidth, &mVideoWidth));
    CHECK(meta->findInt32(kKeyHeight, &mVideoHeight));
    CHECK(meta->findInt32(kKeySampleRate, &mVideoFrameRate));
    CHECK(meta->findInt32(kKeyBitRate, &mVideoBitRate));

    // XXX: Add more color format support
    CHECK(meta->findInt32(kKeyColorFormat, &mVideoColorFormat));
    if (mVideoColorFormat != OMX_COLOR_FormatYUV420Planar) {
        if (mVideoColorFormat != OMX_COLOR_FormatYUV420SemiPlanar) {
            LOGE("Color format %d is not supported", mVideoColorFormat);
            return BAD_VALUE;
        }
        // Allocate spare buffer only when color conversion is needed.
        // Assume the color format is OMX_COLOR_FormatYUV420SemiPlanar.
        mInputFrameData =
            (uint8_t *) malloc((mVideoWidth * mVideoHeight * 3 ) >> 1);
        CHECK(mInputFrameData);
    }

    // XXX: Remove this restriction
    if (mVideoWidth % 16 != 0 || mVideoHeight % 16 != 0) {
        LOGE("Video frame size %dx%d must be a multiple of 16",
            mVideoWidth, mVideoHeight);
        return BAD_VALUE;
    }

    mEncParams = new tagvideoEncOptions;
    memset(mEncParams, 0, sizeof(tagvideoEncOptions));
    if (!PVGetDefaultEncOption(mEncParams, 0)) {
        LOGE("Failed to get default encoding parameters");
        return BAD_VALUE;
    }

    // Need to know which role the encoder is in.
    // XXX: Set the mode proper for other types of applications
    //      like streaming or video conference
    const char *mime;
    CHECK(meta->findCString(kKeyMIMEType, &mime));
    CHECK(!strcmp(mime, MEDIA_MIMETYPE_VIDEO_MPEG4) ||
          !strcmp(mime, MEDIA_MIMETYPE_VIDEO_H263));
    if (!strcmp(mime, MEDIA_MIMETYPE_VIDEO_MPEG4)) {
        mEncParams->encMode = COMBINE_MODE_WITH_ERR_RES;
    } else {
        mEncParams->encMode = H263_MODE;
    }
    mEncParams->encWidth[0] = mVideoWidth;
    mEncParams->encHeight[0] = mVideoHeight;
    mEncParams->encFrameRate[0] = mVideoFrameRate;
    mEncParams->rcType = VBR_1;
    mEncParams->vbvDelay = (float)5.0;

    // Set profile and level
    // If profile and level setting is not correct, failure
    // is reported when the encoder is initialized.
    mEncParams->profile_level = CORE_PROFILE_LEVEL2;
    int32_t profileLevel;
    if (meta->findInt32(kKeyVideoLevel, &profileLevel)) {
        mEncParams->profile_level = (ProfileLevelType)profileLevel;
    }

    mEncParams->packetSize = 32;
    mEncParams->rvlcEnable = PV_OFF;
    mEncParams->numLayers = 1;
    mEncParams->timeIncRes = 1000;
    mEncParams->tickPerSrc = mEncParams->timeIncRes / mVideoFrameRate;

    mEncParams->bitRate[0] = mVideoBitRate;
    mEncParams->iQuant[0] = 15;
    mEncParams->pQuant[0] = 12;
    mEncParams->quantType[0] = 0;
    mEncParams->noFrameSkipped = PV_OFF;

    // Set IDR frame refresh interval
    int32_t iFramesIntervalSec;
    CHECK(meta->findInt32(kKeyIFramesInterval, &iFramesIntervalSec));
    if (iFramesIntervalSec < 0) {
        mEncParams->intraPeriod = -1;
    } else if (iFramesIntervalSec == 0) {
        mEncParams->intraPeriod = 1;  // All I frames
    } else {
        mEncParams->intraPeriod =
            (iFramesIntervalSec * mVideoFrameRate);
    }

    mEncParams->numIntraMB = 0;
    mEncParams->sceneDetect = PV_ON;
    mEncParams->searchRange = 16;
    mEncParams->mv8x8Enable = PV_OFF;
    mEncParams->gobHeaderInterval = 0;
    mEncParams->useACPred = PV_ON;
    mEncParams->intraDCVlcTh = 0;

    mFormat = new MetaData;
    mFormat->setInt32(kKeyWidth, mVideoWidth);
    mFormat->setInt32(kKeyHeight, mVideoHeight);
    mFormat->setInt32(kKeyBitRate, mVideoBitRate);
    mFormat->setInt32(kKeySampleRate, mVideoFrameRate);
    mFormat->setInt32(kKeyColorFormat, mVideoColorFormat);

    mFormat->setCString(kKeyMIMEType, mime);
    mFormat->setCString(kKeyDecoderComponent, "M4vH263Encoder");
    return OK;
}

status_t M4vH263Encoder::start(MetaData *params) {
    LOGV("start");
    if (mInitCheck != OK) {
        return mInitCheck;
    }

    if (mStarted) {
        LOGW("Call start() when encoder already started");
        return OK;
    }

    if (!PVInitVideoEncoder(mHandle, mEncParams)) {
        LOGE("Failed to initialize the encoder");
        return UNKNOWN_ERROR;
    }

    mGroup = new MediaBufferGroup();
    int32_t maxSize;
    if (!PVGetMaxVideoFrameSize(mHandle, &maxSize)) {
        maxSize = 256 * 1024;  // Magic #
    }
    LOGV("Max output buffer size: %d", maxSize);
    mGroup->add_buffer(new MediaBuffer(maxSize));

    mSource->start(params);
    mNumInputFrames = -1;  // 1st frame contains codec specific data
    mStarted = true;

    return OK;
}

status_t M4vH263Encoder::stop() {
    LOGV("stop");
    if (!mStarted) {
        LOGW("Call stop() when encoder has not started");
        return OK;
    }

    if (mInputBuffer) {
        mInputBuffer->release();
        mInputBuffer = NULL;
    }

    if (mGroup) {
        delete mGroup;
        mGroup = NULL;
    }

    if (mInputFrameData) {
        delete mInputFrameData;
        mInputFrameData = NULL;
    }

    CHECK(PVCleanUpVideoEncoder(mHandle));

    mSource->stop();
    mStarted = false;

    return OK;
}

sp<MetaData> M4vH263Encoder::getFormat() {
    LOGV("getFormat");
    return mFormat;
}

status_t M4vH263Encoder::read(
        MediaBuffer **out, const ReadOptions *options) {

    CHECK(!options);
    *out = NULL;

    MediaBuffer *outputBuffer;
    CHECK_EQ(OK, mGroup->acquire_buffer(&outputBuffer));
    uint8_t *outPtr = (uint8_t *) outputBuffer->data();
    int32_t dataLength = outputBuffer->size();

    // Output codec specific data
    if (mNumInputFrames < 0) {
        if (!PVGetVolHeader(mHandle, outPtr, &dataLength, 0)) {
            LOGE("Failed to get VOL header");
            return UNKNOWN_ERROR;
        }
        LOGV("Output VOL header: %d bytes", dataLength);
        outputBuffer->meta_data()->setInt32(kKeyIsCodecConfig, 1);
        outputBuffer->set_range(0, dataLength);
        *out = outputBuffer;
        ++mNumInputFrames;
        return OK;
    }

    // Ready for accepting an input video frame
    if (OK != mSource->read(&mInputBuffer, options)) {
        LOGE("Failed to read from data source");
        outputBuffer->release();
        return UNKNOWN_ERROR;
    }
    int64_t timeUs;
    CHECK(mInputBuffer->meta_data()->findInt64(kKeyTime, &timeUs));
    if (mNextModTimeUs > timeUs) {
        LOGV("mNextModTimeUs %lld > timeUs %lld", mNextModTimeUs, timeUs);
        outputBuffer->set_range(0, 0);
        *out = outputBuffer;
        mInputBuffer->release();
        mInputBuffer = NULL;
        return OK;
    }

    // Color convert to OMX_COLOR_FormatYUV420Planar if necessary
    outputBuffer->meta_data()->setInt64(kKeyTime, timeUs);
    uint8_t *inPtr = (uint8_t *) mInputBuffer->data();
    if (mVideoColorFormat != OMX_COLOR_FormatYUV420Planar) {
        CHECK(mInputFrameData);
        CHECK(mVideoColorFormat == OMX_COLOR_FormatYUV420SemiPlanar);
        ConvertYUV420SemiPlanarToYUV420Planar(
            inPtr, mInputFrameData, mVideoWidth, mVideoHeight);
        inPtr = mInputFrameData;
    }
    CHECK(inPtr != NULL);

    // Ready for encoding a video frame
    VideoEncFrameIO vin, vout;
    vin.height = ((mVideoHeight + 15) >> 4) << 4;
    vin.pitch  = ((mVideoWidth  + 15) >> 4) << 4;
    vin.timestamp = (timeUs + 500) / 1000; // in ms
    vin.yChan = inPtr;
    vin.uChan = vin.yChan + vin.height * vin.pitch;
    vin.vChan = vin.uChan + ((vin.height * vin.pitch) >> 2);
    unsigned long modTimeMs = 0;
    int32_t nLayer = 0;
    MP4HintTrack hintTrack;
    if (!PVEncodeVideoFrame(mHandle, &vin, &vout,
            &modTimeMs, outPtr, &dataLength, &nLayer) ||
        !PVGetHintTrack(mHandle, &hintTrack)) {
        LOGE("Failed to encode frame or get hink track at frame %lld",
            mNumInputFrames);
        outputBuffer->release();
        mInputBuffer->release();
        mInputBuffer = NULL;
        return UNKNOWN_ERROR;
    }
    CHECK_EQ(NULL, PVGetOverrunBuffer(mHandle));
    if (hintTrack.CodeType == 0) {  // I-frame serves as sync frame
        outputBuffer->meta_data()->setInt32(kKeyIsSyncFrame, 1);
    }

    ++mNumInputFrames;
    mNextModTimeUs = modTimeMs * 1000LL;
    outputBuffer->set_range(0, dataLength);
    *out = outputBuffer;
    mInputBuffer->release();
    mInputBuffer = NULL;
    return OK;
}

void M4vH263Encoder::signalBufferReturned(MediaBuffer *buffer) {
}

}  // namespace android
+437 −0

File added.

Preview size limit exceeded, changes collapsed.

Loading