Commit e29be959 authored by Martin Storsjo's avatar Martin Storsjo

Initial import of the VisualOn amrwbenc code from Android/stagefright

parents
/*
* 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 "AMRWBEncoder"
#include <utils/Log.h>
#include "AMRWBEncoder.h"
#include "voAMRWB.h"
#include "cmnMemory.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>
namespace android {
static const int32_t kNumSamplesPerFrame = 320;
static const int32_t kBitsPerSample = 16;
static const int32_t kInputBufferSize = (kBitsPerSample / 8) * kNumSamplesPerFrame;
static const int32_t kSampleRate = 16000;
static const int32_t kNumChannels = 1;
AMRWBEncoder::AMRWBEncoder(const sp<MediaSource> &source, const sp<MetaData> &meta)
: mSource(source),
mMeta(meta),
mStarted(false),
mBufferGroup(NULL),
mInputBuffer(NULL),
mEncoderHandle(NULL),
mApiHandle(NULL),
mMemOperator(NULL),
mAnchorTimeUs(0),
mNumFramesOutput(0),
mNumInputSamples(0) {
}
static VOAMRWBMODE pickModeFromBitRate(int32_t bps) {
CHECK(bps >= 0);
if (bps <= 6600) {
return VOAMRWB_MD66;
} else if (bps <= 8850) {
return VOAMRWB_MD885;
} else if (bps <= 12650) {
return VOAMRWB_MD1265;
} else if (bps <= 14250) {
return VOAMRWB_MD1425;
} else if (bps <= 15850) {
return VOAMRWB_MD1585;
} else if (bps <= 18250) {
return VOAMRWB_MD1825;
} else if (bps <= 19850) {
return VOAMRWB_MD1985;
} else if (bps <= 23050) {
return VOAMRWB_MD2305;
}
return VOAMRWB_MD2385;
}
status_t AMRWBEncoder::initCheck() {
CHECK(mApiHandle == NULL && mEncoderHandle == NULL);
CHECK(mMeta->findInt32(kKeyBitRate, &mBitRate));
mApiHandle = new VO_AUDIO_CODECAPI;
CHECK(mApiHandle);
if (VO_ERR_NONE != voGetAMRWBEncAPI(mApiHandle)) {
LOGE("Failed to get api handle");
return UNKNOWN_ERROR;
}
mMemOperator = new VO_MEM_OPERATOR;
CHECK(mMemOperator != NULL);
mMemOperator->Alloc = cmnMemAlloc;
mMemOperator->Copy = cmnMemCopy;
mMemOperator->Free = cmnMemFree;
mMemOperator->Set = cmnMemSet;
mMemOperator->Check = cmnMemCheck;
VO_CODEC_INIT_USERDATA userData;
memset(&userData, 0, sizeof(userData));
userData.memflag = VO_IMF_USERMEMOPERATOR;
userData.memData = (VO_PTR) mMemOperator;
if (VO_ERR_NONE != mApiHandle->Init(&mEncoderHandle, VO_AUDIO_CodingAMRWB, &userData)) {
LOGE("Failed to init AMRWB encoder");
return UNKNOWN_ERROR;
}
// Configure AMRWB encoder$
VOAMRWBMODE mode = pickModeFromBitRate(mBitRate);
if (VO_ERR_NONE != mApiHandle->SetParam(mEncoderHandle, VO_PID_AMRWB_MODE, &mode)) {
LOGE("Failed to set AMRWB encoder mode to %d", mode);
return UNKNOWN_ERROR;
}
VOAMRWBFRAMETYPE type = VOAMRWB_RFC3267;
if (VO_ERR_NONE != mApiHandle->SetParam(mEncoderHandle, VO_PID_AMRWB_FRAMETYPE, &type)) {
LOGE("Failed to set AMRWB encoder frame type to %d", type);
return UNKNOWN_ERROR;
}
return OK;
}
AMRWBEncoder::~AMRWBEncoder() {
if (mStarted) {
stop();
}
}
status_t AMRWBEncoder::start(MetaData *params) {
if (mStarted) {
LOGW("Call start() when encoder already started");
return OK;
}
mBufferGroup = new MediaBufferGroup;
// The largest buffer size is header + 477 bits
mBufferGroup->add_buffer(new MediaBuffer(1024));
CHECK_EQ(OK, initCheck());
mNumFramesOutput = 0;
mSource->start(params);
mStarted = true;
return OK;
}
status_t AMRWBEncoder::stop() {
if (!mStarted) {
LOGW("Call stop() when encoder has not started");
return OK;
}
if (mInputBuffer) {
mInputBuffer->release();
mInputBuffer = NULL;
}
delete mBufferGroup;
mBufferGroup = NULL;
CHECK_EQ(VO_ERR_NONE, mApiHandle->Uninit(mEncoderHandle));
mEncoderHandle = NULL;
delete mApiHandle;
mApiHandle = NULL;
delete mMemOperator;
mMemOperator;
mStarted = false;
mSource->stop();
return OK;
}
sp<MetaData> AMRWBEncoder::getFormat() {
sp<MetaData> srcFormat = mSource->getFormat();
mMeta->setCString(kKeyMIMEType, MEDIA_MIMETYPE_AUDIO_AMR_WB);
int64_t durationUs;
if (srcFormat->findInt64(kKeyDuration, &durationUs)) {
mMeta->setInt64(kKeyDuration, durationUs);
}
mMeta->setCString(kKeyDecoderComponent, "AMRWBEncoder");
return mMeta;
}
status_t AMRWBEncoder::read(
MediaBuffer **out, const ReadOptions *options) {
status_t err;
*out = NULL;
int64_t seekTimeUs;
ReadOptions::SeekMode mode;
CHECK(options == NULL || !options->getSeekTo(&seekTimeUs, &mode));
bool readFromSource = false;
int64_t wallClockTimeUs = -1;
while (mNumInputSamples < kNumSamplesPerFrame) {
if (mInputBuffer == NULL) {
err = mSource->read(&mInputBuffer, options);
if (err != OK) {
if (mNumInputSamples == 0) {
return ERROR_END_OF_STREAM;
}
memset(&mInputFrame[mNumInputSamples],
0,
sizeof(int16_t)
* (kNumSamplesPerFrame - mNumInputSamples));
mNumInputSamples = 0;
break;
}
size_t align = mInputBuffer->range_length() % sizeof(int16_t);
CHECK_EQ(align, 0);
int64_t timeUs;
if (mInputBuffer->meta_data()->findInt64(kKeyDriftTime, &timeUs)) {
wallClockTimeUs = timeUs;
}
if (mInputBuffer->meta_data()->findInt64(kKeyAnchorTime, &timeUs)) {
mAnchorTimeUs = timeUs;
}
readFromSource = true;
} else {
readFromSource = false;
}
size_t copy =
(kNumSamplesPerFrame - mNumInputSamples) * sizeof(int16_t);
if (copy > mInputBuffer->range_length()) {
copy = mInputBuffer->range_length();
}
memcpy(&mInputFrame[mNumInputSamples],
(const uint8_t *)mInputBuffer->data()
+ mInputBuffer->range_offset(),
copy);
mInputBuffer->set_range(
mInputBuffer->range_offset() + copy,
mInputBuffer->range_length() - copy);
if (mInputBuffer->range_length() == 0) {
mInputBuffer->release();
mInputBuffer = NULL;
}
mNumInputSamples += copy / sizeof(int16_t);
if (mNumInputSamples >= kNumSamplesPerFrame) {
mNumInputSamples %= kNumSamplesPerFrame;
break; // Get a whole input frame 640 bytes
}
}
VO_CODECBUFFER inputData;
memset(&inputData, 0, sizeof(inputData));
inputData.Buffer = (unsigned char*) mInputFrame;
inputData.Length = kInputBufferSize;
CHECK(VO_ERR_NONE == mApiHandle->SetInputData(mEncoderHandle,&inputData));
MediaBuffer *buffer;
CHECK_EQ(mBufferGroup->acquire_buffer(&buffer), OK);
uint8_t *outPtr = (uint8_t *)buffer->data();
VO_CODECBUFFER outputData;
memset(&outputData, 0, sizeof(outputData));
VO_AUDIO_OUTPUTINFO outputInfo;
memset(&outputInfo, 0, sizeof(outputInfo));
VO_U32 ret = VO_ERR_NONE;
outputData.Buffer = outPtr;
outputData.Length = buffer->size();
ret = mApiHandle->GetOutputData(mEncoderHandle, &outputData, &outputInfo);
CHECK(ret == VO_ERR_NONE || ret == VO_ERR_INPUT_BUFFER_SMALL);
buffer->set_range(0, outputData.Length);
++mNumFramesOutput;
int64_t mediaTimeUs = mNumFramesOutput * 20000LL;
buffer->meta_data()->setInt64(kKeyTime, mAnchorTimeUs + mediaTimeUs);
if (readFromSource && wallClockTimeUs != -1) {
buffer->meta_data()->setInt64(kKeyDriftTime, mediaTimeUs - wallClockTimeUs);
}
*out = buffer;
return OK;
}
} // namespace android
LOCAL_PATH := $(call my-dir)
include $(CLEAR_VARS)
include frameworks/base/media/libstagefright/codecs/common/Config.mk
LOCAL_PRELINK_MODULE := false
LOCAL_SRC_FILES := \
AMRWBEncoder.cpp \
src/autocorr.c \
src/az_isp.c \
src/bits.c \
src/c2t64fx.c \
src/c4t64fx.c \
src/convolve.c \
src/cor_h_x.c \
src/decim54.c \
src/deemph.c \
src/dtx.c \
src/g_pitch.c \
src/gpclip.c \
src/homing.c \
src/hp400.c \
src/hp50.c \
src/hp6k.c \
src/hp_wsp.c \
src/int_lpc.c \
src/isp_az.c \
src/isp_isf.c \
src/lag_wind.c \
src/levinson.c \
src/log2.c \
src/lp_dec2.c \
src/math_op.c \
src/oper_32b.c \
src/p_med_ol.c \
src/pit_shrp.c \
src/pitch_f4.c \
src/pred_lt4.c \
src/preemph.c \
src/q_gain2.c \
src/q_pulse.c \
src/qisf_ns.c \
src/qpisf_2s.c \
src/random.c \
src/residu.c \
src/scale.c \
src/stream.c \
src/syn_filt.c \
src/updt_tar.c \
src/util.c \
src/voAMRWBEnc.c \
src/voicefac.c \
src/wb_vad.c \
src/weight_a.c \
src/mem_align.c
ifeq ($(VOTT), v5)
LOCAL_SRC_FILES += \
src/asm/ARMV5E/convolve_opt.s \
src/asm/ARMV5E/cor_h_vec_opt.s \
src/asm/ARMV5E/Deemph_32_opt.s \
src/asm/ARMV5E/Dot_p_opt.s \
src/asm/ARMV5E/Filt_6k_7k_opt.s \
src/asm/ARMV5E/Norm_Corr_opt.s \
src/asm/ARMV5E/pred_lt4_1_opt.s \
src/asm/ARMV5E/residu_asm_opt.s \
src/asm/ARMV5E/scale_sig_opt.s \
src/asm/ARMV5E/Syn_filt_32_opt.s \
src/asm/ARMV5E/syn_filt_opt.s
endif
ifeq ($(VOTT), v7)
LOCAL_SRC_FILES += \
src/asm/ARMV7/convolve_neon.s \
src/asm/ARMV7/cor_h_vec_neon.s \
src/asm/ARMV7/Deemph_32_neon.s \
src/asm/ARMV7/Dot_p_neon.s \
src/asm/ARMV7/Filt_6k_7k_neon.s \
src/asm/ARMV7/Norm_Corr_neon.s \
src/asm/ARMV7/pred_lt4_1_neon.s \
src/asm/ARMV7/residu_asm_neon.s \
src/asm/ARMV7/scale_sig_neon.s \
src/asm/ARMV7/Syn_filt_32_neon.s \
src/asm/ARMV7/syn_filt_neon.s
endif
LOCAL_MODULE := libstagefright_amrwbenc
LOCAL_ARM_MODE := arm
LOCAL_STATIC_LIBRARIES :=
LOCAL_SHARED_LIBRARIES :=
LOCAL_C_INCLUDES := \
frameworks/base/media/libstagefright/include \
frameworks/base/media/libstagefright/codecs/common/include \
frameworks/base/include \
$(LOCAL_PATH)/src \
$(LOCAL_PATH)/inc
LOCAL_CFLAGS := $(VO_CFLAGS)
ifeq ($(VOTT), v5)
LOCAL_CFLAGS += -DARM -DASM_OPT
LOCAL_C_INCLUDES += $(LOCAL_PATH)/src/asm/ARMV5E
endif
ifeq ($(VOTT), v7)
LOCAL_CFLAGS += -DARM -DARMV7 -DASM_OPT
LOCAL_C_INCLUDES += $(LOCAL_PATH)/src/asm/ARMV5E
LOCAL_C_INCLUDES += $(LOCAL_PATH)/src/asm/ARMV7
endif
include $(BUILD_STATIC_LIBRARY)
/*
** Copyright 2003-2010, VisualOn, Inc.
**
** 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.
*/
#ifdef LINUX
#include <dlfcn.h>
#endif
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#include "voAMRWB.h"
#include "cmnMemory.h"
#define VOAMRWB_RFC3267_HEADER_INFO "#!AMR-WB\n"
#define INPUT_SIZE 640
#define OUTPUT_SIZE 1024
unsigned char InputBuf[INPUT_SIZE];
unsigned char OutputBuf[OUTPUT_SIZE];
void usage (void) {
printf ("AMR_WB Encoder HELP Displays this text\n");
printf ("\n");
printf ("Usage:\n");
printf ("AMRWBEnc [options] Input_file output_file \n");
printf ("\n");
printf ("Options +M* +F* +DTX \n");
printf ("Support \n");
printf ("Options +M* for seting compression bitrate mode, default is 23.85kbps\n");
printf (" +M0 = 6.6kbps \n");
printf (" +M1 = 8.85kbps \n");
printf (" +M2 = 12.65kbps \n");
printf (" +M3 = 14.25kbps \n");
printf (" +M4 = 15.58kbps \n");
printf (" +M5 = 18.25kbps \n");
printf (" +M6 = 19.85kbps \n");
printf (" +M7 = 23.05kbps \n");
printf (" +M8 = 23.85kbps \n");
printf ("\n");
printf ("Options +F* for setting output frame Type, default is RFC3267 \n");
printf ("+F0 for AMR_WB Defualt bit extern short data frame type \n");
printf ("+F1 for AMR_WB_ITU bit extern short data frame type \n");
printf ("+F2 for RFC3267\n ");
printf ("\n");
printf ("Options +DTX enable DTX mode, default is disable.\n");
printf ("File names, input raw PCM data, and output is AMR_WB bit-stream file.\n");
printf ("\n");
}
int GetNextBuf(FILE* inFile,unsigned char* dst,int size)
{
int size2 = (int)fread(dst, sizeof(signed char), size,inFile);
return size2;
}
typedef int (VO_API * VOGETAUDIOENCAPI) (VO_AUDIO_CODECAPI * pEncHandle);
int encode(
int mode,
short allow_dtx,
VOAMRWBFRAMETYPE frameType,
const char* srcfile,
const char* dstfile
)
{
int ret = 0;
int returnCode;
FILE *fsrc = NULL;
FILE *fdst = NULL;
int framenum = 0;
int eofFile = 0;
int size1 = 0;
int Relens;
VO_AUDIO_CODECAPI AudioAPI;
VO_MEM_OPERATOR moper;
VO_CODEC_INIT_USERDATA useData;
VO_HANDLE hCodec;
VO_CODECBUFFER inData;
VO_CODECBUFFER outData;
VO_AUDIO_OUTPUTINFO outFormat;
unsigned char *inBuf = InputBuf;
unsigned char *outBuf = OutputBuf;
#ifdef LINUX
void *handle = NULL;
void *pfunc;
VOGETAUDIOENCAPI pGetAPI;
#endif
clock_t start, finish;
double duration = 0.0;
if ((fsrc = fopen (srcfile, "rb")) == NULL)
{
ret = -1;
goto safe_exit;
}
if ((fdst = fopen (dstfile, "wb")) == NULL)
{
ret = -1;
goto safe_exit;
}
moper.Alloc = cmnMemAlloc;
moper.Copy = cmnMemCopy;
moper.Free = cmnMemFree;
moper.Set = cmnMemSet;
moper.Check = cmnMemCheck;
useData.memflag = VO_IMF_USERMEMOPERATOR;
useData.memData = (VO_PTR)(&moper);
#ifdef LINUX
handle = dlopen("/data/local/tmp/voAMRWBEnc.so", RTLD_NOW);
if(handle == 0)
{
printf("open dll error......");
return -1;
}
pfunc = dlsym(handle, "voGetAMRWBEncAPI");
if(pfunc == 0)
{
printf("open function error......");
return -1;
}
pGetAPI = (VOGETAUDIOENCAPI)pfunc;
returnCode = pGetAPI(&AudioAPI);
if(returnCode)
{
printf("get APIs error......");
return -1;
}
#else
ret = voGetAMRWBEncAPI(&AudioAPI);
if(ret)
{
ret = -1;
printf("get APIs error......");
goto safe_exit;
}
#endif
//####################################### Init Encoding Section #########################################
ret = AudioAPI.Init(&hCodec, VO_AUDIO_CodingAMRWB, &useData);
if(ret)
{
ret = -1;
printf("APIs init error......");
goto safe_exit;
}
Relens = GetNextBuf(fsrc,InputBuf,INPUT_SIZE);
if(Relens!=INPUT_SIZE && !feof(fsrc))
{
ret = -1; //Invalid magic number
printf("get next buffer error......");
goto safe_exit;
}
//###################################### set encode Mode ##################################################
ret = AudioAPI.SetParam(hCodec, VO_PID_AMRWB_FRAMETYPE, &frameType);
ret = AudioAPI.SetParam(hCodec, VO_PID_AMRWB_MODE, &mode);
ret = AudioAPI.SetParam(hCodec, VO_PID_AMRWB_DTX, &allow_dtx);
if(frameType == VOAMRWB_RFC3267)
{
/* write RFC3267 Header info to indicate single channel AMR file storage format */
size1 = (int)strlen(VOAMRWB_RFC3267_HEADER_INFO);
memcpy(outBuf, VOAMRWB_RFC3267_HEADER_INFO, size1);
outBuf += size1;
}
//####################################### Encoding Section #########################################
printf(" \n ---------------- Running -------------------------\n ");
do{
inData.Buffer = (unsigned char *)inBuf;
inData.Length = Relens;
outData.Buffer = outBuf;
start = clock();
/* decode one amr block */
returnCode = AudioAPI.SetInputData(hCodec,&inData);
do {
returnCode = AudioAPI.GetOutputData(hCodec,&outData, &outFormat);
if(returnCode == 0)
{
framenum++;
printf(" Frames processed: %hd\r", framenum);
if(framenum == 1)
{
fwrite(OutputBuf, 1, outData.Length + size1, fdst);
fflush(fdst);
}
else
{
fwrite(outData.Buffer, 1, outData.Length, fdst);
fflush(fdst);
}
}
else if(returnCode == VO_ERR_LICENSE_ERROR)
{
printf("Encoder time reach upper limit......");
goto safe_exit;
}
} while(returnCode != VO_ERR_INPUT_BUFFER_SMALL);
finish = clock();
duration += finish - start;
if (!eofFile) {
Relens = GetNextBuf(fsrc, InputBuf, INPUT_SIZE);
inBuf = InputBuf;
if (feof(fsrc) && Relens == 0)
eofFile = 1;
}
} while (!eofFile && returnCode);
//####################################### End Encoding Section #########################################
safe_exit:
returnCode = AudioAPI.Uninit(hCodec);
printf( "\n%2.5f seconds\n", (double)duration/CLOCKS_PER_SEC);
if (fsrc)
fclose(fsrc);
if (fdst)
fclose(fdst);
#ifdef LINUX
dlclose(handle);
#endif
return ret;
}
int main(int argc, char **argv) // for gcc compiler;
{
int mode, r;
int arg, filename=0;
char *inFileName = NULL;
char *outFileName = NULL;
short allow_dtx;
VOAMRWBFRAMETYPE frameType;
printf("\n");
printf("************************Adaptive Multi-Rate Wide Band Encoder (AMR-WB)*******************************\n");