Loading include/media/stagefright/OMXCodec.h +2 −0 Original line number Diff line number Diff line Loading @@ -248,6 +248,8 @@ private: int32_t numChannels, int32_t sampleRate, int32_t bitRate, int32_t aacProfile, bool isADTS); status_t setAC3Format(int32_t numChannels, int32_t sampleRate); void setG711Format(int32_t numChannels); status_t setVideoPortFormatType( Loading media/libstagefright/OMXCodec.cpp +51 −0 Original line number Diff line number Diff line Loading @@ -40,7 +40,9 @@ #include <utils/Vector.h> #include <OMX_Audio.h> #include <OMX_AudioExt.h> #include <OMX_Component.h> #include <OMX_IndexExt.h> #include "include/avc_utils.h" Loading Loading @@ -528,6 +530,17 @@ status_t OMXCodec::configureCodec(const sp<MetaData> &meta) { sampleRate, numChannels); } } else if (!strcasecmp(MEDIA_MIMETYPE_AUDIO_AC3, mMIME)) { int32_t numChannels; int32_t sampleRate; CHECK(meta->findInt32(kKeyChannelCount, &numChannels)); CHECK(meta->findInt32(kKeySampleRate, &sampleRate)); status_t err = setAC3Format(numChannels, sampleRate); if (err != OK) { CODEC_LOGE("setAC3Format() failed (err = %d)", err); return err; } } else if (!strcasecmp(MEDIA_MIMETYPE_AUDIO_G711_ALAW, mMIME) || !strcasecmp(MEDIA_MIMETYPE_AUDIO_G711_MLAW, mMIME)) { // These are PCM-like formats with a fixed sample rate but Loading Loading @@ -1396,6 +1409,8 @@ void OMXCodec::setComponentRole( "audio_decoder.gsm", "audio_encoder.gsm" }, { MEDIA_MIMETYPE_VIDEO_MPEG2, "video_decoder.mpeg2", "video_encoder.mpeg2" }, { MEDIA_MIMETYPE_AUDIO_AC3, "audio_decoder.ac3", "audio_encoder.ac3" }, }; static const size_t kNumMimeToRole = Loading Loading @@ -3491,6 +3506,31 @@ status_t OMXCodec::setAACFormat( return OK; } status_t OMXCodec::setAC3Format(int32_t numChannels, int32_t sampleRate) { OMX_AUDIO_PARAM_ANDROID_AC3TYPE def; InitOMXParams(&def); def.nPortIndex = kPortIndexInput; status_t err = mOMX->getParameter( mNode, (OMX_INDEXTYPE)OMX_IndexParamAudioAndroidAc3, &def, sizeof(def)); if (err != OK) { return err; } def.nChannels = numChannels; def.nSampleRate = sampleRate; return mOMX->setParameter( mNode, (OMX_INDEXTYPE)OMX_IndexParamAudioAndroidAc3, &def, sizeof(def)); } void OMXCodec::setG711Format(int32_t numChannels) { CHECK(!mIsEncoder); setRawAudioFormat(kPortIndexInput, 8000, numChannels); Loading Loading @@ -4424,6 +4464,17 @@ void OMXCodec::initOutputFormat(const sp<MetaData> &inputFormat) { mOutputFormat->setInt32(kKeyChannelCount, numChannels); mOutputFormat->setInt32(kKeySampleRate, sampleRate); mOutputFormat->setInt32(kKeyBitRate, bitRate); } else if (audio_def->eEncoding == (OMX_AUDIO_CODINGTYPE)OMX_AUDIO_CodingAndroidAC3) { mOutputFormat->setCString( kKeyMIMEType, MEDIA_MIMETYPE_AUDIO_AC3); int32_t numChannels, sampleRate, bitRate; inputFormat->findInt32(kKeyChannelCount, &numChannels); inputFormat->findInt32(kKeySampleRate, &sampleRate); inputFormat->findInt32(kKeyBitRate, &bitRate); mOutputFormat->setInt32(kKeyChannelCount, numChannels); mOutputFormat->setInt32(kKeySampleRate, sampleRate); mOutputFormat->setInt32(kKeyBitRate, bitRate); } else { CHECK(!"Should not be here. Unknown audio encoding."); } Loading media/libstagefright/mpeg2ts/ATSParser.cpp +6 −0 Original line number Diff line number Diff line Loading @@ -506,6 +506,11 @@ ATSParser::Stream::Stream( ElementaryStreamQueue::PCM_AUDIO); break; case STREAMTYPE_AC3: mQueue = new ElementaryStreamQueue( ElementaryStreamQueue::AC3); break; default: break; } Loading Loading @@ -614,6 +619,7 @@ bool ATSParser::Stream::isAudio() const { case STREAMTYPE_MPEG2_AUDIO: case STREAMTYPE_MPEG2_AUDIO_ADTS: case STREAMTYPE_PCM_AUDIO: case STREAMTYPE_AC3: return true; default: Loading media/libstagefright/mpeg2ts/ATSParser.h +4 −0 Original line number Diff line number Diff line Loading @@ -88,6 +88,10 @@ struct ATSParser : public RefBase { STREAMTYPE_MPEG2_AUDIO_ADTS = 0x0f, STREAMTYPE_MPEG4_VIDEO = 0x10, STREAMTYPE_H264 = 0x1b, // From ATSC A/53 Part 3:2009, 6.7.1 STREAMTYPE_AC3 = 0x81, STREAMTYPE_PCM_AUDIO = 0x83, }; Loading media/libstagefright/mpeg2ts/ESQueue.cpp +190 −0 Original line number Diff line number Diff line Loading @@ -56,6 +56,122 @@ void ElementaryStreamQueue::clear(bool clearFormat) { } } // Parse AC3 header assuming the current ptr is start position of syncframe, // update metadata only applicable, and return the payload size static unsigned parseAC3SyncFrame( const uint8_t *ptr, size_t size, sp<MetaData> *metaData) { static const unsigned channelCountTable[] = {2, 1, 2, 3, 4, 4, 5, 6}; static const unsigned samplingRateTable[] = {48000, 44100, 32000}; static const unsigned rates[] = {32, 40, 48, 56, 64, 80, 96, 112, 128, 160, 192, 224, 256, 320, 384, 448, 512, 576, 640}; static const unsigned frameSizeTable[19][3] = { { 64, 69, 96 }, { 80, 87, 120 }, { 96, 104, 144 }, { 112, 121, 168 }, { 128, 139, 192 }, { 160, 174, 240 }, { 192, 208, 288 }, { 224, 243, 336 }, { 256, 278, 384 }, { 320, 348, 480 }, { 384, 417, 576 }, { 448, 487, 672 }, { 512, 557, 768 }, { 640, 696, 960 }, { 768, 835, 1152 }, { 896, 975, 1344 }, { 1024, 1114, 1536 }, { 1152, 1253, 1728 }, { 1280, 1393, 1920 }, }; ABitReader bits(ptr, size); unsigned syncStartPos = 0; // in bytes if (bits.numBitsLeft() < 16) { return 0; } if (bits.getBits(16) != 0x0B77) { return 0; } if (bits.numBitsLeft() < 16 + 2 + 6 + 5 + 3 + 3) { ALOGV("Not enough bits left for further parsing"); return 0; } bits.skipBits(16); // crc1 unsigned fscod = bits.getBits(2); if (fscod == 3) { ALOGW("Incorrect fscod in AC3 header"); return 0; } unsigned frmsizecod = bits.getBits(6); if (frmsizecod > 37) { ALOGW("Incorrect frmsizecod in AC3 header"); return 0; } unsigned bsid = bits.getBits(5); if (bsid > 8) { ALOGW("Incorrect bsid in AC3 header. Possibly E-AC-3?"); return 0; } unsigned bsmod = bits.getBits(3); unsigned acmod = bits.getBits(3); unsigned cmixlev = 0; unsigned surmixlev = 0; unsigned dsurmod = 0; if ((acmod & 1) > 0 && acmod != 1) { if (bits.numBitsLeft() < 2) { return 0; } cmixlev = bits.getBits(2); } if ((acmod & 4) > 0) { if (bits.numBitsLeft() < 2) { return 0; } surmixlev = bits.getBits(2); } if (acmod == 2) { if (bits.numBitsLeft() < 2) { return 0; } dsurmod = bits.getBits(2); } if (bits.numBitsLeft() < 1) { return 0; } unsigned lfeon = bits.getBits(1); unsigned samplingRate = samplingRateTable[fscod]; unsigned payloadSize = frameSizeTable[frmsizecod >> 1][fscod]; if (fscod == 1) { payloadSize += frmsizecod & 1; } payloadSize <<= 1; // convert from 16-bit words to bytes unsigned channelCount = channelCountTable[acmod] + lfeon; if (metaData != NULL) { (*metaData)->setCString(kKeyMIMEType, MEDIA_MIMETYPE_AUDIO_AC3); (*metaData)->setInt32(kKeyChannelCount, channelCount); (*metaData)->setInt32(kKeySampleRate, samplingRate); } return payloadSize; } static bool IsSeeminglyValidAC3Header(const uint8_t *ptr, size_t size) { return parseAC3SyncFrame(ptr, size, NULL) > 0; } static bool IsSeeminglyValidADTSHeader(const uint8_t *ptr, size_t size) { if (size < 3) { // Not enough data to verify header. Loading Loading @@ -224,6 +340,33 @@ status_t ElementaryStreamQueue::appendData( break; } case AC3: { uint8_t *ptr = (uint8_t *)data; ssize_t startOffset = -1; for (size_t i = 0; i < size; ++i) { if (IsSeeminglyValidAC3Header(&ptr[i], size - i)) { startOffset = i; break; } } if (startOffset < 0) { return ERROR_MALFORMED; } if (startOffset > 0) { ALOGI("found something resembling an AC3 syncword at " "offset %d", startOffset); } data = &ptr[startOffset]; size -= startOffset; break; } case MPEG_AUDIO: { uint8_t *ptr = (uint8_t *)data; Loading Loading @@ -328,6 +471,8 @@ sp<ABuffer> ElementaryStreamQueue::dequeueAccessUnit() { return dequeueAccessUnitH264(); case AAC: return dequeueAccessUnitAAC(); case AC3: return dequeueAccessUnitAC3(); case MPEG_VIDEO: return dequeueAccessUnitMPEGVideo(); case MPEG4_VIDEO: Loading @@ -340,6 +485,51 @@ sp<ABuffer> ElementaryStreamQueue::dequeueAccessUnit() { } } sp<ABuffer> ElementaryStreamQueue::dequeueAccessUnitAC3() { unsigned syncStartPos = 0; // in bytes unsigned payloadSize = 0; sp<MetaData> format = new MetaData; while (true) { if (syncStartPos + 2 >= mBuffer->size()) { return NULL; } payloadSize = parseAC3SyncFrame( mBuffer->data() + syncStartPos, mBuffer->size() - syncStartPos, &format); if (payloadSize > 0) { break; } ++syncStartPos; } if (mBuffer->size() < syncStartPos + payloadSize) { ALOGV("Not enough buffer size for AC3"); return NULL; } if (mFormat == NULL) { mFormat = format; } sp<ABuffer> accessUnit = new ABuffer(syncStartPos + payloadSize); memcpy(accessUnit->data(), mBuffer->data(), syncStartPos + payloadSize); int64_t timeUs = fetchTimestamp(syncStartPos + payloadSize); CHECK_GE(timeUs, 0ll); accessUnit->meta()->setInt64("timeUs", timeUs); memmove( mBuffer->data(), mBuffer->data() + syncStartPos + payloadSize, mBuffer->size() - syncStartPos - payloadSize); mBuffer->setRange(0, mBuffer->size() - syncStartPos - payloadSize); return accessUnit; } sp<ABuffer> ElementaryStreamQueue::dequeueAccessUnitPCMAudio() { if (mBuffer->size() < 4) { return NULL; Loading Loading
include/media/stagefright/OMXCodec.h +2 −0 Original line number Diff line number Diff line Loading @@ -248,6 +248,8 @@ private: int32_t numChannels, int32_t sampleRate, int32_t bitRate, int32_t aacProfile, bool isADTS); status_t setAC3Format(int32_t numChannels, int32_t sampleRate); void setG711Format(int32_t numChannels); status_t setVideoPortFormatType( Loading
media/libstagefright/OMXCodec.cpp +51 −0 Original line number Diff line number Diff line Loading @@ -40,7 +40,9 @@ #include <utils/Vector.h> #include <OMX_Audio.h> #include <OMX_AudioExt.h> #include <OMX_Component.h> #include <OMX_IndexExt.h> #include "include/avc_utils.h" Loading Loading @@ -528,6 +530,17 @@ status_t OMXCodec::configureCodec(const sp<MetaData> &meta) { sampleRate, numChannels); } } else if (!strcasecmp(MEDIA_MIMETYPE_AUDIO_AC3, mMIME)) { int32_t numChannels; int32_t sampleRate; CHECK(meta->findInt32(kKeyChannelCount, &numChannels)); CHECK(meta->findInt32(kKeySampleRate, &sampleRate)); status_t err = setAC3Format(numChannels, sampleRate); if (err != OK) { CODEC_LOGE("setAC3Format() failed (err = %d)", err); return err; } } else if (!strcasecmp(MEDIA_MIMETYPE_AUDIO_G711_ALAW, mMIME) || !strcasecmp(MEDIA_MIMETYPE_AUDIO_G711_MLAW, mMIME)) { // These are PCM-like formats with a fixed sample rate but Loading Loading @@ -1396,6 +1409,8 @@ void OMXCodec::setComponentRole( "audio_decoder.gsm", "audio_encoder.gsm" }, { MEDIA_MIMETYPE_VIDEO_MPEG2, "video_decoder.mpeg2", "video_encoder.mpeg2" }, { MEDIA_MIMETYPE_AUDIO_AC3, "audio_decoder.ac3", "audio_encoder.ac3" }, }; static const size_t kNumMimeToRole = Loading Loading @@ -3491,6 +3506,31 @@ status_t OMXCodec::setAACFormat( return OK; } status_t OMXCodec::setAC3Format(int32_t numChannels, int32_t sampleRate) { OMX_AUDIO_PARAM_ANDROID_AC3TYPE def; InitOMXParams(&def); def.nPortIndex = kPortIndexInput; status_t err = mOMX->getParameter( mNode, (OMX_INDEXTYPE)OMX_IndexParamAudioAndroidAc3, &def, sizeof(def)); if (err != OK) { return err; } def.nChannels = numChannels; def.nSampleRate = sampleRate; return mOMX->setParameter( mNode, (OMX_INDEXTYPE)OMX_IndexParamAudioAndroidAc3, &def, sizeof(def)); } void OMXCodec::setG711Format(int32_t numChannels) { CHECK(!mIsEncoder); setRawAudioFormat(kPortIndexInput, 8000, numChannels); Loading Loading @@ -4424,6 +4464,17 @@ void OMXCodec::initOutputFormat(const sp<MetaData> &inputFormat) { mOutputFormat->setInt32(kKeyChannelCount, numChannels); mOutputFormat->setInt32(kKeySampleRate, sampleRate); mOutputFormat->setInt32(kKeyBitRate, bitRate); } else if (audio_def->eEncoding == (OMX_AUDIO_CODINGTYPE)OMX_AUDIO_CodingAndroidAC3) { mOutputFormat->setCString( kKeyMIMEType, MEDIA_MIMETYPE_AUDIO_AC3); int32_t numChannels, sampleRate, bitRate; inputFormat->findInt32(kKeyChannelCount, &numChannels); inputFormat->findInt32(kKeySampleRate, &sampleRate); inputFormat->findInt32(kKeyBitRate, &bitRate); mOutputFormat->setInt32(kKeyChannelCount, numChannels); mOutputFormat->setInt32(kKeySampleRate, sampleRate); mOutputFormat->setInt32(kKeyBitRate, bitRate); } else { CHECK(!"Should not be here. Unknown audio encoding."); } Loading
media/libstagefright/mpeg2ts/ATSParser.cpp +6 −0 Original line number Diff line number Diff line Loading @@ -506,6 +506,11 @@ ATSParser::Stream::Stream( ElementaryStreamQueue::PCM_AUDIO); break; case STREAMTYPE_AC3: mQueue = new ElementaryStreamQueue( ElementaryStreamQueue::AC3); break; default: break; } Loading Loading @@ -614,6 +619,7 @@ bool ATSParser::Stream::isAudio() const { case STREAMTYPE_MPEG2_AUDIO: case STREAMTYPE_MPEG2_AUDIO_ADTS: case STREAMTYPE_PCM_AUDIO: case STREAMTYPE_AC3: return true; default: Loading
media/libstagefright/mpeg2ts/ATSParser.h +4 −0 Original line number Diff line number Diff line Loading @@ -88,6 +88,10 @@ struct ATSParser : public RefBase { STREAMTYPE_MPEG2_AUDIO_ADTS = 0x0f, STREAMTYPE_MPEG4_VIDEO = 0x10, STREAMTYPE_H264 = 0x1b, // From ATSC A/53 Part 3:2009, 6.7.1 STREAMTYPE_AC3 = 0x81, STREAMTYPE_PCM_AUDIO = 0x83, }; Loading
media/libstagefright/mpeg2ts/ESQueue.cpp +190 −0 Original line number Diff line number Diff line Loading @@ -56,6 +56,122 @@ void ElementaryStreamQueue::clear(bool clearFormat) { } } // Parse AC3 header assuming the current ptr is start position of syncframe, // update metadata only applicable, and return the payload size static unsigned parseAC3SyncFrame( const uint8_t *ptr, size_t size, sp<MetaData> *metaData) { static const unsigned channelCountTable[] = {2, 1, 2, 3, 4, 4, 5, 6}; static const unsigned samplingRateTable[] = {48000, 44100, 32000}; static const unsigned rates[] = {32, 40, 48, 56, 64, 80, 96, 112, 128, 160, 192, 224, 256, 320, 384, 448, 512, 576, 640}; static const unsigned frameSizeTable[19][3] = { { 64, 69, 96 }, { 80, 87, 120 }, { 96, 104, 144 }, { 112, 121, 168 }, { 128, 139, 192 }, { 160, 174, 240 }, { 192, 208, 288 }, { 224, 243, 336 }, { 256, 278, 384 }, { 320, 348, 480 }, { 384, 417, 576 }, { 448, 487, 672 }, { 512, 557, 768 }, { 640, 696, 960 }, { 768, 835, 1152 }, { 896, 975, 1344 }, { 1024, 1114, 1536 }, { 1152, 1253, 1728 }, { 1280, 1393, 1920 }, }; ABitReader bits(ptr, size); unsigned syncStartPos = 0; // in bytes if (bits.numBitsLeft() < 16) { return 0; } if (bits.getBits(16) != 0x0B77) { return 0; } if (bits.numBitsLeft() < 16 + 2 + 6 + 5 + 3 + 3) { ALOGV("Not enough bits left for further parsing"); return 0; } bits.skipBits(16); // crc1 unsigned fscod = bits.getBits(2); if (fscod == 3) { ALOGW("Incorrect fscod in AC3 header"); return 0; } unsigned frmsizecod = bits.getBits(6); if (frmsizecod > 37) { ALOGW("Incorrect frmsizecod in AC3 header"); return 0; } unsigned bsid = bits.getBits(5); if (bsid > 8) { ALOGW("Incorrect bsid in AC3 header. Possibly E-AC-3?"); return 0; } unsigned bsmod = bits.getBits(3); unsigned acmod = bits.getBits(3); unsigned cmixlev = 0; unsigned surmixlev = 0; unsigned dsurmod = 0; if ((acmod & 1) > 0 && acmod != 1) { if (bits.numBitsLeft() < 2) { return 0; } cmixlev = bits.getBits(2); } if ((acmod & 4) > 0) { if (bits.numBitsLeft() < 2) { return 0; } surmixlev = bits.getBits(2); } if (acmod == 2) { if (bits.numBitsLeft() < 2) { return 0; } dsurmod = bits.getBits(2); } if (bits.numBitsLeft() < 1) { return 0; } unsigned lfeon = bits.getBits(1); unsigned samplingRate = samplingRateTable[fscod]; unsigned payloadSize = frameSizeTable[frmsizecod >> 1][fscod]; if (fscod == 1) { payloadSize += frmsizecod & 1; } payloadSize <<= 1; // convert from 16-bit words to bytes unsigned channelCount = channelCountTable[acmod] + lfeon; if (metaData != NULL) { (*metaData)->setCString(kKeyMIMEType, MEDIA_MIMETYPE_AUDIO_AC3); (*metaData)->setInt32(kKeyChannelCount, channelCount); (*metaData)->setInt32(kKeySampleRate, samplingRate); } return payloadSize; } static bool IsSeeminglyValidAC3Header(const uint8_t *ptr, size_t size) { return parseAC3SyncFrame(ptr, size, NULL) > 0; } static bool IsSeeminglyValidADTSHeader(const uint8_t *ptr, size_t size) { if (size < 3) { // Not enough data to verify header. Loading Loading @@ -224,6 +340,33 @@ status_t ElementaryStreamQueue::appendData( break; } case AC3: { uint8_t *ptr = (uint8_t *)data; ssize_t startOffset = -1; for (size_t i = 0; i < size; ++i) { if (IsSeeminglyValidAC3Header(&ptr[i], size - i)) { startOffset = i; break; } } if (startOffset < 0) { return ERROR_MALFORMED; } if (startOffset > 0) { ALOGI("found something resembling an AC3 syncword at " "offset %d", startOffset); } data = &ptr[startOffset]; size -= startOffset; break; } case MPEG_AUDIO: { uint8_t *ptr = (uint8_t *)data; Loading Loading @@ -328,6 +471,8 @@ sp<ABuffer> ElementaryStreamQueue::dequeueAccessUnit() { return dequeueAccessUnitH264(); case AAC: return dequeueAccessUnitAAC(); case AC3: return dequeueAccessUnitAC3(); case MPEG_VIDEO: return dequeueAccessUnitMPEGVideo(); case MPEG4_VIDEO: Loading @@ -340,6 +485,51 @@ sp<ABuffer> ElementaryStreamQueue::dequeueAccessUnit() { } } sp<ABuffer> ElementaryStreamQueue::dequeueAccessUnitAC3() { unsigned syncStartPos = 0; // in bytes unsigned payloadSize = 0; sp<MetaData> format = new MetaData; while (true) { if (syncStartPos + 2 >= mBuffer->size()) { return NULL; } payloadSize = parseAC3SyncFrame( mBuffer->data() + syncStartPos, mBuffer->size() - syncStartPos, &format); if (payloadSize > 0) { break; } ++syncStartPos; } if (mBuffer->size() < syncStartPos + payloadSize) { ALOGV("Not enough buffer size for AC3"); return NULL; } if (mFormat == NULL) { mFormat = format; } sp<ABuffer> accessUnit = new ABuffer(syncStartPos + payloadSize); memcpy(accessUnit->data(), mBuffer->data(), syncStartPos + payloadSize); int64_t timeUs = fetchTimestamp(syncStartPos + payloadSize); CHECK_GE(timeUs, 0ll); accessUnit->meta()->setInt64("timeUs", timeUs); memmove( mBuffer->data(), mBuffer->data() + syncStartPos + payloadSize, mBuffer->size() - syncStartPos - payloadSize); mBuffer->setRange(0, mBuffer->size() - syncStartPos - payloadSize); return accessUnit; } sp<ABuffer> ElementaryStreamQueue::dequeueAccessUnitPCMAudio() { if (mBuffer->size() < 4) { return NULL; Loading