Merge "stagefright: ACodec: read output port format on first frame" into nyc-dev
diff --git a/include/media/stagefright/ACodec.h b/include/media/stagefright/ACodec.h
index 2446449..bc11da2 100644
--- a/include/media/stagefright/ACodec.h
+++ b/include/media/stagefright/ACodec.h
@@ -25,6 +25,7 @@
#include <media/stagefright/foundation/AHierarchicalStateMachine.h>
#include <media/stagefright/CodecBase.h>
#include <media/stagefright/FrameRenderTracker.h>
+#include <media/stagefright/MediaDefs.h>
#include <media/stagefright/SkipCutBuffer.h>
#include <utils/NativeHandle.h>
#include <OMX_Audio.h>
@@ -36,6 +37,7 @@
struct ABuffer;
struct MemoryDealer;
struct DescribeColorFormat2Params;
+struct DataConverter;
struct ACodec : public AHierarchicalStateMachine, public CodecBase {
ACodec();
@@ -188,8 +190,11 @@
Status mStatus;
unsigned mDequeuedAt;
- sp<ABuffer> mData;
- sp<RefBase> mMemRef;
+ sp<ABuffer> mData; // the client's buffer; if not using data conversion, this is the
+ // codec buffer; otherwise, it is allocated separately
+ sp<RefBase> mMemRef; // and a reference to the IMemory, so it does not go away
+ sp<ABuffer> mCodecData; // the codec's buffer
+ sp<RefBase> mCodecRef; // and a reference to the IMemory
sp<GraphicBuffer> mGraphicBuffer;
sp<NativeHandle> mNativeHandle;
int mFenceFd;
@@ -283,6 +288,7 @@
bool mLegacyAdaptiveExperiment;
int32_t mMetadataBuffersToSubmit;
size_t mNumUndequeuedBuffers;
+ sp<DataConverter> mConverter[2];
int64_t mRepeatFrameDelayUs;
int64_t mMaxPtsGapUs;
@@ -444,7 +450,8 @@
bool encoder, int32_t numChannels, int32_t sampleRate, int32_t compressionLevel);
status_t setupRawAudioFormat(
- OMX_U32 portIndex, int32_t sampleRate, int32_t numChannels);
+ OMX_U32 portIndex, int32_t sampleRate, int32_t numChannels,
+ AudioEncoding encoding = kAudioEncodingPcm16bit);
status_t setPriority(int32_t priority);
status_t setOperatingRate(float rateFloat, bool isVideo);
diff --git a/media/libstagefright/ACodec.cpp b/media/libstagefright/ACodec.cpp
index c4ac735..c9f16f0 100644
--- a/media/libstagefright/ACodec.cpp
+++ b/media/libstagefright/ACodec.cpp
@@ -52,6 +52,7 @@
#include <OMX_AsString.h>
#include "include/avc_utils.h"
+#include "include/DataConverter.h"
#include "omx/OMXUtils.h"
namespace android {
@@ -114,6 +115,13 @@
DISALLOW_EVIL_CONSTRUCTORS(MessageList);
};
+static sp<DataConverter> getCopyConverter() {
+ static pthread_once_t once = PTHREAD_ONCE_INIT; // const-inited
+ static sp<DataConverter> sCopyConverter; // zero-inited
+ pthread_once(&once, [](){ sCopyConverter = new DataConverter(); });
+ return sCopyConverter;
+}
+
struct CodecObserver : public BnOMXObserver {
CodecObserver() {}
@@ -505,6 +513,7 @@
mOutputMetadataType(kMetadataBufferTypeInvalid),
mLegacyAdaptiveExperiment(false),
mMetadataBuffersToSubmit(0),
+ mNumUndequeuedBuffers(0),
mRepeatFrameDelayUs(-1ll),
mMaxPtsGapUs(-1ll),
mMaxFps(-1),
@@ -781,7 +790,7 @@
if (err == OK) {
MetadataBufferType type =
portIndex == kPortIndexOutput ? mOutputMetadataType : mInputMetadataType;
- int32_t bufSize = def.nBufferSize;
+ size_t bufSize = def.nBufferSize;
if (type == kMetadataBufferTypeGrallocSource) {
bufSize = sizeof(VideoGrallocMetadata);
} else if (type == kMetadataBufferTypeANWBuffer) {
@@ -792,33 +801,47 @@
// metadata size as we prefer to generate native source metadata, but component
// may require gralloc source. For camera source, allocate at least enough
// size for native metadata buffers.
- int32_t allottedSize = bufSize;
+ size_t allottedSize = bufSize;
if (portIndex == kPortIndexInput && type >= kMetadataBufferTypeGrallocSource) {
bufSize = max(sizeof(VideoGrallocMetadata), sizeof(VideoNativeMetadata));
} else if (portIndex == kPortIndexInput && type == kMetadataBufferTypeCameraSource) {
- bufSize = max(bufSize, (int32_t)sizeof(VideoNativeMetadata));
+ bufSize = max(bufSize, sizeof(VideoNativeMetadata));
+ }
+
+ size_t conversionBufferSize = 0;
+
+ sp<DataConverter> converter = mConverter[portIndex];
+ if (converter != NULL) {
+ // here we assume sane conversions of max 4:1, so result fits in int32
+ if (portIndex == kPortIndexInput) {
+ conversionBufferSize = converter->sourceSize(bufSize);
+ } else {
+ conversionBufferSize = converter->targetSize(bufSize);
+ }
}
size_t alignment = MemoryDealer::getAllocationAlignment();
- ALOGV("[%s] Allocating %u buffers of size %d/%d (from %u using %s) on %s port",
+ ALOGV("[%s] Allocating %u buffers of size %zu/%zu (from %u using %s) on %s port",
mComponentName.c_str(),
def.nBufferCountActual, bufSize, allottedSize, def.nBufferSize, asString(type),
portIndex == kPortIndexInput ? "input" : "output");
- if (bufSize == 0 || bufSize > kMaxCodecBufferSize) {
+ // verify buffer sizes to avoid overflow in align()
+ if (bufSize == 0 || max(bufSize, conversionBufferSize) > kMaxCodecBufferSize) {
ALOGE("b/22885421");
return NO_MEMORY;
}
// don't modify bufSize as OMX may not expect it to increase after negotiation
size_t alignedSize = align(bufSize, alignment);
- if (def.nBufferCountActual > SIZE_MAX / alignedSize) {
+ size_t alignedConvSize = align(conversionBufferSize, alignment);
+ if (def.nBufferCountActual > SIZE_MAX / (alignedSize + alignedConvSize)) {
ALOGE("b/22885421");
return NO_MEMORY;
}
- size_t totalSize = def.nBufferCountActual * alignedSize;
+ size_t totalSize = def.nBufferCountActual * (alignedSize + alignedConvSize);
mDealer[portIndex] = new MemoryDealer(totalSize, "ACodec");
for (OMX_U32 i = 0; i < def.nBufferCountActual && err == OK; ++i) {
@@ -857,6 +880,7 @@
// because Widevine source only receives these base addresses.
info.mData = new ABuffer(ptr != NULL ? ptr : (void *)native_handle, bufSize);
info.mNativeHandle = NativeHandle::create(native_handle, true /* ownsHandle */);
+ info.mCodecData = info.mData;
} else if (mQuirks & requiresAllocateBufferBit) {
err = mOMX->allocateBufferWithBackup(
mNode, portIndex, mem, &info.mBufferID, allottedSize);
@@ -865,11 +889,27 @@
}
if (mem != NULL) {
- info.mData = new ABuffer(mem->pointer(), bufSize);
+ info.mCodecData = new ABuffer(mem->pointer(), bufSize);
+ info.mCodecRef = mem;
+
if (type == kMetadataBufferTypeANWBuffer) {
((VideoNativeMetadata *)mem->pointer())->nFenceFd = -1;
}
- info.mMemRef = mem;
+
+ // if we require conversion, allocate conversion buffer for client use;
+ // otherwise, reuse codec buffer
+ if (mConverter[portIndex] != NULL) {
+ CHECK_GT(conversionBufferSize, (size_t)0);
+ mem = mDealer[portIndex]->allocate(conversionBufferSize);
+ if (mem == NULL|| mem->pointer() == NULL) {
+ return NO_MEMORY;
+ }
+ info.mData = new ABuffer(mem->pointer(), conversionBufferSize);
+ info.mMemRef = mem;
+ } else {
+ info.mData = info.mCodecData;
+ info.mMemRef = info.mCodecRef;
+ }
}
mBuffers[portIndex].push(info);
@@ -1062,6 +1102,7 @@
info.mIsReadFence = false;
info.mRenderInfo = NULL;
info.mData = new ABuffer(NULL /* data */, bufferSize /* capacity */);
+ info.mCodecData = info.mData;
info.mGraphicBuffer = graphicBuffer;
mBuffers[kPortIndexOutput].push(info);
@@ -1146,11 +1187,13 @@
((VideoNativeMetadata *)mem->pointer())->nFenceFd = -1;
}
info.mData = new ABuffer(mem->pointer(), mem->size());
+ info.mMemRef = mem;
+ info.mCodecData = info.mData;
+ info.mCodecRef = mem;
// we use useBuffer for metadata regardless of quirks
err = mOMX->useBuffer(
mNode, kPortIndexOutput, mem, &info.mBufferID, mem->size());
- info.mMemRef = mem;
mBuffers[kPortIndexOutput].push(info);
ALOGV("[%s] allocated meta buffer with ID %u (pointer = %p)",
@@ -1944,6 +1987,10 @@
}
}
+ AudioEncoding pcmEncoding = kAudioEncodingPcm16bit;
+ (void)msg->findInt32("pcm-encoding", (int32_t*)&pcmEncoding);
+ // invalid encodings will default to PCM-16bit in setupRawAudioFormat.
+
if (video) {
// determine need for software renderer
bool usingSwRenderer = false;
@@ -2148,7 +2195,7 @@
|| !msg->findInt32("sample-rate", &sampleRate)) {
err = INVALID_OPERATION;
} else {
- err = setupRawAudioFormat(kPortIndexInput, sampleRate, numChannels);
+ err = setupRawAudioFormat(kPortIndexInput, sampleRate, numChannels, pcmEncoding);
}
} else if (!strcasecmp(mime, MEDIA_MIMETYPE_AUDIO_AC3)) {
int32_t numChannels;
@@ -2223,6 +2270,25 @@
mOutputFormat = outputFormat;
}
}
+
+ // create data converters if needed
+ if (!video && err == OK) {
+ AudioEncoding codecPcmEncoding = kAudioEncodingPcm16bit;
+ if (encoder) {
+ (void)mInputFormat->findInt32("pcm-encoding", (int32_t*)&codecPcmEncoding);
+ mConverter[kPortIndexInput] = AudioConverter::Create(pcmEncoding, codecPcmEncoding);
+ if (mConverter[kPortIndexInput] != NULL) {
+ mInputFormat->setInt32("pcm-encoding", pcmEncoding);
+ }
+ } else {
+ (void)mOutputFormat->findInt32("pcm-encoding", (int32_t*)&codecPcmEncoding);
+ mConverter[kPortIndexOutput] = AudioConverter::Create(codecPcmEncoding, pcmEncoding);
+ if (mConverter[kPortIndexOutput] != NULL) {
+ mOutputFormat->setInt32("pcm-encoding", pcmEncoding);
+ }
+ }
+ }
+
return err;
}
@@ -2773,7 +2839,7 @@
}
status_t ACodec::setupRawAudioFormat(
- OMX_U32 portIndex, int32_t sampleRate, int32_t numChannels) {
+ OMX_U32 portIndex, int32_t sampleRate, int32_t numChannels, AudioEncoding encoding) {
OMX_PARAM_PORTDEFINITIONTYPE def;
InitOMXParams(&def);
def.nPortIndex = portIndex;
@@ -2806,9 +2872,23 @@
}
pcmParams.nChannels = numChannels;
- pcmParams.eNumData = OMX_NumericalDataSigned;
+ switch (encoding) {
+ case kAudioEncodingPcm8bit:
+ pcmParams.eNumData = OMX_NumericalDataUnsigned;
+ pcmParams.nBitPerSample = 8;
+ break;
+ case kAudioEncodingPcmFloat:
+ pcmParams.eNumData = OMX_NumericalDataFloat;
+ pcmParams.nBitPerSample = 32;
+ break;
+ case kAudioEncodingPcm16bit:
+ pcmParams.eNumData = OMX_NumericalDataSigned;
+ pcmParams.nBitPerSample = 16;
+ break;
+ default:
+ return BAD_VALUE;
+ }
pcmParams.bInterleaved = OMX_TRUE;
- pcmParams.nBitPerSample = 16;
pcmParams.nSamplingRate = sampleRate;
pcmParams.ePCMMode = OMX_AUDIO_PCMModeLinear;
@@ -2816,8 +2896,17 @@
return OMX_ErrorNone;
}
- return mOMX->setParameter(
+ err = mOMX->setParameter(
mNode, OMX_IndexParamAudioPcm, &pcmParams, sizeof(pcmParams));
+ // if we could not set up raw format to non-16-bit, try with 16-bit
+ // NOTE: we will also verify this via readback, in case codec ignores these fields
+ if (err != OK && encoding != kAudioEncodingPcm16bit) {
+ pcmParams.eNumData = OMX_NumericalDataSigned;
+ pcmParams.nBitPerSample = 16;
+ err = mOMX->setParameter(
+ mNode, OMX_IndexParamAudioPcm, &pcmParams, sizeof(pcmParams));
+ }
+ return err;
}
status_t ACodec::configureTunneledVideoPlayback(
@@ -4654,22 +4743,33 @@
if (params.nChannels <= 0
|| (params.nChannels != 1 && !params.bInterleaved)
- || params.nBitPerSample != 16u
- || params.eNumData != OMX_NumericalDataSigned
|| params.ePCMMode != OMX_AUDIO_PCMModeLinear) {
- ALOGE("unsupported PCM port: %u channels%s, %u-bit, %s(%d), %s(%d) mode ",
+ ALOGE("unsupported PCM port: %u channels%s, %u-bit",
params.nChannels,
params.bInterleaved ? " interleaved" : "",
- params.nBitPerSample,
- asString(params.eNumData), params.eNumData,
- asString(params.ePCMMode), params.ePCMMode);
+ params.nBitPerSample);
return FAILED_TRANSACTION;
}
notify->setString("mime", MEDIA_MIMETYPE_AUDIO_RAW);
notify->setInt32("channel-count", params.nChannels);
notify->setInt32("sample-rate", params.nSamplingRate);
- notify->setInt32("pcm-encoding", kAudioEncodingPcm16bit);
+
+ AudioEncoding encoding = kAudioEncodingPcm16bit;
+ if (params.eNumData == OMX_NumericalDataUnsigned
+ && params.nBitPerSample == 8u) {
+ encoding = kAudioEncodingPcm8bit;
+ } else if (params.eNumData == OMX_NumericalDataFloat
+ && params.nBitPerSample == 32u) {
+ encoding = kAudioEncodingPcmFloat;
+ } else if (params.nBitPerSample != 16u
+ || params.eNumData != OMX_NumericalDataSigned) {
+ ALOGE("unsupported PCM port: %s(%d), %s(%d) mode ",
+ asString(params.eNumData), params.eNumData,
+ asString(params.ePCMMode), params.ePCMMode);
+ return FAILED_TRANSACTION;
+ }
+ notify->setInt32("pcm-encoding", encoding);
if (mChannelMaskPresent) {
notify->setInt32("channel-mask", mChannelMask);
@@ -4938,6 +5038,18 @@
return;
}
+ if (!mIsVideo && !mIsEncoder) {
+ AudioEncoding pcmEncoding = kAudioEncodingPcm16bit;
+ (void)mConfigFormat->findInt32("pcm-encoding", (int32_t*)&pcmEncoding);
+ AudioEncoding codecPcmEncoding = kAudioEncodingPcm16bit;
+ (void)mOutputFormat->findInt32("pcm-encoding", (int32_t*)&pcmEncoding);
+
+ mConverter[kPortIndexOutput] = AudioConverter::Create(codecPcmEncoding, pcmEncoding);
+ if (mConverter[kPortIndexOutput] != NULL) {
+ mOutputFormat->setInt32("pcm-encoding", pcmEncoding);
+ }
+ }
+
if (mTunneled) {
sendFormatChange();
}
@@ -5465,20 +5577,21 @@
flags |= OMX_BUFFERFLAG_EOS;
}
- if (buffer != info->mData) {
+ if (buffer != info->mCodecData) {
ALOGV("[%s] Needs to copy input data for buffer %u. (%p != %p)",
mCodec->mComponentName.c_str(),
bufferID,
- buffer.get(), info->mData.get());
+ buffer.get(), info->mCodecData.get());
- if (buffer->size() > info->mData->capacity()) {
- ALOGE("data size (%zu) is greated than buffer capacity (%zu)",
- buffer->size(), // this is the data received
- info->mData->capacity()); // this is out buffer size
- mCodec->signalError(OMX_ErrorUndefined, FAILED_TRANSACTION);
+ sp<DataConverter> converter = mCodec->mConverter[kPortIndexInput];
+ if (converter == NULL) {
+ converter = getCopyConverter();
+ }
+ status_t err = converter->convert(buffer, info->mCodecData);
+ if (err != OK) {
+ mCodec->signalError(OMX_ErrorUndefined, err);
return;
}
- memcpy(info->mData->data(), buffer->data(), buffer->size());
}
if (flags & OMX_BUFFERFLAG_CODECCONFIG) {
@@ -5521,7 +5634,7 @@
mCodec->mNode,
bufferID,
0,
- buffer->size(),
+ info->mCodecData->size(),
flags,
timeUs,
info->mFenceFd);
@@ -5727,8 +5840,17 @@
info->mData->meta()->setPointer("handle", handle);
info->mData->meta()->setInt32("rangeOffset", rangeOffset);
info->mData->meta()->setInt32("rangeLength", rangeLength);
- } else {
+ } else if (info->mData == info->mCodecData) {
info->mData->setRange(rangeOffset, rangeLength);
+ } else {
+ info->mCodecData->setRange(rangeOffset, rangeLength);
+ // in this case we know that mConverter is not null
+ status_t err = mCodec->mConverter[kPortIndexOutput]->convert(
+ info->mCodecData, info->mData);
+ if (err != OK) {
+ mCodec->signalError(OMX_ErrorUndefined, makeNoSideEffectStatus(err));
+ return true;
+ }
}
#if 0
if (mCodec->mNativeWindow == NULL) {
@@ -5944,6 +6066,8 @@
mCodec->mFlags = 0;
mCodec->mInputMetadataType = kMetadataBufferTypeInvalid;
mCodec->mOutputMetadataType = kMetadataBufferTypeInvalid;
+ mCodec->mConverter[0].clear();
+ mCodec->mConverter[1].clear();
mCodec->mComponentName.clear();
}
diff --git a/media/libstagefright/Android.mk b/media/libstagefright/Android.mk
index 557971d..2445842 100644
--- a/media/libstagefright/Android.mk
+++ b/media/libstagefright/Android.mk
@@ -14,6 +14,7 @@
CameraSource.cpp \
CameraSourceTimeLapse.cpp \
CodecBase.cpp \
+ DataConverter.cpp \
DataSource.cpp \
DataURISource.cpp \
DRMExtractor.cpp \
diff --git a/media/libstagefright/DataConverter.cpp b/media/libstagefright/DataConverter.cpp
new file mode 100644
index 0000000..aea47f3
--- /dev/null
+++ b/media/libstagefright/DataConverter.cpp
@@ -0,0 +1,123 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+//#define LOG_NDEBUG 0
+#define LOG_TAG "DataConverter"
+
+#include "include/DataConverter.h"
+
+#include <audio_utils/primitives.h>
+
+#include <media/stagefright/foundation/ABuffer.h>
+#include <media/stagefright/foundation/ADebug.h>
+#include <media/stagefright/foundation/AUtils.h>
+
+namespace android {
+
+status_t DataConverter::convert(const sp<ABuffer> &source, sp<ABuffer> &target) {
+ CHECK(source->base() != target->base());
+ size_t size = targetSize(source->size());
+ status_t err = OK;
+ if (size > target->capacity()) {
+ ALOGE("data size (%zu) is greater than buffer capacity (%zu)",
+ size, // this is the data received/to be converted
+ target->capacity()); // this is out buffer size
+ err = FAILED_TRANSACTION;
+ } else {
+ err = safeConvert(source, target);
+ }
+ target->setRange(0, err == OK ? size : 0);
+ return err;
+}
+
+status_t DataConverter::safeConvert(const sp<ABuffer> &source, sp<ABuffer> &target) {
+ memcpy(target->base(), source->data(), source->size());
+ return OK;
+}
+
+size_t DataConverter::sourceSize(size_t targetSize) {
+ return targetSize;
+}
+
+size_t DataConverter::targetSize(size_t sourceSize) {
+ return sourceSize;
+}
+
+DataConverter::~DataConverter() { }
+
+
+size_t SampleConverterBase::sourceSize(size_t targetSize) {
+ size_t numSamples = targetSize / mTargetSampleSize;
+ if (numSamples > SIZE_MAX / mSourceSampleSize) {
+ ALOGW("limiting source size due to overflow (%zu*%zu/%zu)",
+ targetSize, mSourceSampleSize, mTargetSampleSize);
+ return SIZE_MAX;
+ }
+ return numSamples * mSourceSampleSize;
+}
+
+size_t SampleConverterBase::targetSize(size_t sourceSize) {
+ // we round up on conversion
+ size_t numSamples = divUp(sourceSize, (size_t)mSourceSampleSize);
+ if (numSamples > SIZE_MAX / mTargetSampleSize) {
+ ALOGW("limiting target size due to overflow (%zu*%zu/%zu)",
+ sourceSize, mTargetSampleSize, mSourceSampleSize);
+ return SIZE_MAX;
+ }
+ return numSamples * mTargetSampleSize;
+}
+
+
+static size_t getAudioSampleSize(AudioEncoding e) {
+ switch (e) {
+ case kAudioEncodingPcm16bit: return 2;
+ case kAudioEncodingPcm8bit: return 1;
+ case kAudioEncodingPcmFloat: return 4;
+ default: return 0;
+ }
+}
+
+
+// static
+AudioConverter* AudioConverter::Create(AudioEncoding source, AudioEncoding target) {
+ uint32_t sourceSampleSize = getAudioSampleSize(source);
+ uint32_t targetSampleSize = getAudioSampleSize(target);
+ if (sourceSampleSize && targetSampleSize && sourceSampleSize != targetSampleSize) {
+ return new AudioConverter(source, sourceSampleSize, target, targetSampleSize);
+ }
+ return NULL;
+}
+
+status_t AudioConverter::safeConvert(const sp<ABuffer> &src, sp<ABuffer> &tgt) {
+ if (mTo == kAudioEncodingPcm8bit && mFrom == kAudioEncodingPcm16bit) {
+ memcpy_to_u8_from_i16((uint8_t*)tgt->base(), (const int16_t*)src->data(), src->size() / 2);
+ } else if (mTo == kAudioEncodingPcm8bit && mFrom == kAudioEncodingPcmFloat) {
+ memcpy_to_u8_from_float((uint8_t*)tgt->base(), (const float*)src->data(), src->size() / 4);
+ } else if (mTo == kAudioEncodingPcm16bit && mFrom == kAudioEncodingPcm8bit) {
+ memcpy_to_i16_from_u8((int16_t*)tgt->base(), (const uint8_t*)src->data(), src->size());
+ } else if (mTo == kAudioEncodingPcm16bit && mFrom == kAudioEncodingPcmFloat) {
+ memcpy_to_i16_from_float((int16_t*)tgt->base(), (const float*)src->data(), src->size() / 4);
+ } else if (mTo == kAudioEncodingPcmFloat && mFrom == kAudioEncodingPcm8bit) {
+ memcpy_to_float_from_u8((float*)tgt->base(), (const uint8_t*)src->data(), src->size());
+ } else if (mTo == kAudioEncodingPcmFloat && mFrom == kAudioEncodingPcm16bit) {
+ memcpy_to_float_from_i16((float*)tgt->base(), (const int16_t*)src->data(), src->size() / 2);
+ } else {
+ return INVALID_OPERATION;
+ }
+ return OK;
+}
+
+} // namespace android
diff --git a/media/libstagefright/codecs/raw/SoftRaw.cpp b/media/libstagefright/codecs/raw/SoftRaw.cpp
index c4e0659..acb2b37 100644
--- a/media/libstagefright/codecs/raw/SoftRaw.cpp
+++ b/media/libstagefright/codecs/raw/SoftRaw.cpp
@@ -42,7 +42,9 @@
: SimpleSoftOMXComponent(name, callbacks, appData, component),
mSignalledError(false),
mChannelCount(2),
- mSampleRate(44100) {
+ mSampleRate(44100),
+ mNumericalData(OMX_NumericalDataSigned),
+ mBitsPerSample(16) {
initPorts();
CHECK_EQ(initDecoder(), (status_t)OK);
}
@@ -111,10 +113,10 @@
return OMX_ErrorUndefined;
}
- pcmParams->eNumData = OMX_NumericalDataSigned;
+ pcmParams->eNumData = (OMX_NUMERICALDATATYPE)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;
@@ -166,6 +168,8 @@
mChannelCount = pcmParams->nChannels;
mSampleRate = pcmParams->nSamplingRate;
+ mNumericalData = pcmParams->eNumData;
+ mBitsPerSample = pcmParams->nBitPerSample;
return OMX_ErrorNone;
}
diff --git a/media/libstagefright/codecs/raw/SoftRaw.h b/media/libstagefright/codecs/raw/SoftRaw.h
index 015c4a3..80906b4 100644
--- a/media/libstagefright/codecs/raw/SoftRaw.h
+++ b/media/libstagefright/codecs/raw/SoftRaw.h
@@ -50,6 +50,8 @@
int32_t mChannelCount;
int32_t mSampleRate;
+ int32_t mNumericalData;
+ int32_t mBitsPerSample;
void initPorts();
status_t initDecoder();
diff --git a/media/libstagefright/include/DataConverter.h b/media/libstagefright/include/DataConverter.h
new file mode 100644
index 0000000..8d67921
--- /dev/null
+++ b/media/libstagefright/include/DataConverter.h
@@ -0,0 +1,79 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef STAGEFRIGHT_DATACONVERTER_H_
+#define STAGEFRIGHT_DATACONVERTER_H_
+
+#include <utils/Errors.h>
+#include <utils/RefBase.h>
+
+#include <media/stagefright/MediaDefs.h>
+
+namespace android {
+
+struct ABuffer;
+
+// DataConverter base class, defaults to memcpy
+struct DataConverter : public RefBase {
+ virtual size_t sourceSize(size_t targetSize); // will clamp to SIZE_MAX
+ virtual size_t targetSize(size_t sourceSize); // will clamp to SIZE_MAX
+
+ status_t convert(const sp<ABuffer> &source, sp<ABuffer> &target);
+ virtual ~DataConverter();
+
+protected:
+ virtual status_t safeConvert(const sp<ABuffer> &source, sp<ABuffer> &target);
+};
+
+// SampleConverterBase uses a ratio to calculate the source and target sizes
+// based on source and target sample sizes.
+struct SampleConverterBase : public DataConverter {
+ virtual size_t sourceSize(size_t targetSize);
+ virtual size_t targetSize(size_t sourceSize);
+
+protected:
+ virtual status_t safeConvert(const sp<ABuffer> &source, sp<ABuffer> &target) = 0;
+
+ // sourceSize = sourceSampleSize / targetSampleSize * targetSize
+ SampleConverterBase(uint32_t sourceSampleSize, uint32_t targetSampleSize)
+ : mSourceSampleSize(sourceSampleSize),
+ mTargetSampleSize(targetSampleSize) { }
+ size_t mSourceSampleSize;
+ size_t mTargetSampleSize;
+};
+
+// AudioConverter converts between audio PCM formats
+struct AudioConverter : public SampleConverterBase {
+ // return nullptr if conversion is not needed or not supported
+ static AudioConverter *Create(AudioEncoding source, AudioEncoding target);
+
+protected:
+ virtual status_t safeConvert(const sp<ABuffer> &src, sp<ABuffer> &tgt);
+
+private:
+ AudioConverter(
+ AudioEncoding source, size_t sourceSample,
+ AudioEncoding target, size_t targetSample)
+ : SampleConverterBase(sourceSample, targetSample),
+ mFrom(source),
+ mTo(target) { }
+ AudioEncoding mFrom;
+ AudioEncoding mTo;
+};
+
+} // namespace android
+
+#endif