diff options
| -rw-r--r-- | media/libstagefright/MPEG4Extractor.cpp | 96 | ||||
| -rw-r--r-- | media/libstagefright/include/MPEG4Extractor.h | 3 |
2 files changed, 99 insertions, 0 deletions
diff --git a/media/libstagefright/MPEG4Extractor.cpp b/media/libstagefright/MPEG4Extractor.cpp index 5370c394d390..6274a6c6a648 100644 --- a/media/libstagefright/MPEG4Extractor.cpp +++ b/media/libstagefright/MPEG4Extractor.cpp @@ -28,6 +28,7 @@ #include <string.h> #include <media/stagefright/DataSource.h> +#include "include/ESDS.h" #include <media/stagefright/MediaBuffer.h> #include <media/stagefright/MediaBufferGroup.h> #include <media/stagefright/MediaDebug.h> @@ -898,6 +899,21 @@ status_t MPEG4Extractor::parseChunk(off_t *offset, int depth) { mLastTrack->meta->setData( kKeyESDS, kTypeESDS, &buffer[4], chunk_data_size - 4); + if (mPath.size() >= 2 + && mPath[mPath.size() - 2] == FOURCC('m', 'p', '4', 'a')) { + // Information from the ESDS must be relied on for proper + // setup of sample rate and channel count for MPEG4 Audio. + // The generic header appears to only contain generic + // information... + + status_t err = updateAudioTrackInfoFromESDS_MPEG4Audio( + &buffer[4], chunk_data_size - 4); + + if (err != OK) { + return err; + } + } + *offset += chunk_size; break; } @@ -1121,6 +1137,86 @@ sp<MediaSource> MPEG4Extractor::getTrack(size_t index) { track->meta, mDataSource, track->timescale, track->sampleTable); } +status_t MPEG4Extractor::updateAudioTrackInfoFromESDS_MPEG4Audio( + const void *esds_data, size_t esds_size) { + ESDS esds(esds_data, esds_size); + const uint8_t *csd; + size_t csd_size; + if (esds.getCodecSpecificInfo( + (const void **)&csd, &csd_size) != OK) { + return ERROR_MALFORMED; + } + +#if 0 + printf("ESD of size %d\n", csd_size); + hexdump(csd, csd_size); +#endif + + if (csd_size < 2) { + return ERROR_MALFORMED; + } + + uint32_t objectType = csd[0] >> 3; + + if (objectType == 31) { + return ERROR_UNSUPPORTED; + } + + uint32_t freqIndex = (csd[0] & 7) << 1 | (csd[1] >> 7); + int32_t sampleRate = 0; + int32_t numChannels = 0; + if (freqIndex == 15) { + if (csd_size < 5) { + return ERROR_MALFORMED; + } + + sampleRate = (csd[1] & 0x7f) << 17 + | csd[2] << 9 + | csd[3] << 1 + | (csd[4] >> 7); + + numChannels = (csd[4] >> 3) & 15; + } else { + static uint32_t kSamplingRate[] = { + 96000, 88200, 64000, 48000, 44100, 32000, 24000, 22050, + 16000, 12000, 11025, 8000, 7350 + }; + + if (freqIndex == 13 || freqIndex == 14) { + return ERROR_MALFORMED; + } + + sampleRate = kSamplingRate[freqIndex]; + numChannels = (csd[1] >> 3) & 15; + } + + if (numChannels == 0) { + return ERROR_UNSUPPORTED; + } + + int32_t prevSampleRate; + CHECK(mLastTrack->meta->findInt32(kKeySampleRate, &prevSampleRate)); + + if (prevSampleRate != sampleRate) { + LOGW("mpeg4 audio sample rate different from previous setting. " + "was: %d, now: %d", prevSampleRate, sampleRate); + } + + mLastTrack->meta->setInt32(kKeySampleRate, sampleRate); + + int32_t prevChannelCount; + CHECK(mLastTrack->meta->findInt32(kKeyChannelCount, &prevChannelCount)); + + if (prevChannelCount != numChannels) { + LOGW("mpeg4 audio channel count different from previous setting. " + "was: %d, now: %d", prevChannelCount, numChannels); + } + + mLastTrack->meta->setInt32(kKeyChannelCount, numChannels); + + return OK; +} + //////////////////////////////////////////////////////////////////////////////// MPEG4Source::MPEG4Source( diff --git a/media/libstagefright/include/MPEG4Extractor.h b/media/libstagefright/include/MPEG4Extractor.h index 1a1344654aea..3a63e8872b4e 100644 --- a/media/libstagefright/include/MPEG4Extractor.h +++ b/media/libstagefright/include/MPEG4Extractor.h @@ -65,6 +65,9 @@ private: status_t parseChunk(off_t *offset, int depth); status_t parseMetaData(off_t offset, size_t size); + status_t updateAudioTrackInfoFromESDS_MPEG4Audio( + const void *esds_data, size_t esds_size); + MPEG4Extractor(const MPEG4Extractor &); MPEG4Extractor &operator=(const MPEG4Extractor &); }; |