#include <media/stagefright/foundation/hexdump.h>
#include <media/stagefright/MediaDefs.h>
-#include "ffmpeg_utils/ffmpeg_utils.h"
-
-#undef realloc
-#include <stdlib.h>
+#include "utils/ffmpeg_utils.h"
#define DEBUG_PKT 0
#define DEBUG_FRM 0
params->nVersion.s.nStep = 0;
}
+void SoftFFmpegAudio::setMode(const char *name) {
+ 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.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.atrial.decoder")) {
+ mMode = MODE_TRIAL;
+ } else {
+ TRESPASS();
+ }
+}
+
SoftFFmpegAudio::SoftFFmpegAudio(
const char *name,
const OMX_CALLBACKTYPE *callbacks,
OMX_PTR appData,
OMX_COMPONENTTYPE **component)
: SimpleSoftOMXComponent(name, callbacks, appData, component),
- mMode(MODE_MPEG),
- mCtx(NULL),
- mSwrCtx(NULL),
- mCodecOpened(false),
+ mMode(MODE_NONE),
+ mFFmpegAlreadyInited(false),
+ mCodecAlreadyOpened(false),
mExtradataReady(false),
mIgnoreExtradata(false),
- mFlushComplete(false),
- mSignalledError(false),
- mReceivedEOS(false),
+ mCtx(NULL),
+ mSwrCtx(NULL),
mFrame(NULL),
- mAnchorTimeUs(0),
- mNumFramesOutput(0),
+ mEOSStatus(INPUT_DATA_AVAILABLE),
+ mSignalledError(false),
+ mAudioClock(0),
mInputBufferSize(0),
- mAudioBufferSize(0),
- mNumChannels(2),
- mSamplingRate(44100),
- mBitRate(128040),
- mSamplingFmt(AV_SAMPLE_FMT_S16),
- mAudioConfigChanged(false),
+ mResampledData(NULL),
+ mResampledDataSize(0),
mOutputPortSettingsChange(NONE) {
- 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.ape.decoder")) {
- mMode = MODE_APE;
- } else if (!strcmp(name, "OMX.ffmpeg.wma.decoder")) {
- mMode = MODE_WMA;
- } else if (!strcmp(name, "OMX.ffmpeg.dts.decoder")) {
- mMode = MODE_DTS;
- } else if (!strcmp(name, "OMX.ffmpeg.ra.decoder")) {
- mMode = MODE_RA;
- } else {
- CHECK(!strcmp(name, "OMX.ffmpeg.ac3.decoder"));
- mMode = MODE_AC3;
- }
- LOGV("SoftFFmpegAudio component: %s", name);
+ setMode(name);
+
+ ALOGD("SoftFFmpegAudio component: %s mMode: %d", name, mMode);
initPorts();
CHECK_EQ(initDecoder(), (status_t)OK);
}
SoftFFmpegAudio::~SoftFFmpegAudio() {
- av_freep(&mFrame);
- LOGV("~SoftFFmpegAudio");
+ ALOGV("~SoftFFmpegAudio");
deInitDecoder();
- deInitFFmpeg();
+ 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;
- def.nBufferSize = 8192;
- def.bEnabled = OMX_TRUE;
- def.bPopulated = OMX_FALSE;
- def.eDomain = OMX_PortDomainAudio;
- def.bBuffersContiguous = OMX_FALSE;
- def.nBufferAlignment = 1;
-
- switch (mMode) {
+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_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;
+ 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.eEncoding = OMX_AUDIO_CodingWMA;
+ break;
+ case MODE_RA:
+ 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_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
+ def.format.audio.eEncoding = OMX_AUDIO_CodingAC3;
break;
- case MODE_WMA:
- def.format.audio.cMIMEType = const_cast<char *>(MEDIA_MIMETYPE_AUDIO_WMA);
- def.format.audio.eEncoding = OMX_AUDIO_CodingWMA;
+ case MODE_APE:
+ def.format.audio.cMIMEType = const_cast<char *>(MEDIA_MIMETYPE_AUDIO_APE);
+ def.format.audio.eEncoding = OMX_AUDIO_CodingAPE;
+ break;
+ case MODE_DTS:
+ def.format.audio.cMIMEType = const_cast<char *>(MEDIA_MIMETYPE_AUDIO_DTS);
+ def.format.audio.eEncoding = OMX_AUDIO_CodingDTS;
+ break;
+ case MODE_TRIAL:
+ def.format.audio.cMIMEType = const_cast<char *>(MEDIA_MIMETYPE_AUDIO_FFMPEG);
+ def.format.audio.eEncoding = OMX_AUDIO_CodingAutoDetect;
break;
default:
CHECK(!"Should not be here. Unsupported mime type and compression format");
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->lowres = 0;
if(avctx->lowres > codec->max_lowres){
- LOGW("The maximum value for lowres supported by the decoder is %d",
+ ALOGW("The maximum value for lowres supported by the decoder is %d",
codec->max_lowres);
avctx->lowres= codec->max_lowres;
}
avctx->flags |= CODEC_FLAG_EMU_EDGE;
}
+bool SoftFFmpegAudio::isConfigured() {
+ return mAudioSrcChannels != -1;
+}
+
+void SoftFFmpegAudio::resetCtx() {
+ mCtx->channels = -1;
+ mCtx->sample_rate = -1;
+ mCtx->bit_rate = -1;
+ mCtx->sample_fmt = AV_SAMPLE_FMT_NONE;
+
+ 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;
+ }
+ mFFmpegAlreadyInited = true;
mCtx = avcodec_alloc_context3(NULL);
- if (!mCtx)
- {
- LOGE("avcodec_alloc_context failed.");
+ 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_FLAC:
+ mCtx->codec_id = AV_CODEC_ID_FLAC;
+ break;
+ case MODE_MPEGL2:
+ mCtx->codec_id = AV_CODEC_ID_MP2;
break;
case MODE_AC3:
- mCtx->codec_id = CODEC_ID_AC3;
+ mCtx->codec_id = AV_CODEC_ID_AC3;
break;
- case MODE_WMA:
- mCtx->codec_id = CODEC_ID_WMAV2; // FIXME, CODEC_ID_WMAV1 or CODEC_ID_WMAV2?
+ case MODE_APE:
+ mCtx->codec_id = AV_CODEC_ID_APE;
+ break;
+ case MODE_DTS:
+ mCtx->codec_id = AV_CODEC_ID_DTS;
+ break;
+ case MODE_TRIAL:
+ mCtx->codec_id = AV_CODEC_ID_NONE;
break;
default:
CHECK(!"Should not be here. Unsupported codec");
break;
}
- mCtx->codec = avcodec_find_decoder(mCtx->codec_id);
- if (!mCtx->codec)
- {
- LOGE("find codec failed");
- return BAD_TYPE;
- }
-
- setAVCtxToDefault(mCtx, mCtx->codec);
+ //invalid ctx
+ resetCtx();
- mCtx->channels = mNumChannels;
- mCtx->sample_rate = mSamplingRate;
- mCtx->bit_rate = mBitRate;
- mCtx->sample_fmt = mSamplingFmt;
-
- mAudioSrcFmt = mAudioTgtFmt = AV_SAMPLE_FMT_S16;
- mAudioSrcFreq = mAudioTgtFreq = mSamplingRate;
- mAudioSrcChannels = mAudioTgtChannels = mNumChannels;
- mAudioSrcChannelLayout = mAudioTgtChannelLayout =
- av_get_default_channel_layout(mNumChannels);
+ mCtx->extradata = NULL;
+ mCtx->extradata_size = 0;
memset(mSilenceBuffer, 0, kOutputBufferSize);
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) {
- int32_t channels = 0;
- int32_t sampling_rate = 0;
-
+ //ALOGV("internalGetParameter index:0x%x", index);
switch (index) {
- case OMX_IndexParamAudioAac:
+ case OMX_IndexParamAudioPcm:
{
- OMX_AUDIO_PARAM_AACPROFILETYPE *aacParams =
- (OMX_AUDIO_PARAM_AACPROFILETYPE *)params;
+ OMX_AUDIO_PARAM_PCMMODETYPE *profile =
+ (OMX_AUDIO_PARAM_PCMMODETYPE *)params;
- if (aacParams->nPortIndex != 0) {
+ if (profile->nPortIndex > kOutputPortIndex) {
return OMX_ErrorUndefined;
}
- aacParams->nBitRate = 0;
- aacParams->nAudioBandWidth = 0;
- aacParams->nAACtools = 0;
- aacParams->nAACERtools = 0;
- aacParams->eAACProfile = OMX_AUDIO_AACObjectMain;
- aacParams->eAACStreamFormat = OMX_AUDIO_AACStreamFormatMP4FF;
- aacParams->eChannelMode = OMX_AUDIO_ChannelModeStereo;
+ 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());
- aacParams->nChannels = mNumChannels;
- aacParams->nSampleRate = mSamplingRate;
+ 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_IndexParamAudioPcm:
+
+ case OMX_IndexParamAudioAac:
{
- OMX_AUDIO_PARAM_PCMMODETYPE *pcmParams =
- (OMX_AUDIO_PARAM_PCMMODETYPE *)params;
+ OMX_AUDIO_PARAM_AACPROFILETYPE *profile =
+ (OMX_AUDIO_PARAM_AACPROFILETYPE *)params;
- if (pcmParams->nPortIndex > 1) {
+ if (profile->nPortIndex != kInputPortIndex) {
return OMX_ErrorUndefined;
}
- pcmParams->eNumData = OMX_NumericalDataSigned;
- pcmParams->eEndian = OMX_EndianBig;
- pcmParams->bInterleaved = OMX_TRUE;
- pcmParams->nBitPerSample = 16;
- pcmParams->ePCMMode = OMX_AUDIO_PCMModeLinear;
- pcmParams->eChannelMapping[0] = OMX_AUDIO_ChannelLF;
- pcmParams->eChannelMapping[1] = OMX_AUDIO_ChannelRF;
-
- channels = mNumChannels >= 2 ? 2 : 1;
- sampling_rate = mSamplingRate;
- // 4000 <= nSamplingRate <= 48000
- if (mSamplingRate < 4000) {
- sampling_rate = 4000;
- } else if (mSamplingRate > 48000) {
- sampling_rate = 48000;
- }
+ CHECK(!isConfigured());
- // update src and target(except aac), only once!
- mAudioSrcChannels = mAudioTgtChannels = channels;
- mAudioSrcFreq = mAudioTgtFreq = sampling_rate;
- mAudioSrcFmt = mAudioTgtFmt = AV_SAMPLE_FMT_S16;
- mAudioSrcChannelLayout = mAudioTgtChannelLayout = av_get_default_channel_layout(channels);
+ profile->nBitRate = 0;
+ profile->nAudioBandWidth = 0;
+ profile->nAACtools = 0;
+ profile->nAACERtools = 0;
+ profile->eAACProfile = OMX_AUDIO_AACObjectMain;
+ profile->eAACStreamFormat = OMX_AUDIO_AACStreamFormatMP4FF;
+ profile->eChannelMode = OMX_AUDIO_ChannelModeStereo;
- pcmParams->nChannels = channels;
- pcmParams->nSamplingRate = sampling_rate;
+ profile->nChannels = 0;
+ profile->nSampleRate = 0;
return OMX_ErrorNone;
}
- default:
- return SimpleSoftOMXComponent::internalGetParameter(index, params);
- }
-}
-
-OMX_ERRORTYPE SoftFFmpegAudio::internalSetParameter(
- OMX_INDEXTYPE index, const OMX_PTR params) {
- int32_t channels = 0;
- int32_t sampling_rate = 0;
-
- switch (index) {
- case OMX_IndexParamStandardComponentRole:
+ case OMX_IndexParamAudioMp3:
{
- const OMX_PARAM_COMPONENTROLETYPE *roleParams =
- (const OMX_PARAM_COMPONENTROLETYPE *)params;
+ OMX_AUDIO_PARAM_MP3TYPE *profile =
+ (OMX_AUDIO_PARAM_MP3TYPE *)params;
- bool supported = true;
- 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;
- case MODE_AAC:
- if (strncmp((const char *)roleParams->cRole,
- "audio_decoder.aac", OMX_MAX_STRINGNAME_SIZE - 1))
- supported = false;
- break;
- case MODE_AC3:
- if (strncmp((const char *)roleParams->cRole,
- "audio_decoder.ac3", 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;
- break;
- default:
- CHECK(!"Should not be here. Unsupported role.");
- break;
- }
- if (!supported) {
- LOGE("unsupported role: %s", (const char *)roleParams->cRole);
+ if (profile->nPortIndex != kInputPortIndex) {
return OMX_ErrorUndefined;
}
+ CHECK(!isConfigured());
+
+ profile->nChannels = 0;
+ profile->nSampleRate = 0;
+ profile->nBitRate = 0;
+ profile->nAudioBandWidth = 0;
+ profile->eChannelMode = OMX_AUDIO_ChannelModeStereo;
+ profile->eFormat = OMX_AUDIO_MP3StreamFormatMP1Layer3;
+
return OMX_ErrorNone;
}
- case OMX_IndexParamAudioAac:
+ case OMX_IndexParamAudioVorbis:
{
- const OMX_AUDIO_PARAM_AACPROFILETYPE *aacParams =
- (const OMX_AUDIO_PARAM_AACPROFILETYPE *)params;
+ OMX_AUDIO_PARAM_VORBISTYPE *profile =
+ (OMX_AUDIO_PARAM_VORBISTYPE *)params;
- if (aacParams->nPortIndex != 0) {
+ if (profile->nPortIndex != kInputPortIndex) {
return OMX_ErrorUndefined;
}
- mNumChannels = aacParams->nChannels;
- mSamplingRate = aacParams->nSampleRate;
+ 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->nSampleRate = 0;
+
+ return OMX_ErrorNone;
+ }
+
+ case OMX_IndexParamAudioWma:
+ {
+ OMX_AUDIO_PARAM_WMATYPE *profile =
+ (OMX_AUDIO_PARAM_WMATYPE *)params;
- channels = mNumChannels >= 2 ? 2 : 1;
- sampling_rate = mSamplingRate;
- // 4000 <= nSamplingRate <= 48000
- if (mSamplingRate < 4000) {
- sampling_rate = 4000;
- } else if (mSamplingRate > 48000) {
- sampling_rate = 48000;
+ if (profile->nPortIndex != kInputPortIndex) {
+ return OMX_ErrorUndefined;
}
- // update src and target(only aac), only once!
- mAudioSrcChannels = mAudioTgtChannels = channels;
- mAudioSrcFreq = mAudioTgtFreq = sampling_rate;
- mAudioSrcFmt = mAudioTgtFmt = AV_SAMPLE_FMT_S16;
- mAudioSrcChannelLayout = mAudioTgtChannelLayout = av_get_default_channel_layout(channels);
+ CHECK(!isConfigured());
- LOGV("got OMX_IndexParamAudioAac, mNumChannels: %d, mSamplingRate: %d",
- mNumChannels, mSamplingRate);
+ profile->nChannels = 0;
+ profile->nSamplingRate = 0;
+ profile->nBitRate = 0;
+ profile->eFormat = OMX_AUDIO_WMAFormatUnused;
return OMX_ErrorNone;
}
- default:
- LOGI("internalSetParameter, index: 0x%x", index);
- return SimpleSoftOMXComponent::internalSetParameter(index, params);
- }
-}
-void SoftFFmpegAudio::onQueueFilled(OMX_U32 portIndex) {
- int len = 0;
- int err = 0;
- size_t dataSize = 0;
- int64_t decChannelLayout;
- int32_t inputBufferUsedLength = 0;
- BufferInfo *inInfo = NULL;
- OMX_BUFFERHEADERTYPE *inHeader = NULL;
+ case OMX_IndexParamAudioRa:
+ {
+ OMX_AUDIO_PARAM_RATYPE *profile =
+ (OMX_AUDIO_PARAM_RATYPE *)params;
- if (mSignalledError || mOutputPortSettingsChange != NONE) {
- return;
- }
+ if (profile->nPortIndex != kInputPortIndex) {
+ return OMX_ErrorUndefined;
+ }
- List<BufferInfo *> &inQueue = getPortQueue(0);
- List<BufferInfo *> &outQueue = getPortQueue(1);
+ CHECK(!isConfigured());
- while ((!inQueue.empty() || mInputBufferSize > 0 ||
- mAudioBufferSize > 0 || mFlushComplete) && !outQueue.empty()) {
- if (!inQueue.empty() || mInputBufferSize > 0) {
- inInfo = *inQueue.begin();
- inHeader = inInfo->mHeader;
- } else {
- inInfo = NULL;
- inHeader = NULL;
+ profile->nChannels = 0;
+ profile->nSamplingRate = 0;
+ profile->eFormat = OMX_AUDIO_RAFormatUnused;
+
+ return OMX_ErrorNone;
}
- BufferInfo *outInfo = *outQueue.begin();
- OMX_BUFFERHEADERTYPE *outHeader = outInfo->mHeader;
+ case OMX_IndexParamAudioFlac:
+ {
+ OMX_AUDIO_PARAM_FLACTYPE *profile =
+ (OMX_AUDIO_PARAM_FLACTYPE *)params;
+
+ if (profile->nPortIndex != kInputPortIndex) {
+ return OMX_ErrorUndefined;
+ }
- if (inHeader && inHeader->nFlags & OMX_BUFFERFLAG_EOS) {
- inQueue.erase(inQueue.begin());
- inInfo->mOwnedByUs = false;
- notifyEmptyBufferDone(inHeader);
- mReceivedEOS = true;
- }
+ CHECK(!isConfigured());
- if (mReceivedEOS && (mFlushComplete || !(mCtx->codec->capabilities & CODEC_CAP_DELAY))) {
- outHeader->nFilledLen = 0;
- outHeader->nFlags = OMX_BUFFERFLAG_EOS;
+ profile->nChannels = 0;
+ profile->nSampleRate = 0;
- outQueue.erase(outQueue.begin());
- outInfo->mOwnedByUs = false;
- notifyFillBufferDone(outHeader);
- return;
+ return OMX_ErrorNone;
}
- if (inHeader && inHeader->nFlags & OMX_BUFFERFLAG_CODECCONFIG) {
- LOGI("got extradata, ignore: %d, size: %lu", mIgnoreExtradata, inHeader->nFilledLen);
- hexdump(inHeader->pBuffer + inHeader->nOffset, inHeader->nFilledLen);
- if (!mExtradataReady && !mIgnoreExtradata) {
- int orig_extradata_size = mCtx->extradata_size;
- mCtx->extradata_size += inHeader->nFilledLen;
- mCtx->extradata = (uint8_t *)realloc(mCtx->extradata,
- mCtx->extradata_size + FF_INPUT_BUFFER_PADDING_SIZE);
- if (!mCtx->extradata) {
- LOGE("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;
+ case OMX_IndexParamAudioMp2:
+ {
+ OMX_AUDIO_PARAM_MP2TYPE *profile =
+ (OMX_AUDIO_PARAM_MP2TYPE *)params;
- continue;
+ if (profile->nPortIndex != kInputPortIndex) {
+ return OMX_ErrorUndefined;
}
- if (mIgnoreExtradata) {
- LOGI("got extradata, size: %lu, but ignore it", inHeader->nFilledLen);
- inInfo->mOwnedByUs = false;
- inQueue.erase(inQueue.begin());
- inInfo = NULL;
- notifyEmptyBufferDone(inHeader);
- inHeader = NULL;
- continue;
- }
+ CHECK(!isConfigured());
+
+ profile->nChannels = 0;
+ profile->nSampleRate = 0;
+
+ return OMX_ErrorNone;
}
- if (!mCodecOpened) {
- if (!mExtradataReady && !mIgnoreExtradata) {
- LOGI("extradata is ready");
- hexdump(mCtx->extradata, mCtx->extradata_size);
- mExtradataReady = true;
- }
- LOGI("open ffmpeg decoder now");
+ case OMX_IndexParamAudioAc3:
+ {
+ OMX_AUDIO_PARAM_AC3TYPE *profile =
+ (OMX_AUDIO_PARAM_AC3TYPE *)params;
- err = avcodec_open2(mCtx, mCtx->codec, NULL);
- if (err < 0) {
- LOGE("ffmpeg audio decoder failed to initialize. (%d)", err);
- notify(OMX_EventError, OMX_ErrorUndefined, 0, NULL);
- mSignalledError = true;
- return;
+ if (profile->nPortIndex != kInputPortIndex) {
+ return OMX_ErrorUndefined;
}
- mCodecOpened = true;
- }
- /* update the audio clock with the pts */
- if (inHeader && inHeader->nOffset == 0) {
- mAnchorTimeUs = inHeader->nTimeStamp;
- mInputBufferSize = inHeader->nFilledLen;
+ CHECK(!isConfigured());
+
+ profile->nChannels = 0;
+ profile->nSamplingRate = 0;
+
+ return OMX_ErrorNone;
}
- if (inHeader && mAudioBufferSize == 0 && !mFlushComplete) {
- AVPacket pkt;
- av_init_packet(&pkt);
- if (!mFlushComplete) {
- 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
- LOGV("pkt size: %d, pts: %lld", pkt.size, pkt.pts);
-#endif
- if (!mFrame) {
- if (!(mFrame = avcodec_alloc_frame())) {
- LOGE("ffmpeg audio decoder failed to alloc memory.");
- notify(OMX_EventError, OMX_ErrorInsufficientResources, 0, NULL);
- mSignalledError = true;
- return;
- }
- } else {
- avcodec_get_frame_defaults(mFrame);
- }
+ case OMX_IndexParamAudioApe:
+ {
+ OMX_AUDIO_PARAM_APETYPE *profile =
+ (OMX_AUDIO_PARAM_APETYPE *)params;
- int gotFrm = false;
- inputBufferUsedLength = 0;
- len = avcodec_decode_audio4(mCtx, mFrame, &gotFrm, &pkt);
- if (len < 0) {
- LOGE("ffmpeg audio decoder failed to decode frame. consume pkt len: %d", len);
-
- /* if !mAudioConfigChanged, Don't fill the out buffer */
- if (!mAudioConfigChanged) {
- inInfo->mOwnedByUs = false;
- inQueue.erase(inQueue.begin());
- inInfo = NULL;
- notifyEmptyBufferDone(inHeader);
- inHeader = NULL;
- continue;
- }
-
- inputBufferUsedLength = inHeader->nFilledLen;
- /* if error, we skip the frame and play silence instead */
- mPAudioBuffer = mSilenceBuffer;
- mAudioBufferSize = kOutputBufferSize;
- } else if (!gotFrm) {
- LOGI("ffmpeg audio decoder failed to get frame.");
- /* stop sending empty packets if the decoder is finished */
- if (!pkt.data && mCtx->codec->capabilities & CODEC_CAP_DELAY)
- mFlushComplete = true;
- continue;
- } else {
- /**
- * FIXME, check mAudioConfigChanged when the first time you call the audio4!
- * mCtx->sample_rate and mCtx->channels may be changed by audio decoder later, why???
- */
- if (!mAudioConfigChanged) {
- if (mCtx->channels != mNumChannels || mCtx->sample_rate != mSamplingRate || mCtx->sample_fmt != mSamplingFmt) {
- LOGI("audio OMX_EventPortSettingsChanged, mCtx->channels: %d, mNumChannels: %d, mCtx->sample_rate: %d, mSamplingRate: %d",
- mCtx->channels, mNumChannels, mCtx->sample_rate, mSamplingRate);
- mNumChannels = mCtx->channels;
- mSamplingRate = mCtx->sample_rate;
- mSamplingFmt = mCtx->sample_fmt;
- mAudioConfigChanged = true;
- notify(OMX_EventPortSettingsChanged, 1, 0, NULL);
- mOutputPortSettingsChange = AWAITING_DISABLED;
- return;
- } else {
- // match with the default, set mAudioConfigChanged true anyway!
- mAudioConfigChanged = true;
- }
- }
-
- dataSize = av_samples_get_buffer_size(NULL, mNumChannels, mFrame->nb_samples, mSamplingFmt, 1);
-
- //LOGV("audio decoder get buffer size: %d", dataSize);
-
- decChannelLayout = av_get_default_channel_layout(mNumChannels);
- if (mSamplingFmt != mAudioSrcFmt ||
- decChannelLayout != mAudioSrcChannelLayout ||
- mSamplingRate != mAudioSrcFreq ) {
- if (mSwrCtx)
- swr_free(&mSwrCtx);
- mSwrCtx = swr_alloc_set_opts(NULL,
- mAudioTgtChannelLayout, mAudioTgtFmt, mAudioTgtFreq,
- decChannelLayout, mSamplingFmt, mSamplingRate,
- 0, NULL);
- if (!mSwrCtx || swr_init(mSwrCtx) < 0) {
- LOGE("Cannot create sample rate converter for conversion of %d Hz %s %d channels to %d Hz %s %d channels!",
- mSamplingRate,
- av_get_sample_fmt_name(mSamplingFmt),
- mNumChannels,
- mAudioTgtFreq,
- av_get_sample_fmt_name(mAudioTgtFmt),
- mAudioTgtChannels);
- notify(OMX_EventError, OMX_ErrorUndefined, 0, NULL);
- mSignalledError = true;
- return;
- }
-
- LOGI("Create sample rate converter for conversion of %d Hz %s %d channels to %d Hz %s %d channels!",
- mSamplingRate,
- av_get_sample_fmt_name(mSamplingFmt),
- mNumChannels,
- mAudioTgtFreq,
- av_get_sample_fmt_name(mAudioTgtFmt),
- mAudioTgtChannels);
-
- mAudioSrcChannelLayout = decChannelLayout;
- mAudioSrcChannels = mNumChannels;
- mAudioSrcFreq = mSamplingRate;
- mAudioSrcFmt = mSamplingFmt;
- }
-
- if (mSwrCtx) {
- const uint8_t *in[] = { mFrame->data[0] };
- uint8_t *out[] = {mAudioBuf2};
- int len2 = swr_convert(mSwrCtx, out, sizeof(mAudioBuf2) / mAudioTgtChannels / av_get_bytes_per_sample(mAudioTgtFmt),
- in, mFrame->nb_samples);
- if (len2 < 0) {
- LOGE("audio_resample() failed");
- break;
- }
- if (len2 == sizeof(mAudioBuf2) / mAudioTgtChannels / av_get_bytes_per_sample(mAudioTgtFmt)) {
- LOGE("warning: audio buffer is probably too small");
- swr_init(mSwrCtx);
- }
- mPAudioBuffer = mAudioBuf2;
- mAudioBufferSize = len2 * mAudioTgtChannels * av_get_bytes_per_sample(mAudioTgtFmt);
- } else {
- mPAudioBuffer = mFrame->data[0];
- mAudioBufferSize = dataSize;
- }
-
- inputBufferUsedLength = len;
-#if DEBUG_FRM
- LOGV("ffmpeg audio decoder get frame. consume pkt len: %d, nb_samples(before resample): %d, mAudioBufferSize: %d",
- len, mFrame->nb_samples, mAudioBufferSize);
-#endif
+ if (profile->nPortIndex != kInputPortIndex) {
+ return OMX_ErrorUndefined;
}
- }
- size_t copyToOutputBufferLen = mAudioBufferSize;
- if (mAudioBufferSize > kOutputBufferSize)
- copyToOutputBufferLen = kOutputBufferSize;
+ CHECK(!isConfigured());
- outHeader->nOffset = 0;
- outHeader->nFilledLen = copyToOutputBufferLen;
- outHeader->nTimeStamp = mAnchorTimeUs + (mNumFramesOutput * 1000000ll) / mSamplingRate;
- memcpy(outHeader->pBuffer, mPAudioBuffer, copyToOutputBufferLen);
- outHeader->nFlags = 0;
+ profile->nChannels = 0;
+ profile->nSamplingRate = 0;
-#if DEBUG_FRM
- LOGV("ffmpeg audio decoder, fill out buffer, pts: %lld, mNumFramesOutput: %lld", outHeader->nTimeStamp, mNumFramesOutput);
-#endif
+ return OMX_ErrorNone;
+ }
+
+ case OMX_IndexParamAudioDts:
+ {
+ OMX_AUDIO_PARAM_DTSTYPE *profile =
+ (OMX_AUDIO_PARAM_DTSTYPE *)params;
- mPAudioBuffer += copyToOutputBufferLen;
- mAudioBufferSize -= copyToOutputBufferLen;
- mNumFramesOutput += copyToOutputBufferLen / (av_get_bytes_per_sample(mCtx->sample_fmt) * mNumChannels);
+ if (profile->nPortIndex != kInputPortIndex) {
+ return OMX_ErrorUndefined;
+ }
+ CHECK(!isConfigured());
- // reset mNumFramesOutput
- if (mAudioBufferSize == 0)
- mNumFramesOutput = 0;
+ profile->nChannels = 0;
+ profile->nSamplingRate = 0;
+ return OMX_ErrorNone;
+ }
- if (inHeader) {
- 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;
+ case OMX_IndexParamAudioFFmpeg:
+ {
+ OMX_AUDIO_PARAM_FFMPEGTYPE *profile =
+ (OMX_AUDIO_PARAM_FFMPEGTYPE *)params;
- mInputBufferSize = 0;
+ 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;
}
- outInfo->mOwnedByUs = false;
- outQueue.erase(outQueue.begin());
- outInfo = NULL;
- notifyFillBufferDone(outHeader);
- outHeader = NULL;
+ default:
+
+ return SimpleSoftOMXComponent::internalGetParameter(index, params);
}
}
-void SoftFFmpegAudio::onPortFlushCompleted(OMX_U32 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);
- }
+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;
+ break;
+ case MODE_MPEG:
+ if (strncmp((const char *)roleParams->cRole,
+ "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;
+ break;
+ case MODE_RA:
+ if (strncmp((const char *)roleParams->cRole,
+ "audio_decoder.ra", OMX_MAX_STRINGNAME_SIZE - 1))
+ supported = false;
+ break;
+ case MODE_FLAC:
+ if (strncmp((const char *)roleParams->cRole,
+ "audio_decoder.flac", 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;
+ case MODE_AC3:
+ if (strncmp((const char *)roleParams->cRole,
+ "audio_decoder.ac3", OMX_MAX_STRINGNAME_SIZE - 1))
+ supported = false;
+ break;
+ case MODE_APE:
+ if (strncmp((const char *)roleParams->cRole,
+ "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_TRIAL:
+ if (strncmp((const char *)roleParams->cRole,
+ "audio_decoder.trial", OMX_MAX_STRINGNAME_SIZE - 1))
+ supported = false;
+ break;
+ default:
+ CHECK(!"Should not be here. Unsupported role.");
+ break;
+ }
+
+ if (!supported) {
+ ALOGE("unsupported role: %s", (const char *)roleParams->cRole);
+ return OMX_ErrorUndefined;
+ }
+
+ return OMX_ErrorNone;
+}
+
+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
+ channels = mCtx->channels >= 2 ? 2 : 1;
+
+ //4000 <= sampling rate <= 48000
+ if (sampling_rate < 4000) {
+ sampling_rate = 4000;
+ } else if (sampling_rate > 48000) {
+ sampling_rate = 48000;
+ }
+
+ mAudioSrcChannels = mAudioTgtChannels = channels;
+ mAudioSrcFreq = mAudioTgtFreq = sampling_rate;
+ mAudioSrcFmt = mAudioTgtFmt = AV_SAMPLE_FMT_S16;
+ mAudioSrcChannelLayout = mAudioTgtChannelLayout =
+ av_get_default_channel_layout(channels);
+}
+
+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 *roleParams =
+ (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 != kOutputPortIndex) {
+ return OMX_ErrorUndefined;
+ }
+
+ CHECK(!isConfigured());
+
+ mCtx->channels = profile->nChannels;
+ mCtx->sample_rate = profile->nSamplingRate;
+ mCtx->bits_per_coded_sample = profile->nBitPerSample;
+
+ ALOGV("set OMX_IndexParamAudioPcm, nChannels:%lu, "
+ "nSampleRate:%lu, nBitsPerSample:%lu",
+ profile->nChannels, profile->nSamplingRate,
+ profile->nBitPerSample);
+
+ return OMX_ErrorNone;
+ }
+
+ case OMX_IndexParamAudioAac:
+ {
+ const OMX_AUDIO_PARAM_AACPROFILETYPE *profile =
+ (const OMX_AUDIO_PARAM_AACPROFILETYPE *)params;
+
+ 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;
+
+ adjustAudioParams();
+
+ 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 != kInputPortIndex) {
+ return OMX_ErrorUndefined;
+ }
+
+ CHECK(!isConfigured());
+
+ if (profile->eFormat == OMX_AUDIO_WMAFormat7) {
+ mCtx->codec_id = AV_CODEC_ID_WMAV2;
+ } else if (profile->eFormat == OMX_AUDIO_WMAFormat8) {
+ mCtx->codec_id = AV_CODEC_ID_WMAPRO;
+ } else if (profile->eFormat == OMX_AUDIO_WMAFormat9) {
+ mCtx->codec_id = AV_CODEC_ID_WMALOSSLESS;
+ } else {
+ ALOGE("unsupported wma codec: 0x%x", profile->eFormat);
+ return OMX_ErrorUndefined;
+ }
+
+ mCtx->channels = profile->nChannels;
+ mCtx->sample_rate = profile->nSamplingRate;
+
+ // wmadec needs bitrate, block_align
+ mCtx->bit_rate = profile->nBitRate;
+ mCtx->block_align = profile->nBlockAlign;
+
+ adjustAudioParams();
+
+ ALOGV("set OMX_IndexParamAudioWma, nChannels:%u, "
+ "nSampleRate:%lu, nBitRate:%lu, nBlockAlign:%u",
+ profile->nChannels, profile->nSamplingRate,
+ profile->nBitRate, profile->nBlockAlign);
+
+ return OMX_ErrorNone;
+ }
+
+ case OMX_IndexParamAudioRa:
+ {
+ OMX_AUDIO_PARAM_RATYPE *profile =
+ (OMX_AUDIO_PARAM_RATYPE *)params;
+
+ if (profile->nPortIndex != kInputPortIndex) {
+ return OMX_ErrorUndefined;
+ }
+
+ CHECK(!isConfigured());
+
+ mCtx->channels = profile->nChannels;
+ mCtx->sample_rate = profile->nSamplingRate;
+
+ // FIXME, HACK!!!, I use the nNumRegions parameter pass blockAlign!!!
+ // the cook audio codec need blockAlign!
+ mCtx->block_align = profile->nNumRegions;
+
+ adjustAudioParams();
+
+ ALOGV("set OMX_IndexParamAudioRa, nChannels:%lu, "
+ "nSampleRate:%lu, nBlockAlign:%d",
+ profile->nChannels, profile->nSamplingRate, mCtx->block_align);
+
+ 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 != kInputPortIndex) {
+ return OMX_ErrorUndefined;
+ }
+
+ CHECK(!isConfigured());
+
+ mCtx->channels = profile->nChannels;
+ mCtx->sample_rate = profile->nSamplingRate;
+
+ //ape decoder need bits_per_coded_sample
+ mCtx->bits_per_coded_sample = profile->nBitsPerSample;
+
+ adjustAudioParams();
+
+ ALOGV("set OMX_IndexParamAudioApe, nChannels:%lu, "
+ "nSampleRate:%lu, nBitsPerSample:%lu",
+ profile->nChannels, profile->nSamplingRate,
+ profile->nBitsPerSample);
+
+ 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());
+
+ mCtx->channels = profile->nChannels;
+ mCtx->sample_rate = profile->nSamplingRate;
+
+ adjustAudioParams();
+
+ ALOGV("set OMX_IndexParamAudioDts, nChannels:%lu, nSampleRate:%lu",
+ profile->nChannels, profile->nSamplingRate);
+
+ 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());
+
+
+ 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;
+ }
+
+ default:
+
+ return SimpleSoftOMXComponent::internalSetParameter(index, params);
+ }
+}
+
+int32_t SoftFFmpegAudio::handleExtradata() {
+ List<BufferInfo *> &inQueue = getPortQueue(kInputPortIndex);
+ BufferInfo *inInfo = *inQueue.begin();
+ OMX_BUFFERHEADERTYPE *inHeader = inInfo->mHeader;
+
+ 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;
+ }
+
+ 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;
+
+ return ERR_OK;
+}
+
+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::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 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;
+
+ CHECK_EQ(mResampledDataSize, 0);
+
+ if (!is_flush) {
+ inInfo = *inQueue.begin();
+ CHECK(inInfo != NULL);
+ inHeader = inInfo->mHeader;
+
+ if (mInputBufferSize == 0) {
+ updateTimeStamp(inHeader);
+ mInputBufferSize = inHeader->nFilledLen;
+ }
+ }
+
+ 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();
+ }
+ }
+
+ if (!is_flush) {
+ 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) {
+ CHECK_EQ(mInputBufferSize, 0);
+ inQueue.erase(inQueue.begin());
+ inInfo->mOwnedByUs = false;
+ notifyEmptyBufferDone(inHeader);
+ }
+ }
+
+ return ret;
+}
+
+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
+
+ 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 (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;
+ }
+
+ 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 (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;
+ }
+
+ 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);
+
+#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;
+
+#if DEBUG_FRM
+ ALOGV("ffmpeg audio decoder(no resample),"
+ "nb_samples(before resample):%d, mResampledDataSize:%d",
+ mFrame->nb_samples, mResampledDataSize);
+#endif
+ }
+
+ return ERR_OK;
+}
+
+void SoftFFmpegAudio::drainOneOutputBuffer() {
+ List<BufferInfo *> &outQueue = getPortQueue(kOutputPortIndex);
+ BufferInfo *outInfo = *outQueue.begin();
+ CHECK(outInfo != NULL);
+ OMX_BUFFERHEADERTYPE *outHeader = outInfo->mHeader;
+
+ CHECK_GT(mResampledDataSize, 0);
+
+ size_t copy = mResampledDataSize;
+ if (mResampledDataSize > kOutputBufferSize) {
+ copy = kOutputBufferSize;
+ }
+
+ outHeader->nOffset = 0;
+ outHeader->nFilledLen = copy;
+ outHeader->nTimeStamp = mAudioClock;
+ memcpy(outHeader->pBuffer, mResampledData, copy);
+ outHeader->nFlags = 0;
+
+ //update mResampledSize
+ mResampledData += copy;
+ mResampledDataSize -= copy;
+
+ //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
+
+ outQueue.erase(outQueue.begin());
+ outInfo->mOwnedByUs = false;
+ notifyFillBufferDone(outHeader);
+}
+
+void SoftFFmpegAudio::drainEOSOutputBuffer() {
+ List<BufferInfo *> &outQueue = getPortQueue(kOutputPortIndex);
+ BufferInfo *outInfo = *outQueue.begin();
+ CHECK(outInfo != NULL);
+ OMX_BUFFERHEADERTYPE *outHeader = outInfo->mHeader;
+
+ CHECK_EQ(mResampledDataSize, 0);
+
+ ALOGD("ffmpeg audio decoder fill eos outbuf");
+
+ outHeader->nTimeStamp = 0;
+ outHeader->nFilledLen = 0;
+ outHeader->nFlags = OMX_BUFFERFLAG_EOS;
+
+ outQueue.erase(outQueue.begin());
+ outInfo->mOwnedByUs = false;
+ notifyFillBufferDone(outHeader);
+
+ mEOSStatus = OUTPUT_FRAMES_FLUSHED;
+}
+
+void SoftFFmpegAudio::drainAllOutputBuffers() {
+ List<BufferInfo *> &outQueue = getPortQueue(kOutputPortIndex);
+
+ if (!mCodecAlreadyOpened) {
+ drainEOSOutputBuffer();
+ mEOSStatus = OUTPUT_FRAMES_FLUSHED;
+ return;
+ }
+
+ if(!(mCtx->codec->capabilities & CODEC_CAP_DELAY)) {
+ drainEOSOutputBuffer();
+ mEOSStatus = OUTPUT_FRAMES_FLUSHED;
+ return;
+ }
+
+ 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);
+ }
+ }
+
+ if (mResampledDataSize > 0) {
+ drainOneOutputBuffer();
+ }
+ }
+}
+
+void SoftFFmpegAudio::onQueueFilled(OMX_U32 portIndex) {
+ BufferInfo *inInfo = NULL;
+ OMX_BUFFERHEADERTYPE *inHeader = NULL;
+
+ if (mSignalledError || mOutputPortSettingsChange != NONE) {
+ return;
+ }
+
+ if (mEOSStatus == OUTPUT_FRAMES_FLUSHED) {
+ return;
+ }
+
+ List<BufferInfo *> &inQueue = getPortQueue(kInputPortIndex);
+ List<BufferInfo *> &outQueue = getPortQueue(kOutputPortIndex);
+
+ while (((mEOSStatus != INPUT_DATA_AVAILABLE) || !inQueue.empty())
+ && !outQueue.empty()) {
+
+ if (mEOSStatus == INPUT_EOS_SEEN) {
+ drainAllOutputBuffers();
+ return;
+ }
+
+ inInfo = *inQueue.begin();
+ inHeader = inInfo->mHeader;
+
+ 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;
+ }
+ }
+
+ 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);
+ }
+ }
+
+ if (mResampledDataSize > 0) {
+ drainOneOutputBuffer();
+ }
+ }
+}
+
+void SoftFFmpegAudio::onPortFlushCompleted(OMX_U32 portIndex) {
+ ALOGV("ffmpeg audio decoder flush port(%lu)", portIndex);
+ 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;
+ }
}
void SoftFFmpegAudio::onPortEnableCompleted(OMX_U32 portIndex, bool enabled) {
- if (portIndex != 1) {
+ if (portIndex != kOutputPortIndex) {
return;
}