* limitations under the License.
*/
-//#define LOG_NDEBUG 0
#define LOG_TAG "SoftFFmpegAudio"
#include <utils/Log.h>
#include <cutils/properties.h>
#include <media/stagefright/foundation/ADebug.h>
#include <media/stagefright/foundation/hexdump.h>
+#include <media/stagefright/ACodec.h>
#include <media/stagefright/MediaDefs.h>
-#include <media/stagefright/OMXCodec.h>
#include <OMX_AudioExt.h>
#include <OMX_IndexExt.h>
#define DEBUG_PKT 0
#define DEBUG_FRM 0
+#define DEBUG_EXTRADATA 0
namespace android {
template<class T>
static void InitOMXParams(T *params) {
+ memset(params, 0, sizeof(T));
params->nSize = sizeof(T);
params->nVersion.s.nVersionMajor = 1;
params->nVersion.s.nVersionMinor = 0;
setAudioClock(0);
- char value[PROPERTY_VALUE_MAX] = {0};
- property_get("audio.offload.24bit.enable", value, "1");
- mHighResAudioEnabled = atoi(value);
-
- ALOGD("SoftFFmpegAudio component: %s mCodingType: %d mHighResAudioEnabled: %d",
- name, mCodingType, mHighResAudioEnabled);
+ ALOGD("SoftFFmpegAudio component: %s mCodingType: %d",
+ name, mCodingType);
initPorts();
CHECK_EQ(initDecoder(codecID), (status_t)OK);
def.nBufferSize = 1000000; // dts!
} else {
// max aggregated buffer size from nuplayer
- def.nBufferSize = 24 * 1024;
+ def.nBufferSize = 32 * 1024;
}
def.bEnabled = OMX_TRUE;
int fast = 0;
avctx->workaround_bugs = 1;
- avctx->lowres = 0;
- if(avctx->lowres > codec->max_lowres){
- ALOGW("The maximum value for lowres supported by the decoder is %d",
- codec->max_lowres);
- avctx->lowres= codec->max_lowres;
- }
avctx->idct_algo = 0;
avctx->skip_frame = AVDISCARD_DEFAULT;
avctx->skip_idct = AVDISCARD_DEFAULT;
avctx->skip_loop_filter = AVDISCARD_DEFAULT;
avctx->error_concealment = 3;
- avctx->flags |= CODEC_FLAG_BITEXACT;
+ avctx->flags |= AV_CODEC_FLAG_BITEXACT;
- if(avctx->lowres) avctx->flags |= CODEC_FLAG_EMU_EDGE;
- if (fast) avctx->flags2 |= CODEC_FLAG2_FAST;
- if(codec->capabilities & CODEC_CAP_DR1)
+ if (fast) avctx->flags2 |= AV_CODEC_FLAG2_FAST;
+#ifdef CODEC_FLAG_EMU_EDGE
+ if (codec->capabilities & AV_CODEC_CAP_DR1)
avctx->flags |= CODEC_FLAG_EMU_EDGE;
+#endif
}
bool SoftFFmpegAudio::isConfigured() {
if (mCodecAlreadyOpened) {
avcodec_close(mCtx);
- av_free(mCtx);
- mCtx = NULL;
+ mCodecAlreadyOpened = false;
}
+ av_free(mCtx);
+ mCtx = NULL;
}
if (mFrame) {
- av_freep(&mFrame);
+ av_frame_free(&mFrame);
mFrame = NULL;
}
+#ifdef LIBAV_CONFIG_H
+#else
if (mSwrCtx) {
swr_free(&mSwrCtx);
mSwrCtx = NULL;
}
+#endif
}
OMX_ERRORTYPE SoftFFmpegAudio::internalGetParameter(
profile->eEndian = OMX_EndianBig;
profile->bInterleaved = OMX_TRUE;
profile->ePCMMode = OMX_AUDIO_PCMModeLinear;
+ profile->nBitPerSample = 32;
+ profile->eNumData = OMX_NumericalDataFloat;
if (isConfigured()) {
- profile->nBitPerSample = av_get_bytes_per_sample(mAudioTgtFmt) > 2 ? 24 : 16;
- } else {
- profile->nBitPerSample = mHighResAudioEnabled ? 24 : 16;
+ switch (av_get_packed_sample_fmt(mAudioTgtFmt)) {
+ case AV_SAMPLE_FMT_U8:
+ profile->nBitPerSample = 8;
+ profile->eNumData = OMX_NumericalDataUnsigned;
+ break;
+ case AV_SAMPLE_FMT_S16:
+ profile->nBitPerSample = 16;
+ profile->eNumData = OMX_NumericalDataSigned;
+ break;
+ case AV_SAMPLE_FMT_S32:
+ profile->nBitPerSample = 32;
+ profile->eNumData = OMX_NumericalDataSigned;
+ break;
+ default:
+ profile->nBitPerSample = 32;
+ profile->eNumData = OMX_NumericalDataFloat;
+ break;
+ }
}
- if (getOMXChannelMapping(mAudioTgtChannels, profile->eChannelMapping) != OK) {
+ if (ACodec::getOMXChannelMapping(mAudioTgtChannels, profile->eChannelMapping) != OK) {
return OMX_ErrorNone;
}
profile->nSamplingRate = mAudioTgtFreq;
//mCtx has been updated(adjustAudioParams)!
- ALOGV("get pcm params, nChannels:%lu, nSamplingRate:%lu, nBitsPerSample:%lu",
+ ALOGV("get pcm params, nChannels:%u, nSamplingRate:%u, nBitPerSample:%u",
profile->nChannels, profile->nSamplingRate, profile->nBitPerSample);
return OMX_ErrorNone;
profile->nChannels = mCtx->channels;
profile->nSampleRate = mCtx->sample_rate;
-
+ profile->nCompressionLevel = mCtx->bits_per_raw_sample;
return OMX_ErrorNone;
}
return OMX_ErrorNone;
}
+ case OMX_IndexParamAudioAlac:
+ {
+ OMX_AUDIO_PARAM_ALACTYPE *profile =
+ (OMX_AUDIO_PARAM_ALACTYPE *)params;
+
+ if (profile->nPortIndex != kInputPortIndex) {
+ return OMX_ErrorUndefined;
+ }
+
+ profile->nChannels = mCtx->channels;
+ profile->nSamplingRate = mCtx->sample_rate;
+
+ profile->nBitsPerSample = mCtx->bits_per_coded_sample;
+
+ return OMX_ErrorNone;
+ }
+
case OMX_IndexParamAudioApe:
{
OMX_AUDIO_PARAM_APETYPE *profile =
void SoftFFmpegAudio::adjustAudioParams() {
- uint32_t max_rate = 48000;
-
mReconfiguring = isConfigured();
// let android audio mixer to downmix if there is no multichannel output
// and use number of channels from the source file, useful for HDMI/offload output
mAudioTgtChannels = mCtx->channels;
- // 4000 <= sampling rate <= 48000/192000
- if (mHighResAudioEnabled) {
- max_rate = 192000;
- }
-
- mAudioTgtFreq = FFMIN(max_rate, FFMAX(8000, mCtx->sample_rate));
+ mAudioTgtFreq = FFMIN(192000, FFMAX(8000, mCtx->sample_rate));
mAudioTgtChannels = mCtx->channels;
mAudioTgtFreq = mCtx->sample_rate;
return OMX_ErrorUndefined;
}
- if (mHighResAudioEnabled &&
- (profile->nBitPerSample > 16 || profile->nBitPerSample == 0)) {
- mAudioTgtFmt = AV_SAMPLE_FMT_S32;
- } else {
- mAudioTgtFmt = AV_SAMPLE_FMT_S16;
+ switch (profile->nBitPerSample) {
+ case 8:
+ mAudioTgtFmt = AV_SAMPLE_FMT_U8;
+ break;
+ case 16:
+ mAudioTgtFmt = AV_SAMPLE_FMT_S16;
+ break;
+ case 24:
+ mAudioTgtFmt = AV_SAMPLE_FMT_S32;
+ break;
+ case 32:
+ if (profile->eNumData == OMX_NumericalDataFloat) {
+ mAudioTgtFmt = AV_SAMPLE_FMT_FLT;
+ break;
+ }
+ mAudioTgtFmt = AV_SAMPLE_FMT_S32;
+ break;
+ default:
+ ALOGE("Unknown PCM encoding, assuming floating point");
+ mAudioTgtFmt = AV_SAMPLE_FMT_FLT;
}
mAudioTgtFreq = profile->nSamplingRate;
mAudioTgtChannels = profile->nChannels;
- ALOGV("set OMX_IndexParamAudioPcm, nChannels:%lu, "
- "nSampleRate:%lu, nBitsPerSample:%lu",
+ ALOGV("set OMX_IndexParamAudioPcm, nChannels:%u, "
+ "nSampleRate:%u, nBitPerSample:%u",
profile->nChannels, profile->nSamplingRate,
profile->nBitPerSample);
adjustAudioParams();
- ALOGV("set OMX_IndexParamAudioAac, nChannels:%lu, nSampleRate:%lu",
+ ALOGV("set OMX_IndexParamAudioAac, nChannels:%u, nSampleRate:%u",
profile->nChannels, profile->nSampleRate);
return OMX_ErrorNone;
adjustAudioParams();
- ALOGV("set OMX_IndexParamAudioMp3, nChannels:%lu, nSampleRate:%lu",
+ ALOGV("set OMX_IndexParamAudioMp3, nChannels:%u, nSampleRate:%u",
profile->nChannels, profile->nSampleRate);
return OMX_ErrorNone;
adjustAudioParams();
ALOGD("set OMX_IndexParamAudioVorbis, "
- "nChannels=%lu, nSampleRate=%lu, nBitRate=%lu, "
- "nMinBitRate=%lu, nMaxBitRate=%lu",
+ "nChannels=%u, nSampleRate=%u, nBitRate=%u, "
+ "nMinBitRate=%u, nMaxBitRate=%u",
profile->nChannels, profile->nSampleRate,
profile->nBitRate, profile->nMinBitRate,
profile->nMaxBitRate);
adjustAudioParams();
ALOGV("set OMX_IndexParamAudioWma, nChannels:%u, "
- "nSampleRate:%lu, nBitRate:%lu, nBlockAlign:%u",
+ "nSampleRate:%u, nBitRate:%u, nBlockAlign:%u",
profile->nChannels, profile->nSamplingRate,
profile->nBitRate, profile->nBlockAlign);
adjustAudioParams();
- ALOGV("set OMX_IndexParamAudioRa, nChannels:%lu, "
- "nSampleRate:%lu, nBlockAlign:%d",
+ ALOGV("set OMX_IndexParamAudioRa, nChannels:%u, "
+ "nSampleRate:%u, nBlockAlign:%d",
profile->nChannels, profile->nSamplingRate, mCtx->block_align);
return OMX_ErrorNone;
adjustAudioParams();
- ALOGV("set OMX_IndexParamAudioFlac, nChannels:%lu, nSampleRate:%lu ",
+ ALOGV("set OMX_IndexParamAudioFlac, nChannels:%u, nSampleRate:%u ",
profile->nChannels, profile->nSampleRate);
return OMX_ErrorNone;
adjustAudioParams();
- ALOGV("set OMX_IndexParamAudioMp2, nChannels:%lu, nSampleRate:%lu",
+ ALOGV("set OMX_IndexParamAudioMp2, nChannels:%u, nSampleRate:%u",
profile->nChannels, profile->nSampleRate);
return OMX_ErrorNone;
adjustAudioParams();
- ALOGV("set OMX_IndexParamAudioAc3, nChannels:%lu, nSampleRate:%lu",
+ ALOGV("set OMX_IndexParamAudioAc3, nChannels:%u, nSampleRate:%u",
profile->nChannels, profile->nSamplingRate);
return OMX_ErrorNone;
adjustAudioParams();
- ALOGV("set OMX_IndexParamAudioAndroidAc3, nChannels:%lu, nSampleRate:%lu",
+ ALOGV("set OMX_IndexParamAudioAndroidAc3, nChannels:%u, nSampleRate:%u",
profile->nChannels, profile->nSampleRate);
return OMX_ErrorNone;
}
+ case OMX_IndexParamAudioAlac:
+ {
+ OMX_AUDIO_PARAM_ALACTYPE *profile =
+ (OMX_AUDIO_PARAM_ALACTYPE *)params;
+
+ if (profile->nPortIndex != kInputPortIndex) {
+ return OMX_ErrorUndefined;
+ }
+
+ mCtx->channels = profile->nChannels;
+ mCtx->sample_rate = profile->nSamplingRate;
+ mCtx->bits_per_coded_sample = profile->nBitsPerSample;
+
+ adjustAudioParams();
+
+ ALOGV("set OMX_IndexParamAudioAlac, nChannels:%u, "
+ "nSampleRate:%u, nBitsPerSample:%u",
+ profile->nChannels, profile->nSamplingRate,
+ profile->nBitsPerSample);
+
+ return OMX_ErrorNone;
+ }
case OMX_IndexParamAudioApe:
{
adjustAudioParams();
- ALOGV("set OMX_IndexParamAudioApe, nChannels:%lu, "
- "nSampleRate:%lu, nBitsPerSample:%lu",
+ ALOGV("set OMX_IndexParamAudioApe, nChannels:%u, "
+ "nSampleRate:%u, nBitsPerSample:%u",
profile->nChannels, profile->nSamplingRate,
profile->nBitsPerSample);
adjustAudioParams();
- ALOGV("set OMX_IndexParamAudioDts, nChannels:%lu, nSampleRate:%lu",
+ ALOGV("set OMX_IndexParamAudioDts, nChannels:%u, nSampleRate:%u",
profile->nChannels, profile->nSamplingRate);
return OMX_ErrorNone;
adjustAudioParams();
ALOGD("set OMX_IndexParamAudioFFmpeg, "
- "eCodecId:%ld(%s), nChannels:%lu, nBitRate:%lu, "
- "nBitsPerSample:%lu, nSampleRate:%lu, "
- "nBlockAlign:%lu, eSampleFormat:%lu(%s)",
+ "eCodecId:%d(%s), nChannels:%u, nBitRate:%u, "
+ "nBitsPerSample:%u, nSampleRate:%u, "
+ "nBlockAlign:%u, eSampleFormat:%u(%s)",
profile->eCodecId, avcodec_get_name(mCtx->codec_id),
profile->nChannels, profile->nBitRate,
profile->nBitsPerSample, profile->nSampleRate,
BufferInfo *inInfo = *inQueue.begin();
OMX_BUFFERHEADERTYPE *inHeader = inInfo->mHeader;
- ALOGI("got extradata, ignore: %d, size: %lu",
+#if DEBUG_EXTRADATA
+ ALOGI("got extradata, ignore: %d, size: %u",
mIgnoreExtradata, inHeader->nFilledLen);
hexdump(inHeader->pBuffer + inHeader->nOffset, inHeader->nFilledLen);
+#endif
if (mIgnoreExtradata) {
- ALOGI("got extradata, size: %lu, but ignore it", inHeader->nFilledLen);
+ ALOGI("got extradata, size: %u, but ignore it", inHeader->nFilledLen);
} else {
if (!mExtradataReady) {
uint32_t ret = ERR_OK;
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);
+ mCtx->extradata_size + AV_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);
+ memset(mCtx->extradata + mCtx->extradata_size, 0, AV_INPUT_BUFFER_PADDING_SIZE);
}
}
}
}
deinitVorbisHdr();
}
+#if DEBUG_EXTRADATA
ALOGI("extradata is ready, size: %d", mCtx->extradata_size);
hexdump(mCtx->extradata, mCtx->extradata_size);
+#endif
mExtradataReady = true;
}
int gotFrm = false;
int32_t ret = ERR_OK;
int32_t inputBufferUsedLength = 0;
- bool is_flush = (mEOSStatus != INPUT_DATA_AVAILABLE);
+ bool is_flush = (mEOSStatus == OUTPUT_FRAMES_FLUSHED);
List<BufferInfo *> &inQueue = getPortQueue(kInputPortIndex);
BufferInfo *inInfo = NULL;
OMX_BUFFERHEADERTYPE *inHeader = NULL;
CHECK_EQ(mResampledDataSize, 0);
- if (!is_flush) {
+ if (!is_flush && !inQueue.empty()) {
inInfo = *inQueue.begin();
- CHECK(inInfo != NULL);
- inHeader = inInfo->mHeader;
+ if (inInfo != NULL) {
+ inHeader = inInfo->mHeader;
- if (mInputBufferSize == 0) {
- updateTimeStamp(inHeader);
- mInputBufferSize = inHeader->nFilledLen;
+ if (mInputBufferSize == 0) {
+ updateTimeStamp(inHeader);
+ mInputBufferSize = inHeader->nFilledLen;
+ }
}
}
+ if (mEOSStatus == INPUT_EOS_SEEN && (!inHeader || inHeader->nFilledLen == 0)
+ && !(mCtx->codec->capabilities & AV_CODEC_CAP_DELAY)) {
+ return ERR_FLUSHED;
+ }
+
AVPacket pkt;
initPacket(&pkt, inHeader);
- av_frame_unref(mFrame);
len = avcodec_decode_audio4(mCtx, mFrame, &gotFrm, &pkt);
+ av_packet_unref(&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");
ALOGI("ffmpeg audio decoder failed to get frame.");
#endif
//stop sending empty packets if the decoder is finished
- if (is_flush && mCtx->codec->capabilities & CODEC_CAP_DELAY) {
+ if (is_flush && mCtx->codec->capabilities & AV_CODEC_CAP_DELAY) {
ALOGI("ffmpeg audio decoder failed to get more frames when flush.");
ret = ERR_FLUSHED;
} else {
} 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);
+ if (inHeader != NULL) {
+ CHECK_GE(inHeader->nFilledLen, inputBufferUsedLength);
+ inHeader->nOffset += inputBufferUsedLength;
+ inHeader->nFilledLen -= inputBufferUsedLength;
+
+ if (inHeader->nFilledLen == 0) {
+ CHECK_EQ(mInputBufferSize, 0);
+ inQueue.erase(inQueue.begin());
+ inInfo->mOwnedByUs = false;
+ notifyEmptyBufferDone(inHeader);
+ }
}
}
return ret;
}
+#ifdef LIBAV_CONFIG_H
+#define av_frame_get_channels(f) av_get_channel_layout_nb_channels(f->channel_layout)
+#endif
+
int32_t SoftFFmpegAudio::resampleAudio() {
int channels = 0;
int64_t channelLayout = 0;
|| mAudioSrcFmt != mAudioTgtFmt
|| mAudioSrcChannelLayout != mAudioTgtChannelLayout
|| mAudioSrcFreq != mAudioTgtFreq))) {
+#ifdef LIBAV_CONFIG_H
+ if (!mSwrCtx) {
+#else
if (mSwrCtx) {
swr_free(&mSwrCtx);
}
channelLayout, (enum AVSampleFormat)mFrame->format, mFrame->sample_rate,
0, NULL);
if (!mSwrCtx || swr_init(mSwrCtx) < 0) {
+#endif
ALOGE("Cannot create sample rate converter for conversion "
"of %d Hz %s %d channels to %d Hz %s %d channels!",
mFrame->sample_rate,
}
if (mSwrCtx) {
+#ifdef LIBAV_CONFIG_H
+#else
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);
mAudioTgtChannels,
av_get_sample_fmt_name(mAudioTgtFmt));
#endif
+#endif
} else {
mResampledData = mFrame->data[0];
mResampledDataSize = dataSize;
return;
}
- if(!(mCtx->codec->capabilities & CODEC_CAP_DELAY)) {
- drainEOSOutputBuffer();
- mEOSStatus = OUTPUT_FRAMES_FLUSHED;
- return;
- }
-
while (!outQueue.empty()) {
if (mResampledDataSize == 0) {
int32_t err = decodeAudio();
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);
+ ALOGD("ffmpeg audio decoder eos");
mEOSStatus = INPUT_EOS_SEEN;
continue;
}
}
void SoftFFmpegAudio::onPortFlushCompleted(OMX_U32 portIndex) {
- ALOGV("ffmpeg audio decoder flush port(%lu)", portIndex);
+ ALOGV("ffmpeg audio decoder flush port(%u)", portIndex);
if (portIndex == kInputPortIndex) {
- if (mCtx && mCtx->codec) {
+ if (mCtx && avcodec_is_open(mCtx)) {
//Make sure that the next buffer output does not still
//depend on fragments from the last one decoded.
avcodec_flush_buffers(mCtx);
sAudioClock = (int64_t*) malloc(sizeof(int64_t));
*sAudioClock = 0;
}
- ALOGV("getAudioClock: %lld", *sAudioClock);
+ ALOGV("getAudioClock: %" PRId64, *sAudioClock);
return *sAudioClock;
}
initDecoder(codecID);
mSignalledError = false;
mOutputPortSettingsChange = NONE;
+ mEOSStatus = INPUT_DATA_AVAILABLE;
}
SoftOMXComponent* SoftFFmpegAudio::createSoftOMXComponent(