FlacDecoder: Enable float support
Test: MediaCodecTest#testFlacIdentity
Bug: 122117025
Change-Id: I9a80a61fbcfc615305b39befbbd9840748098a6a
diff --git a/media/codec2/components/flac/C2SoftFlacDec.cpp b/media/codec2/components/flac/C2SoftFlacDec.cpp
index f1e2f51..86b16e8 100644
--- a/media/codec2/components/flac/C2SoftFlacDec.cpp
+++ b/media/codec2/components/flac/C2SoftFlacDec.cpp
@@ -83,8 +83,21 @@
DefineParam(mInputMaxBufSize, C2_PARAMKEY_INPUT_MAX_BUFFER_SIZE)
.withConstValue(new C2StreamMaxBufferSizeInfo::input(0u, 32768))
.build());
+
+ addParameter(
+ DefineParam(mPcmEncodingInfo, C2_PARAMKEY_PCM_ENCODING)
+ .withDefault(new C2StreamPcmEncodingInfo::output(0u, C2Config::PCM_16))
+ .withFields({C2F(mPcmEncodingInfo, value).oneOf({
+ C2Config::PCM_16,
+ // C2Config::PCM_8,
+ C2Config::PCM_FLOAT})
+ })
+ .withSetter((Setter<decltype(*mPcmEncodingInfo)>::StrictValueWithNoDeps))
+ .build());
}
+ int32_t getPcmEncodingInfo() const { return mPcmEncodingInfo->value; }
+
private:
std::shared_ptr<C2StreamFormatConfig::input> mInputFormat;
std::shared_ptr<C2StreamFormatConfig::output> mOutputFormat;
@@ -94,6 +107,7 @@
std::shared_ptr<C2StreamChannelCountInfo::output> mChannelCount;
std::shared_ptr<C2BitrateTuning::input> mBitrate;
std::shared_ptr<C2StreamMaxBufferSizeInfo::input> mInputMaxBufSize;
+ std::shared_ptr<C2StreamPcmEncodingInfo::output> mPcmEncodingInfo;
};
C2SoftFlacDec::C2SoftFlacDec(
@@ -263,11 +277,11 @@
return;
}
- size_t outSize;
- if (mHasStreamInfo)
- outSize = mStreamInfo.max_blocksize * mStreamInfo.channels * sizeof(short);
- else
- outSize = kMaxBlockSize * FLACDecoder::kMaxChannels * sizeof(short);
+ const bool outputFloat = mIntf->getPcmEncodingInfo() == C2Config::PCM_FLOAT;
+ const size_t sampleSize = outputFloat ? sizeof(float) : sizeof(short);
+ size_t outSize = mHasStreamInfo ?
+ mStreamInfo.max_blocksize * mStreamInfo.channels * sampleSize
+ : kMaxBlockSize * FLACDecoder::kMaxChannels * sampleSize;
std::shared_ptr<C2LinearBlock> block;
C2MemoryUsage usage = { C2MemoryUsage::CPU_READ, C2MemoryUsage::CPU_WRITE };
@@ -284,9 +298,8 @@
return;
}
- short *output = reinterpret_cast<short *>(wView.data());
status_t decoderErr = mFLACDecoder->decodeOneFrame(
- input, inSize, output, &outSize);
+ input, inSize, wView.data(), &outSize, outputFloat);
if (decoderErr != OK) {
ALOGE("process: FLACDecoder decodeOneFrame returns error %d", decoderErr);
mSignalledError = true;
diff --git a/media/libstagefright/ACodec.cpp b/media/libstagefright/ACodec.cpp
index ceb8a13..2ea5286 100644
--- a/media/libstagefright/ACodec.cpp
+++ b/media/libstagefright/ACodec.cpp
@@ -2183,7 +2183,8 @@
err = setupG711Codec(encoder, sampleRate, numChannels);
}
} else if (!strcasecmp(mime, MEDIA_MIMETYPE_AUDIO_FLAC)) {
- int32_t numChannels = 0, sampleRate = 0, compressionLevel = -1;
+ // numChannels needs to be set to properly communicate PCM values.
+ int32_t numChannels = 2, sampleRate = 44100, compressionLevel = -1;
if (encoder &&
(!msg->findInt32("channel-count", &numChannels)
|| !msg->findInt32("sample-rate", &sampleRate))) {
@@ -2209,7 +2210,7 @@
}
}
err = setupFlacCodec(
- encoder, numChannels, sampleRate, compressionLevel);
+ encoder, numChannels, sampleRate, compressionLevel, pcmEncoding);
}
} else if (!strcasecmp(mime, MEDIA_MIMETYPE_AUDIO_RAW)) {
int32_t numChannels, sampleRate;
@@ -3033,8 +3034,8 @@
}
status_t ACodec::setupFlacCodec(
- bool encoder, int32_t numChannels, int32_t sampleRate, int32_t compressionLevel) {
-
+ bool encoder, int32_t numChannels, int32_t sampleRate, int32_t compressionLevel,
+ AudioEncoding encoding) {
if (encoder) {
OMX_AUDIO_PARAM_FLACTYPE def;
InitOMXParams(&def);
@@ -3057,7 +3058,8 @@
return setupRawAudioFormat(
encoder ? kPortIndexInput : kPortIndexOutput,
sampleRate,
- numChannels);
+ numChannels,
+ encoding);
}
status_t ACodec::setupRawAudioFormat(
@@ -3115,6 +3117,7 @@
pcmParams.ePCMMode = OMX_AUDIO_PCMModeLinear;
if (getOMXChannelMapping(numChannels, pcmParams.eChannelMapping) != OK) {
+ ALOGE("%s: incorrect numChannels: %d", __func__, numChannels);
return OMX_ErrorNone;
}
diff --git a/media/libstagefright/codecs/flac/dec/SoftFlacDecoder.cpp b/media/libstagefright/codecs/flac/dec/SoftFlacDecoder.cpp
index 4db0060..842a7ce 100644
--- a/media/libstagefright/codecs/flac/dec/SoftFlacDecoder.cpp
+++ b/media/libstagefright/codecs/flac/dec/SoftFlacDecoder.cpp
@@ -89,12 +89,12 @@
def.eDir = OMX_DirOutput;
def.nBufferCountMin = kNumOutputBuffers;
def.nBufferCountActual = def.nBufferCountMin;
- def.nBufferSize = 4096 * FLACDecoder::kMaxChannels;
+ def.nBufferSize = kNumSamplesPerFrame * FLACDecoder::kMaxChannels * sizeof(float);
def.bEnabled = OMX_TRUE;
def.bPopulated = OMX_FALSE;
def.eDomain = OMX_PortDomainAudio;
def.bBuffersContiguous = OMX_FALSE;
- def.nBufferAlignment = 2;
+ def.nBufferAlignment = sizeof(float);
def.format.audio.cMIMEType = const_cast<char *>("audio/raw");
def.format.audio.pNativeRender = NULL;
@@ -173,7 +173,7 @@
flacParams->nChannels = mStreamInfo.channels;
flacParams->nSampleRate = mStreamInfo.sample_rate;
} else {
- flacParams->nChannels = 1;
+ flacParams->nChannels = 2;
flacParams->nSampleRate = 44100;
}
@@ -195,10 +195,10 @@
return OMX_ErrorBadPortIndex;
}
- pcmParams->eNumData = OMX_NumericalDataSigned;
+ pcmParams->eNumData = mNumericalData;
pcmParams->eEndian = OMX_EndianBig;
pcmParams->bInterleaved = OMX_TRUE;
- pcmParams->nBitPerSample = 16;
+ pcmParams->nBitPerSample = mBitsPerSample;
pcmParams->ePCMMode = OMX_AUDIO_PCMModeLinear;
pcmParams->eChannelMapping[0] = OMX_AUDIO_ChannelLF;
pcmParams->eChannelMapping[1] = OMX_AUDIO_ChannelRF;
@@ -211,7 +211,7 @@
pcmParams->nChannels = mStreamInfo.channels;
pcmParams->nSamplingRate = mStreamInfo.sample_rate;
} else {
- pcmParams->nChannels = 1;
+ pcmParams->nChannels = 2;
pcmParams->nSamplingRate = 44100;
}
@@ -281,6 +281,19 @@
return OMX_ErrorBadPortIndex;
}
+ if (pcmParams->eNumData == OMX_NumericalDataFloat && pcmParams->nBitPerSample == 32) {
+ mNumericalData = OMX_NumericalDataFloat;
+ mBitsPerSample = 32;
+ } else if (pcmParams->eNumData == OMX_NumericalDataSigned
+ && pcmParams->nBitPerSample == 16) {
+ mNumericalData = OMX_NumericalDataSigned;
+ mBitsPerSample = 16;
+ } else {
+ ALOGE("Invalid eNumData %d, nBitsPerSample %d",
+ pcmParams->eNumData, pcmParams->nBitPerSample);
+ return OMX_ErrorUndefined;
+ }
+
return OMX_ErrorNone;
}
@@ -301,11 +314,13 @@
List<BufferInfo *> &inQueue = getPortQueue(0);
List<BufferInfo *> &outQueue = getPortQueue(1);
+ const bool outputFloat = mNumericalData == OMX_NumericalDataFloat;
+
ALOGV("onQueueFilled %d/%d:", inQueue.empty(), outQueue.empty());
while ((!inQueue.empty() || mSawInputEOS) && !outQueue.empty() && !mFinishedDecoder) {
BufferInfo *outInfo = *outQueue.begin();
OMX_BUFFERHEADERTYPE *outHeader = outInfo->mHeader;
- int16_t *outBuffer = reinterpret_cast<int16_t *>(outHeader->pBuffer + outHeader->nOffset);
+ void *outBuffer = reinterpret_cast<void *>(outHeader->pBuffer + outHeader->nOffset);
size_t outBufferSize = outHeader->nAllocLen - outHeader->nOffset;
int64_t timeStamp = 0;
@@ -374,7 +389,7 @@
}
status_t decoderErr = mFLACDecoder->decodeOneFrame(
- inBuffer, inBufferLength, outBuffer, &outBufferSize);
+ inBuffer, inBufferLength, outBuffer, &outBufferSize, outputFloat);
if (decoderErr != OK) {
ALOGE("onQueueFilled: FLACDecoder decodeOneFrame returns error %d", decoderErr);
mSignalledError = true;
@@ -393,7 +408,9 @@
continue;
}
} else if (mSawInputEOS) {
- status_t decoderErr = mFLACDecoder->decodeOneFrame(NULL, 0, outBuffer, &outBufferSize);
+ status_t decoderErr = mFLACDecoder->decodeOneFrame(
+ nullptr /* inBuffer */, 0 /* inBufferLen */,
+ outBuffer, &outBufferSize, outputFloat);
mFinishedDecoder = true;
if (decoderErr != OK) {
ALOGE("onQueueFilled: FLACDecoder finish returns error %d", decoderErr);
@@ -456,7 +473,8 @@
mOutputPortSettingsChange = AWAITING_ENABLED;
PortInfo *info = editPortInfo(1 /* portIndex */);
if (!info->mDef.bEnabled) {
- info->mDef.nBufferSize = mStreamInfo.max_blocksize * mStreamInfo.channels * 2;
+ info->mDef.nBufferSize =
+ mStreamInfo.max_blocksize * mStreamInfo.channels * sizeof(float);
}
break;
}
diff --git a/media/libstagefright/codecs/flac/dec/SoftFlacDecoder.h b/media/libstagefright/codecs/flac/dec/SoftFlacDecoder.h
index b63f7ad..ba02074 100644
--- a/media/libstagefright/codecs/flac/dec/SoftFlacDecoder.h
+++ b/media/libstagefright/codecs/flac/dec/SoftFlacDecoder.h
@@ -45,10 +45,14 @@
virtual void onReset() override;
private:
+ static constexpr unsigned int kNumSamplesPerFrame = 2048; // adjusted based on stream.
+
enum {
kNumInputBuffers = 4,
kNumOutputBuffers = 4,
};
+ OMX_NUMERICALDATATYPE mNumericalData = OMX_NumericalDataSigned;
+ OMX_U32 mBitsPerSample = 16;
FLACDecoder *mFLACDecoder;
FLAC__StreamMetadata_StreamInfo mStreamInfo;
diff --git a/media/libstagefright/flac/dec/Android.bp b/media/libstagefright/flac/dec/Android.bp
index 751b053..307c9b0 100644
--- a/media/libstagefright/flac/dec/Android.bp
+++ b/media/libstagefright/flac/dec/Android.bp
@@ -27,11 +27,17 @@
},
static: {
- whole_static_libs: ["libFLAC"],
+ whole_static_libs: [
+ "libFLAC",
+ "libaudioutils",
+ ],
},
shared: {
- static_libs: ["libFLAC"],
+ static_libs: [
+ "libFLAC",
+ "libaudioutils",
+ ],
},
shared_libs: [
diff --git a/media/libstagefright/flac/dec/FLACDecoder.cpp b/media/libstagefright/flac/dec/FLACDecoder.cpp
index dfdc41c..cef0bc6 100644
--- a/media/libstagefright/flac/dec/FLACDecoder.cpp
+++ b/media/libstagefright/flac/dec/FLACDecoder.cpp
@@ -20,6 +20,7 @@
#include "FLACDecoder.h"
+#include <audio_utils/primitives.h> // float_from_i32
#include <media/stagefright/foundation/ADebug.h>
#include <media/stagefright/foundation/hexdump.h>
#include <media/stagefright/MediaDefs.h>
@@ -117,104 +118,43 @@
mErrorStatus = status;
}
-// Copy samples from FLAC native 32-bit non-interleaved to 16-bit interleaved.
+// Copy samples from FLAC native 32-bit non-interleaved to 16-bit signed
+// or 32-bit float interleaved.
+// TODO: Consider moving to audio_utils. See similar code at FLACExtractor.cpp
// These are candidates for optimization if needed.
-static void copyMono8(
- int16_t *dst,
- const int * src[FLACDecoder::kMaxChannels],
+static void copyTo16Signed(
+ short *dst,
+ const int *const *src,
unsigned nSamples,
- unsigned /* nChannels */) {
- for (unsigned i = 0; i < nSamples; ++i) {
- *dst++ = src[0][i] << 8;
- }
-}
-
-static void copyStereo8(
- int16_t *dst,
- const int * src[FLACDecoder::kMaxChannels],
- unsigned nSamples,
- unsigned /* nChannels */) {
- for (unsigned i = 0; i < nSamples; ++i) {
- *dst++ = src[0][i] << 8;
- *dst++ = src[1][i] << 8;
- }
-}
-
-static void copyMultiCh8(
- int16_t *dst,
- const int * src[FLACDecoder::kMaxChannels],
- unsigned nSamples,
- unsigned nChannels) {
- for (unsigned i = 0; i < nSamples; ++i) {
- for (unsigned c = 0; c < nChannels; ++c) {
- *dst++ = src[c][i] << 8;
+ unsigned nChannels,
+ unsigned bitsPerSample) {
+ const int leftShift = 16 - (int)bitsPerSample; // cast to int to prevent unsigned overflow.
+ if (leftShift >= 0) {
+ for (unsigned i = 0; i < nSamples; ++i) {
+ for (unsigned c = 0; c < nChannels; ++c) {
+ *dst++ = src[c][i] << leftShift;
+ }
+ }
+ } else {
+ const int rightShift = -leftShift;
+ for (unsigned i = 0; i < nSamples; ++i) {
+ for (unsigned c = 0; c < nChannels; ++c) {
+ *dst++ = src[c][i] >> rightShift;
+ }
}
}
}
-static void copyMono16(
- int16_t *dst,
- const int * src[FLACDecoder::kMaxChannels],
+static void copyToFloat(
+ float *dst,
+ const int *const *src,
unsigned nSamples,
- unsigned /* nChannels */) {
- for (unsigned i = 0; i < nSamples; ++i) {
- *dst++ = src[0][i];
- }
-}
-
-static void copyStereo16(
- int16_t *dst,
- const int * src[FLACDecoder::kMaxChannels],
- unsigned nSamples,
- unsigned /* nChannels */) {
- for (unsigned i = 0; i < nSamples; ++i) {
- *dst++ = src[0][i];
- *dst++ = src[1][i];
- }
-}
-
-static void copyMultiCh16(
- int16_t *dst,
- const int * src[FLACDecoder::kMaxChannels],
- unsigned nSamples,
- unsigned nChannels) {
+ unsigned nChannels,
+ unsigned bitsPerSample) {
+ const unsigned leftShift = 32 - bitsPerSample;
for (unsigned i = 0; i < nSamples; ++i) {
for (unsigned c = 0; c < nChannels; ++c) {
- *dst++ = src[c][i];
- }
- }
-}
-
-// TODO: 24-bit versions should do dithering or noise-shaping, here or in AudioFlinger
-static void copyMono24(
- int16_t *dst,
- const int * src[FLACDecoder::kMaxChannels],
- unsigned nSamples,
- unsigned /* nChannels */) {
- for (unsigned i = 0; i < nSamples; ++i) {
- *dst++ = src[0][i] >> 8;
- }
-}
-
-static void copyStereo24(
- int16_t *dst,
- const int * src[FLACDecoder::kMaxChannels],
- unsigned nSamples,
- unsigned /* nChannels */) {
- for (unsigned i = 0; i < nSamples; ++i) {
- *dst++ = src[0][i] >> 8;
- *dst++ = src[1][i] >> 8;
- }
-}
-
-static void copyMultiCh24(
- int16_t *dst,
- const int * src[FLACDecoder::kMaxChannels],
- unsigned nSamples,
- unsigned nChannels) {
- for (unsigned i = 0; i < nSamples; ++i) {
- for (unsigned c = 0; c < nChannels; ++c) {
- *dst++ = src[c][i] >> 8;
+ *dst++ = float_from_i32(src[c][i] << leftShift);
}
}
}
@@ -238,8 +178,7 @@
mStreamInfoValid(false),
mWriteRequested(false),
mWriteCompleted(false),
- mErrorStatus((FLAC__StreamDecoderErrorStatus) -1),
- mCopy(nullptr) {
+ mErrorStatus((FLAC__StreamDecoderErrorStatus) -1) {
ALOGV("ctor:");
memset(&mStreamInfo, 0, sizeof(mStreamInfo));
memset(&mWriteHeader, 0, sizeof(mWriteHeader));
@@ -379,6 +318,7 @@
case 8:
case 16:
case 24:
+ case 32: // generally rare, but is supported in the framework
break;
default:
@@ -387,31 +327,6 @@
return ERROR_MALFORMED;
}
- // configure the appropriate copy function, defaulting to trespass
- static const struct {
- unsigned mChannels;
- unsigned mBitsPerSample;
- void (*mCopy)(int16_t *dst, const int * src[kMaxChannels],
- unsigned nSamples, unsigned nChannels);
- } table[] = {
- { 1, 8, copyMono8 },
- { 2, 8, copyStereo8 },
- { 8, 8, copyMultiCh8 },
- { 1, 16, copyMono16 },
- { 2, 16, copyStereo16 },
- { 8, 16, copyMultiCh16 },
- { 1, 24, copyMono24 },
- { 2, 24, copyStereo24 },
- { 8, 24, copyMultiCh24 },
- };
- for (const auto &entry : table) {
- if (entry.mChannels >= getChannels() &&
- entry.mBitsPerSample == getBitsPerSample()) {
- mCopy = entry.mCopy;
- break;
- }
- }
-
// Now we have all metadata blocks.
mBufferPos = 0;
mBufferDataSize = 0;
@@ -420,7 +335,7 @@
}
status_t FLACDecoder::decodeOneFrame(const uint8_t *inBuffer, size_t inBufferLen,
- int16_t *outBuffer, size_t *outBufferLen) {
+ void *outBuffer, size_t *outBufferLen, bool outputFloat) {
ALOGV("decodeOneFrame: input size(%zu)", inBufferLen);
if (!mStreamInfoValid) {
@@ -469,21 +384,33 @@
return ERROR_MALFORMED;
}
- size_t bufferSize = blocksize * getChannels() * sizeof(int16_t);
+ const unsigned channels = getChannels();
+ const size_t sampleSize = outputFloat ? sizeof(float) : sizeof(int16_t);
+ const size_t frameSize = channels * sampleSize;
+ size_t bufferSize = blocksize * frameSize;
if (bufferSize > *outBufferLen) {
ALOGW("decodeOneFrame: output buffer holds only partial frame %zu:%zu",
*outBufferLen, bufferSize);
- blocksize = *outBufferLen / (getChannels() * sizeof(int16_t));
- bufferSize = blocksize * getChannels() * sizeof(int16_t);
+ blocksize = *outBufferLen / frameSize;
+ bufferSize = blocksize * frameSize;
}
- if (mCopy == nullptr) {
- ALOGE("decodeOneFrame: format is not supported: channels(%d), BitsPerSample(%d)",
- getChannels(), getBitsPerSample());
- return ERROR_UNSUPPORTED;
- }
// copy PCM from FLAC write buffer to output buffer, with interleaving
- (*mCopy)(outBuffer, mWriteBuffer, blocksize, getChannels());
+
+ const unsigned bitsPerSample = getBitsPerSample();
+ if (outputFloat) {
+ copyToFloat(reinterpret_cast<float*>(outBuffer),
+ mWriteBuffer,
+ blocksize,
+ channels,
+ bitsPerSample);
+ } else {
+ copyTo16Signed(reinterpret_cast<short*>(outBuffer),
+ mWriteBuffer,
+ blocksize,
+ channels,
+ bitsPerSample);
+ }
*outBufferLen = bufferSize;
return OK;
}
diff --git a/media/libstagefright/flac/dec/FLACDecoder.h b/media/libstagefright/flac/dec/FLACDecoder.h
index af419a2..694fccb 100644
--- a/media/libstagefright/flac/dec/FLACDecoder.h
+++ b/media/libstagefright/flac/dec/FLACDecoder.h
@@ -41,7 +41,7 @@
status_t parseMetadata(const uint8_t *inBuffer, size_t inBufferLen);
status_t decodeOneFrame(const uint8_t *inBuffer, size_t inBufferLen,
- int16_t *outBuffer, size_t *outBufferLen);
+ void *outBuffer, size_t *outBufferLen, bool outputFloat = false);
void flush();
virtual ~FLACDecoder();
@@ -89,8 +89,6 @@
// most recent error reported by libFLAC decoder
FLAC__StreamDecoderErrorStatus mErrorStatus;
- void (*mCopy)(int16_t *dst, const int *src[kMaxChannels], unsigned nSamples, unsigned nChannels);
-
status_t init();
// FLAC stream decoder callbacks as C++ instance methods
diff --git a/media/libstagefright/include/media/stagefright/ACodec.h b/media/libstagefright/include/media/stagefright/ACodec.h
index 9b2853e..9d46d2d 100644
--- a/media/libstagefright/include/media/stagefright/ACodec.h
+++ b/media/libstagefright/include/media/stagefright/ACodec.h
@@ -488,7 +488,8 @@
status_t setupG711Codec(bool encoder, int32_t sampleRate, int32_t numChannels);
status_t setupFlacCodec(
- bool encoder, int32_t numChannels, int32_t sampleRate, int32_t compressionLevel);
+ bool encoder, int32_t numChannels, int32_t sampleRate, int32_t compressionLevel,
+ AudioEncoding encoding);
status_t setupRawAudioFormat(
OMX_U32 portIndex, int32_t sampleRate, int32_t numChannels,