blob: 1abc4472d4507a6eeab2e2441d582ca054379255 [file] [log] [blame]
/*
* Copyright (C) 2011 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.
*/
/**
*************************************************************************
* @file VideoEditorVideoEncoder.cpp
* @brief StageFright shell video encoder
*************************************************************************
*/
#define LOG_NDEBUG 1
#define LOG_TAG "VIDEOEDITOR_VIDEOENCODER"
/*******************
* HEADERS *
*******************/
#include "M4OSA_Debug.h"
#include "M4SYS_AccessUnit.h"
#include "VideoEditorVideoEncoder.h"
#include "MediaBufferPuller.h"
#include <I420ColorConverter.h>
#include <unistd.h>
#include "utils/Log.h"
#include "utils/Vector.h"
#include <media/stagefright/foundation/ADebug.h>
#include <media/stagefright/MediaSource.h>
#include <media/stagefright/MediaDefs.h>
#include <media/stagefright/MetaData.h>
#include <media/stagefright/OMXClient.h>
#include <media/stagefright/OMXCodec.h>
#include <media/MediaProfiles.h>
#include "OMX_Video.h"
#include "IntelVideoEditorEncoderSource.h"
#include "IntelVideoEditorAVCEncoder.h"
#include "IntelVideoEditorH263Encoder.h"
#include "IntelVideoEditorUtils.h"
/********************
* DEFINITIONS *
********************/
// Force using hardware encoder
#define VIDEOEDITOR_FORCECODEC kHardwareCodecsOnly
#if !defined(VIDEOEDITOR_FORCECODEC)
#error "Cannot force DSI retrieval if codec type is not fixed"
#endif
/********************
* SOURCE CLASS *
********************/
namespace android {
struct VideoEditorVideoEncoderSource : public MediaSource {
public:
static sp<VideoEditorVideoEncoderSource> Create(
const sp<MetaData> &format);
virtual status_t start(MetaData *params = NULL);
virtual status_t stop();
virtual sp<MetaData> getFormat();
virtual status_t read(MediaBuffer **buffer,
const ReadOptions *options = NULL);
virtual int32_t storeBuffer(MediaBuffer *buffer);
virtual int32_t getNumberOfBuffersInQueue();
protected:
virtual ~VideoEditorVideoEncoderSource();
private:
struct MediaBufferChain {
MediaBuffer* buffer;
MediaBufferChain* nextLink;
};
enum State {
CREATED,
STARTED,
ERROR
};
VideoEditorVideoEncoderSource(const sp<MetaData> &format);
// Don't call me
VideoEditorVideoEncoderSource(const VideoEditorVideoEncoderSource &);
VideoEditorVideoEncoderSource &operator=(
const VideoEditorVideoEncoderSource &);
MediaBufferChain* mFirstBufferLink;
MediaBufferChain* mLastBufferLink;
int32_t mNbBuffer;
bool mIsEOS;
State mState;
sp<MetaData> mEncFormat;
Mutex mLock;
Condition mBufferCond;
};
sp<VideoEditorVideoEncoderSource> VideoEditorVideoEncoderSource::Create(
const sp<MetaData> &format) {
sp<VideoEditorVideoEncoderSource> aSource =
new VideoEditorVideoEncoderSource(format);
return aSource;
}
VideoEditorVideoEncoderSource::VideoEditorVideoEncoderSource(
const sp<MetaData> &format):
mFirstBufferLink(NULL),
mLastBufferLink(NULL),
mNbBuffer(0),
mIsEOS(false),
mState(CREATED),
mEncFormat(format) {
ALOGV("VideoEditorVideoEncoderSource::VideoEditorVideoEncoderSource");
}
VideoEditorVideoEncoderSource::~VideoEditorVideoEncoderSource() {
// Safety clean up
if( STARTED == mState ) {
stop();
}
}
status_t VideoEditorVideoEncoderSource::start(MetaData *meta) {
status_t err = OK;
ALOGV("VideoEditorVideoEncoderSource::start() begin");
if( CREATED != mState ) {
ALOGV("VideoEditorVideoEncoderSource::start: invalid state %d", mState);
return UNKNOWN_ERROR;
}
mState = STARTED;
ALOGV("VideoEditorVideoEncoderSource::start() END (0x%x)", err);
return err;
}
status_t VideoEditorVideoEncoderSource::stop() {
status_t err = OK;
ALOGV("VideoEditorVideoEncoderSource::stop() begin");
if( STARTED != mState ) {
ALOGV("VideoEditorVideoEncoderSource::stop: invalid state %d", mState);
return UNKNOWN_ERROR;
}
// Release the buffer chain
int32_t i = 0;
MediaBufferChain* tmpLink = NULL;
while( mFirstBufferLink ) {
i++;
tmpLink = mFirstBufferLink;
mFirstBufferLink = mFirstBufferLink->nextLink;
delete tmpLink;
}
ALOGV("VideoEditorVideoEncoderSource::stop : %d buffer remained", i);
mFirstBufferLink = NULL;
mLastBufferLink = NULL;
mState = CREATED;
ALOGV("VideoEditorVideoEncoderSource::stop() END (0x%x)", err);
return err;
}
sp<MetaData> VideoEditorVideoEncoderSource::getFormat() {
ALOGV("VideoEditorVideoEncoderSource::getFormat");
return mEncFormat;
}
status_t VideoEditorVideoEncoderSource::read(MediaBuffer **buffer,
const ReadOptions *options) {
Mutex::Autolock autolock(mLock);
MediaSource::ReadOptions readOptions;
status_t err = OK;
MediaBufferChain* tmpLink = NULL;
ALOGV("VideoEditorVideoEncoderSource::read() begin");
if ( STARTED != mState ) {
ALOGV("VideoEditorVideoEncoderSource::read: invalid state %d", mState);
return UNKNOWN_ERROR;
}
while (mFirstBufferLink == NULL && !mIsEOS) {
mBufferCond.wait(mLock);
}
// End of stream?
if (mFirstBufferLink == NULL) {
*buffer = NULL;
ALOGV("VideoEditorVideoEncoderSource::read : EOS");
return ERROR_END_OF_STREAM;
}
// Get a buffer from the chain
*buffer = mFirstBufferLink->buffer;
tmpLink = mFirstBufferLink;
mFirstBufferLink = mFirstBufferLink->nextLink;
if ( NULL == mFirstBufferLink ) {
mLastBufferLink = NULL;
}
delete tmpLink;
mNbBuffer--;
ALOGV("VideoEditorVideoEncoderSource::read() END (0x%x)", err);
return err;
}
int32_t VideoEditorVideoEncoderSource::storeBuffer(MediaBuffer *buffer) {
Mutex::Autolock autolock(mLock);
status_t err = OK;
ALOGV("VideoEditorVideoEncoderSource::storeBuffer() begin");
if( NULL == buffer ) {
ALOGV("VideoEditorVideoEncoderSource::storeBuffer : reached EOS");
mIsEOS = true;
} else {
MediaBufferChain* newLink = new MediaBufferChain;
newLink->buffer = buffer;
newLink->nextLink = NULL;
if( NULL != mLastBufferLink ) {
mLastBufferLink->nextLink = newLink;
} else {
mFirstBufferLink = newLink;
}
mLastBufferLink = newLink;
mNbBuffer++;
}
mBufferCond.signal();
ALOGV("VideoEditorVideoEncoderSource::storeBuffer() end");
return mNbBuffer;
}
int32_t VideoEditorVideoEncoderSource::getNumberOfBuffersInQueue() {
Mutex::Autolock autolock(mLock);
return mNbBuffer;
}
/**
******************************************************************************
* structure VideoEditorVideoEncoder_Context
* @brief This structure defines the context of the StageFright video encoder
* shell
******************************************************************************
*/
typedef enum {
CREATED = 0x1,
OPENED = 0x2,
STARTED = 0x4,
BUFFERING = 0x8,
READING = 0x10
} VideoEditorVideoEncoder_State;
typedef struct {
VideoEditorVideoEncoder_State mState;
M4ENCODER_Format mFormat;
M4WRITER_DataInterface* mWriterDataInterface;
M4VPP_apply_fct* mPreProcFunction;
M4VPP_Context mPreProcContext;
M4SYS_AccessUnit* mAccessUnit;
M4ENCODER_Params* mCodecParams;
M4ENCODER_Header mHeader;
H264MCS_ProcessEncodedNALU_fct* mH264NALUPostProcessFct;
M4OSA_Context mH264NALUPostProcessCtx;
M4OSA_UInt32 mLastCTS;
sp<IntelVideoEditorEncoderSource> mEncoderSource;
OMXClient mClient;
sp<MediaSource> mEncoder;
OMX_COLOR_FORMATTYPE mEncoderColorFormat;
MediaBufferPuller* mPuller;
I420ColorConverter* mI420ColorConverter;
uint32_t mNbInputFrames;
double mFirstInputCts;
double mLastInputCts;
uint32_t mNbOutputFrames;
int64_t mFirstOutputCts;
int64_t mLastOutputCts;
MediaProfiles *mVideoEditorProfile;
int32_t mMaxPrefetchFrames;
} VideoEditorVideoEncoder_Context;
/********************
* TOOLS *
********************/
M4OSA_ERR VideoEditorVideoEncoder_getDSI(M4ENCODER_Context pContext,
sp<MetaData> metaData) {
M4OSA_ERR err = M4NO_ERROR;
VideoEditorVideoEncoder_Context* pEncoderContext = M4OSA_NULL;
status_t result = OK;
int32_t nbBuffer = 0;
int32_t stride = 0;
int32_t height = 0;
int32_t framerate = 0;
int32_t isCodecConfig = 0;
size_t size = 0;
uint32_t codecFlags = 0;
MediaBuffer* inputBuffer = NULL;
MediaBuffer* outputBuffer = NULL;
sp<IntelVideoEditorEncoderSource> encoderSource = NULL;
sp<MediaSource> encoder = NULL;;
OMXClient client;
ALOGV("VideoEditorVideoEncoder_getDSI begin");
// Input parameters check
VIDEOEDITOR_CHECK(M4OSA_NULL != pContext, M4ERR_PARAMETER);
VIDEOEDITOR_CHECK(M4OSA_NULL != metaData.get(), M4ERR_PARAMETER);
pEncoderContext = (VideoEditorVideoEncoder_Context*)pContext;
VIDEOEDITOR_CHECK(CREATED == pEncoderContext->mState, M4ERR_STATE);
// Create the encoder source
encoderSource = IntelVideoEditorEncoderSource::Create(metaData);
VIDEOEDITOR_CHECK(NULL != encoderSource.get(), M4ERR_STATE);
// Create Hardware encoder
encoder = new IntelVideoEditorAVCEncoder(encoderSource,metaData);
VIDEOEDITOR_CHECK(NULL != encoder.get(), M4ERR_STATE);
/**
* Send fake frames and retrieve the DSI
*/
// Send a fake frame to the source
metaData->findInt32(kKeyStride, &stride);
metaData->findInt32(kKeyHeight, &height);
metaData->findInt32(kKeySampleRate, &framerate);
result = encoder->start();
VIDEOEDITOR_CHECK(OK == result, M4ERR_STATE);
encoderSource->requestBuffer(&inputBuffer);
inputBuffer->meta_data()->setInt64(kKeyTime, 0);
nbBuffer = encoderSource->storeBuffer(inputBuffer);
encoderSource->storeBuffer(NULL); // Signal EOS
// Call read once to get the DSI
result = encoder->read(&outputBuffer, NULL);
VIDEOEDITOR_CHECK(OK == result, M4ERR_STATE);
VIDEOEDITOR_CHECK(outputBuffer->meta_data()->findInt32(
kKeyIsCodecConfig, &isCodecConfig) && isCodecConfig, M4ERR_STATE);
VIDEOEDITOR_CHECK(M4OSA_NULL == pEncoderContext->mHeader.pBuf, M4ERR_STATE);
if ( M4ENCODER_kH264 == pEncoderContext->mFormat ) {
// For H264, format the DSI
LOGV("outputBuffer->range_offset() = %d, outputBuffer->range_length() = %d",
outputBuffer->range_offset(), outputBuffer->range_length());
result = buildAVCCodecSpecificData(
(uint8_t**)(&(pEncoderContext->mHeader.pBuf)),
(size_t*)(&(pEncoderContext->mHeader.Size)),
(const uint8_t*)outputBuffer->data() + outputBuffer->range_offset(),
outputBuffer->range_length(), encoder->getFormat().get());
outputBuffer->release();
VIDEOEDITOR_CHECK(OK == result, M4ERR_STATE);
} else {
// For MPEG4, just copy the DSI
pEncoderContext->mHeader.Size =
(M4OSA_UInt32)outputBuffer->range_length();
SAFE_MALLOC(pEncoderContext->mHeader.pBuf, M4OSA_Int8,
pEncoderContext->mHeader.Size, "Encoder header");
memcpy((void *)pEncoderContext->mHeader.pBuf,
(void *)((M4OSA_MemAddr8)(outputBuffer->data())+outputBuffer->range_offset()),
pEncoderContext->mHeader.Size);
outputBuffer->release();
}
result = encoder->stop();
VIDEOEDITOR_CHECK(OK == result, M4ERR_STATE);
cleanUp:
// Destroy the graph
if ( encoder != NULL ) { encoder.clear(); }
//client.disconnect();
if ( encoderSource != NULL ) { encoderSource.clear(); }
if ( M4NO_ERROR == err ) {
ALOGV("VideoEditorVideoEncoder_getDSI no error");
} else {
ALOGV("VideoEditorVideoEncoder_getDSI ERROR 0x%X", err);
}
ALOGV("VideoEditorVideoEncoder_getDSI end");
return err;
}
/********************
* ENGINE INTERFACE *
********************/
M4OSA_ERR VideoEditorVideoEncoder_cleanup(M4ENCODER_Context pContext) {
M4OSA_ERR err = M4NO_ERROR;
VideoEditorVideoEncoder_Context* pEncoderContext = M4OSA_NULL;
ALOGV("VideoEditorVideoEncoder_cleanup begin");
// Input parameters check
VIDEOEDITOR_CHECK(M4OSA_NULL != pContext, M4ERR_PARAMETER);
pEncoderContext = (VideoEditorVideoEncoder_Context*)pContext;
VIDEOEDITOR_CHECK(CREATED == pEncoderContext->mState, M4ERR_STATE);
// Release memory
SAFE_FREE(pEncoderContext->mHeader.pBuf);
SAFE_FREE(pEncoderContext);
pContext = M4OSA_NULL;
cleanUp:
if ( M4NO_ERROR == err ) {
ALOGV("VideoEditorVideoEncoder_cleanup no error");
} else {
ALOGV("VideoEditorVideoEncoder_cleanup ERROR 0x%X", err);
}
ALOGV("VideoEditorVideoEncoder_cleanup end");
return err;
}
M4OSA_ERR VideoEditorVideoEncoder_init(M4ENCODER_Format format,
M4ENCODER_Context* pContext,
M4WRITER_DataInterface* pWriterDataInterface,
M4VPP_apply_fct* pVPPfct, M4VPP_Context pVPPctxt,
M4OSA_Void* pExternalAPI, M4OSA_Void* pUserData) {
M4OSA_ERR err = M4NO_ERROR;
VideoEditorVideoEncoder_Context* pEncoderContext = M4OSA_NULL;
int encoderInput = OMX_COLOR_FormatYUV420Planar;
ALOGV("VideoEditorVideoEncoder_init begin: format %d", format);
// Input parameters check
VIDEOEDITOR_CHECK(M4OSA_NULL != pContext, M4ERR_PARAMETER);
VIDEOEDITOR_CHECK(M4OSA_NULL != pWriterDataInterface, M4ERR_PARAMETER);
VIDEOEDITOR_CHECK(M4OSA_NULL != pVPPfct, M4ERR_PARAMETER);
VIDEOEDITOR_CHECK(M4OSA_NULL != pVPPctxt, M4ERR_PARAMETER);
// Context allocation & initialization
SAFE_MALLOC(pEncoderContext, VideoEditorVideoEncoder_Context, 1,
"VideoEditorVideoEncoder");
pEncoderContext->mState = CREATED;
pEncoderContext->mFormat = format;
pEncoderContext->mWriterDataInterface = pWriterDataInterface;
pEncoderContext->mPreProcFunction = pVPPfct;
pEncoderContext->mPreProcContext = pVPPctxt;
pEncoderContext->mPuller = NULL;
// Get color converter and determine encoder input format
pEncoderContext->mI420ColorConverter = new I420ColorConverter;
if (pEncoderContext->mI420ColorConverter->isLoaded()) {
encoderInput = pEncoderContext->mI420ColorConverter->getEncoderInputFormat();
}
if (encoderInput == OMX_COLOR_FormatYUV420Planar) {
delete pEncoderContext->mI420ColorConverter;
pEncoderContext->mI420ColorConverter = NULL;
}
pEncoderContext->mEncoderColorFormat = (OMX_COLOR_FORMATTYPE)encoderInput;
ALOGI("encoder input format = 0x%X\n", encoderInput);
*pContext = pEncoderContext;
cleanUp:
if ( M4NO_ERROR == err ) {
ALOGV("VideoEditorVideoEncoder_init no error");
} else {
VideoEditorVideoEncoder_cleanup(pEncoderContext);
*pContext = M4OSA_NULL;
ALOGV("VideoEditorVideoEncoder_init ERROR 0x%X", err);
}
ALOGV("VideoEditorVideoEncoder_init end");
return err;
}
M4OSA_ERR VideoEditorVideoEncoder_init_H263(M4ENCODER_Context* pContext,
M4WRITER_DataInterface* pWriterDataInterface, M4VPP_apply_fct* pVPPfct,
M4VPP_Context pVPPctxt, M4OSA_Void* pExternalAPI, M4OSA_Void* pUserData)
{
return VideoEditorVideoEncoder_init(M4ENCODER_kH263, pContext,
pWriterDataInterface, pVPPfct, pVPPctxt, pExternalAPI, pUserData);
}
M4OSA_ERR VideoEditorVideoEncoder_init_MPEG4(M4ENCODER_Context* pContext,
M4WRITER_DataInterface* pWriterDataInterface, M4VPP_apply_fct* pVPPfct,
M4VPP_Context pVPPctxt, M4OSA_Void* pExternalAPI, M4OSA_Void* pUserData)
{
return VideoEditorVideoEncoder_init(M4ENCODER_kMPEG4, pContext,
pWriterDataInterface, pVPPfct, pVPPctxt, pExternalAPI, pUserData);
}
M4OSA_ERR VideoEditorVideoEncoder_init_H264(M4ENCODER_Context* pContext,
M4WRITER_DataInterface* pWriterDataInterface, M4VPP_apply_fct* pVPPfct,
M4VPP_Context pVPPctxt, M4OSA_Void* pExternalAPI, M4OSA_Void* pUserData)
{
return VideoEditorVideoEncoder_init(M4ENCODER_kH264, pContext,
pWriterDataInterface, pVPPfct, pVPPctxt, pExternalAPI, pUserData);
}
M4OSA_ERR VideoEditorVideoEncoder_close(M4ENCODER_Context pContext) {
M4OSA_ERR err = M4NO_ERROR;
VideoEditorVideoEncoder_Context* pEncoderContext = M4OSA_NULL;
ALOGV("VideoEditorVideoEncoder_close begin");
// Input parameters check
VIDEOEDITOR_CHECK(M4OSA_NULL != pContext, M4ERR_PARAMETER);
pEncoderContext = (VideoEditorVideoEncoder_Context*)pContext;
VIDEOEDITOR_CHECK(OPENED == pEncoderContext->mState, M4ERR_STATE);
// Release memory
SAFE_FREE(pEncoderContext->mCodecParams);
// Destroy the graph
pEncoderContext->mEncoder.clear();
// pEncoderContext->mClient.disconnect();
pEncoderContext->mEncoderSource.clear();
delete pEncoderContext->mPuller;
pEncoderContext->mPuller = NULL;
delete pEncoderContext->mI420ColorConverter;
pEncoderContext->mI420ColorConverter = NULL;
// Set the new state
pEncoderContext->mState = CREATED;
cleanUp:
if( M4NO_ERROR == err ) {
ALOGV("VideoEditorVideoEncoder_close no error");
} else {
ALOGV("VideoEditorVideoEncoder_close ERROR 0x%X", err);
}
ALOGV("VideoEditorVideoEncoder_close end");
return err;
}
M4OSA_ERR VideoEditorVideoEncoder_open(M4ENCODER_Context pContext,
M4SYS_AccessUnit* pAU, M4OSA_Void* pParams) {
M4OSA_ERR err = M4NO_ERROR;
VideoEditorVideoEncoder_Context* pEncoderContext = M4OSA_NULL;
M4ENCODER_Params* pCodecParams = M4OSA_NULL;
status_t result = OK;
sp<MetaData> encoderMetadata = NULL;
const char* mime = NULL;
int32_t iProfile = 0;
int32_t iLevel = 0;
int32_t iFrameRate = 0;
uint32_t codecFlags = 0;
ALOGV(">>> VideoEditorVideoEncoder_open begin");
// Input parameters check
VIDEOEDITOR_CHECK(M4OSA_NULL != pContext, M4ERR_PARAMETER);
VIDEOEDITOR_CHECK(M4OSA_NULL != pAU, M4ERR_PARAMETER);
VIDEOEDITOR_CHECK(M4OSA_NULL != pParams, M4ERR_PARAMETER);
pEncoderContext = (VideoEditorVideoEncoder_Context*)pContext;
pCodecParams = (M4ENCODER_Params*)pParams;
VIDEOEDITOR_CHECK(CREATED == pEncoderContext->mState, M4ERR_STATE);
// Context initialization
pEncoderContext->mAccessUnit = pAU;
pEncoderContext->mVideoEditorProfile = MediaProfiles::getInstance();
pEncoderContext->mMaxPrefetchFrames =
pEncoderContext->mVideoEditorProfile->getVideoEditorCapParamByName(
"maxPrefetchYUVFrames");
// Allocate & initialize the encoding parameters
SAFE_MALLOC(pEncoderContext->mCodecParams, M4ENCODER_Params, 1,
"VideoEditorVideoEncoder");
pEncoderContext->mCodecParams->InputFormat = pCodecParams->InputFormat;
pEncoderContext->mCodecParams->InputFrameWidth =
pCodecParams->InputFrameWidth;
pEncoderContext->mCodecParams->InputFrameHeight =
pCodecParams->InputFrameHeight;
pEncoderContext->mCodecParams->FrameWidth = pCodecParams->FrameWidth;
pEncoderContext->mCodecParams->FrameHeight = pCodecParams->FrameHeight;
pEncoderContext->mCodecParams->Bitrate = pCodecParams->Bitrate;
pEncoderContext->mCodecParams->FrameRate = pCodecParams->FrameRate;
pEncoderContext->mCodecParams->Format = pCodecParams->Format;
pEncoderContext->mCodecParams->videoProfile = pCodecParams->videoProfile;
pEncoderContext->mCodecParams->videoLevel= pCodecParams->videoLevel;
// Check output format consistency and resolution
VIDEOEDITOR_CHECK(
pEncoderContext->mCodecParams->Format == pEncoderContext->mFormat,
M4ERR_PARAMETER);
VIDEOEDITOR_CHECK(0 == pEncoderContext->mCodecParams->FrameWidth % 16,
M4ERR_PARAMETER);
VIDEOEDITOR_CHECK(0 == pEncoderContext->mCodecParams->FrameHeight % 16,
M4ERR_PARAMETER);
/**
* StageFright graph building
*/
// Create the meta data for the encoder
encoderMetadata = new MetaData;
switch( pEncoderContext->mCodecParams->Format ) {
case M4ENCODER_kH263:
mime = MEDIA_MIMETYPE_VIDEO_H263;
break;
case M4ENCODER_kMPEG4:
mime = MEDIA_MIMETYPE_VIDEO_MPEG4;
break;
case M4ENCODER_kH264:
mime = MEDIA_MIMETYPE_VIDEO_AVC;
break;
default:
VIDEOEDITOR_CHECK(!"VideoEncoder_open : incorrect input format",
M4ERR_PARAMETER);
break;
}
iProfile = pEncoderContext->mCodecParams->videoProfile;
iLevel = pEncoderContext->mCodecParams->videoLevel;
ALOGV("Encoder mime %s profile %d, level %d",
mime,iProfile, iLevel);
ALOGV("Encoder w %d, h %d, bitrate %d, fps %d",
pEncoderContext->mCodecParams->FrameWidth,
pEncoderContext->mCodecParams->FrameHeight,
pEncoderContext->mCodecParams->Bitrate,
pEncoderContext->mCodecParams->FrameRate);
CHECK(iProfile != 0x7fffffff);
CHECK(iLevel != 0x7fffffff);
encoderMetadata->setCString(kKeyMIMEType, mime);
encoderMetadata->setInt32(kKeyVideoProfile, iProfile);
//FIXME:
// Temp: Do not set the level for Mpeg4 / H.263 Enc
// as OMX.Nvidia.mp4.encoder and OMX.Nvidia.h263.encoder
// return 0x80001019
if (pEncoderContext->mCodecParams->Format == M4ENCODER_kH264) {
encoderMetadata->setInt32(kKeyVideoLevel, iLevel);
}
encoderMetadata->setInt32(kKeyWidth,
(int32_t)pEncoderContext->mCodecParams->FrameWidth);
encoderMetadata->setInt32(kKeyStride,
(int32_t)pEncoderContext->mCodecParams->FrameWidth);
encoderMetadata->setInt32(kKeyHeight,
(int32_t)pEncoderContext->mCodecParams->FrameHeight);
encoderMetadata->setInt32(kKeySliceHeight,
(int32_t)pEncoderContext->mCodecParams->FrameHeight);
switch( pEncoderContext->mCodecParams->FrameRate ) {
case M4ENCODER_k5_FPS: iFrameRate = 5; break;
case M4ENCODER_k7_5_FPS: iFrameRate = 8; break;
case M4ENCODER_k10_FPS: iFrameRate = 10; break;
case M4ENCODER_k12_5_FPS: iFrameRate = 13; break;
case M4ENCODER_k15_FPS: iFrameRate = 15; break;
case M4ENCODER_k20_FPS: iFrameRate = 20; break;
case M4ENCODER_k25_FPS: iFrameRate = 25; break;
case M4ENCODER_k30_FPS: iFrameRate = 30; break;
case M4ENCODER_kVARIABLE_FPS:
iFrameRate = 30;
ALOGI("Frame rate set to M4ENCODER_kVARIABLE_FPS: set to 30");
break;
case M4ENCODER_kUSE_TIMESCALE:
iFrameRate = 30;
ALOGI("Frame rate set to M4ENCODER_kUSE_TIMESCALE: set to 30");
break;
default:
VIDEOEDITOR_CHECK(!"VideoEncoder_open:incorrect framerate",
M4ERR_STATE);
break;
}
encoderMetadata->setInt32(kKeyFrameRate, iFrameRate);
encoderMetadata->setInt32(kKeyBitRate,
(int32_t)pEncoderContext->mCodecParams->Bitrate);
encoderMetadata->setInt32(kKeyIFramesInterval, 1);
encoderMetadata->setInt32(kKeyColorFormat,
pEncoderContext->mEncoderColorFormat);
if (pEncoderContext->mCodecParams->Format != M4ENCODER_kH263) {
// Get the encoder DSI
err = VideoEditorVideoEncoder_getDSI(pEncoderContext, encoderMetadata);
VIDEOEDITOR_CHECK(M4NO_ERROR == err, err);
}
// Create the encoder source
pEncoderContext->mEncoderSource = IntelVideoEditorEncoderSource::Create(
encoderMetadata);
VIDEOEDITOR_CHECK(
NULL != pEncoderContext->mEncoderSource.get(), M4ERR_STATE);
// Create the HW Encoder
if (pEncoderContext->mCodecParams->Format == M4ENCODER_kH264) {
pEncoderContext->mEncoder = new IntelVideoEditorAVCEncoder(
pEncoderContext->mEncoderSource, encoderMetadata);
} else if (pEncoderContext->mCodecParams->Format == M4ENCODER_kH263) {
pEncoderContext->mEncoder = new IntelVideoEditorH263Encoder(
pEncoderContext->mEncoderSource, encoderMetadata);
}
VIDEOEDITOR_CHECK(NULL != pEncoderContext->mEncoder.get(), M4ERR_STATE);
ALOGV("VideoEditorVideoEncoder_open : DONE");
pEncoderContext->mPuller = new MediaBufferPuller(
pEncoderContext->mEncoder);
// Set the new state
pEncoderContext->mState = OPENED;
cleanUp:
if( M4NO_ERROR == err ) {
ALOGV("VideoEditorVideoEncoder_open no error");
} else {
VideoEditorVideoEncoder_close(pEncoderContext);
ALOGV("VideoEditorVideoEncoder_open ERROR 0x%X", err);
}
ALOGV("VideoEditorVideoEncoder_open end");
return err;
}
M4OSA_ERR VideoEditorVideoEncoder_processInputBuffer(
M4ENCODER_Context pContext, M4OSA_Double Cts,
M4OSA_Bool bReachedEOS) {
M4OSA_ERR err = M4NO_ERROR;
VideoEditorVideoEncoder_Context* pEncoderContext = M4OSA_NULL;
M4VIFI_ImagePlane pOutPlane[3];
MediaBuffer* buffer = NULL;
int32_t nbBuffer = 0;
ALOGV("VideoEditorVideoEncoder_processInputBuffer begin: cts %f", Cts);
// Input parameters check
VIDEOEDITOR_CHECK(M4OSA_NULL != pContext, M4ERR_PARAMETER);
pEncoderContext = (VideoEditorVideoEncoder_Context*)pContext;
pOutPlane[0].pac_data = M4OSA_NULL;
pOutPlane[1].pac_data = M4OSA_NULL;
pOutPlane[2].pac_data = M4OSA_NULL;
if ( M4OSA_FALSE == bReachedEOS ) {
M4OSA_UInt32 sizeY = pEncoderContext->mCodecParams->FrameWidth *
pEncoderContext->mCodecParams->FrameHeight;
M4OSA_UInt32 sizeU = sizeY >> 2;
M4OSA_UInt32 size = sizeY + 2*sizeU;
M4OSA_UInt8* pData = M4OSA_NULL;
buffer = new MediaBuffer((size_t)size);
pData = (M4OSA_UInt8*)buffer->data() + buffer->range_offset();
// Prepare the output image for pre-processing
pOutPlane[0].u_width = pEncoderContext->mCodecParams->FrameWidth;
pOutPlane[0].u_height = pEncoderContext->mCodecParams->FrameHeight;
pOutPlane[0].u_topleft = 0;
pOutPlane[0].u_stride = pOutPlane[0].u_width;
pOutPlane[1].u_width = pOutPlane[0].u_width/2;
pOutPlane[1].u_height = pOutPlane[0].u_height/2;
pOutPlane[1].u_topleft = 0;
pOutPlane[1].u_stride = pOutPlane[0].u_stride/2;
pOutPlane[2].u_width = pOutPlane[1].u_width;
pOutPlane[2].u_height = pOutPlane[1].u_height;
pOutPlane[2].u_topleft = 0;
pOutPlane[2].u_stride = pOutPlane[1].u_stride;
pOutPlane[0].pac_data = pData;
pOutPlane[1].pac_data = pData + sizeY;
pOutPlane[2].pac_data = pData + sizeY + sizeU;
// Apply pre-processing
err = pEncoderContext->mPreProcFunction(
pEncoderContext->mPreProcContext, M4OSA_NULL, pOutPlane);
VIDEOEDITOR_CHECK(M4NO_ERROR == err, err);
// Convert MediaBuffer to the encoder input format if necessary
if (pEncoderContext->mI420ColorConverter) {
I420ColorConverter* converter = pEncoderContext->mI420ColorConverter;
int actualWidth = pEncoderContext->mCodecParams->FrameWidth;
int actualHeight = pEncoderContext->mCodecParams->FrameHeight;
int encoderWidth, encoderHeight;
ARect encoderRect;
int encoderBufferSize;
if (converter->getEncoderInputBufferInfo(
actualWidth, actualHeight,
&encoderWidth, &encoderHeight,
&encoderRect, &encoderBufferSize) == 0) {
MediaBuffer* newBuffer;
pEncoderContext->mEncoderSource->requestBuffer(&newBuffer);
if (converter->convertI420ToEncoderInput(
pData, // srcBits
actualWidth, actualHeight,
encoderWidth, encoderHeight,
encoderRect,
(uint8_t*)newBuffer->data() + newBuffer->range_offset()) < 0) {
ALOGE("convertI420ToEncoderInput failed");
}
// switch to new buffer
buffer->release();
buffer = newBuffer;
}
}
// Set the metadata
buffer->meta_data()->setInt64(kKeyTime, (int64_t)(Cts*1000));
}
// Push the buffer to the source, a NULL buffer, notifies the source of EOS
nbBuffer = pEncoderContext->mEncoderSource->storeBuffer(buffer);
cleanUp:
if ( M4NO_ERROR == err ) {
ALOGV("VideoEditorVideoEncoder_processInputBuffer error 0x%X", err);
} else {
if( NULL != buffer ) {
buffer->release();
}
ALOGV("VideoEditorVideoEncoder_processInputBuffer ERROR 0x%X", err);
}
ALOGV("VideoEditorVideoEncoder_processInputBuffer end");
return err;
}
M4OSA_ERR VideoEditorVideoEncoder_processOutputBuffer(
M4ENCODER_Context pContext, MediaBuffer* buffer) {
M4OSA_ERR err = M4NO_ERROR;
VideoEditorVideoEncoder_Context* pEncoderContext = M4OSA_NULL;
M4OSA_UInt32 Cts = 0;
uint8_t *data;
uint32_t length;
int32_t i32Tmp = 0;
int64_t i64Tmp = 0;
status_t result = OK;
LOGV("VideoEditorVideoEncoder_processOutputBuffer begin");
// Input parameters check
VIDEOEDITOR_CHECK(M4OSA_NULL != pContext, M4ERR_PARAMETER);
VIDEOEDITOR_CHECK(M4OSA_NULL != buffer, M4ERR_PARAMETER);
pEncoderContext = (VideoEditorVideoEncoder_Context*)pContext;
// Process the returned AU
if ( 0 == buffer->range_length() ) {
// Encoder has no data yet, nothing unusual
LOGV("VideoEditorVideoEncoder_processOutputBuffer : buffer is empty");
goto cleanUp;
}
VIDEOEDITOR_CHECK(0 == ((M4OSA_UInt32)buffer->data())%4, M4ERR_PARAMETER);
VIDEOEDITOR_CHECK(buffer->meta_data().get(), M4ERR_PARAMETER);
if ( buffer->meta_data()->findInt32(kKeyIsCodecConfig, &i32Tmp) && i32Tmp ){
LOGV("VideoEditorVideoEncoder_processOutputBuffer DSI %d",buffer->range_length());
removeAVCCodecSpecificData(&data,&length,(const uint8_t*) buffer->data(),buffer->range_length(),NULL);
buffer->set_range(buffer->range_offset() + length, buffer->range_length() - length);
}
// Check the CTS
VIDEOEDITOR_CHECK(buffer->meta_data()->findInt64(kKeyTime, &i64Tmp),
M4ERR_STATE);
pEncoderContext->mNbOutputFrames++;
if ( 0 > pEncoderContext->mFirstOutputCts ) {
pEncoderContext->mFirstOutputCts = i64Tmp;
}
pEncoderContext->mLastOutputCts = i64Tmp;
Cts = (M4OSA_Int32)(i64Tmp/1000);
LOGV("[TS_CHECK] VI/ENC WRITE frame %d @ %lld -> %d (last %d)",
pEncoderContext->mNbOutputFrames, i64Tmp, Cts,
pEncoderContext->mLastCTS);
if ( Cts < pEncoderContext->mLastCTS ) {
LOGV("VideoEncoder_processOutputBuffer WARNING : Cts is going "
"backwards %d < %d", Cts, pEncoderContext->mLastCTS);
goto cleanUp;
}
LOGV("VideoEditorVideoEncoder_processOutputBuffer : %d %d",
Cts, pEncoderContext->mLastCTS);
// Retrieve the AU container
err = pEncoderContext->mWriterDataInterface->pStartAU(
pEncoderContext->mWriterDataInterface->pWriterContext,
pEncoderContext->mAccessUnit->stream->streamID,
pEncoderContext->mAccessUnit);
VIDEOEDITOR_CHECK(M4NO_ERROR == err, err);
// Format the AU
VIDEOEDITOR_CHECK(
buffer->range_length() <= pEncoderContext->mAccessUnit->size,
M4ERR_PARAMETER);
// Remove H264 AU start code
if ( M4ENCODER_kH264 == pEncoderContext->mFormat ) {
if (!memcmp((const uint8_t *)buffer->data() + \
buffer->range_offset(), "\x00\x00\x00\x01", 4) ) {
buffer->set_range(buffer->range_offset() + 4,
buffer->range_length() - 4);
}
}
if ( (M4ENCODER_kH264 == pEncoderContext->mFormat) &&
(M4OSA_NULL != pEncoderContext->mH264NALUPostProcessFct) ) {
// H264 trimming case, NALU post processing is needed
M4OSA_Int32 outputSize = pEncoderContext->mAccessUnit->size;
err = pEncoderContext->mH264NALUPostProcessFct(
pEncoderContext->mH264NALUPostProcessCtx,
(M4OSA_UInt8*)buffer->data()+buffer->range_offset(),
buffer->range_length(),
(M4OSA_UInt8*)pEncoderContext->mAccessUnit->dataAddress,
&outputSize);
VIDEOEDITOR_CHECK(M4NO_ERROR == err, err);
pEncoderContext->mAccessUnit->size = (M4OSA_UInt32)outputSize;
} else {
// The AU can just be copied
memcpy((void *)pEncoderContext->mAccessUnit->\
dataAddress, (void *)((M4OSA_MemAddr8)(buffer->data())+buffer->\
range_offset()), buffer->range_length());
pEncoderContext->mAccessUnit->size =
(M4OSA_UInt32)buffer->range_length();
}
if ( buffer->meta_data()->findInt32(kKeyIsSyncFrame,&i32Tmp) && i32Tmp){
pEncoderContext->mAccessUnit->attribute = AU_RAP;
} else {
pEncoderContext->mAccessUnit->attribute = AU_P_Frame;
}
pEncoderContext->mLastCTS = Cts;
pEncoderContext->mAccessUnit->CTS = Cts;
pEncoderContext->mAccessUnit->DTS = Cts;
LOGV("VideoEditorVideoEncoder_processOutputBuffer: AU @ 0x%X 0x%X %d %d",
pEncoderContext->mAccessUnit->dataAddress,
*pEncoderContext->mAccessUnit->dataAddress,
pEncoderContext->mAccessUnit->size,
pEncoderContext->mAccessUnit->CTS);
// Write the AU
err = pEncoderContext->mWriterDataInterface->pProcessAU(
pEncoderContext->mWriterDataInterface->pWriterContext,
pEncoderContext->mAccessUnit->stream->streamID,
pEncoderContext->mAccessUnit);
VIDEOEDITOR_CHECK(M4NO_ERROR == err, err);
cleanUp:
if( M4NO_ERROR == err ) {
LOGV("VideoEditorVideoEncoder_processOutputBuffer no error");
} else {
if (pEncoderContext != NULL) {
SAFE_FREE(pEncoderContext->mHeader.pBuf);
pEncoderContext->mHeader.Size = 0;
}
LOGV("VideoEditorVideoEncoder_processOutputBuffer ERROR 0x%X", err);
}
LOGV("VideoEditorVideoEncoder_processOutputBuffer end");
return err;
}
M4OSA_ERR VideoEditorVideoEncoder_encode(M4ENCODER_Context pContext,
M4VIFI_ImagePlane* pInPlane, M4OSA_Double Cts,
M4ENCODER_FrameMode FrameMode) {
M4OSA_ERR err = M4NO_ERROR;
VideoEditorVideoEncoder_Context* pEncoderContext = M4OSA_NULL;
status_t result = OK;
MediaBuffer* outputBuffer = NULL;
ALOGV("VideoEditorVideoEncoder_encode 0x%X %f %d", pInPlane, Cts, FrameMode);
VIDEOEDITOR_CHECK(M4OSA_NULL != pContext, M4ERR_PARAMETER);
pEncoderContext = (VideoEditorVideoEncoder_Context*)pContext;
if ( STARTED == pEncoderContext->mState ) {
pEncoderContext->mState = BUFFERING;
}
VIDEOEDITOR_CHECK(
(BUFFERING | READING) & pEncoderContext->mState, M4ERR_STATE);
pEncoderContext->mNbInputFrames++;
if ( 0 > pEncoderContext->mFirstInputCts ) {
pEncoderContext->mFirstInputCts = Cts;
}
pEncoderContext->mLastInputCts = Cts;
ALOGV("VideoEditorVideoEncoder_encode 0x%X %d %f (%d)", pInPlane, FrameMode,
Cts, pEncoderContext->mLastCTS);
// Push the input buffer to the encoder source
err = VideoEditorVideoEncoder_processInputBuffer(pEncoderContext, Cts,
M4OSA_FALSE);
VIDEOEDITOR_CHECK(M4NO_ERROR == err, err);
// Notify the source in case of EOS
if ( M4ENCODER_kLastFrame == FrameMode ) {
err = VideoEditorVideoEncoder_processInputBuffer(
pEncoderContext, 0, M4OSA_TRUE);
VIDEOEDITOR_CHECK(M4NO_ERROR == err, err);
}
if ( BUFFERING == pEncoderContext->mState ) {
// Prefetch is complete, start reading
pEncoderContext->mState = READING;
}
// Read
while (1) {
MediaBuffer *outputBuffer =
pEncoderContext->mPuller->getBufferNonBlocking();
if (outputBuffer == NULL) {
break;
} else {
// Provide the encoded AU to the writer
err = VideoEditorVideoEncoder_processOutputBuffer(pEncoderContext,
outputBuffer);
VIDEOEDITOR_CHECK(M4NO_ERROR == err, err);
pEncoderContext->mPuller->putBuffer(outputBuffer);
}
}
cleanUp:
if( M4NO_ERROR == err ) {
ALOGV("VideoEditorVideoEncoder_encode no error");
} else {
ALOGV("VideoEditorVideoEncoder_encode ERROR 0x%X", err);
}
ALOGV("VideoEditorVideoEncoder_encode end");
return err;
}
M4OSA_ERR VideoEditorVideoEncoder_start(M4ENCODER_Context pContext) {
M4OSA_ERR err = M4NO_ERROR;
VideoEditorVideoEncoder_Context* pEncoderContext = M4OSA_NULL;
status_t result = OK;
ALOGV("VideoEditorVideoEncoder_start begin");
// Input parameters check
VIDEOEDITOR_CHECK(M4OSA_NULL != pContext, M4ERR_PARAMETER);
pEncoderContext = (VideoEditorVideoEncoder_Context*)pContext;
VIDEOEDITOR_CHECK(OPENED == pEncoderContext->mState, M4ERR_STATE);
pEncoderContext->mNbInputFrames = 0;
pEncoderContext->mFirstInputCts = -1.0;
pEncoderContext->mLastInputCts = -1.0;
pEncoderContext->mNbOutputFrames = 0;
pEncoderContext->mFirstOutputCts = -1;
pEncoderContext->mLastOutputCts = -1;
result = pEncoderContext->mEncoder->start();
VIDEOEDITOR_CHECK(OK == result, M4ERR_STATE);
pEncoderContext->mPuller->start();
// Set the new state
pEncoderContext->mState = STARTED;
cleanUp:
if ( M4NO_ERROR == err ) {
ALOGV("VideoEditorVideoEncoder_start no error");
} else {
ALOGV("VideoEditorVideoEncoder_start ERROR 0x%X", err);
}
ALOGV("VideoEditorVideoEncoder_start end");
return err;
}
M4OSA_ERR VideoEditorVideoEncoder_stop(M4ENCODER_Context pContext) {
M4OSA_ERR err = M4NO_ERROR;
VideoEditorVideoEncoder_Context* pEncoderContext = M4OSA_NULL;
MediaBuffer* outputBuffer = NULL;
status_t result = OK;
ALOGV("VideoEditorVideoEncoder_stop begin");
// Input parameters check
VIDEOEDITOR_CHECK(M4OSA_NULL != pContext, M4ERR_PARAMETER);
pEncoderContext = (VideoEditorVideoEncoder_Context*)pContext;
// Send EOS again to make sure the source doesn't block.
err = VideoEditorVideoEncoder_processInputBuffer(pEncoderContext, 0,
M4OSA_TRUE);
VIDEOEDITOR_CHECK(M4NO_ERROR == err, err);
// Process the remaining buffers if necessary
if ( (BUFFERING | READING) & pEncoderContext->mState ) {
while (1) {
MediaBuffer *outputBuffer =
pEncoderContext->mPuller->getBufferBlocking();
if (outputBuffer == NULL) break;
err = VideoEditorVideoEncoder_processOutputBuffer(
pEncoderContext, outputBuffer);
VIDEOEDITOR_CHECK(M4NO_ERROR == err, err);
pEncoderContext->mPuller->putBuffer(outputBuffer);
}
pEncoderContext->mState = STARTED;
}
// Stop the graph module if necessary
if ( STARTED == pEncoderContext->mState ) {
pEncoderContext->mPuller->stop();
pEncoderContext->mEncoder->stop();
pEncoderContext->mState = OPENED;
}
if (pEncoderContext->mNbInputFrames != pEncoderContext->mNbOutputFrames) {
ALOGW("Some frames were not encoded: input(%d) != output(%d)",
pEncoderContext->mNbInputFrames, pEncoderContext->mNbOutputFrames);
}
cleanUp:
if ( M4NO_ERROR == err ) {
ALOGV("VideoEditorVideoEncoder_stop no error");
} else {
ALOGV("VideoEditorVideoEncoder_stop ERROR 0x%X", err);
}
ALOGV("VideoEditorVideoEncoder_stop end");
return err;
}
M4OSA_ERR VideoEditorVideoEncoder_regulBitRate(M4ENCODER_Context pContext) {
ALOGW("regulBitRate is not implemented");
return M4NO_ERROR;
}
M4OSA_ERR VideoEditorVideoEncoder_setOption(M4ENCODER_Context pContext,
M4OSA_UInt32 optionID, M4OSA_DataOption optionValue) {
M4OSA_ERR err = M4NO_ERROR;
VideoEditorVideoEncoder_Context* pEncoderContext = M4OSA_NULL;
ALOGV("VideoEditorVideoEncoder_setOption start optionID 0x%X", optionID);
// Input parameters check
VIDEOEDITOR_CHECK(M4OSA_NULL != pContext, M4ERR_PARAMETER);
pEncoderContext = (VideoEditorVideoEncoder_Context*)pContext;
switch( optionID ) {
case M4ENCODER_kOptionID_SetH264ProcessNALUfctsPtr:
pEncoderContext->mH264NALUPostProcessFct =
(H264MCS_ProcessEncodedNALU_fct*)optionValue;
break;
case M4ENCODER_kOptionID_H264ProcessNALUContext:
pEncoderContext->mH264NALUPostProcessCtx =
(M4OSA_Context)optionValue;
break;
default:
ALOGV("VideoEditorVideoEncoder_setOption: unsupported optionId 0x%X",
optionID);
VIDEOEDITOR_CHECK(M4OSA_FALSE, M4ERR_BAD_OPTION_ID);
break;
}
cleanUp:
if ( M4NO_ERROR == err ) {
ALOGV("VideoEditorVideoEncoder_setOption no error");
} else {
ALOGV("VideoEditorVideoEncoder_setOption ERROR 0x%X", err);
}
ALOGV("VideoEditorVideoEncoder_setOption end");
return err;
}
M4OSA_ERR VideoEditorVideoEncoder_getOption(M4ENCODER_Context pContext,
M4OSA_UInt32 optionID, M4OSA_DataOption optionValue) {
M4OSA_ERR err = M4NO_ERROR;
VideoEditorVideoEncoder_Context* pEncoderContext = M4OSA_NULL;
ALOGV("VideoEditorVideoEncoder_getOption begin optinId 0x%X", optionID);
// Input parameters check
VIDEOEDITOR_CHECK(M4OSA_NULL != pContext, M4ERR_PARAMETER);
pEncoderContext = (VideoEditorVideoEncoder_Context*)pContext;
switch( optionID ) {
case M4ENCODER_kOptionID_EncoderHeader:
VIDEOEDITOR_CHECK(
M4OSA_NULL != pEncoderContext->mHeader.pBuf, M4ERR_STATE);
*(M4ENCODER_Header**)optionValue = &(pEncoderContext->mHeader);
break;
default:
ALOGV("VideoEditorVideoEncoder_getOption: unsupported optionId 0x%X",
optionID);
VIDEOEDITOR_CHECK(M4OSA_FALSE, M4ERR_BAD_OPTION_ID);
break;
}
cleanUp:
if ( M4NO_ERROR == err ) {
ALOGV("VideoEditorVideoEncoder_getOption no error");
} else {
ALOGV("VideoEditorVideoEncoder_getOption ERROR 0x%X", err);
}
return err;
}
M4OSA_ERR VideoEditorVideoEncoder_getInterface(M4ENCODER_Format format,
M4ENCODER_Format* pFormat,
M4ENCODER_GlobalInterface** pEncoderInterface, M4ENCODER_OpenMode mode){
M4OSA_ERR err = M4NO_ERROR;
// Input parameters check
VIDEOEDITOR_CHECK(M4OSA_NULL != pFormat, M4ERR_PARAMETER);
VIDEOEDITOR_CHECK(M4OSA_NULL != pEncoderInterface, M4ERR_PARAMETER);
ALOGV("VideoEditorVideoEncoder_getInterface begin 0x%x 0x%x %d", pFormat,
pEncoderInterface, mode);
SAFE_MALLOC(*pEncoderInterface, M4ENCODER_GlobalInterface, 1,
"VideoEditorVideoEncoder");
*pFormat = format;
switch( format ) {
case M4ENCODER_kH263:
{
(*pEncoderInterface)->pFctInit =
VideoEditorVideoEncoder_init_H263;
break;
}
case M4ENCODER_kMPEG4:
{
(*pEncoderInterface)->pFctInit =
VideoEditorVideoEncoder_init_MPEG4;
break;
}
case M4ENCODER_kH264:
{
(*pEncoderInterface)->pFctInit =
VideoEditorVideoEncoder_init_H264;
break;
}
default:
ALOGV("VideoEditorVideoEncoder_getInterface : unsupported format %d",
format);
VIDEOEDITOR_CHECK(M4OSA_FALSE, M4ERR_PARAMETER);
break;
}
(*pEncoderInterface)->pFctOpen = VideoEditorVideoEncoder_open;
(*pEncoderInterface)->pFctStart = VideoEditorVideoEncoder_start;
(*pEncoderInterface)->pFctStop = VideoEditorVideoEncoder_stop;
(*pEncoderInterface)->pFctPause = M4OSA_NULL;
(*pEncoderInterface)->pFctResume = M4OSA_NULL;
(*pEncoderInterface)->pFctClose = VideoEditorVideoEncoder_close;
(*pEncoderInterface)->pFctCleanup = VideoEditorVideoEncoder_cleanup;
(*pEncoderInterface)->pFctRegulBitRate =
VideoEditorVideoEncoder_regulBitRate;
(*pEncoderInterface)->pFctEncode = VideoEditorVideoEncoder_encode;
(*pEncoderInterface)->pFctSetOption = VideoEditorVideoEncoder_setOption;
(*pEncoderInterface)->pFctGetOption = VideoEditorVideoEncoder_getOption;
cleanUp:
if( M4NO_ERROR == err ) {
ALOGV("VideoEditorVideoEncoder_getInterface no error");
} else {
*pEncoderInterface = M4OSA_NULL;
ALOGV("VideoEditorVideoEncoder_getInterface ERROR 0x%X", err);
}
return err;
}
extern "C" {
M4OSA_ERR VideoEditorVideoEncoder_getInterface_H263(M4ENCODER_Format* pFormat,
M4ENCODER_GlobalInterface** pEncoderInterface, M4ENCODER_OpenMode mode){
LOGI("VideoEditorVideoEncoder_getInterface_H263: Intel Version");
return VideoEditorVideoEncoder_getInterface(M4ENCODER_kH263, pFormat,
pEncoderInterface, mode);
}
M4OSA_ERR VideoEditorVideoEncoder_getInterface_MPEG4(M4ENCODER_Format* pFormat,
M4ENCODER_GlobalInterface** pEncoderInterface, M4ENCODER_OpenMode mode){
LOGI("VideoEditorVideoEncoder_getInterface_MPEG4: Intel Version");
return VideoEditorVideoEncoder_getInterface(M4ENCODER_kMPEG4, pFormat,
pEncoderInterface, mode);
}
M4OSA_ERR VideoEditorVideoEncoder_getInterface_H264(M4ENCODER_Format* pFormat,
M4ENCODER_GlobalInterface** pEncoderInterface, M4ENCODER_OpenMode mode){
LOGI("VideoEditorVideoEncoder_getInterface_H264: Intel Version");
return VideoEditorVideoEncoder_getInterface(M4ENCODER_kH264, pFormat,
pEncoderInterface, mode);
}
} // extern "C"
} // namespace android