Merge "Support AMR, G.711 and vorbis audio in ACodec and friends."
This commit is contained in:
committed by
Android (Google) Code Review
commit
781ae92f11
@@ -46,7 +46,8 @@ struct Controller : public AHandler {
|
|||||||
mDecodeAudio(decodeAudio),
|
mDecodeAudio(decodeAudio),
|
||||||
mSurface(surface),
|
mSurface(surface),
|
||||||
mRenderToSurface(renderToSurface),
|
mRenderToSurface(renderToSurface),
|
||||||
mCodec(new ACodec) {
|
mCodec(new ACodec),
|
||||||
|
mIsVorbis(false) {
|
||||||
CHECK(!mDecodeAudio || mSurface == NULL);
|
CHECK(!mDecodeAudio || mSurface == NULL);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -85,6 +86,12 @@ protected:
|
|||||||
if (!strncasecmp(mDecodeAudio ? "audio/" : "video/",
|
if (!strncasecmp(mDecodeAudio ? "audio/" : "video/",
|
||||||
mime, 6)) {
|
mime, 6)) {
|
||||||
mSource = extractor->getTrack(i);
|
mSource = extractor->getTrack(i);
|
||||||
|
|
||||||
|
if (!strcasecmp(mime, MEDIA_MIMETYPE_AUDIO_VORBIS)) {
|
||||||
|
mIsVorbis = true;
|
||||||
|
} else {
|
||||||
|
mIsVorbis = false;
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -227,6 +234,7 @@ private:
|
|||||||
bool mRenderToSurface;
|
bool mRenderToSurface;
|
||||||
sp<ACodec> mCodec;
|
sp<ACodec> mCodec;
|
||||||
sp<MediaSource> mSource;
|
sp<MediaSource> mSource;
|
||||||
|
bool mIsVorbis;
|
||||||
|
|
||||||
Vector<sp<ABuffer> > mCSD;
|
Vector<sp<ABuffer> > mCSD;
|
||||||
size_t mCSDIndex;
|
size_t mCSDIndex;
|
||||||
@@ -367,6 +375,20 @@ private:
|
|||||||
memcpy(buffer->data(), codec_specific_data,
|
memcpy(buffer->data(), codec_specific_data,
|
||||||
codec_specific_data_size);
|
codec_specific_data_size);
|
||||||
|
|
||||||
|
buffer->meta()->setInt32("csd", true);
|
||||||
|
mCSD.push(buffer);
|
||||||
|
} else if (meta->findData(kKeyVorbisInfo, &type, &data, &size)) {
|
||||||
|
sp<ABuffer> buffer = new ABuffer(size);
|
||||||
|
memcpy(buffer->data(), data, size);
|
||||||
|
|
||||||
|
buffer->meta()->setInt32("csd", true);
|
||||||
|
mCSD.push(buffer);
|
||||||
|
|
||||||
|
CHECK(meta->findData(kKeyVorbisBooks, &type, &data, &size));
|
||||||
|
|
||||||
|
buffer = new ABuffer(size);
|
||||||
|
memcpy(buffer->data(), data, size);
|
||||||
|
|
||||||
buffer->meta()->setInt32("csd", true);
|
buffer->meta()->setInt32("csd", true);
|
||||||
mCSD.push(buffer);
|
mCSD.push(buffer);
|
||||||
}
|
}
|
||||||
@@ -423,10 +445,17 @@ private:
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (inBuffer->range_length() > sizeLeft) {
|
size_t sizeNeeded = inBuffer->range_length();
|
||||||
|
if (mIsVorbis) {
|
||||||
|
// Vorbis data is suffixed with the number of
|
||||||
|
// valid samples on the page.
|
||||||
|
sizeNeeded += sizeof(int32_t);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (sizeNeeded > sizeLeft) {
|
||||||
if (outBuffer->size() == 0) {
|
if (outBuffer->size() == 0) {
|
||||||
LOGE("Unable to fit even a single input buffer of size %d.",
|
LOGE("Unable to fit even a single input buffer of size %d.",
|
||||||
inBuffer->range_length());
|
sizeNeeded);
|
||||||
}
|
}
|
||||||
CHECK_GT(outBuffer->size(), 0u);
|
CHECK_GT(outBuffer->size(), 0u);
|
||||||
|
|
||||||
@@ -448,10 +477,22 @@ private:
|
|||||||
+ inBuffer->range_offset(),
|
+ inBuffer->range_offset(),
|
||||||
inBuffer->range_length());
|
inBuffer->range_length());
|
||||||
|
|
||||||
outBuffer->setRange(
|
if (mIsVorbis) {
|
||||||
0, outBuffer->size() + inBuffer->range_length());
|
int32_t numPageSamples;
|
||||||
|
if (!inBuffer->meta_data()->findInt32(
|
||||||
|
kKeyValidSamples, &numPageSamples)) {
|
||||||
|
numPageSamples = -1;
|
||||||
|
}
|
||||||
|
|
||||||
sizeLeft -= inBuffer->range_length();
|
memcpy(outBuffer->data()
|
||||||
|
+ outBuffer->size() + inBuffer->range_length(),
|
||||||
|
&numPageSamples, sizeof(numPageSamples));
|
||||||
|
}
|
||||||
|
|
||||||
|
outBuffer->setRange(
|
||||||
|
0, outBuffer->size() + sizeNeeded);
|
||||||
|
|
||||||
|
sizeLeft -= sizeNeeded;
|
||||||
|
|
||||||
inBuffer->release();
|
inBuffer->release();
|
||||||
inBuffer = NULL;
|
inBuffer = NULL;
|
||||||
|
|||||||
@@ -151,6 +151,12 @@ private:
|
|||||||
OMX_VIDEO_CODINGTYPE compressionFormat);
|
OMX_VIDEO_CODINGTYPE compressionFormat);
|
||||||
|
|
||||||
status_t setupAACDecoder(int32_t numChannels, int32_t sampleRate);
|
status_t setupAACDecoder(int32_t numChannels, int32_t sampleRate);
|
||||||
|
status_t setupAMRDecoder(bool isWAMR);
|
||||||
|
status_t setupG711Decoder(int32_t numChannels);
|
||||||
|
|
||||||
|
status_t setupRawAudioFormat(
|
||||||
|
OMX_U32 portIndex, int32_t sampleRate, int32_t numChannels);
|
||||||
|
|
||||||
status_t setMinBufferSize(OMX_U32 portIndex, size_t size);
|
status_t setMinBufferSize(OMX_U32 portIndex, size_t size);
|
||||||
|
|
||||||
status_t initNativeWindow();
|
status_t initNativeWindow();
|
||||||
|
|||||||
@@ -687,6 +687,8 @@ void ACodec::setComponentRole(
|
|||||||
"audio_decoder.amrwb", "audio_encoder.amrwb" },
|
"audio_decoder.amrwb", "audio_encoder.amrwb" },
|
||||||
{ MEDIA_MIMETYPE_AUDIO_AAC,
|
{ MEDIA_MIMETYPE_AUDIO_AAC,
|
||||||
"audio_decoder.aac", "audio_encoder.aac" },
|
"audio_decoder.aac", "audio_encoder.aac" },
|
||||||
|
{ MEDIA_MIMETYPE_AUDIO_VORBIS,
|
||||||
|
"audio_decoder.vorbis", "audio_encoder.vorbis" },
|
||||||
{ MEDIA_MIMETYPE_VIDEO_AVC,
|
{ MEDIA_MIMETYPE_VIDEO_AVC,
|
||||||
"video_decoder.avc", "video_encoder.avc" },
|
"video_decoder.avc", "video_encoder.avc" },
|
||||||
{ MEDIA_MIMETYPE_VIDEO_MPEG4,
|
{ MEDIA_MIMETYPE_VIDEO_MPEG4,
|
||||||
@@ -750,9 +752,19 @@ void ACodec::configureCodec(
|
|||||||
CHECK(msg->findInt32("sample-rate", &sampleRate));
|
CHECK(msg->findInt32("sample-rate", &sampleRate));
|
||||||
|
|
||||||
CHECK_EQ(setupAACDecoder(numChannels, sampleRate), (status_t)OK);
|
CHECK_EQ(setupAACDecoder(numChannels, sampleRate), (status_t)OK);
|
||||||
} else if (!strcasecmp(mime, MEDIA_MIMETYPE_AUDIO_MPEG)) {
|
} else if (!strcasecmp(mime, MEDIA_MIMETYPE_AUDIO_AMR_NB)) {
|
||||||
} else {
|
CHECK_EQ(setupAMRDecoder(false /* isWAMR */), (status_t)OK);
|
||||||
TRESPASS();
|
} else if (!strcasecmp(mime, MEDIA_MIMETYPE_AUDIO_AMR_WB)) {
|
||||||
|
CHECK_EQ(setupAMRDecoder(true /* isWAMR */), (status_t)OK);
|
||||||
|
} else if (!strcasecmp(mime, MEDIA_MIMETYPE_AUDIO_G711_ALAW)
|
||||||
|
|| !strcasecmp(mime, MEDIA_MIMETYPE_AUDIO_G711_MLAW)) {
|
||||||
|
// These are PCM-like formats with a fixed sample rate but
|
||||||
|
// a variable number of channels.
|
||||||
|
|
||||||
|
int32_t numChannels;
|
||||||
|
CHECK(msg->findInt32("channel-count", &numChannels));
|
||||||
|
|
||||||
|
CHECK_EQ(setupG711Decoder(numChannels), (status_t)OK);
|
||||||
}
|
}
|
||||||
|
|
||||||
int32_t maxInputSize;
|
int32_t maxInputSize;
|
||||||
@@ -824,6 +836,84 @@ status_t ACodec::setupAACDecoder(int32_t numChannels, int32_t sampleRate) {
|
|||||||
return err;
|
return err;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
status_t ACodec::setupAMRDecoder(bool isWAMR) {
|
||||||
|
OMX_AUDIO_PARAM_AMRTYPE def;
|
||||||
|
InitOMXParams(&def);
|
||||||
|
def.nPortIndex = kPortIndexInput;
|
||||||
|
|
||||||
|
status_t err =
|
||||||
|
mOMX->getParameter(mNode, OMX_IndexParamAudioAmr, &def, sizeof(def));
|
||||||
|
|
||||||
|
if (err != OK) {
|
||||||
|
return err;
|
||||||
|
}
|
||||||
|
|
||||||
|
def.eAMRFrameFormat = OMX_AUDIO_AMRFrameFormatFSF;
|
||||||
|
|
||||||
|
def.eAMRBandMode =
|
||||||
|
isWAMR ? OMX_AUDIO_AMRBandModeWB0 : OMX_AUDIO_AMRBandModeNB0;
|
||||||
|
|
||||||
|
return mOMX->setParameter(mNode, OMX_IndexParamAudioAmr, &def, sizeof(def));
|
||||||
|
}
|
||||||
|
|
||||||
|
status_t ACodec::setupG711Decoder(int32_t numChannels) {
|
||||||
|
return setupRawAudioFormat(
|
||||||
|
kPortIndexInput, 8000 /* sampleRate */, numChannels);
|
||||||
|
}
|
||||||
|
|
||||||
|
status_t ACodec::setupRawAudioFormat(
|
||||||
|
OMX_U32 portIndex, int32_t sampleRate, int32_t numChannels) {
|
||||||
|
OMX_PARAM_PORTDEFINITIONTYPE def;
|
||||||
|
InitOMXParams(&def);
|
||||||
|
def.nPortIndex = portIndex;
|
||||||
|
|
||||||
|
status_t err = mOMX->getParameter(
|
||||||
|
mNode, OMX_IndexParamPortDefinition, &def, sizeof(def));
|
||||||
|
|
||||||
|
if (err != OK) {
|
||||||
|
return err;
|
||||||
|
}
|
||||||
|
|
||||||
|
def.format.audio.eEncoding = OMX_AUDIO_CodingPCM;
|
||||||
|
|
||||||
|
err = mOMX->setParameter(
|
||||||
|
mNode, OMX_IndexParamPortDefinition, &def, sizeof(def));
|
||||||
|
|
||||||
|
if (err != OK) {
|
||||||
|
return err;
|
||||||
|
}
|
||||||
|
|
||||||
|
OMX_AUDIO_PARAM_PCMMODETYPE pcmParams;
|
||||||
|
InitOMXParams(&pcmParams);
|
||||||
|
pcmParams.nPortIndex = portIndex;
|
||||||
|
|
||||||
|
err = mOMX->getParameter(
|
||||||
|
mNode, OMX_IndexParamAudioPcm, &pcmParams, sizeof(pcmParams));
|
||||||
|
|
||||||
|
if (err != OK) {
|
||||||
|
return err;
|
||||||
|
}
|
||||||
|
|
||||||
|
pcmParams.nChannels = numChannels;
|
||||||
|
pcmParams.eNumData = OMX_NumericalDataSigned;
|
||||||
|
pcmParams.bInterleaved = OMX_TRUE;
|
||||||
|
pcmParams.nBitPerSample = 16;
|
||||||
|
pcmParams.nSamplingRate = sampleRate;
|
||||||
|
pcmParams.ePCMMode = OMX_AUDIO_PCMModeLinear;
|
||||||
|
|
||||||
|
if (numChannels == 1) {
|
||||||
|
pcmParams.eChannelMapping[0] = OMX_AUDIO_ChannelCF;
|
||||||
|
} else {
|
||||||
|
CHECK_EQ(numChannels, 2);
|
||||||
|
|
||||||
|
pcmParams.eChannelMapping[0] = OMX_AUDIO_ChannelLF;
|
||||||
|
pcmParams.eChannelMapping[1] = OMX_AUDIO_ChannelRF;
|
||||||
|
}
|
||||||
|
|
||||||
|
return mOMX->setParameter(
|
||||||
|
mNode, OMX_IndexParamAudioPcm, &pcmParams, sizeof(pcmParams));
|
||||||
|
}
|
||||||
|
|
||||||
status_t ACodec::setVideoPortFormatType(
|
status_t ACodec::setVideoPortFormatType(
|
||||||
OMX_U32 portIndex,
|
OMX_U32 portIndex,
|
||||||
OMX_VIDEO_CODINGTYPE compressionFormat,
|
OMX_VIDEO_CODINGTYPE compressionFormat,
|
||||||
|
|||||||
@@ -1485,6 +1485,8 @@ void OMXCodec::setComponentRole(
|
|||||||
"audio_decoder.amrwb", "audio_encoder.amrwb" },
|
"audio_decoder.amrwb", "audio_encoder.amrwb" },
|
||||||
{ MEDIA_MIMETYPE_AUDIO_AAC,
|
{ MEDIA_MIMETYPE_AUDIO_AAC,
|
||||||
"audio_decoder.aac", "audio_encoder.aac" },
|
"audio_decoder.aac", "audio_encoder.aac" },
|
||||||
|
{ MEDIA_MIMETYPE_AUDIO_VORBIS,
|
||||||
|
"audio_decoder.vorbis", "audio_encoder.vorbis" },
|
||||||
{ MEDIA_MIMETYPE_VIDEO_AVC,
|
{ MEDIA_MIMETYPE_VIDEO_AVC,
|
||||||
"video_decoder.avc", "video_encoder.avc" },
|
"video_decoder.avc", "video_encoder.avc" },
|
||||||
{ MEDIA_MIMETYPE_VIDEO_MPEG4,
|
{ MEDIA_MIMETYPE_VIDEO_MPEG4,
|
||||||
|
|||||||
Reference in New Issue
Block a user