Loading media/extractors/mp4/MPEG4Extractor.cpp +103 −22 Original line number Diff line number Diff line Loading @@ -68,6 +68,7 @@ enum { }; class MPEG4Source : public MediaTrack { static const size_t kMaxPcmFrameSize = 8192; public: // Caller retains ownership of both "dataSource" and "sampleTable". MPEG4Source(MetaDataBase &format, Loading Loading @@ -127,7 +128,7 @@ private: bool mIsAVC; bool mIsHEVC; bool mIsAC4; bool mIsPcm; size_t mNALLengthSize; bool mStarted; Loading Loading @@ -332,6 +333,11 @@ static const char *FourCC2MIME(uint32_t fourcc) { return MEDIA_MIMETYPE_VIDEO_HEVC; case FOURCC('a', 'c', '-', '4'): return MEDIA_MIMETYPE_AUDIO_AC4; case FOURCC('t', 'w', 'o', 's'): case FOURCC('s', 'o', 'w', 't'): return MEDIA_MIMETYPE_AUDIO_RAW; default: ALOGW("Unknown fourcc: %c%c%c%c", (fourcc >> 24) & 0xff, Loading Loading @@ -1488,6 +1494,8 @@ status_t MPEG4Extractor::parseChunk(off64_t *offset, int depth) { case FOURCC('e', 'n', 'c', 'a'): case FOURCC('s', 'a', 'm', 'r'): case FOURCC('s', 'a', 'w', 'b'): case FOURCC('t', 'w', 'o', 's'): case FOURCC('s', 'o', 'w', 't'): { if (mIsQT && chunk_type == FOURCC('m', 'p', '4', 'a') && depth >= 1 && mPath[depth - 1] == FOURCC('w', 'a', 'v', 'e')) { Loading Loading @@ -1557,6 +1565,13 @@ status_t MPEG4Extractor::parseChunk(off64_t *offset, int depth) { // if the chunk type is enca, we'll get the type from the frma box later mLastTrack->meta.setCString(kKeyMIMEType, FourCC2MIME(chunk_type)); AdjustChannelsAndRate(chunk_type, &num_channels, &sample_rate); if (!strcasecmp(MEDIA_MIMETYPE_AUDIO_RAW, FourCC2MIME(chunk_type))) { mLastTrack->meta.setInt32(kKeyBitsPerSample, sample_size); if (chunk_type == FOURCC('t', 'w', 'o', 's')) { mLastTrack->meta.setInt32(kKeyPcmBigEndian, 1); } } } ALOGV("*** coding='%s' %d channels, size %d, rate %d\n", chunk, num_channels, sample_size, sample_rate); Loading Loading @@ -4106,6 +4121,7 @@ MPEG4Source::MPEG4Source( mIsAVC(false), mIsHEVC(false), mIsAC4(false), mIsPcm(false), mNALLengthSize(0), mStarted(false), mGroup(NULL), Loading Loading @@ -4168,6 +4184,27 @@ MPEG4Source::MPEG4Source( mNALLengthSize = 1 + (ptr[14 + 7] & 3); } mIsPcm = !strcasecmp(mime, MEDIA_MIMETYPE_AUDIO_RAW); if (mIsPcm) { int32_t numChannels = 0; int32_t bitsPerSample = 0; CHECK(mFormat.findInt32(kKeyBitsPerSample, &bitsPerSample)); CHECK(mFormat.findInt32(kKeyChannelCount, &numChannels)); int32_t bytesPerSample = bitsPerSample >> 3; int32_t pcmSampleSize = bytesPerSample * numChannels; size_t maxSampleSize; status_t err = mSampleTable->getMaxSampleSize(&maxSampleSize); if (err != OK || maxSampleSize != static_cast<size_t>(pcmSampleSize) || bitsPerSample != 16) { // Not supported mIsPcm = false; } else { mFormat.setInt32(kKeyMaxInputSize, pcmSampleSize * kMaxPcmFrameSize); } } CHECK(format.findInt32(kKeyTrackID, &mTrackId)); } Loading Loading @@ -5082,6 +5119,49 @@ status_t MPEG4Source::read( if ((!mIsAVC && !mIsHEVC && !mIsAC4) || mWantsNALFragments) { if (newBuffer) { if (mIsPcm) { // The twos' PCM block reader assumes that all samples has the same size. uint32_t samplesToRead = mSampleTable->getLastSampleIndexInChunk() - mCurrentSampleIndex + 1; if (samplesToRead > kMaxPcmFrameSize) { samplesToRead = kMaxPcmFrameSize; } ALOGV("Reading %d PCM frames of size %zu at index %d to stop of chunk at %d", samplesToRead, size, mCurrentSampleIndex, mSampleTable->getLastSampleIndexInChunk()); size_t totalSize = samplesToRead * size; uint8_t* buf = (uint8_t *)mBuffer->data(); ssize_t bytesRead = mDataSource->readAt(offset, buf, totalSize); if (bytesRead < (ssize_t)totalSize) { mBuffer->release(); mBuffer = NULL; return ERROR_IO; } mBuffer->meta_data().clear(); mBuffer->meta_data().setInt64(kKeyTime, ((int64_t)cts * 1000000) / mTimescale); mBuffer->meta_data().setInt32(kKeyIsSyncFrame, 1); int32_t byteOrder; mFormat.findInt32(kKeyPcmBigEndian, &byteOrder); if (byteOrder == 1) { // Big-endian -> little-endian uint16_t *dstData = (uint16_t *)buf; uint16_t *srcData = (uint16_t *)buf; for (size_t j = 0; j < bytesRead / sizeof(uint16_t); j++) { dstData[j] = ntohs(srcData[j]); } } mCurrentSampleIndex += samplesToRead; mBuffer->set_range(0, totalSize); } else { ssize_t num_bytes_read = mDataSource->readAt(offset, (uint8_t *)mBuffer->data(), size); Loading Loading @@ -5111,6 +5191,7 @@ status_t MPEG4Source::read( ++mCurrentSampleIndex; } } if (!mIsAVC && !mIsHEVC && !mIsAC4) { *out = mBuffer; Loading media/extractors/mp4/SampleIterator.h +5 −0 Original line number Diff line number Diff line Loading @@ -36,6 +36,11 @@ struct SampleIterator { uint32_t getSampleTime() const { return mCurrentSampleTime; } uint32_t getSampleDuration() const { return mCurrentSampleDuration; } uint32_t getLastSampleIndexInChunk() const { return mCurrentSampleIndex + mSamplesPerChunk - ((mCurrentSampleIndex - mFirstChunkSampleIndex) % mSamplesPerChunk) - 1; } status_t getSampleSizeDirect( uint32_t sampleIndex, size_t *size); Loading media/extractors/mp4/SampleTable.cpp +5 −0 Original line number Diff line number Diff line Loading @@ -946,6 +946,11 @@ status_t SampleTable::getSampleSize_l( sampleIndex, sampleSize); } uint32_t SampleTable::getLastSampleIndexInChunk() { Mutex::Autolock autoLock(mLock); return mSampleIterator->getLastSampleIndexInChunk(); } status_t SampleTable::getMetaDataForSample( uint32_t sampleIndex, off64_t *offset, Loading media/extractors/mp4/SampleTable.h +3 −0 Original line number Diff line number Diff line Loading @@ -69,6 +69,9 @@ public: bool *isSyncSample = NULL, uint32_t *sampleDuration = NULL); // call only after getMetaDataForSample has been called successfully. uint32_t getLastSampleIndexInChunk(); enum { kFlagBefore, kFlagAfter, Loading media/libmediaextractor/include/media/stagefright/MetaDataBase.h +2 −0 Original line number Diff line number Diff line Loading @@ -53,6 +53,7 @@ enum { kKeyFrameRate = 'frmR', // int32_t (video frame rate fps) kKeyBitRate = 'brte', // int32_t (bps) kKeyMaxBitRate = 'mxBr', // int32_t (bps) kKeyBitsPerSample = 'bits', // int32_t (bits per sample) kKeyStreamHeader = 'stHd', // raw data kKeyESDS = 'esds', // raw data kKeyAACProfile = 'aacp', // int32_t Loading Loading @@ -225,6 +226,7 @@ enum { kKeyExifOffset = 'exof', // int64_t, Exif data offset kKeyExifSize = 'exsz', // int64_t, Exif data size kKeyIsExif = 'exif', // bool (int32_t) buffer contains exif data block kKeyPcmBigEndian = 'pcmb', // bool (int32_t) }; enum { Loading Loading
media/extractors/mp4/MPEG4Extractor.cpp +103 −22 Original line number Diff line number Diff line Loading @@ -68,6 +68,7 @@ enum { }; class MPEG4Source : public MediaTrack { static const size_t kMaxPcmFrameSize = 8192; public: // Caller retains ownership of both "dataSource" and "sampleTable". MPEG4Source(MetaDataBase &format, Loading Loading @@ -127,7 +128,7 @@ private: bool mIsAVC; bool mIsHEVC; bool mIsAC4; bool mIsPcm; size_t mNALLengthSize; bool mStarted; Loading Loading @@ -332,6 +333,11 @@ static const char *FourCC2MIME(uint32_t fourcc) { return MEDIA_MIMETYPE_VIDEO_HEVC; case FOURCC('a', 'c', '-', '4'): return MEDIA_MIMETYPE_AUDIO_AC4; case FOURCC('t', 'w', 'o', 's'): case FOURCC('s', 'o', 'w', 't'): return MEDIA_MIMETYPE_AUDIO_RAW; default: ALOGW("Unknown fourcc: %c%c%c%c", (fourcc >> 24) & 0xff, Loading Loading @@ -1488,6 +1494,8 @@ status_t MPEG4Extractor::parseChunk(off64_t *offset, int depth) { case FOURCC('e', 'n', 'c', 'a'): case FOURCC('s', 'a', 'm', 'r'): case FOURCC('s', 'a', 'w', 'b'): case FOURCC('t', 'w', 'o', 's'): case FOURCC('s', 'o', 'w', 't'): { if (mIsQT && chunk_type == FOURCC('m', 'p', '4', 'a') && depth >= 1 && mPath[depth - 1] == FOURCC('w', 'a', 'v', 'e')) { Loading Loading @@ -1557,6 +1565,13 @@ status_t MPEG4Extractor::parseChunk(off64_t *offset, int depth) { // if the chunk type is enca, we'll get the type from the frma box later mLastTrack->meta.setCString(kKeyMIMEType, FourCC2MIME(chunk_type)); AdjustChannelsAndRate(chunk_type, &num_channels, &sample_rate); if (!strcasecmp(MEDIA_MIMETYPE_AUDIO_RAW, FourCC2MIME(chunk_type))) { mLastTrack->meta.setInt32(kKeyBitsPerSample, sample_size); if (chunk_type == FOURCC('t', 'w', 'o', 's')) { mLastTrack->meta.setInt32(kKeyPcmBigEndian, 1); } } } ALOGV("*** coding='%s' %d channels, size %d, rate %d\n", chunk, num_channels, sample_size, sample_rate); Loading Loading @@ -4106,6 +4121,7 @@ MPEG4Source::MPEG4Source( mIsAVC(false), mIsHEVC(false), mIsAC4(false), mIsPcm(false), mNALLengthSize(0), mStarted(false), mGroup(NULL), Loading Loading @@ -4168,6 +4184,27 @@ MPEG4Source::MPEG4Source( mNALLengthSize = 1 + (ptr[14 + 7] & 3); } mIsPcm = !strcasecmp(mime, MEDIA_MIMETYPE_AUDIO_RAW); if (mIsPcm) { int32_t numChannels = 0; int32_t bitsPerSample = 0; CHECK(mFormat.findInt32(kKeyBitsPerSample, &bitsPerSample)); CHECK(mFormat.findInt32(kKeyChannelCount, &numChannels)); int32_t bytesPerSample = bitsPerSample >> 3; int32_t pcmSampleSize = bytesPerSample * numChannels; size_t maxSampleSize; status_t err = mSampleTable->getMaxSampleSize(&maxSampleSize); if (err != OK || maxSampleSize != static_cast<size_t>(pcmSampleSize) || bitsPerSample != 16) { // Not supported mIsPcm = false; } else { mFormat.setInt32(kKeyMaxInputSize, pcmSampleSize * kMaxPcmFrameSize); } } CHECK(format.findInt32(kKeyTrackID, &mTrackId)); } Loading Loading @@ -5082,6 +5119,49 @@ status_t MPEG4Source::read( if ((!mIsAVC && !mIsHEVC && !mIsAC4) || mWantsNALFragments) { if (newBuffer) { if (mIsPcm) { // The twos' PCM block reader assumes that all samples has the same size. uint32_t samplesToRead = mSampleTable->getLastSampleIndexInChunk() - mCurrentSampleIndex + 1; if (samplesToRead > kMaxPcmFrameSize) { samplesToRead = kMaxPcmFrameSize; } ALOGV("Reading %d PCM frames of size %zu at index %d to stop of chunk at %d", samplesToRead, size, mCurrentSampleIndex, mSampleTable->getLastSampleIndexInChunk()); size_t totalSize = samplesToRead * size; uint8_t* buf = (uint8_t *)mBuffer->data(); ssize_t bytesRead = mDataSource->readAt(offset, buf, totalSize); if (bytesRead < (ssize_t)totalSize) { mBuffer->release(); mBuffer = NULL; return ERROR_IO; } mBuffer->meta_data().clear(); mBuffer->meta_data().setInt64(kKeyTime, ((int64_t)cts * 1000000) / mTimescale); mBuffer->meta_data().setInt32(kKeyIsSyncFrame, 1); int32_t byteOrder; mFormat.findInt32(kKeyPcmBigEndian, &byteOrder); if (byteOrder == 1) { // Big-endian -> little-endian uint16_t *dstData = (uint16_t *)buf; uint16_t *srcData = (uint16_t *)buf; for (size_t j = 0; j < bytesRead / sizeof(uint16_t); j++) { dstData[j] = ntohs(srcData[j]); } } mCurrentSampleIndex += samplesToRead; mBuffer->set_range(0, totalSize); } else { ssize_t num_bytes_read = mDataSource->readAt(offset, (uint8_t *)mBuffer->data(), size); Loading Loading @@ -5111,6 +5191,7 @@ status_t MPEG4Source::read( ++mCurrentSampleIndex; } } if (!mIsAVC && !mIsHEVC && !mIsAC4) { *out = mBuffer; Loading
media/extractors/mp4/SampleIterator.h +5 −0 Original line number Diff line number Diff line Loading @@ -36,6 +36,11 @@ struct SampleIterator { uint32_t getSampleTime() const { return mCurrentSampleTime; } uint32_t getSampleDuration() const { return mCurrentSampleDuration; } uint32_t getLastSampleIndexInChunk() const { return mCurrentSampleIndex + mSamplesPerChunk - ((mCurrentSampleIndex - mFirstChunkSampleIndex) % mSamplesPerChunk) - 1; } status_t getSampleSizeDirect( uint32_t sampleIndex, size_t *size); Loading
media/extractors/mp4/SampleTable.cpp +5 −0 Original line number Diff line number Diff line Loading @@ -946,6 +946,11 @@ status_t SampleTable::getSampleSize_l( sampleIndex, sampleSize); } uint32_t SampleTable::getLastSampleIndexInChunk() { Mutex::Autolock autoLock(mLock); return mSampleIterator->getLastSampleIndexInChunk(); } status_t SampleTable::getMetaDataForSample( uint32_t sampleIndex, off64_t *offset, Loading
media/extractors/mp4/SampleTable.h +3 −0 Original line number Diff line number Diff line Loading @@ -69,6 +69,9 @@ public: bool *isSyncSample = NULL, uint32_t *sampleDuration = NULL); // call only after getMetaDataForSample has been called successfully. uint32_t getLastSampleIndexInChunk(); enum { kFlagBefore, kFlagAfter, Loading
media/libmediaextractor/include/media/stagefright/MetaDataBase.h +2 −0 Original line number Diff line number Diff line Loading @@ -53,6 +53,7 @@ enum { kKeyFrameRate = 'frmR', // int32_t (video frame rate fps) kKeyBitRate = 'brte', // int32_t (bps) kKeyMaxBitRate = 'mxBr', // int32_t (bps) kKeyBitsPerSample = 'bits', // int32_t (bits per sample) kKeyStreamHeader = 'stHd', // raw data kKeyESDS = 'esds', // raw data kKeyAACProfile = 'aacp', // int32_t Loading Loading @@ -225,6 +226,7 @@ enum { kKeyExifOffset = 'exof', // int64_t, Exif data offset kKeyExifSize = 'exsz', // int64_t, Exif data size kKeyIsExif = 'exif', // bool (int32_t) buffer contains exif data block kKeyPcmBigEndian = 'pcmb', // bool (int32_t) }; enum { Loading