Fix no sound with FDR-AX100 recorded 4k video
1.Pcm(twos and sowt) parsing support in MPEG4Extractor
2.Pcm data reading from SampleTable support
Bug: 80501047
Test: Play XAVC-S Video and check if the audio is heard
Change-Id: I5edc7f1920c80e23dfdb069259d19e28240799b5
diff --git a/media/extractors/mp4/MPEG4Extractor.cpp b/media/extractors/mp4/MPEG4Extractor.cpp
index 8412812..d10d0d6 100644
--- a/media/extractors/mp4/MPEG4Extractor.cpp
+++ b/media/extractors/mp4/MPEG4Extractor.cpp
@@ -68,6 +68,7 @@
};
class MPEG4Source : public MediaTrack {
+static const size_t kMaxPcmFrameSize = 8192;
public:
// Caller retains ownership of both "dataSource" and "sampleTable".
MPEG4Source(MetaDataBase &format,
@@ -127,7 +128,7 @@
bool mIsAVC;
bool mIsHEVC;
bool mIsAC4;
-
+ bool mIsPcm;
size_t mNALLengthSize;
bool mStarted;
@@ -329,6 +330,11 @@
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,
@@ -1478,6 +1484,8 @@
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')) {
@@ -1547,6 +1555,13 @@
// 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);
@@ -3947,6 +3962,7 @@
mIsAVC(false),
mIsHEVC(false),
mIsAC4(false),
+ mIsPcm(false),
mNALLengthSize(0),
mStarted(false),
mGroup(NULL),
@@ -4009,6 +4025,27 @@
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));
}
@@ -4923,34 +4960,78 @@
if ((!mIsAVC && !mIsHEVC && !mIsAC4) || mWantsNALFragments) {
if (newBuffer) {
- ssize_t num_bytes_read =
- mDataSource->readAt(offset, (uint8_t *)mBuffer->data(), size);
+ if (mIsPcm) {
+ // The twos' PCM block reader assumes that all samples has the same size.
- if (num_bytes_read < (ssize_t)size) {
- mBuffer->release();
- mBuffer = NULL;
+ uint32_t samplesToRead = mSampleTable->getLastSampleIndexInChunk()
+ - mCurrentSampleIndex + 1;
+ if (samplesToRead > kMaxPcmFrameSize) {
+ samplesToRead = kMaxPcmFrameSize;
+ }
- return ERROR_IO;
- }
+ ALOGV("Reading %d PCM frames of size %zu at index %d to stop of chunk at %d",
+ samplesToRead, size, mCurrentSampleIndex,
+ mSampleTable->getLastSampleIndexInChunk());
- CHECK(mBuffer != NULL);
- mBuffer->set_range(0, size);
- mBuffer->meta_data().clear();
- mBuffer->meta_data().setInt64(
- kKeyTime, ((int64_t)cts * 1000000) / mTimescale);
- mBuffer->meta_data().setInt64(
- kKeyDuration, ((int64_t)stts * 1000000) / mTimescale);
+ 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;
- if (targetSampleTimeUs >= 0) {
- mBuffer->meta_data().setInt64(
- kKeyTargetTime, targetSampleTimeUs);
- }
+ return ERROR_IO;
+ }
- if (isSyncSample) {
+ mBuffer->meta_data().clear();
+ mBuffer->meta_data().setInt64(kKeyTime, ((int64_t)cts * 1000000) / mTimescale);
mBuffer->meta_data().setInt32(kKeyIsSyncFrame, 1);
- }
- ++mCurrentSampleIndex;
+ 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);
+
+ if (num_bytes_read < (ssize_t)size) {
+ mBuffer->release();
+ mBuffer = NULL;
+
+ return ERROR_IO;
+ }
+
+ CHECK(mBuffer != NULL);
+ mBuffer->set_range(0, size);
+ mBuffer->meta_data().clear();
+ mBuffer->meta_data().setInt64(
+ kKeyTime, ((int64_t)cts * 1000000) / mTimescale);
+ mBuffer->meta_data().setInt64(
+ kKeyDuration, ((int64_t)stts * 1000000) / mTimescale);
+
+ if (targetSampleTimeUs >= 0) {
+ mBuffer->meta_data().setInt64(
+ kKeyTargetTime, targetSampleTimeUs);
+ }
+
+ if (isSyncSample) {
+ mBuffer->meta_data().setInt32(kKeyIsSyncFrame, 1);
+ }
+
+ ++mCurrentSampleIndex;
+ }
}
if (!mIsAVC && !mIsHEVC && !mIsAC4) {
diff --git a/media/extractors/mp4/SampleIterator.h b/media/extractors/mp4/SampleIterator.h
index 6a3fd3b..6e4f60e 100644
--- a/media/extractors/mp4/SampleIterator.h
+++ b/media/extractors/mp4/SampleIterator.h
@@ -36,6 +36,11 @@
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);
diff --git a/media/extractors/mp4/SampleTable.cpp b/media/extractors/mp4/SampleTable.cpp
index 81c353e..28fe717 100644
--- a/media/extractors/mp4/SampleTable.cpp
+++ b/media/extractors/mp4/SampleTable.cpp
@@ -946,6 +946,11 @@
sampleIndex, sampleSize);
}
+uint32_t SampleTable::getLastSampleIndexInChunk() {
+ Mutex::Autolock autoLock(mLock);
+ return mSampleIterator->getLastSampleIndexInChunk();
+}
+
status_t SampleTable::getMetaDataForSample(
uint32_t sampleIndex,
off64_t *offset,
diff --git a/media/extractors/mp4/SampleTable.h b/media/extractors/mp4/SampleTable.h
index e4e974b..dd68860 100644
--- a/media/extractors/mp4/SampleTable.h
+++ b/media/extractors/mp4/SampleTable.h
@@ -69,6 +69,9 @@
bool *isSyncSample = NULL,
uint32_t *sampleDuration = NULL);
+ // call only after getMetaDataForSample has been called successfully.
+ uint32_t getLastSampleIndexInChunk();
+
enum {
kFlagBefore,
kFlagAfter,