#include <media/stagefright/foundation/hexdump.h>
#include <media/stagefright/MediaDefs.h>
-#include <OMX_FFExt.h>
-
#include "utils/ffmpeg_utils.h"
-//#undef realloc
-//#include <stdlib.h>
-
#define DEBUG_PKT 0
#define DEBUG_FRM 0
}
void SoftFFmpegAudio::setMode(const char *name) {
- if (!strcmp(name, "OMX.ffmpeg.mp3.decoder")) {
+ if (!strcmp(name, "OMX.ffmpeg.aac.decoder")) {
+ mMode = MODE_AAC;
+ } else if (!strcmp(name, "OMX.ffmpeg.mp3.decoder")) {
mMode = MODE_MPEG;
mIgnoreExtradata = true;
- } else if (!strcmp(name, "OMX.ffmpeg.mp1.decoder")) {
- mMode = MODE_MPEGL1;
- } else if (!strcmp(name, "OMX.ffmpeg.mp2.decoder")) {
- mMode = MODE_MPEGL2;
- } else if (!strcmp(name, "OMX.ffmpeg.aac.decoder")) {
- mMode = MODE_AAC;
+ } else if (!strcmp(name, "OMX.ffmpeg.vorbis.decoder")) {
+ mMode = MODE_VORBIS;
} else if (!strcmp(name, "OMX.ffmpeg.wma.decoder")) {
mMode = MODE_WMA;
} else if (!strcmp(name, "OMX.ffmpeg.ra.decoder")) {
mMode = MODE_RA;
+ } else if (!strcmp(name, "OMX.ffmpeg.flac.decoder")) {
+ mMode = MODE_FLAC;
+ } else if (!strcmp(name, "OMX.ffmpeg.mp2.decoder")) {
+ mMode = MODE_MPEGL2;
} else if (!strcmp(name, "OMX.ffmpeg.ac3.decoder")) {
mMode = MODE_AC3;
} else if (!strcmp(name, "OMX.ffmpeg.ape.decoder")) {
mMode = MODE_APE;
} else if (!strcmp(name, "OMX.ffmpeg.dts.decoder")) {
mMode = MODE_DTS;
- } else if (!strcmp(name, "OMX.ffmpeg.flac.decoder")) {
- mMode = MODE_FLAC;
- } else if (!strcmp(name, "OMX.ffmpeg.vorbis.decoder")) {
- mMode = MODE_VORBIS;
- } else if (!strcmp(name, "OMX.ffmpeg.aheuristic.decoder")) {
- mMode = MODE_HEURISTIC;
+ } else if (!strcmp(name, "OMX.ffmpeg.atrial.decoder")) {
+ mMode = MODE_TRIAL;
} else {
TRESPASS();
}
OMX_PTR appData,
OMX_COMPONENTTYPE **component)
: SimpleSoftOMXComponent(name, callbacks, appData, component),
- mMode(MODE_MPEG),
- mFFmpegInited(false),
- mCtx(NULL),
- mSwrCtx(NULL),
+ mMode(MODE_NONE),
+ mFFmpegAlreadyInited(false),
mCodecAlreadyOpened(false),
mExtradataReady(false),
mIgnoreExtradata(false),
- mFlushComplete(false),
- mSignalledError(false),
- mReceivedEOS(false),
+ mCtx(NULL),
+ mSwrCtx(NULL),
mFrame(NULL),
+ mEOSStatus(INPUT_DATA_AVAILABLE),
+ mSignalledError(false),
mAudioClock(0),
mInputBufferSize(0),
+ mResampledData(NULL),
mResampledDataSize(0),
mOutputPortSettingsChange(NONE) {
SoftFFmpegAudio::~SoftFFmpegAudio() {
ALOGV("~SoftFFmpegAudio");
- av_freep(&mFrame);
- mFrame = NULL;
deInitDecoder();
- if (mFFmpegInited) {
+ if (mFFmpegAlreadyInited) {
deInitFFmpeg();
}
}
-void SoftFFmpegAudio::initPorts() {
- OMX_PARAM_PORTDEFINITIONTYPE def;
- InitOMXParams(&def);
-
- def.nPortIndex = 0;
- def.eDir = OMX_DirInput;
- def.nBufferCountMin = kNumBuffers;
- def.nBufferCountActual = def.nBufferCountMin;
- if (mMode == MODE_APE) {
- def.nBufferSize = 1000000; // ape!
- } else if (mMode == MODE_DTS) {
- def.nBufferSize = 1000000; // dts!
- } else {
- def.nBufferSize = 20480; // 8192 is too small
- }
- def.bEnabled = OMX_TRUE;
- def.bPopulated = OMX_FALSE;
- def.eDomain = OMX_PortDomainAudio;
- def.bBuffersContiguous = OMX_FALSE;
- def.nBufferAlignment = 1;
-
- switch (mMode) {
- case MODE_MPEG:
- def.format.audio.cMIMEType = const_cast<char *>(MEDIA_MIMETYPE_AUDIO_MPEG);
- def.format.audio.eEncoding = OMX_AUDIO_CodingMP3;
- break;
- case MODE_MPEGL1:
- def.format.audio.cMIMEType = const_cast<char *>(MEDIA_MIMETYPE_AUDIO_MPEG_LAYER_I);
- def.format.audio.eEncoding = OMX_AUDIO_CodingMP3;
- break;
- case MODE_MPEGL2:
- def.format.audio.cMIMEType = const_cast<char *>(MEDIA_MIMETYPE_AUDIO_MPEG_LAYER_II);
- def.format.audio.eEncoding = OMX_AUDIO_CodingMP3;
- break;
+void SoftFFmpegAudio::initInputFormat(uint32_t mode,
+ OMX_PARAM_PORTDEFINITIONTYPE &def) {
+ switch (mode) {
case MODE_AAC:
def.format.audio.cMIMEType = const_cast<char *>(MEDIA_MIMETYPE_AUDIO_AAC);
def.format.audio.eEncoding = OMX_AUDIO_CodingAAC;
break;
- case MODE_AC3:
- def.format.audio.cMIMEType = const_cast<char *>(MEDIA_MIMETYPE_AUDIO_AC3);
- // TODO
- //def.format.audio.eEncoding = OMX_AUDIO_CodingAC3;
- def.format.audio.eEncoding = OMX_AUDIO_CodingAutoDetect; // right?? orz
+ case MODE_MPEG:
+ def.format.audio.cMIMEType = const_cast<char *>(MEDIA_MIMETYPE_AUDIO_MPEG);
+ def.format.audio.eEncoding = OMX_AUDIO_CodingMP3;
+ break;
+ case MODE_VORBIS:
+ def.format.audio.cMIMEType = const_cast<char *>(MEDIA_MIMETYPE_AUDIO_VORBIS);
+ def.format.audio.eEncoding = OMX_AUDIO_CodingVORBIS;
break;
case MODE_WMA:
def.format.audio.cMIMEType = const_cast<char *>(MEDIA_MIMETYPE_AUDIO_WMA);
def.format.audio.cMIMEType = const_cast<char *>(MEDIA_MIMETYPE_AUDIO_RA);
def.format.audio.eEncoding = OMX_AUDIO_CodingRA;
break;
+ case MODE_FLAC:
+ def.format.audio.cMIMEType = const_cast<char *>(MEDIA_MIMETYPE_AUDIO_FLAC);
+ def.format.audio.eEncoding = OMX_AUDIO_CodingFLAC;
+ break;
+ case MODE_MPEGL2:
+ def.format.audio.cMIMEType = const_cast<char *>(MEDIA_MIMETYPE_AUDIO_MPEG_LAYER_II);
+ def.format.audio.eEncoding = OMX_AUDIO_CodingMP3;
+ break;
+ case MODE_AC3:
+ def.format.audio.cMIMEType = const_cast<char *>(MEDIA_MIMETYPE_AUDIO_AC3);
+ def.format.audio.eEncoding = OMX_AUDIO_CodingAC3;
+ break;
case MODE_APE:
def.format.audio.cMIMEType = const_cast<char *>(MEDIA_MIMETYPE_AUDIO_APE);
def.format.audio.eEncoding = OMX_AUDIO_CodingAPE;
def.format.audio.cMIMEType = const_cast<char *>(MEDIA_MIMETYPE_AUDIO_DTS);
def.format.audio.eEncoding = OMX_AUDIO_CodingDTS;
break;
- case MODE_FLAC:
- def.format.audio.cMIMEType = const_cast<char *>(MEDIA_MIMETYPE_AUDIO_FLAC);
- def.format.audio.eEncoding = OMX_AUDIO_CodingFLAC;
- break;
- case MODE_VORBIS:
- def.format.audio.cMIMEType = const_cast<char *>(MEDIA_MIMETYPE_AUDIO_VORBIS);
- def.format.audio.eEncoding = OMX_AUDIO_CodingVORBIS;
- break;
- case MODE_HEURISTIC:
+ case MODE_TRIAL:
def.format.audio.cMIMEType = const_cast<char *>(MEDIA_MIMETYPE_AUDIO_FFMPEG);
def.format.audio.eEncoding = OMX_AUDIO_CodingAutoDetect;
break;
def.format.audio.pNativeRender = NULL;
def.format.audio.bFlagErrorConcealment = OMX_FALSE;
+}
+
+void SoftFFmpegAudio::initPorts() {
+ OMX_PARAM_PORTDEFINITIONTYPE def;
+ InitOMXParams(&def);
+
+ def.nPortIndex = 0;
+ def.eDir = OMX_DirInput;
+ def.nBufferCountMin = kNumInputBuffers;
+ def.nBufferCountActual = def.nBufferCountMin;
+ if (mMode == MODE_APE) {
+ def.nBufferSize = 1000000; // ape!
+ } else if (mMode == MODE_DTS) {
+ def.nBufferSize = 1000000; // dts!
+ } else {
+ def.nBufferSize = 20480; // 8192 is too small
+ }
+ def.bEnabled = OMX_TRUE;
+ def.bPopulated = OMX_FALSE;
+ def.eDomain = OMX_PortDomainAudio;
+ def.bBuffersContiguous = OMX_FALSE;
+ def.nBufferAlignment = 1;
+
+ initInputFormat(mMode, def);
addPort(def);
def.nPortIndex = 1;
def.eDir = OMX_DirOutput;
- def.nBufferCountMin = kNumBuffers;
+ def.nBufferCountMin = kNumOutputBuffers;
def.nBufferCountActual = def.nBufferCountMin;
def.nBufferSize = kOutputBufferSize;
def.bEnabled = OMX_TRUE;
addPort(def);
}
-void SoftFFmpegAudio::setAVCtxToDefault(AVCodecContext *avctx, const AVCodec *codec) {
+void SoftFFmpegAudio::setDefaultCtx(AVCodecContext *avctx, const AVCodec *codec) {
int fast = 0;
avctx->workaround_bugs = 1;
avctx->flags |= CODEC_FLAG_EMU_EDGE;
}
+bool SoftFFmpegAudio::isConfigured() {
+ return mAudioSrcChannels != -1;
+}
-void SoftFFmpegAudio::configDefaultCtx() {
- mCtx->channels = 2;
- mCtx->sample_rate = 44100;
- mCtx->bit_rate = 0;
- mCtx->sample_fmt = AV_SAMPLE_FMT_S16;
+void SoftFFmpegAudio::resetCtx() {
+ mCtx->channels = -1;
+ mCtx->sample_rate = -1;
+ mCtx->bit_rate = -1;
+ mCtx->sample_fmt = AV_SAMPLE_FMT_NONE;
- mAudioSrcChannels = mAudioTgtChannels = 2;
- mAudioSrcFreq = mAudioTgtFreq = 44100;
- mAudioSrcFmt = mAudioTgtFmt = AV_SAMPLE_FMT_S16;
- mAudioSrcChannelLayout = mAudioTgtChannelLayout =
- av_get_default_channel_layout(2);
+ mAudioSrcChannels = mAudioTgtChannels = -1;
+ mAudioSrcFreq = mAudioTgtFreq = -1;
+ mAudioSrcFmt = mAudioTgtFmt = AV_SAMPLE_FMT_NONE;
+ mAudioSrcChannelLayout = mAudioTgtChannelLayout = 0;
}
status_t SoftFFmpegAudio::initDecoder() {
status_t status;
status = initFFmpeg();
- if (status != OK)
+ if (status != OK) {
return NO_INIT;
-
- mFFmpegInited = true;
+ }
+ mFFmpegAlreadyInited = true;
mCtx = avcodec_alloc_context3(NULL);
- if (!mCtx)
- {
+ if (!mCtx) {
ALOGE("avcodec_alloc_context failed.");
return NO_MEMORY;
}
mCtx->codec_type = AVMEDIA_TYPE_AUDIO;
switch (mMode) {
+ case MODE_AAC:
+ mCtx->codec_id = AV_CODEC_ID_AAC;
+ break;
case MODE_MPEG:
- mCtx->codec_id = CODEC_ID_MP3;
+ mCtx->codec_id = AV_CODEC_ID_MP3;
break;
- case MODE_MPEGL1:
- mCtx->codec_id = CODEC_ID_MP1;
+ case MODE_VORBIS:
+ mCtx->codec_id = AV_CODEC_ID_VORBIS;
break;
- case MODE_MPEGL2:
- mCtx->codec_id = CODEC_ID_MP2;
+ case MODE_WMA:
+ mCtx->codec_id = AV_CODEC_ID_WMAV2; //should be adjusted later
break;
- case MODE_AAC:
- mCtx->codec_id = CODEC_ID_AAC;
+ case MODE_RA:
+ mCtx->codec_id = AV_CODEC_ID_COOK;
break;
- case MODE_AC3:
- mCtx->codec_id = CODEC_ID_AC3;
+ case MODE_FLAC:
+ mCtx->codec_id = AV_CODEC_ID_FLAC;
break;
- case MODE_WMA:
- mCtx->codec_id = CODEC_ID_WMAV2; // FIXME, CODEC_ID_WMAV1 or CODEC_ID_WMAV2?
+ case MODE_MPEGL2:
+ mCtx->codec_id = AV_CODEC_ID_MP2;
break;
- case MODE_RA:
- mCtx->codec_id = CODEC_ID_COOK;
+ case MODE_AC3:
+ mCtx->codec_id = AV_CODEC_ID_AC3;
break;
case MODE_APE:
- mCtx->codec_id = CODEC_ID_APE;
+ mCtx->codec_id = AV_CODEC_ID_APE;
break;
case MODE_DTS:
- mCtx->codec_id = CODEC_ID_DTS;
- break;
- case MODE_FLAC:
- mCtx->codec_id = CODEC_ID_FLAC;
+ mCtx->codec_id = AV_CODEC_ID_DTS;
break;
- case MODE_VORBIS:
- mCtx->codec_id = CODEC_ID_VORBIS;
- break;
- case MODE_HEURISTIC:
- mCtx->codec_id = CODEC_ID_NONE;
+ case MODE_TRIAL:
+ mCtx->codec_id = AV_CODEC_ID_NONE;
break;
default:
CHECK(!"Should not be here. Unsupported codec");
break;
}
- //default config
- configDefaultCtx();
+ //invalid ctx
+ resetCtx();
mCtx->extradata = NULL;
mCtx->extradata_size = 0;
void SoftFFmpegAudio::deInitDecoder() {
if (mCtx) {
- //avcodec_flush_buffers(mCtx); // is it necessary? crash sometimes if call it
if (!mCtx->extradata) {
av_free(mCtx->extradata);
mCtx->extradata = NULL;
mCtx->extradata_size = 0;
}
- avcodec_close(mCtx);
- av_free(mCtx);
- mCtx = NULL;
+ if (mCodecAlreadyOpened) {
+ avcodec_close(mCtx);
+ av_free(mCtx);
+ mCtx = NULL;
+ }
+ }
+ if (mFrame) {
+ av_freep(&mFrame);
+ mFrame = NULL;
}
-
if (mSwrCtx) {
swr_free(&mSwrCtx);
mSwrCtx = NULL;
OMX_ERRORTYPE SoftFFmpegAudio::internalGetParameter(
OMX_INDEXTYPE index, OMX_PTR params) {
+ //ALOGV("internalGetParameter index:0x%x", index);
switch (index) {
+ case OMX_IndexParamAudioPcm:
+ {
+ OMX_AUDIO_PARAM_PCMMODETYPE *profile =
+ (OMX_AUDIO_PARAM_PCMMODETYPE *)params;
+
+ if (profile->nPortIndex > kOutputPortIndex) {
+ return OMX_ErrorUndefined;
+ }
+
+ profile->eNumData = OMX_NumericalDataSigned;
+ profile->eEndian = OMX_EndianBig;
+ profile->bInterleaved = OMX_TRUE;
+ profile->nBitPerSample = 16;
+ profile->ePCMMode = OMX_AUDIO_PCMModeLinear;
+ profile->eChannelMapping[0] = OMX_AUDIO_ChannelLF;
+ profile->eChannelMapping[1] = OMX_AUDIO_ChannelRF;
+
+ CHECK(isConfigured());
+
+ profile->nChannels = mAudioSrcChannels;
+ profile->nSamplingRate = mAudioSrcFreq;
+
+ //mCtx has been updated(adjustAudioParams)!
+ ALOGV("get pcm params, nChannels:%lu, nSamplingRate:%lu",
+ profile->nChannels, profile->nSamplingRate);
+
+ return OMX_ErrorNone;
+ }
+
case OMX_IndexParamAudioAac:
{
OMX_AUDIO_PARAM_AACPROFILETYPE *profile =
(OMX_AUDIO_PARAM_AACPROFILETYPE *)params;
- if (profile->nPortIndex != 0) {
+ if (profile->nPortIndex != kInputPortIndex) {
return OMX_ErrorUndefined;
}
+ CHECK(!isConfigured());
+
profile->nBitRate = 0;
profile->nAudioBandWidth = 0;
profile->nAACtools = 0;
return OMX_ErrorNone;
}
- case OMX_IndexParamAudioWma:
+
+ case OMX_IndexParamAudioMp3:
{
- OMX_AUDIO_PARAM_WMATYPE *profile =
- (OMX_AUDIO_PARAM_WMATYPE *)params;
+ OMX_AUDIO_PARAM_MP3TYPE *profile =
+ (OMX_AUDIO_PARAM_MP3TYPE *)params;
- if (profile->nPortIndex != 0) {
+ if (profile->nPortIndex != kInputPortIndex) {
return OMX_ErrorUndefined;
}
+ CHECK(!isConfigured());
+
profile->nChannels = 0;
- profile->nSamplingRate = 0;
+ profile->nSampleRate = 0;
profile->nBitRate = 0;
- profile->eFormat = OMX_AUDIO_WMAFormatUnused;
+ profile->nAudioBandWidth = 0;
+ profile->eChannelMode = OMX_AUDIO_ChannelModeStereo;
+ profile->eFormat = OMX_AUDIO_MP3StreamFormatMP1Layer3;
return OMX_ErrorNone;
}
- case OMX_IndexParamAudioRa:
+ case OMX_IndexParamAudioVorbis:
{
- OMX_AUDIO_PARAM_RATYPE *profile =
- (OMX_AUDIO_PARAM_RATYPE *)params;
+ OMX_AUDIO_PARAM_VORBISTYPE *profile =
+ (OMX_AUDIO_PARAM_VORBISTYPE *)params;
- if (profile->nPortIndex != 0) {
+ if (profile->nPortIndex != kInputPortIndex) {
return OMX_ErrorUndefined;
}
+ CHECK(!isConfigured());
+
+ profile->nBitRate = 0;
+ profile->nMinBitRate = 0;
+ profile->nMaxBitRate = 0;
+ profile->nAudioBandWidth = 0;
+ profile->nQuality = 3;
+ profile->bManaged = OMX_FALSE;
+ profile->bDownmix = OMX_FALSE;
+
profile->nChannels = 0;
- profile->nSamplingRate = 0;
- profile->eFormat = OMX_AUDIO_RAFormatUnused;
+ profile->nSampleRate = 0;
return OMX_ErrorNone;
}
- case OMX_IndexParamAudioApe:
+
+ case OMX_IndexParamAudioWma:
{
- OMX_AUDIO_PARAM_APETYPE *profile =
- (OMX_AUDIO_PARAM_APETYPE *)params;
+ OMX_AUDIO_PARAM_WMATYPE *profile =
+ (OMX_AUDIO_PARAM_WMATYPE *)params;
- if (profile->nPortIndex != 0) {
+ if (profile->nPortIndex != kInputPortIndex) {
return OMX_ErrorUndefined;
}
+ CHECK(!isConfigured());
+
profile->nChannels = 0;
profile->nSamplingRate = 0;
+ profile->nBitRate = 0;
+ profile->eFormat = OMX_AUDIO_WMAFormatUnused;
return OMX_ErrorNone;
}
- case OMX_IndexParamAudioDts:
+
+ case OMX_IndexParamAudioRa:
{
- OMX_AUDIO_PARAM_DTSTYPE *profile =
- (OMX_AUDIO_PARAM_DTSTYPE *)params;
+ OMX_AUDIO_PARAM_RATYPE *profile =
+ (OMX_AUDIO_PARAM_RATYPE *)params;
- if (profile->nPortIndex != 0) {
+ if (profile->nPortIndex != kInputPortIndex) {
return OMX_ErrorUndefined;
}
+ CHECK(!isConfigured());
+
profile->nChannels = 0;
profile->nSamplingRate = 0;
+ profile->eFormat = OMX_AUDIO_RAFormatUnused;
return OMX_ErrorNone;
}
+
case OMX_IndexParamAudioFlac:
{
OMX_AUDIO_PARAM_FLACTYPE *profile =
(OMX_AUDIO_PARAM_FLACTYPE *)params;
- if (profile->nPortIndex != 0) {
+ if (profile->nPortIndex != kInputPortIndex) {
return OMX_ErrorUndefined;
}
+ CHECK(!isConfigured());
+
profile->nChannels = 0;
profile->nSampleRate = 0;
return OMX_ErrorNone;
}
- case OMX_IndexParamAudioPcm:
+
+ case OMX_IndexParamAudioMp2:
{
- OMX_AUDIO_PARAM_PCMMODETYPE *profile =
- (OMX_AUDIO_PARAM_PCMMODETYPE *)params;
+ OMX_AUDIO_PARAM_MP2TYPE *profile =
+ (OMX_AUDIO_PARAM_MP2TYPE *)params;
- if (profile->nPortIndex > 1) {
+ if (profile->nPortIndex != kInputPortIndex) {
return OMX_ErrorUndefined;
}
- profile->eNumData = OMX_NumericalDataSigned;
- profile->eEndian = OMX_EndianBig;
- profile->bInterleaved = OMX_TRUE;
- profile->nBitPerSample = 16;
- profile->ePCMMode = OMX_AUDIO_PCMModeLinear;
- profile->eChannelMapping[0] = OMX_AUDIO_ChannelLF;
- profile->eChannelMapping[1] = OMX_AUDIO_ChannelRF;
-
- profile->nChannels = mCtx->channels;
- profile->nSamplingRate = mCtx->sample_rate;
+ CHECK(!isConfigured());
- //NOTE: mCtx is the default(configDefaultCtx), or has
- //been updated(adjustAudioParameter)!!!
- ALOGV("get pcm params, nChannels:%lu, nSamplingRate:%lu",
- profile->nChannels, profile->nSamplingRate);
+ profile->nChannels = 0;
+ profile->nSampleRate = 0;
return OMX_ErrorNone;
}
- case OMX_IndexParamAudioVorbis:
+
+ case OMX_IndexParamAudioAc3:
{
- OMX_AUDIO_PARAM_VORBISTYPE *profile =
- (OMX_AUDIO_PARAM_VORBISTYPE *)params;
+ OMX_AUDIO_PARAM_AC3TYPE *profile =
+ (OMX_AUDIO_PARAM_AC3TYPE *)params;
- if (profile->nPortIndex != 0) {
+ if (profile->nPortIndex != kInputPortIndex) {
return OMX_ErrorUndefined;
}
- profile->nBitRate = 0;
- profile->nMinBitRate = 0;
- profile->nMaxBitRate = 0;
- profile->nAudioBandWidth = 0;
- profile->nQuality = 3;
- profile->bManaged = OMX_FALSE;
- profile->bDownmix = OMX_FALSE;
+ CHECK(!isConfigured());
+
+ profile->nChannels = 0;
+ profile->nSamplingRate = 0;
- profile->nChannels = 1;
- profile->nSampleRate = 44100;
-/*
- if (!isConfigured()) {
- profile->nChannels = 1;
- profile->nSampleRate = 44100;
- } else {
- profile->nChannels = mVi->channels;
- profile->nSampleRate = mVi->rate;
- profile->nBitRate = mVi->bitrate_nominal;
- profile->nMinBitRate = mVi->bitrate_lower;
- profile->nMaxBitRate = mVi->bitrate_upper;
- }
-*/
return OMX_ErrorNone;
}
- default:
- if ((OMX_FF_INDEXTYPE)index == OMX_IndexParamAudioFFmpeg)
- {
- OMX_AUDIO_PARAM_FFMPEGTYPE *profile =
- (OMX_AUDIO_PARAM_FFMPEGTYPE *)params;
-
- if (profile->nPortIndex != 0) {
- return OMX_ErrorUndefined;
- }
-
- profile->eCodecId = 0;
- profile->nChannels = 0;
- profile->nBitRate = 0;
- profile->nBitsPerSample = 0;
- profile->nSampleRate = 0;
- profile->nBlockAlign = 0;
- profile->eSampleFormat = 0;
-
- return OMX_ErrorNone;
+ case OMX_IndexParamAudioApe:
+ {
+ OMX_AUDIO_PARAM_APETYPE *profile =
+ (OMX_AUDIO_PARAM_APETYPE *)params;
+
+ if (profile->nPortIndex != kInputPortIndex) {
+ return OMX_ErrorUndefined;
}
- return SimpleSoftOMXComponent::internalGetParameter(index, params);
- }
-}
+ CHECK(!isConfigured());
-OMX_ERRORTYPE SoftFFmpegAudio::isRoleSupported(
- const OMX_PARAM_COMPONENTROLETYPE *roleParams) {
- bool supported = true;
+ profile->nChannels = 0;
+ profile->nSamplingRate = 0;
- switch (mMode) {
- case MODE_MPEG:
- if (strncmp((const char *)roleParams->cRole,
- "audio_decoder.mp3", OMX_MAX_STRINGNAME_SIZE - 1))
- supported = false;
- break;
- case MODE_MPEGL1:
- if (strncmp((const char *)roleParams->cRole,
- "audio_decoder.mp1", OMX_MAX_STRINGNAME_SIZE - 1))
- supported = false;
- break;
- case MODE_MPEGL2:
- if (strncmp((const char *)roleParams->cRole,
- "audio_decoder.mp2", OMX_MAX_STRINGNAME_SIZE - 1))
- supported = false;
- break;
+ return OMX_ErrorNone;
+ }
+
+ case OMX_IndexParamAudioDts:
+ {
+ OMX_AUDIO_PARAM_DTSTYPE *profile =
+ (OMX_AUDIO_PARAM_DTSTYPE *)params;
+
+ if (profile->nPortIndex != kInputPortIndex) {
+ return OMX_ErrorUndefined;
+ }
+
+ CHECK(!isConfigured());
+
+ profile->nChannels = 0;
+ profile->nSamplingRate = 0;
+
+ return OMX_ErrorNone;
+ }
+
+ case OMX_IndexParamAudioFFmpeg:
+ {
+ OMX_AUDIO_PARAM_FFMPEGTYPE *profile =
+ (OMX_AUDIO_PARAM_FFMPEGTYPE *)params;
+
+ if (profile->nPortIndex != kInputPortIndex) {
+ return OMX_ErrorUndefined;
+ }
+
+ CHECK(!isConfigured());
+
+ profile->eCodecId = 0;
+ profile->nChannels = 0;
+ profile->nBitRate = 0;
+ profile->nBitsPerSample = 0;
+ profile->nSampleRate = 0;
+ profile->nBlockAlign = 0;
+ profile->eSampleFormat = 0;
+
+ return OMX_ErrorNone;
+ }
+
+ default:
+
+ return SimpleSoftOMXComponent::internalGetParameter(index, params);
+ }
+}
+
+OMX_ERRORTYPE SoftFFmpegAudio::isRoleSupported(
+ const OMX_PARAM_COMPONENTROLETYPE *roleParams) {
+ bool supported = true;
+
+ switch (mMode) {
case MODE_AAC:
if (strncmp((const char *)roleParams->cRole,
"audio_decoder.aac", OMX_MAX_STRINGNAME_SIZE - 1))
- supported = false;
+ supported = false;
break;
- case MODE_AC3:
+ case MODE_MPEG:
if (strncmp((const char *)roleParams->cRole,
- "audio_decoder.ac3", OMX_MAX_STRINGNAME_SIZE - 1))
- supported = false;
+ "audio_decoder.mp3", OMX_MAX_STRINGNAME_SIZE - 1))
+ supported = false;
+ break;
+ case MODE_VORBIS:
+ if (strncmp((const char *)roleParams->cRole,
+ "audio_decoder.vorbis", OMX_MAX_STRINGNAME_SIZE - 1))
+ supported = false;
break;
case MODE_WMA:
if (strncmp((const char *)roleParams->cRole,
"audio_decoder.wma", OMX_MAX_STRINGNAME_SIZE - 1))
- supported = false;
+ supported = false;
break;
case MODE_RA:
if (strncmp((const char *)roleParams->cRole,
"audio_decoder.ra", OMX_MAX_STRINGNAME_SIZE - 1))
- supported = false;
+ supported = false;
break;
- case MODE_APE:
+ case MODE_FLAC:
if (strncmp((const char *)roleParams->cRole,
- "audio_decoder.ape", OMX_MAX_STRINGNAME_SIZE - 1))
- supported = false;
+ "audio_decoder.flac", OMX_MAX_STRINGNAME_SIZE - 1))
+ supported = false;
break;
- case MODE_DTS:
+ case MODE_MPEGL2:
if (strncmp((const char *)roleParams->cRole,
- "audio_decoder.dts", OMX_MAX_STRINGNAME_SIZE - 1))
- supported = false;
+ "audio_decoder.mp2", OMX_MAX_STRINGNAME_SIZE - 1))
+ supported = false;
break;
- case MODE_FLAC:
+ case MODE_AC3:
if (strncmp((const char *)roleParams->cRole,
- "audio_decoder.flac", OMX_MAX_STRINGNAME_SIZE - 1))
- supported = false;
+ "audio_decoder.ac3", OMX_MAX_STRINGNAME_SIZE - 1))
+ supported = false;
break;
- case MODE_VORBIS:
+ case MODE_APE:
if (strncmp((const char *)roleParams->cRole,
- "audio_decoder.vorbis", OMX_MAX_STRINGNAME_SIZE - 1))
- supported = false;
+ "audio_decoder.ape", OMX_MAX_STRINGNAME_SIZE - 1))
+ supported = false;
+ break;
+ case MODE_DTS:
+ if (strncmp((const char *)roleParams->cRole,
+ "audio_decoder.dts", OMX_MAX_STRINGNAME_SIZE - 1))
+ supported = false;
break;
- case MODE_HEURISTIC:
+ case MODE_TRIAL:
if (strncmp((const char *)roleParams->cRole,
- "audio_decoder.heuristic", OMX_MAX_STRINGNAME_SIZE - 1))
- supported = false;
+ "audio_decoder.trial", OMX_MAX_STRINGNAME_SIZE - 1))
+ supported = false;
break;
default:
CHECK(!"Should not be here. Unsupported role.");
return OMX_ErrorNone;
}
-void SoftFFmpegAudio::adjustAudioParameter() {
+void SoftFFmpegAudio::adjustAudioParams() {
int32_t channels = 0;
int32_t sampling_rate = 0;
+ CHECK(!isConfigured());
+
sampling_rate = mCtx->sample_rate;
//channels support 1 or 2 only
OMX_ERRORTYPE SoftFFmpegAudio::internalSetParameter(
OMX_INDEXTYPE index, const OMX_PTR params) {
+ //ALOGV("internalSetParameter index:0x%x", index);
switch (index) {
case OMX_IndexParamStandardComponentRole:
{
(const OMX_PARAM_COMPONENTROLETYPE *)params;
return isRoleSupported(roleParams);
}
+
case OMX_IndexParamAudioPcm:
{
const OMX_AUDIO_PARAM_PCMMODETYPE *profile =
(const OMX_AUDIO_PARAM_PCMMODETYPE *)params;
- if (profile->nPortIndex != 1) {
+ if (profile->nPortIndex != kOutputPortIndex) {
return OMX_ErrorUndefined;
}
+ CHECK(!isConfigured());
+
mCtx->channels = profile->nChannels;
mCtx->sample_rate = profile->nSamplingRate;
mCtx->bits_per_coded_sample = profile->nBitPerSample;
return OMX_ErrorNone;
}
+
case OMX_IndexParamAudioAac:
{
const OMX_AUDIO_PARAM_AACPROFILETYPE *profile =
(const OMX_AUDIO_PARAM_AACPROFILETYPE *)params;
- if (profile->nPortIndex != 0) {
+ if (profile->nPortIndex != kInputPortIndex) {
+ return OMX_ErrorUndefined;
+ }
+
+ CHECK(!isConfigured());
+
+ mCtx->channels = profile->nChannels;
+ mCtx->sample_rate = profile->nSampleRate;
+
+ adjustAudioParams();
+
+ ALOGV("set OMX_IndexParamAudioAac, nChannels:%lu, nSampleRate:%lu",
+ profile->nChannels, profile->nSampleRate);
+
+ return OMX_ErrorNone;
+ }
+
+ case OMX_IndexParamAudioMp3:
+ {
+ const OMX_AUDIO_PARAM_MP3TYPE *profile =
+ (const OMX_AUDIO_PARAM_MP3TYPE *)params;
+
+ if (profile->nPortIndex != kInputPortIndex) {
return OMX_ErrorUndefined;
}
+ CHECK(!isConfigured());
+
mCtx->channels = profile->nChannels;
mCtx->sample_rate = profile->nSampleRate;
- adjustAudioParameter();
+ adjustAudioParams();
- ALOGV("set OMX_IndexParamAudioAac, nChannels:%lu, nSamplingRate:%lu",
+ ALOGV("set OMX_IndexParamAudioMp3, nChannels:%lu, nSampleRate:%lu",
profile->nChannels, profile->nSampleRate);
return OMX_ErrorNone;
}
+
+ case OMX_IndexParamAudioVorbis:
+ {
+ const OMX_AUDIO_PARAM_VORBISTYPE *profile =
+ (const OMX_AUDIO_PARAM_VORBISTYPE *)params;
+
+ if (profile->nPortIndex != kInputPortIndex) {
+ return OMX_ErrorUndefined;
+ }
+
+ CHECK(!isConfigured());
+
+ mCtx->channels = profile->nChannels;
+ mCtx->sample_rate = profile->nSampleRate;
+
+ adjustAudioParams();
+
+ ALOGD("set OMX_IndexParamAudioVorbis, "
+ "nChannels=%lu, nSampleRate=%lu, nBitRate=%lu, "
+ "nMinBitRate=%lu, nMaxBitRate=%lu",
+ profile->nChannels, profile->nSampleRate,
+ profile->nBitRate, profile->nMinBitRate,
+ profile->nMaxBitRate);
+
+ return OMX_ErrorNone;
+ }
+
case OMX_IndexParamAudioWma:
{
OMX_AUDIO_PARAM_WMATYPE *profile =
(OMX_AUDIO_PARAM_WMATYPE *)params;
- if (profile->nPortIndex != 0) {
+ if (profile->nPortIndex != kInputPortIndex) {
return OMX_ErrorUndefined;
}
+ CHECK(!isConfigured());
+
if (profile->eFormat == OMX_AUDIO_WMAFormat7) {
- mCtx->codec_id = CODEC_ID_WMAV2;
+ mCtx->codec_id = AV_CODEC_ID_WMAV2;
} else if (profile->eFormat == OMX_AUDIO_WMAFormat8) {
- mCtx->codec_id = CODEC_ID_WMAPRO;
+ mCtx->codec_id = AV_CODEC_ID_WMAPRO;
} else if (profile->eFormat == OMX_AUDIO_WMAFormat9) {
- mCtx->codec_id = CODEC_ID_WMALOSSLESS;
+ mCtx->codec_id = AV_CODEC_ID_WMALOSSLESS;
} else {
ALOGE("unsupported wma codec: 0x%x", profile->eFormat);
return OMX_ErrorUndefined;
mCtx->bit_rate = profile->nBitRate;
mCtx->block_align = profile->nBlockAlign;
- adjustAudioParameter();
+ adjustAudioParams();
ALOGV("set OMX_IndexParamAudioWma, nChannels:%u, "
"nSampleRate:%lu, nBitRate:%lu, nBlockAlign:%u",
return OMX_ErrorNone;
}
+
case OMX_IndexParamAudioRa:
{
OMX_AUDIO_PARAM_RATYPE *profile =
(OMX_AUDIO_PARAM_RATYPE *)params;
- if (profile->nPortIndex != 0) {
+ if (profile->nPortIndex != kInputPortIndex) {
return OMX_ErrorUndefined;
}
+ CHECK(!isConfigured());
+
mCtx->channels = profile->nChannels;
mCtx->sample_rate = profile->nSamplingRate;
// the cook audio codec need blockAlign!
mCtx->block_align = profile->nNumRegions;
- adjustAudioParameter();
+ adjustAudioParams();
ALOGV("set OMX_IndexParamAudioRa, nChannels:%lu, "
"nSampleRate:%lu, nBlockAlign:%d",
return OMX_ErrorNone;
}
+
+ case OMX_IndexParamAudioFlac:
+ {
+ OMX_AUDIO_PARAM_FLACTYPE *profile =
+ (OMX_AUDIO_PARAM_FLACTYPE *)params;
+
+ if (profile->nPortIndex != kInputPortIndex) {
+ return OMX_ErrorUndefined;
+ }
+
+ CHECK(!isConfigured());
+
+ mCtx->channels = profile->nChannels;
+ mCtx->sample_rate = profile->nSampleRate;
+
+ adjustAudioParams();
+
+ ALOGV("set OMX_IndexParamAudioFlac, nChannels:%lu, nSampleRate:%lu",
+ profile->nChannels, profile->nSampleRate);
+
+ return OMX_ErrorNone;
+ }
+
+ case OMX_IndexParamAudioMp2:
+ {
+ OMX_AUDIO_PARAM_MP2TYPE *profile =
+ (OMX_AUDIO_PARAM_MP2TYPE *)params;
+
+ if (profile->nPortIndex != kInputPortIndex) {
+ return OMX_ErrorUndefined;
+ }
+
+ CHECK(!isConfigured());
+
+ mCtx->channels = profile->nChannels;
+ mCtx->sample_rate = profile->nSampleRate;
+
+ adjustAudioParams();
+
+ ALOGV("set OMX_IndexParamAudioMp2, nChannels:%lu, nSampleRate:%lu",
+ profile->nChannels, profile->nSampleRate);
+
+ return OMX_ErrorNone;
+ }
+
+ case OMX_IndexParamAudioAc3:
+ {
+ OMX_AUDIO_PARAM_AC3TYPE *profile =
+ (OMX_AUDIO_PARAM_AC3TYPE *)params;
+
+ if (profile->nPortIndex != kInputPortIndex) {
+ return OMX_ErrorUndefined;
+ }
+
+ CHECK(!isConfigured());
+
+ mCtx->channels = profile->nChannels;
+ mCtx->sample_rate = profile->nSamplingRate;
+
+ adjustAudioParams();
+
+ ALOGV("set OMX_IndexParamAudioFlac, nChannels:%lu, nSampleRate:%lu",
+ profile->nChannels, profile->nSamplingRate);
+
+ return OMX_ErrorNone;
+ }
+
case OMX_IndexParamAudioApe:
{
OMX_AUDIO_PARAM_APETYPE *profile =
(OMX_AUDIO_PARAM_APETYPE *)params;
- if (profile->nPortIndex != 0) {
+ if (profile->nPortIndex != kInputPortIndex) {
return OMX_ErrorUndefined;
}
+ CHECK(!isConfigured());
+
mCtx->channels = profile->nChannels;
mCtx->sample_rate = profile->nSamplingRate;
- // ape decoder need bits_per_coded_sample
+ //ape decoder need bits_per_coded_sample
mCtx->bits_per_coded_sample = profile->nBitsPerSample;
- adjustAudioParameter();
+ adjustAudioParams();
ALOGV("set OMX_IndexParamAudioApe, nChannels:%lu, "
"nSampleRate:%lu, nBitsPerSample:%lu",
return OMX_ErrorNone;
}
+
case OMX_IndexParamAudioDts:
{
OMX_AUDIO_PARAM_DTSTYPE *profile =
(OMX_AUDIO_PARAM_DTSTYPE *)params;
- if (profile->nPortIndex != 0) {
+ if (profile->nPortIndex != kInputPortIndex) {
return OMX_ErrorUndefined;
}
+ CHECK(!isConfigured());
+
mCtx->channels = profile->nChannels;
mCtx->sample_rate = profile->nSamplingRate;
- adjustAudioParameter();
+ adjustAudioParams();
- ALOGV("set OMX_IndexParamAudioDts, nChannels:%lu, nSamplingRate:%lu",
+ ALOGV("set OMX_IndexParamAudioDts, nChannels:%lu, nSampleRate:%lu",
profile->nChannels, profile->nSamplingRate);
return OMX_ErrorNone;
}
- case OMX_IndexParamAudioFlac:
+
+ case OMX_IndexParamAudioFFmpeg:
{
- OMX_AUDIO_PARAM_FLACTYPE *profile =
- (OMX_AUDIO_PARAM_FLACTYPE *)params;
+ OMX_AUDIO_PARAM_FFMPEGTYPE *profile =
+ (OMX_AUDIO_PARAM_FFMPEGTYPE *)params;
- if (profile->nPortIndex != 0) {
+ if (profile->nPortIndex != kInputPortIndex) {
return OMX_ErrorUndefined;
}
+ CHECK(!isConfigured());
+
+
+ mCtx->codec_id = (enum AVCodecID)profile->eCodecId;
mCtx->channels = profile->nChannels;
+ mCtx->bit_rate = profile->nBitRate;
+ mCtx->bits_per_coded_sample = profile->nBitsPerSample;
mCtx->sample_rate = profile->nSampleRate;
+ mCtx->block_align = profile->nBlockAlign;
+ mCtx->sample_fmt = (AVSampleFormat)profile->eSampleFormat;
+
+ adjustAudioParams();
+
+ ALOGD("set OMX_IndexParamAudioFFmpeg, "
+ "eCodecId:%ld(%s), nChannels:%lu, nBitRate:%lu, "
+ "nBitsPerSample:%lu, nSampleRate:%lu, "
+ "nBlockAlign:%lu, eSampleFormat:%lu(%s)",
+ profile->eCodecId, avcodec_get_name(mCtx->codec_id),
+ profile->nChannels, profile->nBitRate,
+ profile->nBitsPerSample, profile->nSampleRate,
+ profile->nBlockAlign, profile->eSampleFormat,
+ av_get_sample_fmt_name(mCtx->sample_fmt));
+ return OMX_ErrorNone;
+ }
- adjustAudioParameter();
+ default:
- ALOGV("set OMX_IndexParamAudioFlac, nChannels:%lu, nSamplingRate:%lu",
- profile->nChannels, profile->nSampleRate);
+ return SimpleSoftOMXComponent::internalSetParameter(index, params);
+ }
+}
- return OMX_ErrorNone;
- }
- case OMX_IndexParamAudioVorbis:
- {
- const OMX_AUDIO_PARAM_VORBISTYPE *profile =
- (const OMX_AUDIO_PARAM_VORBISTYPE *)params;
+int32_t SoftFFmpegAudio::handleExtradata() {
+ List<BufferInfo *> &inQueue = getPortQueue(kInputPortIndex);
+ BufferInfo *inInfo = *inQueue.begin();
+ OMX_BUFFERHEADERTYPE *inHeader = inInfo->mHeader;
- if (profile->nPortIndex != 0) {
- return OMX_ErrorUndefined;
+ ALOGI("got extradata, ignore: %d, size: %lu",
+ mIgnoreExtradata, inHeader->nFilledLen);
+ hexdump(inHeader->pBuffer + inHeader->nOffset, inHeader->nFilledLen);
+
+ if (mIgnoreExtradata) {
+ ALOGI("got extradata, size: %lu, but ignore it", inHeader->nFilledLen);
+ } else {
+ if (!mExtradataReady) {
+ int orig_extradata_size = mCtx->extradata_size;
+ mCtx->extradata_size += inHeader->nFilledLen;
+ mCtx->extradata = (uint8_t *)av_realloc(mCtx->extradata,
+ mCtx->extradata_size + FF_INPUT_BUFFER_PADDING_SIZE);
+ if (!mCtx->extradata) {
+ ALOGE("ffmpeg audio decoder failed to alloc extradata memory.");
+ return ERR_OOM;
}
- mCtx->channels = profile->nChannels;
- mCtx->sample_rate = profile->nSampleRate;
+ memcpy(mCtx->extradata + orig_extradata_size,
+ inHeader->pBuffer + inHeader->nOffset, inHeader->nFilledLen);
+ memset(mCtx->extradata + mCtx->extradata_size, 0, FF_INPUT_BUFFER_PADDING_SIZE);
+ }
+ }
- ALOGD("set OMX_IndexParamAudioVorbis, "
- "nChannels=%lu, nSampleRate=%lu, nBitRate=%lu, "
- "nMinBitRate=%lu, nMaxBitRate=%lu",
- profile->nChannels, profile->nSampleRate,
- profile->nBitRate, profile->nMinBitRate,
- profile->nMaxBitRate);
+ inInfo->mOwnedByUs = false;
+ inQueue.erase(inQueue.begin());
+ inInfo = NULL;
+ notifyEmptyBufferDone(inHeader);
+ inHeader = NULL;
- return OMX_ErrorNone;
- }
- default:
- if ((OMX_FF_INDEXTYPE)index == OMX_IndexParamAudioFFmpeg)
- {
- OMX_AUDIO_PARAM_FFMPEGTYPE *profile =
- (OMX_AUDIO_PARAM_FFMPEGTYPE *)params;
-
- if (profile->nPortIndex != 0) {
- return OMX_ErrorUndefined;
- }
-
- mCtx->codec_id = (enum AVCodecID)profile->eCodecId;
- mCtx->channels = profile->nChannels;
- mCtx->bit_rate = profile->nBitRate;
- mCtx->bits_per_coded_sample = profile->nBitsPerSample;
- mCtx->sample_rate = profile->nSampleRate;
- mCtx->block_align = profile->nBlockAlign;
- mCtx->sample_fmt = (AVSampleFormat)profile->eSampleFormat;
-
- adjustAudioParameter();
-
- ALOGD("set OMX_IndexParamAudioFFmpeg, "
- "eCodecId:%ld(%s), nChannels:%lu, nBitRate:%lu, "
- "nBitsPerSample:%lu, nSampleRate:%lu, "
- "nBlockAlign:%lu, eSampleFormat:%lu(%s)",
- profile->eCodecId, avcodec_get_name(mCtx->codec_id),
- profile->nChannels, profile->nBitRate,
- profile->nBitsPerSample, profile->nSampleRate,
- profile->nBlockAlign, profile->eSampleFormat,
- av_get_sample_fmt_name(mCtx->sample_fmt));
-
- return OMX_ErrorNone;
- }
+ return ERR_OK;
+}
- ALOGI("internalSetParameter, index: 0x%x", index);
- return SimpleSoftOMXComponent::internalSetParameter(index, params);
+int32_t SoftFFmpegAudio::openDecoder() {
+ if (mCodecAlreadyOpened) {
+ return ERR_OK;
}
+
+ if (!mExtradataReady && !mIgnoreExtradata) {
+ ALOGI("extradata is ready, size: %d", mCtx->extradata_size);
+ hexdump(mCtx->extradata, mCtx->extradata_size);
+ mExtradataReady = true;
+ }
+
+ //find decoder
+ mCtx->codec = avcodec_find_decoder(mCtx->codec_id);
+ if (!mCtx->codec) {
+ ALOGE("ffmpeg audio decoder failed to find codec");
+ return ERR_CODEC_NOT_FOUND;
+ }
+
+ CHECK(isConfigured());
+
+ setDefaultCtx(mCtx, mCtx->codec);
+
+ ALOGD("begin to open ffmpeg audio decoder(%s), mCtx sample_rate: %d, "
+ "channels: %d, , sample_fmt: %s",
+ avcodec_get_name(mCtx->codec_id),
+ mCtx->sample_rate, mCtx->channels,
+ av_get_sample_fmt_name(mCtx->sample_fmt));
+
+ int err = avcodec_open2(mCtx, mCtx->codec, NULL);
+ if (err < 0) {
+ ALOGE("ffmpeg audio decoder failed to initialize.(%s)", av_err2str(err));
+ return ERR_DECODER_OPEN_FAILED;
+ }
+ mCodecAlreadyOpened = true;
+
+ ALOGD("open ffmpeg audio decoder(%s) success, mCtx sample_rate: %d, "
+ "channels: %d, sample_fmt: %s",
+ avcodec_get_name(mCtx->codec_id),
+ mCtx->sample_rate, mCtx->channels,
+ av_get_sample_fmt_name(mCtx->sample_fmt));
+
+ mFrame = avcodec_alloc_frame();
+ if (!mFrame) {
+ ALOGE("oom for video frame");
+ return ERR_OOM;
+ }
+
+ return ERR_OK;
}
-void SoftFFmpegAudio::onQueueFilled(OMX_U32 portIndex) {
+void SoftFFmpegAudio::updateTimeStamp(OMX_BUFFERHEADERTYPE *inHeader) {
+ CHECK_EQ(mInputBufferSize, 0);
+
+ //XXX reset to AV_NOPTS_VALUE if the pts is invalid
+ if (inHeader->nTimeStamp == SF_NOPTS_VALUE) {
+ inHeader->nTimeStamp = AV_NOPTS_VALUE;
+ }
+
+ //update the audio clock if the pts is valid
+ if (inHeader->nTimeStamp != AV_NOPTS_VALUE) {
+ mAudioClock = inHeader->nTimeStamp;
+ }
+}
+
+void SoftFFmpegAudio::initPacket(AVPacket *pkt,
+ OMX_BUFFERHEADERTYPE *inHeader) {
+ memset(pkt, 0, sizeof(AVPacket));
+ av_init_packet(pkt);
+
+ if (inHeader) {
+ pkt->data = (uint8_t *)inHeader->pBuffer + inHeader->nOffset;
+ pkt->size = inHeader->nFilledLen;
+ pkt->pts = inHeader->nTimeStamp; //ingore it, we will compute it
+ } else {
+ pkt->data = NULL;
+ pkt->size = 0;
+ pkt->pts = AV_NOPTS_VALUE;
+ }
+
+#if DEBUG_PKT
+ if (pkt->pts != AV_NOPTS_VALUE)
+ {
+ ALOGV("pkt size:%d, pts:%lld", pkt->size, pkt->pts);
+ } else {
+ ALOGV("pkt size:%d, pts:N/A", pkt->size);
+ }
+#endif
+}
+
+int32_t SoftFFmpegAudio::decodeAudio() {
int len = 0;
- int err = 0;
- size_t dataSize = 0;
- int64_t decChannelLayout = 0;
+ int gotFrm = false;
+ int32_t ret = ERR_OK;
int32_t inputBufferUsedLength = 0;
+ bool is_flush = (mEOSStatus != INPUT_DATA_AVAILABLE);
+ List<BufferInfo *> &inQueue = getPortQueue(kInputPortIndex);
BufferInfo *inInfo = NULL;
OMX_BUFFERHEADERTYPE *inHeader = NULL;
- if (mSignalledError || mOutputPortSettingsChange != NONE) {
- return;
+ CHECK_EQ(mResampledDataSize, 0);
+
+ if (!is_flush) {
+ inInfo = *inQueue.begin();
+ CHECK(inInfo != NULL);
+ inHeader = inInfo->mHeader;
+
+ if (mInputBufferSize == 0) {
+ updateTimeStamp(inHeader);
+ mInputBufferSize = inHeader->nFilledLen;
+ }
}
- List<BufferInfo *> &inQueue = getPortQueue(0);
- List<BufferInfo *> &outQueue = getPortQueue(1);
+ AVPacket pkt;
+ initPacket(&pkt, inHeader);
+ av_frame_unref(mFrame);
+ avcodec_get_frame_defaults(mFrame);
+
+ len = avcodec_decode_audio4(mCtx, mFrame, &gotFrm, &pkt);
+ //a negative error code is returned if an error occurred during decoding
+ if (len < 0) {
+ ALOGW("ffmpeg audio decoder err, we skip the frame and play silence instead");
+ mResampledData = mSilenceBuffer;
+ mResampledDataSize = kOutputBufferSize;
+ ret = ERR_OK;
+ } else {
+#if DEBUG_PKT
+ ALOGV("ffmpeg audio decoder, consume pkt len: %d", len);
+#endif
+ if (!gotFrm) {
+ ALOGI("ffmpeg audio decoder failed to get frame.");
+ //stop sending empty packets if the decoder is finished
+ if (is_flush && mCtx->codec->capabilities & CODEC_CAP_DELAY) {
+ ret = ERR_FLUSHED;
+ } else {
+ ret = ERR_NO_FRM;
+ }
+ } else {
+ ret = resampleAudio();
+ }
+ }
- while ((!inQueue.empty() //there are input buffers to be emptied
- || mResampledDataSize > 0 //there are left decoded frame
- || mReceivedEOS) //need to fill eos outbuffer
- && !outQueue.empty()) { //there are out buffers to be filled
- if (!inQueue.empty()) {
- inInfo = *inQueue.begin();
- inHeader = inInfo->mHeader;
+ if (!is_flush) {
+ if (len < 0) {
+ //if error, we skip the frame
+ inputBufferUsedLength = mInputBufferSize;
} else {
- inInfo = NULL;
- inHeader = NULL;
+ inputBufferUsedLength = len;
}
- BufferInfo *outInfo = *outQueue.begin();
- OMX_BUFFERHEADERTYPE *outHeader = outInfo->mHeader;
+ CHECK_GE(inHeader->nFilledLen, inputBufferUsedLength);
+ inHeader->nOffset += inputBufferUsedLength;
+ inHeader->nFilledLen -= inputBufferUsedLength;
+ mInputBufferSize -= inputBufferUsedLength;
- //empty eos
- if (inHeader && inHeader->nFlags & OMX_BUFFERFLAG_EOS) {
- CHECK(mInputBufferSize == 0);
- ALOGD("ffmpeg audio decoder empty eos inbuf");
+ if (inHeader->nFilledLen == 0) {
+ CHECK_EQ(mInputBufferSize, 0);
inQueue.erase(inQueue.begin());
inInfo->mOwnedByUs = false;
notifyEmptyBufferDone(inHeader);
- mReceivedEOS = true;
- continue; //empty eos input buffer
}
+ }
- //fill eos
- if (mReceivedEOS && (mFlushComplete || !(mCtx->codec->capabilities & CODEC_CAP_DELAY))) {
- ALOGD("ffmpeg audio decoder fill eos outbuf");
- outHeader->nFilledLen = 0;
- outHeader->nFlags = OMX_BUFFERFLAG_EOS;
+ return ret;
+}
- outQueue.erase(outQueue.begin());
- outInfo->mOwnedByUs = false;
- notifyFillBufferDone(outHeader);
- return;
- }
+int32_t SoftFFmpegAudio::resampleAudio() {
+ int channels = 0;
+ int64_t channelLayout = 0;
+ size_t dataSize = 0;
+
+ dataSize = av_samples_get_buffer_size(NULL, av_frame_get_channels(mFrame),
+ mFrame->nb_samples, (enum AVSampleFormat)mFrame->format, 1);
+
+#if DEBUG_FRM
+ ALOGV("ffmpeg audio decoder, nb_samples:%d, get buffer size:%d",
+ mFrame->nb_samples, dataSize);
+#endif
- //prepare extradata
- if (inHeader && inHeader->nFlags & OMX_BUFFERFLAG_CODECCONFIG) {
- ALOGI("got extradata, ignore: %d, size: %lu", mIgnoreExtradata, inHeader->nFilledLen);
- hexdump(inHeader->pBuffer + inHeader->nOffset, inHeader->nFilledLen);
+ channels = av_get_channel_layout_nb_channels(mFrame->channel_layout);
+ channelLayout =
+ (mFrame->channel_layout && av_frame_get_channels(mFrame) == channels) ?
+ mFrame->channel_layout : av_get_default_channel_layout(av_frame_get_channels(mFrame));
- if (mIgnoreExtradata) {
- ALOGI("got extradata, size: %lu, but ignore it", inHeader->nFilledLen);
- inInfo->mOwnedByUs = false;
- inQueue.erase(inQueue.begin());
- inInfo = NULL;
- notifyEmptyBufferDone(inHeader);
- inHeader = NULL;
+ if (mFrame->format != mAudioSrcFmt
+ || channelLayout != mAudioSrcChannelLayout
+ || mFrame->sample_rate != mAudioSrcFreq) {
+ if (mSwrCtx) {
+ swr_free(&mSwrCtx);
+ }
+ mSwrCtx = swr_alloc_set_opts(NULL,
+ mAudioTgtChannelLayout, mAudioTgtFmt, mAudioTgtFreq,
+ channelLayout, (enum AVSampleFormat)mFrame->format, mFrame->sample_rate,
+ 0, NULL);
+ if (!mSwrCtx || swr_init(mSwrCtx) < 0) {
+ ALOGE("Cannot create sample rate converter for conversion "
+ "of %d Hz %s %d channels to %d Hz %s %d channels!",
+ mFrame->sample_rate,
+ av_get_sample_fmt_name((enum AVSampleFormat)mFrame->format),
+ av_frame_get_channels(mFrame),
+ mAudioTgtFreq,
+ av_get_sample_fmt_name(mAudioTgtFmt),
+ mAudioTgtChannels);
+ return ERR_SWR_INIT_FAILED;
+ }
- continue;
- }
+ char src_layout_name[1024] = {0};
+ char tgt_layout_name[1024] = {0};
+ av_get_channel_layout_string(src_layout_name, sizeof(src_layout_name),
+ mCtx->channels, channelLayout);
+ av_get_channel_layout_string(tgt_layout_name, sizeof(tgt_layout_name),
+ mAudioTgtChannels, mAudioTgtChannelLayout);
+ ALOGI("Create sample rate converter for conversion "
+ "of %d Hz %s %d channels(%s) "
+ "to %d Hz %s %d channels(%s)!",
+ mFrame->sample_rate,
+ av_get_sample_fmt_name((enum AVSampleFormat)mFrame->format),
+ av_frame_get_channels(mFrame),
+ src_layout_name,
+ mAudioTgtFreq,
+ av_get_sample_fmt_name(mAudioTgtFmt),
+ mAudioTgtChannels,
+ tgt_layout_name);
+
+ mAudioSrcChannelLayout = channelLayout;
+ mAudioSrcChannels = av_frame_get_channels(mFrame);
+ mAudioSrcFreq = mFrame->sample_rate;
+ mAudioSrcFmt = (enum AVSampleFormat)mFrame->format;
+ }
- if (!mExtradataReady) {
- int orig_extradata_size = mCtx->extradata_size;
- mCtx->extradata_size += inHeader->nFilledLen;
- mCtx->extradata = (uint8_t *)av_realloc(mCtx->extradata,
- mCtx->extradata_size + FF_INPUT_BUFFER_PADDING_SIZE);
- if (!mCtx->extradata) {
- ALOGE("ffmpeg audio decoder failed to alloc extradata memory.");
- notify(OMX_EventError, OMX_ErrorInsufficientResources, 0, NULL);
- mSignalledError = true;
- return;
- }
-
- memcpy(mCtx->extradata + orig_extradata_size,
- inHeader->pBuffer + inHeader->nOffset, inHeader->nFilledLen);
- memset(mCtx->extradata + mCtx->extradata_size, 0, FF_INPUT_BUFFER_PADDING_SIZE);
-
- inInfo->mOwnedByUs = false;
- inQueue.erase(inQueue.begin());
- inInfo = NULL;
- notifyEmptyBufferDone(inHeader);
- inHeader = NULL;
+ if (mSwrCtx) {
+ const uint8_t **in = (const uint8_t **)mFrame->extended_data;
+ uint8_t *out[] = {mAudioBuffer};
+ int out_count = sizeof(mAudioBuffer) / mAudioTgtChannels / av_get_bytes_per_sample(mAudioTgtFmt);
+ int out_size = av_samples_get_buffer_size(NULL, mAudioTgtChannels, out_count, mAudioTgtFmt, 0);
+ int len2 = 0;
+ if (out_size < 0) {
+ ALOGE("av_samples_get_buffer_size() failed");
+ return ERR_INVALID_PARAM;
+ }
- continue;
- }
+ len2 = swr_convert(mSwrCtx, out, out_count, in, mFrame->nb_samples);
+ if (len2 < 0) {
+ ALOGE("audio_resample() failed");
+ return ERR_RESAMPLE_FAILED;
+ }
+ if (len2 == out_count) {
+ ALOGE("warning: audio buffer is probably too small");
+ swr_init(mSwrCtx);
}
+ mResampledData = mAudioBuffer;
+ mResampledDataSize = len2 * mAudioTgtChannels * av_get_bytes_per_sample(mAudioTgtFmt);
- //open codec
- if (!mCodecAlreadyOpened) {
- if (!mExtradataReady && !mIgnoreExtradata) {
- ALOGI("extradata is ready, size: %d", mCtx->extradata_size);
- hexdump(mCtx->extradata, mCtx->extradata_size);
- mExtradataReady = true;
- }
+#if DEBUG_FRM
+ ALOGV("ffmpeg audio decoder(resample), mFrame->nb_samples:%d, len2:%d, mResampledDataSize:%d, "
+ "src channel:%u, src fmt:%s, tgt channel:%u, tgt fmt:%s",
+ mFrame->nb_samples, len2, mResampledDataSize,
+ av_frame_get_channels(mFrame),
+ av_get_sample_fmt_name((enum AVSampleFormat)mFrame->format),
+ mAudioTgtChannels,
+ av_get_sample_fmt_name(mAudioTgtFmt));
+#endif
+ } else {
+ mResampledData = mFrame->data[0];
+ mResampledDataSize = dataSize;
- // find decoder
- mCtx->codec = avcodec_find_decoder(mCtx->codec_id);
- if (!mCtx->codec) {
- ALOGE("ffmpeg audio decoder failed to find codec");
- notify(OMX_EventError, OMX_ErrorUndefined, 0, NULL);
- mSignalledError = true;
- return;
- }
+#if DEBUG_FRM
+ ALOGV("ffmpeg audio decoder(no resample),"
+ "nb_samples(before resample):%d, mResampledDataSize:%d",
+ mFrame->nb_samples, mResampledDataSize);
+#endif
+ }
- setAVCtxToDefault(mCtx, mCtx->codec);
+ return ERR_OK;
+}
- ALOGD("begin to open ffmpeg audio decoder, mCtx sample_rate: %d, "
- "channels: %d, , sample_fmt: %s",
- mCtx->sample_rate, mCtx->channels,
- av_get_sample_fmt_name(mCtx->sample_fmt));
+void SoftFFmpegAudio::drainOneOutputBuffer() {
+ List<BufferInfo *> &outQueue = getPortQueue(kOutputPortIndex);
+ BufferInfo *outInfo = *outQueue.begin();
+ CHECK(outInfo != NULL);
+ OMX_BUFFERHEADERTYPE *outHeader = outInfo->mHeader;
- err = avcodec_open2(mCtx, mCtx->codec, NULL);
- if (err < 0) {
- ALOGE("ffmpeg audio decoder failed to initialize. (%d)", err);
- notify(OMX_EventError, OMX_ErrorUndefined, 0, NULL);
- mSignalledError = true;
- return;
- }
+ CHECK_GT(mResampledDataSize, 0);
- mCodecAlreadyOpened = true;
+ size_t copy = mResampledDataSize;
+ if (mResampledDataSize > kOutputBufferSize) {
+ copy = kOutputBufferSize;
+ }
- ALOGD("open ffmpeg audio decoder success, mCtx sample_rate: %d, "
- "channels: %d, sample_fmt: %s",
- mCtx->sample_rate, mCtx->channels,
- av_get_sample_fmt_name(mCtx->sample_fmt));
- }
+ outHeader->nOffset = 0;
+ outHeader->nFilledLen = copy;
+ outHeader->nTimeStamp = mAudioClock;
+ memcpy(outHeader->pBuffer, mResampledData, copy);
+ outHeader->nFlags = 0;
- //update the audio clock with the pts
- if (inHeader && inHeader->nOffset == 0
- && mInputBufferSize == 0 // the last input buffer have be emptied
- && mResampledDataSize == 0) { // the last decoded frame have be filled
- if (inHeader->nTimeStamp != SF_NOPTS_VALUE) {
- mAudioClock = inHeader->nTimeStamp; //if no pts in input buffer
- } else {
- //reset to AV_NOPTS_VALUE
- inHeader->nTimeStamp = AV_NOPTS_VALUE;
- }
- mInputBufferSize = inHeader->nFilledLen;
- }
+ //update mResampledSize
+ mResampledData += copy;
+ mResampledDataSize -= copy;
- if ((inHeader && mResampledDataSize == 0) //hope to get more decoded frame while have not read eos pkt
- || (mReceivedEOS && !mFlushComplete)) { //hope to get left decoded frame while have read eos pkt
- AVPacket pkt;
- memset(&pkt, 0, sizeof(pkt));
- av_init_packet(&pkt);
-
- if (inHeader) {
- CHECK(mResampledDataSize == 0);
- pkt.data = (uint8_t *)inHeader->pBuffer + inHeader->nOffset;
- pkt.size = inHeader->nFilledLen;
- pkt.pts = inHeader->nTimeStamp; // ingore it, we will compute it
- } else {
- CHECK(mReceivedEOS == true);
- CHECK(mFlushComplete == false);
- pkt.data = NULL;
- pkt.size = 0;
- pkt.pts = AV_NOPTS_VALUE;
- }
-#if DEBUG_PKT
- if (pkt.pts != AV_NOPTS_VALUE)
- {
- ALOGV("pkt size:%d, pts:%lld", pkt.size, pkt.pts);
- } else {
- ALOGV("pkt size:%d, pts:N/A", pkt.size);
- }
+ //update audio pts
+ size_t frames = copy / (av_get_bytes_per_sample(mAudioTgtFmt) * mAudioTgtChannels);
+ mAudioClock += (frames * 1000000ll) / mAudioTgtFreq;
+
+#if DEBUG_FRM
+ ALOGV("ffmpeg audio decoder, fill out buffer, copy:%u, pts: %lld",
+ copy, outHeader->nTimeStamp);
#endif
- if (!mFrame) {
- if (!(mFrame = avcodec_alloc_frame())) {
- ALOGE("ffmpeg audio decoder failed to alloc memory.");
- notify(OMX_EventError, OMX_ErrorInsufficientResources, 0, NULL);
- mSignalledError = true;
- return;
- }
- } else {
- avcodec_get_frame_defaults(mFrame);
- }
- int gotFrm = false;
- inputBufferUsedLength = 0;
+ outQueue.erase(outQueue.begin());
+ outInfo->mOwnedByUs = false;
+ notifyFillBufferDone(outHeader);
+}
- //decode audio packet
- len = avcodec_decode_audio4(mCtx, mFrame, &gotFrm, &pkt);
+void SoftFFmpegAudio::drainEOSOutputBuffer() {
+ List<BufferInfo *> &outQueue = getPortQueue(kOutputPortIndex);
+ BufferInfo *outInfo = *outQueue.begin();
+ CHECK(outInfo != NULL);
+ OMX_BUFFERHEADERTYPE *outHeader = outInfo->mHeader;
- //A negative error code is returned if an error occurred during decoding
- if (len < 0) {
- ALOGE("ffmpeg audio decoder failed to decode frame. "
- "consume pkt len: %d", len);
+ CHECK_EQ(mResampledDataSize, 0);
- //if error, we skip the frame and play silence instead
- mResampledData = mSilenceBuffer;
- mResampledDataSize = kOutputBufferSize; //FIXME, need to calculate the size
- }
+ ALOGD("ffmpeg audio decoder fill eos outbuf");
-#if DEBUG_PKT
- ALOGV("ffmpeg audio decoder, consume pkt len: %d", len);
-#endif
+ outHeader->nTimeStamp = 0;
+ outHeader->nFilledLen = 0;
+ outHeader->nFlags = OMX_BUFFERFLAG_EOS;
- if (inHeader) {
- CHECK(mFlushComplete == false);
-
- if (len < 0) {
- //if error, we skip the frame
- inputBufferUsedLength = mInputBufferSize;
- } else {
- inputBufferUsedLength = len;
- }
-
- CHECK_GE(inHeader->nFilledLen, inputBufferUsedLength);
- inHeader->nOffset += inputBufferUsedLength;
- inHeader->nFilledLen -= inputBufferUsedLength;
- mInputBufferSize -= inputBufferUsedLength;
- if (inHeader->nFilledLen == 0) {
- inInfo->mOwnedByUs = false;
- inQueue.erase(inQueue.begin());
- inInfo = NULL;
- notifyEmptyBufferDone(inHeader);
- inHeader = NULL;
-
- //reset mInputBufferSize
- mInputBufferSize = 0;
- }
- }
+ outQueue.erase(outQueue.begin());
+ outInfo->mOwnedByUs = false;
+ notifyFillBufferDone(outHeader);
- if (!gotFrm) {
- ALOGI("ffmpeg audio decoder failed to get more frame.");
- //stop sending empty packets if the decoder is finished
- if (!pkt.data && mCtx->codec->capabilities & CODEC_CAP_DELAY)
- mFlushComplete = true;
- continue;
- }
+ mEOSStatus = OUTPUT_FRAMES_FLUSHED;
+}
- dataSize = av_samples_get_buffer_size(NULL, av_frame_get_channels(mFrame),
- mFrame->nb_samples, (enum AVSampleFormat)mFrame->format, 1);
+void SoftFFmpegAudio::drainAllOutputBuffers() {
+ List<BufferInfo *> &outQueue = getPortQueue(kOutputPortIndex);
-#if DEBUG_FRM
- ALOGV("ffmpeg audio decoder, nb_samples:%d, get buffer size:%d",
- mFrame->nb_samples, dataSize);
-#endif
+ if (!mCodecAlreadyOpened) {
+ drainEOSOutputBuffer();
+ mEOSStatus = OUTPUT_FRAMES_FLUSHED;
+ return;
+ }
- decChannelLayout =
- (mFrame->channel_layout && av_frame_get_channels(mFrame) == av_get_channel_layout_nb_channels(mFrame->channel_layout)) ?
- mFrame->channel_layout : av_get_default_channel_layout(av_frame_get_channels(mFrame));
-
- if (mFrame->format != mAudioSrcFmt
- || decChannelLayout != mAudioSrcChannelLayout
- || mFrame->sample_rate != mAudioSrcFreq) {
- if (mSwrCtx)
- swr_free(&mSwrCtx);
- mSwrCtx = swr_alloc_set_opts(NULL,
- mAudioTgtChannelLayout, mAudioTgtFmt, mAudioTgtFreq,
- decChannelLayout, (enum AVSampleFormat)mFrame->format, mFrame->sample_rate,
- 0, NULL);
- if (!mSwrCtx || swr_init(mSwrCtx) < 0) {
- ALOGE("Cannot create sample rate converter for conversion "
- "of %d Hz %s %d channels to %d Hz %s %d channels!",
- mFrame->sample_rate,
- av_get_sample_fmt_name((enum AVSampleFormat)mFrame->format),
- av_frame_get_channels(mFrame),
- mAudioTgtFreq,
- av_get_sample_fmt_name(mAudioTgtFmt),
- mAudioTgtChannels);
- notify(OMX_EventError, OMX_ErrorUndefined, 0, NULL);
- mSignalledError = true;
- return;
- }
-
- char src_layout_name[1024] = {0};
- char tgt_layout_name[1024] = {0};
- av_get_channel_layout_string(src_layout_name, sizeof(src_layout_name),
- mCtx->channels, decChannelLayout);
- av_get_channel_layout_string(tgt_layout_name, sizeof(tgt_layout_name),
- mAudioTgtChannels, mAudioTgtChannelLayout);
- ALOGI("Create sample rate converter for conversion "
- "of %d Hz %s %d channels(%s) "
- "to %d Hz %s %d channels(%s)!",
- mFrame->sample_rate,
- av_get_sample_fmt_name((enum AVSampleFormat)mFrame->format),
- av_frame_get_channels(mFrame),
- src_layout_name,
- mAudioTgtFreq,
- av_get_sample_fmt_name(mAudioTgtFmt),
- mAudioTgtChannels,
- tgt_layout_name);
-
- mAudioSrcChannelLayout = decChannelLayout;
- mAudioSrcChannels = av_frame_get_channels(mFrame);
- mAudioSrcFreq = mFrame->sample_rate;
- mAudioSrcFmt = (enum AVSampleFormat)mFrame->format;
- }
+ if(!(mCtx->codec->capabilities & CODEC_CAP_DELAY)) {
+ drainEOSOutputBuffer();
+ mEOSStatus = OUTPUT_FRAMES_FLUSHED;
+ return;
+ }
- if (mSwrCtx) {
- const uint8_t **in = (const uint8_t **)mFrame->extended_data;
- uint8_t *out[] = {mAudioBuffer};
- int out_count = sizeof(mAudioBuffer) / mAudioTgtChannels / av_get_bytes_per_sample(mAudioTgtFmt);
- int out_size = av_samples_get_buffer_size(NULL, mAudioTgtChannels, out_count, mAudioTgtFmt, 0);
- int len2 = 0;
- if (out_size < 0) {
- ALOGE("av_samples_get_buffer_size() failed");
- break; //TODO
- }
-#if DEBUG_FRM
- ALOGV("swr_convert 1, out_count:%d, mFrame->nb_samples:%d, "
- "src channel:%u, src fmt:%s, tgt channel:%u, tgt fmt:%s",
- out_count, mFrame->nb_samples,
- av_frame_get_channels(mFrame),
- av_get_sample_fmt_name((enum AVSampleFormat)mFrame->format),
- mAudioTgtChannels,
- av_get_sample_fmt_name(mAudioTgtFmt));
-#endif
+ while (!outQueue.empty()) {
+ if (mResampledDataSize == 0) {
+ int32_t err = decodeAudio();
+ if (err < ERR_OK) {
+ notify(OMX_EventError, OMX_ErrorUndefined, 0, NULL);
+ mSignalledError = true;
+ return;
+ } else if (err == ERR_FLUSHED) {
+ drainEOSOutputBuffer();
+ return;
+ } else {
+ CHECK_EQ(err, ERR_OK);
+ }
+ }
- len2 = swr_convert(mSwrCtx, out, out_count, in, mFrame->nb_samples);
- if (len2 < 0) {
- ALOGE("audio_resample() failed");
- break;
- }
- if (len2 == out_count) {
- ALOGE("warning: audio buffer is probably too small");
- swr_init(mSwrCtx);
- }
- mResampledData = mAudioBuffer;
- mResampledDataSize = len2 * mAudioTgtChannels *
- av_get_bytes_per_sample(mAudioTgtFmt);
-#if DEBUG_FRM
- ALOGV("swr_convert 2, len2:%d, mResampledDataSize:%d",
- len2, mResampledDataSize);
-#endif
- } else {
- mResampledData = mFrame->data[0];
- mResampledDataSize = dataSize;
- }
+ if (mResampledDataSize > 0) {
+ drainOneOutputBuffer();
+ }
+ }
+}
-#if DEBUG_FRM
- ALOGV("ffmpeg audio decoder get frame. consume pkt len:%d, "
- "nb_samples(before resample):%d, mResampledDataSize:%d",
- len, mFrame->nb_samples, mResampledDataSize);
-#endif
- } //if ((inHeader && mResampledDataSize == 0) || (mReceivedEOS && !mFlushComplete))
+void SoftFFmpegAudio::onQueueFilled(OMX_U32 portIndex) {
+ BufferInfo *inInfo = NULL;
+ OMX_BUFFERHEADERTYPE *inHeader = NULL;
- size_t copyToOutputBufferLen = mResampledDataSize;
- if (mResampledDataSize > kOutputBufferSize)
- copyToOutputBufferLen = kOutputBufferSize;
+ if (mSignalledError || mOutputPortSettingsChange != NONE) {
+ return;
+ }
- outHeader->nOffset = 0;
- outHeader->nFilledLen = copyToOutputBufferLen;
- outHeader->nTimeStamp = mAudioClock;
- memcpy(outHeader->pBuffer, mResampledData, copyToOutputBufferLen);
- outHeader->nFlags = 0;
+ if (mEOSStatus == OUTPUT_FRAMES_FLUSHED) {
+ return;
+ }
-#if DEBUG_FRM
- ALOGV("ffmpeg audio decoder, fill out buffer, "
- "pts: %lld", outHeader->nTimeStamp);
-#endif
+ List<BufferInfo *> &inQueue = getPortQueue(kInputPortIndex);
+ List<BufferInfo *> &outQueue = getPortQueue(kOutputPortIndex);
+
+ while (((mEOSStatus != INPUT_DATA_AVAILABLE) || !inQueue.empty())
+ && !outQueue.empty()) {
- mResampledData += copyToOutputBufferLen;
- mResampledDataSize -= copyToOutputBufferLen;
- size_t numFramesOutput = copyToOutputBufferLen /
- (av_get_bytes_per_sample(mAudioTgtFmt) * mAudioTgtChannels);
+ if (mEOSStatus == INPUT_EOS_SEEN) {
+ drainAllOutputBuffers();
+ return;
+ }
+ inInfo = *inQueue.begin();
+ inHeader = inInfo->mHeader;
-#if DEBUG_FRM
- ALOGV("ffmpeg audio decoder, copyToOutputBufferLen:%d, "
- "mAudioTgtChannels:%d, mAudioTgtFreq:%d, bytes_per_sample:%d",
- copyToOutputBufferLen, mAudioTgtChannels,
- mAudioTgtFreq, av_get_bytes_per_sample(mAudioTgtFmt));
-#endif
+ if (inHeader->nFlags & OMX_BUFFERFLAG_EOS) {
+ ALOGD("ffmpeg audio decoder empty eos inbuf");
+ inQueue.erase(inQueue.begin());
+ inInfo->mOwnedByUs = false;
+ notifyEmptyBufferDone(inHeader);
+ mEOSStatus = INPUT_EOS_SEEN;
+ continue;
+ }
+
+ if (inHeader->nFlags & OMX_BUFFERFLAG_CODECCONFIG) {
+ if (handleExtradata() != ERR_OK) {
+ notify(OMX_EventError, OMX_ErrorUndefined, 0, NULL);
+ mSignalledError = true;
+ return;
+ }
+ continue;
+ }
+
+ if (!mCodecAlreadyOpened) {
+ if (openDecoder() != ERR_OK) {
+ notify(OMX_EventError, OMX_ErrorUndefined, 0, NULL);
+ mSignalledError = true;
+ return;
+ }
+ }
- //update audio pts
- mAudioClock += (numFramesOutput * 1000000ll) / mAudioTgtFreq;
+ if (mResampledDataSize == 0) {
+ int32_t err = decodeAudio();
+ if (err < ERR_OK) {
+ notify(OMX_EventError, OMX_ErrorUndefined, 0, NULL);
+ mSignalledError = true;
+ return;
+ } else if (err == ERR_NO_FRM) {
+ CHECK_EQ(mResampledDataSize, 0);
+ continue;
+ } else {
+ CHECK_EQ(err, ERR_OK);
+ }
+ }
- outInfo->mOwnedByUs = false;
- outQueue.erase(outQueue.begin());
- outInfo = NULL;
- notifyFillBufferDone(outHeader);
- outHeader = NULL;
+ if (mResampledDataSize > 0) {
+ drainOneOutputBuffer();
+ }
}
}
void SoftFFmpegAudio::onPortFlushCompleted(OMX_U32 portIndex) {
ALOGV("ffmpeg audio decoder flush port(%lu)", portIndex);
- if (portIndex == 0 && mCtx) {
- // Make sure that the next buffer output does not still
- // depend on fragments from the last one decoded.
- avcodec_flush_buffers(mCtx);
+ if (portIndex == kInputPortIndex) {
+ if (mCtx) {
+ //Make sure that the next buffer output does not still
+ //depend on fragments from the last one decoded.
+ avcodec_flush_buffers(mCtx);
+ }
+
+ mAudioClock = 0;
+ mInputBufferSize = 0;
+ mResampledDataSize = 0;
+ mResampledData = NULL;
+ mEOSStatus = INPUT_DATA_AVAILABLE;
}
- mReceivedEOS = false;
- mFlushComplete = false;
- mAudioClock = 0;
- mInputBufferSize = 0;
- mResampledDataSize = 0;
- mResampledData = NULL;
- //don't free mFrame!
}
void SoftFFmpegAudio::onPortEnableCompleted(OMX_U32 portIndex, bool enabled) {
- if (portIndex != 1) {
+ if (portIndex != kOutputPortIndex) {
return;
}