FlacEncoder: Enable float support
Test: MediaCodecTest#testFlacIdentity
Bug: 122264366
Change-Id: Ic692ce0d5dc8358cbd173013c9d4f68b7e45a8ad
diff --git a/media/codec2/components/flac/Android.bp b/media/codec2/components/flac/Android.bp
index d485964..e5eb51d 100644
--- a/media/codec2/components/flac/Android.bp
+++ b/media/codec2/components/flac/Android.bp
@@ -23,5 +23,8 @@
srcs: ["C2SoftFlacEnc.cpp"],
- static_libs: ["libFLAC"],
+ static_libs: [
+ "libaudioutils",
+ "libFLAC",
+ ],
}
diff --git a/media/codec2/components/flac/C2SoftFlacEnc.cpp b/media/codec2/components/flac/C2SoftFlacEnc.cpp
index e4192c7..4ea35c2 100644
--- a/media/codec2/components/flac/C2SoftFlacEnc.cpp
+++ b/media/codec2/components/flac/C2SoftFlacEnc.cpp
@@ -18,6 +18,7 @@
#define LOG_TAG "C2SoftFlacEnc"
#include <log/log.h>
+#include <audio_utils/primitives.h>
#include <media/stagefright/foundation/MediaDefs.h>
#include <C2PlatformSupport.h>
@@ -72,11 +73,23 @@
DefineParam(mInputMaxBufSize, C2_PARAMKEY_INPUT_MAX_BUFFER_SIZE)
.withConstValue(new C2StreamMaxBufferSizeInfo::input(0u, 4608))
.build());
+
+ addParameter(
+ DefineParam(mPcmEncodingInfo, C2_PARAMKEY_PCM_ENCODING)
+ .withDefault(new C2StreamPcmEncodingInfo::input(0u, C2Config::PCM_16))
+ .withFields({C2F(mPcmEncodingInfo, value).oneOf({
+ C2Config::PCM_16,
+ // C2Config::PCM_8,
+ C2Config::PCM_FLOAT})
+ })
+ .withSetter((Setter<decltype(*mPcmEncodingInfo)>::StrictValueWithNoDeps))
+ .build());
}
uint32_t getSampleRate() const { return mSampleRate->value; }
uint32_t getChannelCount() const { return mChannelCount->value; }
uint32_t getBitrate() const { return mBitrate->value; }
+ int32_t getPcmEncodingInfo() const { return mPcmEncodingInfo->value; }
private:
std::shared_ptr<C2StreamFormatConfig::input> mInputFormat;
@@ -87,6 +100,7 @@
std::shared_ptr<C2StreamChannelCountInfo::input> mChannelCount;
std::shared_ptr<C2BitrateTuning::output> mBitrate;
std::shared_ptr<C2StreamMaxBufferSizeInfo::input> mInputMaxBufSize;
+ std::shared_ptr<C2StreamPcmEncodingInfo::input> mPcmEncodingInfo;
};
constexpr char COMPONENT_NAME[] = "c2.android.flac.encoder";
@@ -224,12 +238,15 @@
mWroteHeader = true;
}
- uint32_t sampleRate = mIntf->getSampleRate();
- uint32_t channelCount = mIntf->getChannelCount();
- uint64_t outTimeStamp = mProcessedSamples * 1000000ll / sampleRate;
+ const uint32_t sampleRate = mIntf->getSampleRate();
+ const uint32_t channelCount = mIntf->getChannelCount();
+ const bool inputFloat = mIntf->getPcmEncodingInfo() == C2Config::PCM_FLOAT;
+ const unsigned sampleSize = inputFloat ? sizeof(float) : sizeof(int16_t);
+ const unsigned frameSize = channelCount * sampleSize;
+ const uint64_t outTimeStamp = mProcessedSamples * 1000000ll / sampleRate;
size_t outCapacity = inSize;
- outCapacity += mBlockSize * channelCount * sizeof(int16_t);
+ outCapacity += mBlockSize * frameSize;
C2MemoryUsage usage = { C2MemoryUsage::CPU_READ, C2MemoryUsage::CPU_WRITE };
c2_status_t err = pool->fetchLinearBlock(outCapacity, usage, &mOutputBlock);
@@ -250,14 +267,19 @@
size_t inPos = 0;
while (inPos < inSize) {
const uint8_t *inPtr = rView.data() + inOffset;
- size_t processSize = MIN(kInBlockSize * channelCount * sizeof(int16_t), (inSize - inPos));
- const unsigned nbInputFrames = processSize / (channelCount * sizeof(int16_t));
- const unsigned nbInputSamples = processSize / sizeof(int16_t);
- const int16_t *pcm16 = reinterpret_cast<const int16_t *>(inPtr + inPos);
- ALOGV("about to encode %zu bytes", processSize);
+ const size_t processSize = MIN(kInBlockSize * frameSize, (inSize - inPos));
+ const unsigned nbInputFrames = processSize / frameSize;
+ const unsigned nbInputSamples = processSize / sampleSize;
- for (unsigned i = 0; i < nbInputSamples; i++) {
- mInputBufferPcm32[i] = (FLAC__int32) pcm16[i];
+ ALOGV("about to encode %zu bytes", processSize);
+ if (inputFloat) {
+ const float * const pcmFloat = reinterpret_cast<const float *>(inPtr + inPos);
+ memcpy_to_q8_23_from_float_with_clamp(mInputBufferPcm32, pcmFloat, nbInputSamples);
+ } else {
+ const int16_t * const pcm16 = reinterpret_cast<const int16_t *>(inPtr + inPos);
+ for (unsigned i = 0; i < nbInputSamples; i++) {
+ mInputBufferPcm32[i] = (FLAC__int32) pcm16[i];
+ }
}
FLAC__bool ok = FLAC__stream_encoder_process_interleaved(
@@ -342,10 +364,12 @@
return UNKNOWN_ERROR;
}
+ const bool inputFloat = mIntf->getPcmEncodingInfo() == C2Config::PCM_FLOAT;
+ const int bitsPerSample = inputFloat ? 24 : 16;
FLAC__bool ok = true;
ok = ok && FLAC__stream_encoder_set_channels(mFlacStreamEncoder, mIntf->getChannelCount());
ok = ok && FLAC__stream_encoder_set_sample_rate(mFlacStreamEncoder, mIntf->getSampleRate());
- ok = ok && FLAC__stream_encoder_set_bits_per_sample(mFlacStreamEncoder, 16);
+ ok = ok && FLAC__stream_encoder_set_bits_per_sample(mFlacStreamEncoder, bitsPerSample);
ok = ok && FLAC__stream_encoder_set_compression_level(mFlacStreamEncoder, mCompressionLevel);
ok = ok && FLAC__stream_encoder_set_verify(mFlacStreamEncoder, false);
if (!ok) {
diff --git a/media/libstagefright/codecs/flac/enc/Android.bp b/media/libstagefright/codecs/flac/enc/Android.bp
index 9b696da..b32ab08 100644
--- a/media/libstagefright/codecs/flac/enc/Android.bp
+++ b/media/libstagefright/codecs/flac/enc/Android.bp
@@ -28,7 +28,10 @@
],
header_libs: ["libbase_headers"],
- static_libs: ["libFLAC"],
+ static_libs: [
+ "libaudioutils",
+ "libFLAC",
+ ],
name: "libstagefright_soft_flacenc",
vendor_available: true,
diff --git a/media/libstagefright/codecs/flac/enc/SoftFlacEncoder.cpp b/media/libstagefright/codecs/flac/enc/SoftFlacEncoder.cpp
index 955f211..3add006 100644
--- a/media/libstagefright/codecs/flac/enc/SoftFlacEncoder.cpp
+++ b/media/libstagefright/codecs/flac/enc/SoftFlacEncoder.cpp
@@ -20,7 +20,7 @@
#include <utils/Log.h>
#include "SoftFlacEncoder.h"
-
+#include <audio_utils/primitives.h>
#include <media/stagefright/foundation/ADebug.h>
#include <media/stagefright/MediaDefs.h>
@@ -75,7 +75,9 @@
}
if (!mSignalledError) { // no use allocating input buffer if we had an error above
- mInputBufferPcm32 = (FLAC__int32*) malloc(sizeof(FLAC__int32) * 2 * kMaxNumSamplesPerFrame);
+ // 2x the pcm16 samples can exist with the same size as pcmFloat samples.
+ mInputBufferPcm32 = (FLAC__int32*) malloc(
+ sizeof(FLAC__int32) * kNumSamplesPerFrame * kMaxChannels * 2);
if (mInputBufferPcm32 == NULL) {
ALOGE("SoftFlacEncoder::SoftFlacEncoder(name=%s) error allocating internal input buffer", name);
mSignalledError = true;
@@ -115,14 +117,14 @@
// configure input port of the encoder
def.nPortIndex = 0;
def.eDir = OMX_DirInput;
- def.nBufferCountMin = kNumBuffers;// TODO verify that 1 is enough
+ def.nBufferCountMin = kNumBuffers;
def.nBufferCountActual = def.nBufferCountMin;
def.nBufferSize = kMaxInputBufferSize;
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;
@@ -134,7 +136,7 @@
// configure output port of the encoder
def.nPortIndex = 1;
def.eDir = OMX_DirOutput;
- def.nBufferCountMin = kNumBuffers;// TODO verify that 1 is enough
+ def.nBufferCountMin = kNumBuffers;
def.nBufferCountActual = def.nBufferCountMin;
def.nBufferSize = kMaxOutputBufferSize;
def.bEnabled = OMX_TRUE;
@@ -193,10 +195,10 @@
return OMX_ErrorUndefined;
}
- 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;
@@ -270,12 +272,26 @@
return OMX_ErrorUndefined;
}
- if (pcmParams->nChannels < 1 || pcmParams->nChannels > 2) {
+ if (pcmParams->nChannels < 1 || pcmParams->nChannels > kMaxChannels) {
return OMX_ErrorUndefined;
}
mNumChannels = pcmParams->nChannels;
mSampleRate = pcmParams->nSamplingRate;
+
+ 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("%s: invalid eNumData %d, nBitsPerSample %d",
+ __func__, pcmParams->eNumData, pcmParams->nBitPerSample);
+ return OMX_ErrorUndefined;
+ }
+
ALOGV("will encode %d channels at %dHz", mNumChannels, mSampleRate);
return configureEncoder();
@@ -356,6 +372,10 @@
List<BufferInfo *> &inQueue = getPortQueue(0);
List<BufferInfo *> &outQueue = getPortQueue(1);
+ const bool inputFloat = mNumericalData == OMX_NumericalDataFloat;
+ const size_t sampleSize = inputFloat ? sizeof(float) : sizeof(int16_t);
+ const size_t frameSize = sampleSize * mNumChannels;
+
FLAC__bool ok = true;
while ((!inQueue.empty() || mSawInputEOS) && !outQueue.empty() && !mSentOutputEOS) {
@@ -381,13 +401,21 @@
mEncoderReturnedNbBytes = 0;
mCurrentInputTimeStamp = inHeader->nTimeStamp;
- const unsigned nbInputFrames = inHeader->nFilledLen / (2 * mNumChannels);
- const unsigned nbInputSamples = inHeader->nFilledLen / 2;
- const OMX_S16 * const pcm16 = reinterpret_cast<OMX_S16 *>(inHeader->pBuffer);
+ const unsigned nbInputFrames = inHeader->nFilledLen / frameSize;
+ const unsigned nbInputSamples = inHeader->nFilledLen / sampleSize;
- CHECK_LE(nbInputSamples, 2 * kMaxNumSamplesPerFrame);
- for (unsigned i=0 ; i < nbInputSamples ; i++) {
- mInputBufferPcm32[i] = (FLAC__int32) pcm16[i];
+ if (inputFloat) {
+ CHECK_LE(nbInputSamples, kNumSamplesPerFrame * kMaxChannels);
+ const float * const pcmFloat = reinterpret_cast<float *>(inHeader->pBuffer);
+ memcpy_to_q8_23_from_float_with_clamp(
+ mInputBufferPcm32, pcmFloat, nbInputSamples);
+ } else {
+ // note nbInputSamples may be 2x as large for pcm16 data.
+ CHECK_LE(nbInputSamples, kNumSamplesPerFrame * kMaxChannels * 2);
+ const int16_t * const pcm16 = reinterpret_cast<int16_t *>(inHeader->pBuffer);
+ for (unsigned i = 0; i < nbInputSamples; ++i) {
+ mInputBufferPcm32[i] = (FLAC__int32) pcm16[i];
+ }
}
ALOGV(" about to encode %u samples per channel", nbInputFrames);
ok = FLAC__stream_encoder_process_interleaved(
@@ -526,10 +554,12 @@
return OMX_ErrorInvalidState;
}
+ const bool inputFloat = mNumericalData == OMX_NumericalDataFloat;
+ const int codecBitsPerSample = inputFloat ? 24 : 16;
FLAC__bool ok = true;
ok = ok && FLAC__stream_encoder_set_channels(mFlacStreamEncoder, mNumChannels);
ok = ok && FLAC__stream_encoder_set_sample_rate(mFlacStreamEncoder, mSampleRate);
- ok = ok && FLAC__stream_encoder_set_bits_per_sample(mFlacStreamEncoder, 16);
+ ok = ok && FLAC__stream_encoder_set_bits_per_sample(mFlacStreamEncoder, codecBitsPerSample);
ok = ok && FLAC__stream_encoder_set_compression_level(mFlacStreamEncoder,
(unsigned)mCompressionLevel);
ok = ok && FLAC__stream_encoder_set_verify(mFlacStreamEncoder, false);
diff --git a/media/libstagefright/codecs/flac/enc/SoftFlacEncoder.h b/media/libstagefright/codecs/flac/enc/SoftFlacEncoder.h
index 64a6b1e..722fc13 100644
--- a/media/libstagefright/codecs/flac/enc/SoftFlacEncoder.h
+++ b/media/libstagefright/codecs/flac/enc/SoftFlacEncoder.h
@@ -45,8 +45,10 @@
private:
const unsigned int kNumBuffers = 2;
- const unsigned int kMaxNumSamplesPerFrame = 1152;
- const unsigned int kMaxInputBufferSize = kMaxNumSamplesPerFrame * sizeof(int16_t) * 2;
+ static constexpr unsigned int kMaxChannels = 2;
+ static constexpr unsigned int kNumSamplesPerFrame = 1152;
+ static constexpr unsigned int kMaxInputBufferSize =
+ kNumSamplesPerFrame * kMaxChannels * sizeof(float);
const unsigned int kMaxOutputBufferSize = 65536; //TODO check if this can be reduced
bool mSignalledError;
@@ -54,6 +56,8 @@
OMX_U32 mNumChannels;
OMX_U32 mSampleRate;
OMX_U32 mCompressionLevel;
+ OMX_NUMERICALDATATYPE mNumericalData = OMX_NumericalDataSigned;
+ OMX_U32 mBitsPerSample = 16;
// should the data received by the callback be written to the output port
bool mEncoderWriteData;