Extract AudioPresentations from AC4 in MP4 and TS
Translates MPEG-4 AC4 DSI AC4Presentations to AudioPresentation.
Parses MPEG2-TS audio preselection descriptors from MPEG2-TS.
Adds AudioPresentationInfo interface to native MediaExtractor.
Test: Manually test
Bug: 119312182
Change-Id: I61286b38543e114aeaef331aa013bc2d2d7626c3
diff --git a/include/media/AudioPresentationInfo.h b/include/media/AudioPresentationInfo.h
deleted file mode 100644
index e91a992..0000000
--- a/include/media/AudioPresentationInfo.h
+++ /dev/null
@@ -1,79 +0,0 @@
-/*
- * Copyright (C) 2018 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#ifndef AUDIO_PRESENTATION_INFO_H_
-#define AUDIO_PRESENTATION_INFO_H_
-
-#include <sstream>
-#include <stdint.h>
-
-#include <utils/KeyedVector.h>
-#include <utils/RefBase.h>
-#include <utils/String8.h>
-#include <utils/Vector.h>
-
-namespace android {
-
-enum mastering_indication {
- MASTERING_NOT_INDICATED,
- MASTERED_FOR_STEREO,
- MASTERED_FOR_SURROUND,
- MASTERED_FOR_3D,
- MASTERED_FOR_HEADPHONE,
-};
-
-struct AudioPresentation : public RefBase {
- int32_t mPresentationId;
- int32_t mProgramId;
- KeyedVector<String8, String8> mLabels;
- String8 mLanguage;
- int32_t mMasteringIndication;
- bool mAudioDescriptionAvailable;
- bool mSpokenSubtitlesAvailable;
- bool mDialogueEnhancementAvailable;
-
- AudioPresentation() {
- mPresentationId = -1;
- mProgramId = -1;
- mLanguage = "";
- mMasteringIndication = MASTERING_NOT_INDICATED;
- mAudioDescriptionAvailable = false;
- mSpokenSubtitlesAvailable = false;
- mDialogueEnhancementAvailable = false;
- }
-};
-
-typedef Vector<sp<AudioPresentation>> AudioPresentations;
-
-class AudioPresentationInfo : public RefBase {
- public:
- AudioPresentationInfo();
-
- ~AudioPresentationInfo();
-
- void addPresentation(sp<AudioPresentation> presentation);
-
- size_t countPresentations() const;
-
- const sp<AudioPresentation> getPresentation(size_t index) const;
-
- private:
- AudioPresentations mPresentations;
-};
-
-} // namespace android
-
-#endif // AUDIO_PRESENTATION_INFO_H_
diff --git a/media/extractors/mp4/MPEG4Extractor.cpp b/media/extractors/mp4/MPEG4Extractor.cpp
index c3bdc92..337ff2a 100644
--- a/media/extractors/mp4/MPEG4Extractor.cpp
+++ b/media/extractors/mp4/MPEG4Extractor.cpp
@@ -38,6 +38,7 @@
#include <media/stagefright/foundation/ABuffer.h>
#include <media/stagefright/foundation/ADebug.h>
#include <media/stagefright/foundation/AMessage.h>
+#include <media/stagefright/foundation/AudioPresentationInfo.h>
#include <media/stagefright/foundation/AUtils.h>
#include <media/stagefright/foundation/ByteUtils.h>
#include <media/stagefright/foundation/ColorUtils.h>
@@ -2753,6 +2754,75 @@
AMediaFormat_setString(mLastTrack->meta, AMEDIAFORMAT_KEY_MIME, MEDIA_MIMETYPE_AUDIO_AC4);
AMediaFormat_setInt32(mLastTrack->meta, AMEDIAFORMAT_KEY_CHANNEL_COUNT, channelCount);
AMediaFormat_setInt32(mLastTrack->meta, AMEDIAFORMAT_KEY_SAMPLE_RATE, sampleRate);
+
+ AudioPresentationCollection presentations;
+ // translate the AC4 presentation information to audio presentations for this track
+ AC4DSIParser::AC4Presentations ac4Presentations = parser.getPresentations();
+ if (!ac4Presentations.empty()) {
+ for (const auto& ac4Presentation : ac4Presentations) {
+ auto& presentation = ac4Presentation.second;
+ if (!presentation.mEnabled) {
+ continue;
+ }
+ AudioPresentationV1 ap;
+ ap.mPresentationId = presentation.mGroupIndex;
+ ap.mProgramId = presentation.mProgramID;
+ ap.mLanguage = presentation.mLanguage;
+ if (presentation.mPreVirtualized) {
+ ap.mMasteringIndication = MASTERED_FOR_HEADPHONE;
+ } else {
+ switch (presentation.mChannelMode) {
+ case AC4Parser::AC4Presentation::kChannelMode_Mono:
+ case AC4Parser::AC4Presentation::kChannelMode_Stereo:
+ ap.mMasteringIndication = MASTERED_FOR_STEREO;
+ break;
+ case AC4Parser::AC4Presentation::kChannelMode_3_0:
+ case AC4Parser::AC4Presentation::kChannelMode_5_0:
+ case AC4Parser::AC4Presentation::kChannelMode_5_1:
+ case AC4Parser::AC4Presentation::kChannelMode_7_0_34:
+ case AC4Parser::AC4Presentation::kChannelMode_7_1_34:
+ case AC4Parser::AC4Presentation::kChannelMode_7_0_52:
+ case AC4Parser::AC4Presentation::kChannelMode_7_1_52:
+ ap.mMasteringIndication = MASTERED_FOR_SURROUND;
+ break;
+ case AC4Parser::AC4Presentation::kChannelMode_7_0_322:
+ case AC4Parser::AC4Presentation::kChannelMode_7_1_322:
+ case AC4Parser::AC4Presentation::kChannelMode_7_0_4:
+ case AC4Parser::AC4Presentation::kChannelMode_7_1_4:
+ case AC4Parser::AC4Presentation::kChannelMode_9_0_4:
+ case AC4Parser::AC4Presentation::kChannelMode_9_1_4:
+ case AC4Parser::AC4Presentation::kChannelMode_22_2:
+ ap.mMasteringIndication = MASTERED_FOR_3D;
+ break;
+ default:
+ ALOGE("Invalid channel mode in AC4 presentation");
+ return ERROR_MALFORMED;
+ }
+ }
+
+ ap.mAudioDescriptionAvailable = (presentation.mContentClassifier ==
+ AC4Parser::AC4Presentation::kVisuallyImpaired);
+ ap.mSpokenSubtitlesAvailable = (presentation.mContentClassifier ==
+ AC4Parser::AC4Presentation::kVoiceOver);
+ ap.mDialogueEnhancementAvailable = presentation.mHasDialogEnhancements;
+ if (!ap.mLanguage.empty()) {
+ ap.mLabels.emplace(ap.mLanguage, presentation.mDescription);
+ }
+ presentations.push_back(std::move(ap));
+ }
+ }
+
+ if (presentations.empty()) {
+ // Clear audio presentation info in metadata.
+ AMediaFormat_setBuffer(
+ mLastTrack->meta, AMEDIAFORMAT_KEY_AUDIO_PRESENTATION_INFO, nullptr, 0);
+ } else {
+ std::ostringstream outStream(std::ios::out);
+ serializeAudioPresentations(presentations, &outStream);
+ AMediaFormat_setBuffer(
+ mLastTrack->meta, AMEDIAFORMAT_KEY_AUDIO_PRESENTATION_INFO,
+ outStream.str().data(), outStream.str().size());
+ }
return OK;
}
diff --git a/media/libmediaextractor/include/media/stagefright/MetaDataBase.h b/media/libmediaextractor/include/media/stagefright/MetaDataBase.h
index 72efcdf..9f2deda 100644
--- a/media/libmediaextractor/include/media/stagefright/MetaDataBase.h
+++ b/media/libmediaextractor/include/media/stagefright/MetaDataBase.h
@@ -225,6 +225,9 @@
// Key for ALAC Magic Cookie
kKeyAlacMagicCookie = 'almc', // raw data
+
+ // AC-4 AudioPresentationInfo
+ kKeyAudioPresentationInfo = 'audP', // raw data
};
enum {
diff --git a/media/libstagefright/Android.bp b/media/libstagefright/Android.bp
index d96d358..55b0862 100644
--- a/media/libstagefright/Android.bp
+++ b/media/libstagefright/Android.bp
@@ -96,7 +96,6 @@
"AHierarchicalStateMachine.cpp",
"AMRWriter.cpp",
"AudioPlayer.cpp",
- "AudioPresentationInfo.cpp",
"AudioSource.cpp",
"BufferImpl.cpp",
"CallbackDataSource.cpp",
diff --git a/media/libstagefright/AudioPresentationInfo.cpp b/media/libstagefright/AudioPresentationInfo.cpp
deleted file mode 100644
index 86e1859..0000000
--- a/media/libstagefright/AudioPresentationInfo.cpp
+++ /dev/null
@@ -1,45 +0,0 @@
-/*
- * Copyright (C) 2018 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-// #define LOG_NDEBUG 0
-#define LOG_TAG "AudioPresentationInfo"
-
-#include <media/AudioPresentationInfo.h>
-
-namespace android {
-
-AudioPresentationInfo::AudioPresentationInfo() {
-}
-
-AudioPresentationInfo::~AudioPresentationInfo() {
- mPresentations.clear();
-}
-
-void AudioPresentationInfo::addPresentation(sp<AudioPresentation> presentation) {
- mPresentations.push(presentation);
-}
-
-size_t AudioPresentationInfo::countPresentations() const {
- return mPresentations.size();
-}
-
-// Returns an AudioPresentation for the given valid index
-// index must be >=0 and < countPresentations()
-const sp<AudioPresentation> AudioPresentationInfo::getPresentation(size_t index) const {
- return mPresentations[index];
-}
-
-} // namespace android
diff --git a/media/libstagefright/NuMediaExtractor.cpp b/media/libstagefright/NuMediaExtractor.cpp
index f94648c..f5178dd 100644
--- a/media/libstagefright/NuMediaExtractor.cpp
+++ b/media/libstagefright/NuMediaExtractor.cpp
@@ -794,4 +794,32 @@
return false;
}
+// Return OK if we have received an audio presentation info.
+// Return ERROR_UNSUPPORTED if the track has no audio presentation.
+// Return INVALID_OPERATION if audio presentation metadata version does not match.
+status_t NuMediaExtractor::getAudioPresentations(
+ size_t trackIndex, AudioPresentationCollection *presentations) const {
+ Mutex::Autolock autoLock(mLock);
+
+ if (mImpl == NULL) {
+ return -EINVAL;
+ }
+
+ if (trackIndex >= mImpl->countTracks()) {
+ return -ERANGE;
+ }
+
+ sp<MetaData> meta = mImpl->getTrackMetaData(trackIndex);
+
+ uint32_t type;
+ const void *data;
+ size_t size;
+ if (meta != NULL && meta->findData(kKeyAudioPresentationInfo, &type, &data, &size)) {
+ std::istringstream inStream(std::string(static_cast<const char*>(data), size));
+ return deserializeAudioPresentations(&inStream, presentations);
+ }
+ ALOGE("Source does not contain any audio presentation");
+ return ERROR_UNSUPPORTED;
+}
+
} // namespace android
diff --git a/media/libstagefright/Utils.cpp b/media/libstagefright/Utils.cpp
index 4aee9d5..53c32b2 100644
--- a/media/libstagefright/Utils.cpp
+++ b/media/libstagefright/Utils.cpp
@@ -615,6 +615,7 @@
static std::vector<std::pair<const char *, uint32_t>> bufferMappings {
{
{ "albumart", kKeyAlbumArt },
+ { "audio-presentation-info", kKeyAudioPresentationInfo },
{ "pssh", kKeyPssh },
{ "crypto-iv", kKeyCryptoIV },
{ "crypto-key", kKeyCryptoKey },
diff --git a/media/libstagefright/foundation/Android.bp b/media/libstagefright/foundation/Android.bp
index 5b7961d..861528e 100644
--- a/media/libstagefright/foundation/Android.bp
+++ b/media/libstagefright/foundation/Android.bp
@@ -61,6 +61,7 @@
"AMessage.cpp",
"AString.cpp",
"AStringUtils.cpp",
+ "AudioPresentationInfo.cpp",
"ByteUtils.cpp",
"ColorUtils.cpp",
"MediaDefs.cpp",
diff --git a/media/libstagefright/foundation/AudioPresentationInfo.cpp b/media/libstagefright/foundation/AudioPresentationInfo.cpp
new file mode 100644
index 0000000..4b8e969
--- /dev/null
+++ b/media/libstagefright/foundation/AudioPresentationInfo.cpp
@@ -0,0 +1,136 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+// #define LOG_NDEBUG 0
+#define LOG_TAG "AudioPresentationInfo"
+
+#include <vector>
+
+#include "AudioPresentationInfo.h"
+
+#include <utils/Log.h>
+
+namespace android {
+
+void serializeAudioPresentations(const AudioPresentationCollection& presentations,
+ std::ostream* serializedOutput) {
+ uint32_t numPresentations = presentations.size();
+ serializedOutput->write(reinterpret_cast<char*>(&numPresentations), sizeof(numPresentations));
+ for (const auto& ap : presentations) {
+ if (ap.mVersion == PRESENTATION_VERSION_1) {
+ serializedOutput->write(
+ const_cast<char*>(reinterpret_cast<const char*>(&ap.mVersion)),
+ sizeof(ap.mVersion));
+ serializedOutput->write(
+ const_cast<char*>(reinterpret_cast<const char*>(&ap.mPresentationId)),
+ sizeof(ap.mPresentationId));
+ serializedOutput->write(
+ const_cast<char*>(reinterpret_cast<const char*>(&ap.mProgramId)),
+ sizeof(ap.mProgramId));
+
+ uint32_t numLabels = ap.mLabels.size();
+ serializedOutput->write(
+ const_cast<char*>(reinterpret_cast<const char*>(&numLabels)),
+ sizeof(numLabels));
+ for (const auto& label : ap.mLabels) {
+ uint32_t labelKeySize = label.first.size();
+ serializedOutput->write(
+ const_cast<char*>(reinterpret_cast<const char*>(&labelKeySize)),
+ sizeof(labelKeySize));
+ serializedOutput->write(label.first.c_str(), labelKeySize);
+
+ uint32_t labelValSize = label.second.size();
+ serializedOutput->write(
+ const_cast<char*>(reinterpret_cast<const char*>(&labelValSize)),
+ sizeof(labelValSize));
+ serializedOutput->write(label.second.c_str(), labelValSize);
+ }
+
+ uint32_t langSize = ap.mLanguage.size();
+ serializedOutput->write(
+ const_cast<char*>(reinterpret_cast<const char*>(&langSize)),
+ sizeof(langSize));
+ serializedOutput->write(ap.mLanguage.c_str(), langSize);
+
+ serializedOutput->write(
+ const_cast<char*>(reinterpret_cast<const char*>(&ap.mMasteringIndication)),
+ sizeof(ap.mMasteringIndication));
+ serializedOutput->write(
+ const_cast<char*>(reinterpret_cast<const char*>(&ap.mAudioDescriptionAvailable)),
+ sizeof(ap.mAudioDescriptionAvailable));
+ serializedOutput->write(
+ const_cast<char*>(reinterpret_cast<const char*>(&ap.mSpokenSubtitlesAvailable)),
+ sizeof(ap.mSpokenSubtitlesAvailable));
+ serializedOutput->write(
+ const_cast<char*>(reinterpret_cast<const char*>(&ap.mDialogueEnhancementAvailable)),
+ sizeof(ap.mDialogueEnhancementAvailable));
+ }
+ }
+}
+
+status_t deserializeAudioPresentations(std::istream* serializedInput,
+ AudioPresentationCollection *presentations) {
+ uint32_t numPresentations;
+ serializedInput->read(reinterpret_cast<char*>(&numPresentations), sizeof(numPresentations));
+ for (uint32_t i = 0; i < numPresentations; ++i) {
+ uint32_t version;
+ serializedInput->read(reinterpret_cast<char*>(&version), sizeof(version));
+ if (version == PRESENTATION_VERSION_1) {
+ AudioPresentationV1 ap;
+ serializedInput->read(
+ reinterpret_cast<char*>(&ap.mPresentationId),
+ sizeof(ap.mPresentationId));
+ serializedInput->read(reinterpret_cast<char*>(&ap.mProgramId), sizeof(ap.mProgramId));
+
+ uint32_t numLabels;
+ serializedInput->read(reinterpret_cast<char*>(&numLabels), sizeof(numLabels));
+ for (uint32_t j = 0; j < numLabels; ++j) {
+ uint32_t labelKeySize;
+ serializedInput->read(reinterpret_cast<char*>(&labelKeySize), sizeof(labelKeySize));
+ std::vector<char> labelKey(labelKeySize);
+ serializedInput->read(labelKey.data(), labelKeySize);
+
+ uint32_t labelValSize;
+ serializedInput->read(reinterpret_cast<char*>(&labelValSize), sizeof(labelValSize));
+ std::vector<char> labelVal(labelValSize);
+ serializedInput->read(labelVal.data(), labelValSize);
+ ap.mLabels.emplace(
+ std::string(reinterpret_cast<char*>(labelKey.data()), labelKeySize),
+ std::string(reinterpret_cast<char*>(labelVal.data()), labelValSize));
+ }
+ uint32_t languageSize;
+ serializedInput->read(reinterpret_cast<char*>(&languageSize), sizeof(languageSize));
+ std::vector<char> language(languageSize);
+ serializedInput->read(language.data(), languageSize);
+ ap.mLanguage = std::string(reinterpret_cast<char*>(language.data()), languageSize);
+ serializedInput->read(reinterpret_cast<char*>(&ap.mMasteringIndication),
+ sizeof(ap.mMasteringIndication));
+ serializedInput->read(reinterpret_cast<char*>(&ap.mAudioDescriptionAvailable),
+ sizeof(ap.mAudioDescriptionAvailable));
+ serializedInput->read(reinterpret_cast<char*>(&ap.mSpokenSubtitlesAvailable),
+ sizeof(ap.mSpokenSubtitlesAvailable));
+ serializedInput->read(reinterpret_cast<char*>(&ap.mDialogueEnhancementAvailable),
+ sizeof(ap.mDialogueEnhancementAvailable));
+ presentations->push_back(std::move(ap));
+ } else {
+ ALOGE("Audio presentation info version is not supported");
+ return INVALID_OPERATION;
+ }
+ }
+ return OK;
+}
+
+} // namespace android
diff --git a/media/libstagefright/foundation/include/media/stagefright/foundation/AudioPresentationInfo.h b/media/libstagefright/foundation/include/media/stagefright/foundation/AudioPresentationInfo.h
new file mode 100644
index 0000000..4bd4d9f
--- /dev/null
+++ b/media/libstagefright/foundation/include/media/stagefright/foundation/AudioPresentationInfo.h
@@ -0,0 +1,68 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef AUDIO_PRESENTATION_INFO_H_
+#define AUDIO_PRESENTATION_INFO_H_
+
+#include <map>
+#include <sstream>
+#include <stdint.h>
+#include <vector>
+
+#include <utils/Errors.h>
+
+namespace android {
+
+enum AudioPresentationVersion {
+ PRESENTATION_VERSION_UNDEFINED = 0,
+ PRESENTATION_VERSION_1,
+};
+
+enum MasteringIndication {
+ MASTERING_NOT_INDICATED,
+ MASTERED_FOR_STEREO,
+ MASTERED_FOR_SURROUND,
+ MASTERED_FOR_3D,
+ MASTERED_FOR_HEADPHONE,
+};
+
+struct AudioPresentation {
+ uint32_t mVersion = PRESENTATION_VERSION_UNDEFINED;
+ int32_t mPresentationId = -1;
+ int32_t mProgramId = -1;
+ std::map<std::string, std::string> mLabels;
+ std::string mLanguage;
+ MasteringIndication mMasteringIndication = MASTERING_NOT_INDICATED;
+ bool mAudioDescriptionAvailable = false;
+ bool mSpokenSubtitlesAvailable = false;
+ bool mDialogueEnhancementAvailable = false;
+};
+
+struct AudioPresentationV1 : public AudioPresentation {
+ AudioPresentationV1() {
+ mVersion = PRESENTATION_VERSION_1;
+ }
+};
+
+typedef std::vector<AudioPresentation> AudioPresentationCollection;
+
+void serializeAudioPresentations(const AudioPresentationCollection& presentations,
+ std::ostream* serializedOutput);
+status_t deserializeAudioPresentations(std::istream* serializedInput,
+ AudioPresentationCollection *presentations);
+} // namespace android
+
+#endif // AUDIO_PRESENTATION_INFO_H_
diff --git a/media/libstagefright/include/media/stagefright/NuMediaExtractor.h b/media/libstagefright/include/media/stagefright/NuMediaExtractor.h
index 641ccfa..8dc8d38 100644
--- a/media/libstagefright/include/media/stagefright/NuMediaExtractor.h
+++ b/media/libstagefright/include/media/stagefright/NuMediaExtractor.h
@@ -20,6 +20,7 @@
#include <list>
#include <media/mediaplayer.h>
#include <media/stagefright/foundation/ABase.h>
+#include <media/stagefright/foundation/AudioPresentationInfo.h>
#include <media/IMediaExtractor.h>
#include <media/MediaSource.h>
#include <utils/Errors.h>
@@ -95,6 +96,9 @@
bool getCachedDuration(int64_t *durationUs, bool *eos) const;
+ status_t getAudioPresentations(size_t trackIdx,
+ AudioPresentationCollection *presentations) const;
+
protected:
virtual ~NuMediaExtractor();
diff --git a/media/libstagefright/mpeg2ts/ATSParser.cpp b/media/libstagefright/mpeg2ts/ATSParser.cpp
index aa4a4db..cf93fcf 100644
--- a/media/libstagefright/mpeg2ts/ATSParser.cpp
+++ b/media/libstagefright/mpeg2ts/ATSParser.cpp
@@ -210,6 +210,7 @@
sp<ABuffer> mDescrambledBuffer;
List<SubSampleInfo> mSubSamples;
sp<IDescrambler> mDescrambler;
+ AudioPresentationCollection mAudioPresentations;
// Flush accumulated payload if necessary --- i.e. at EOS or at the start of
// another payload. event is set if the flushed payload is PES with a sync
@@ -525,6 +526,8 @@
CADescriptor streamCA;
info.mTypeExt = EXT_DESCRIPTOR_DVB_RESERVED_MAX;
+
+ info.mAudioPresentations.clear();
bool hasStreamCA = false;
while (ES_info_length > 2 && infoBytesRemaining >= 0) {
unsigned descriptor_tag = br->getBits(8);
@@ -549,12 +552,94 @@
descriptor_tag == DESCRIPTOR_DVB_EXTENSION && descriptor_length >= 1) {
unsigned descTagExt = br->getBits(8);
ALOGV(" tag_ext = 0x%02x", descTagExt);
- if (descTagExt == EXT_DESCRIPTOR_DVB_AC4) {
- info.mTypeExt = EXT_DESCRIPTOR_DVB_AC4;
- }
ES_info_length -= descriptor_length;
descriptor_length--;
- br->skipBits(descriptor_length * 8);
+ // The AC4 descriptor is used in the PSI PMT to identify streams which carry AC4
+ // audio.
+ if (descTagExt == EXT_DESCRIPTOR_DVB_AC4) {
+ info.mTypeExt = EXT_DESCRIPTOR_DVB_AC4;
+ br->skipBits(descriptor_length * 8);
+ } else if (descTagExt == EXT_DESCRIPTOR_DVB_AUDIO_PRESELECTION &&
+ descriptor_length >= 1) {
+ // DVB BlueBook A038 Table 110
+ unsigned num_preselections = br->getBits(5);
+ br->skipBits(3); // reserved
+ for (unsigned i = 0; i < num_preselections; ++i) {
+ if (br->numBitsLeft() < 16) {
+ ALOGE("Not enough data left in bitreader!");
+ return ERROR_MALFORMED;
+ }
+ AudioPresentationV1 ap;
+ ap.mPresentationId = br->getBits(5); // preselection_id
+
+ // audio_rendering_indication
+ ap.mMasteringIndication = static_cast<MasteringIndication>(br->getBits(3));
+ ap.mAudioDescriptionAvailable = (br->getBits(1) == 1);
+ ap.mSpokenSubtitlesAvailable = (br->getBits(1) == 1);
+ ap.mDialogueEnhancementAvailable = (br->getBits(1) == 1);
+
+ bool interactivity_enabled = (br->getBits(1) == 1);
+ MY_LOGV(" interactivity_enabled = %d", interactivity_enabled);
+
+ bool language_code_present = (br->getBits(1) == 1);
+ bool text_label_present = (br->getBits(1) == 1);
+
+ bool multi_stream_info_present = (br->getBits(1) == 1);
+ bool future_extension = (br->getBits(1) == 1);
+ if (language_code_present) {
+ if (br->numBitsLeft() < 24) {
+ ALOGE("Not enough data left in bitreader!");
+ return ERROR_MALFORMED;
+ }
+ char language[4];
+ language[0] = br->getBits(8);
+ language[1] = br->getBits(8);
+ language[2] = br->getBits(8);
+ language[3] = 0;
+ ap.mLanguage = String8(language);
+ }
+
+ // This maps the presentation id to the message id in the
+ // EXT_DESCRIPTOR_DVB_MESSAGE so that we can get the presentation label.
+ if (text_label_present) {
+ if (br->numBitsLeft() < 8) {
+ ALOGE("Not enough data left in bitreader!");
+ return ERROR_MALFORMED;
+ }
+ unsigned message_id = br->getBits(8);
+ MY_LOGV(" message_id = %u", message_id);
+ }
+
+ if (multi_stream_info_present) {
+ if (br->numBitsLeft() < 8) {
+ ALOGE("Not enough data left in bitreader!");
+ return ERROR_MALFORMED;
+ }
+ unsigned num_aux_components = br->getBits(3);
+ br->skipBits(5); // reserved
+ if (br->numBitsLeft() < (num_aux_components * 8)) {
+ ALOGE("Not enough data left in bitreader!");
+ return ERROR_MALFORMED;
+ }
+ br->skipBits(num_aux_components * 8); // component_tag
+ }
+ if (future_extension) {
+ if (br->numBitsLeft() < 8) {
+ return ERROR_MALFORMED;
+ }
+ br->skipBits(3); // reserved
+ unsigned future_extension_length = br->getBits(5);
+ if (br->numBitsLeft() < (future_extension_length * 8)) {
+ ALOGE("Not enough data left in bitreader!");
+ return ERROR_MALFORMED;
+ }
+ br->skipBits(future_extension_length * 8); // future_extension_byte
+ }
+ info.mAudioPresentations.push_back(std::move(ap));
+ }
+ } else {
+ br->skipBits(descriptor_length * 8);
+ }
} else {
ES_info_length -= descriptor_length;
br->skipBits(descriptor_length * 8);
@@ -754,7 +839,8 @@
mEOSReached(false),
mPrevPTS(0),
mQueue(NULL),
- mScrambled(info.mCADescriptor.mSystemID >= 0) {
+ mScrambled(info.mCADescriptor.mSystemID >= 0),
+ mAudioPresentations(info.mAudioPresentations) {
mSampleEncrypted =
mStreamType == STREAMTYPE_H264_ENCRYPTED ||
mStreamType == STREAMTYPE_AAC_ENCRYPTED ||
@@ -1633,6 +1719,7 @@
}
mSource = new AnotherPacketSource(meta);
mSource->queueAccessUnit(accessUnit);
+ mSource->convertAudioPresentationInfoToMetadata(mAudioPresentations);
ALOGV("onPayloadData: created AnotherPacketSource PID 0x%08x of type 0x%02x",
mElementaryPID, mStreamType);
}
diff --git a/media/libstagefright/mpeg2ts/ATSParser.h b/media/libstagefright/mpeg2ts/ATSParser.h
index 9ece21e..0ff2d7e 100644
--- a/media/libstagefright/mpeg2ts/ATSParser.h
+++ b/media/libstagefright/mpeg2ts/ATSParser.h
@@ -23,6 +23,7 @@
#include <media/MediaSource.h>
#include <media/stagefright/foundation/ABase.h>
#include <media/stagefright/foundation/AMessage.h>
+#include <media/stagefright/foundation/AudioPresentationInfo.h>
#include <utils/KeyedVector.h>
#include <utils/Vector.h>
#include <utils/RefBase.h>
@@ -163,7 +164,7 @@
};
enum {
- // From ISO/IEC 13818-1: 2007 (E), Table 2-29
+ // From ISO/IEC 13818-1: 2007 (E), Table 2-45
DESCRIPTOR_CA = 0x09,
// DVB BlueBook A038 Table 12
@@ -172,8 +173,9 @@
// DVB BlueBook A038 Table 109
enum {
- EXT_DESCRIPTOR_DVB_AC4 = 0x15,
- EXT_DESCRIPTOR_DVB_RESERVED_MAX = 0x7F,
+ EXT_DESCRIPTOR_DVB_AC4 = 0x15,
+ EXT_DESCRIPTOR_DVB_AUDIO_PRESELECTION = 0x19,
+ EXT_DESCRIPTOR_DVB_RESERVED_MAX = 0x7F,
};
protected:
@@ -196,6 +198,7 @@
unsigned mTypeExt;
unsigned mPID;
CADescriptor mCADescriptor;
+ AudioPresentationCollection mAudioPresentations;
};
sp<CasManager> mCasManager;
diff --git a/media/libstagefright/mpeg2ts/AnotherPacketSource.cpp b/media/libstagefright/mpeg2ts/AnotherPacketSource.cpp
index 9e154a3..e2c5031 100644
--- a/media/libstagefright/mpeg2ts/AnotherPacketSource.cpp
+++ b/media/libstagefright/mpeg2ts/AnotherPacketSource.cpp
@@ -697,4 +697,23 @@
return firstMeta;
}
+void AnotherPacketSource::convertAudioPresentationInfoToMetadata(
+ const AudioPresentationCollection& presentations) {
+ sp<MetaData> meta = getFormat();
+ if (meta == NULL) {
+ return;
+ }
+ if (presentations.empty()) {
+ // Clear audio presentation info in metadata.
+ Mutex::Autolock autoLock(mLock);
+ meta->remove(kKeyAudioPresentationInfo);
+ } else {
+ std::ostringstream outStream(std::ios::out);
+ serializeAudioPresentations(presentations, &outStream);
+ Mutex::Autolock autoLock(mLock);
+ meta->setData(kKeyAudioPresentationInfo, MetaData::TYPE_NONE,
+ outStream.str().data(), outStream.str().size());
+ }
+}
+
} // namespace android
diff --git a/media/libstagefright/mpeg2ts/AnotherPacketSource.h b/media/libstagefright/mpeg2ts/AnotherPacketSource.h
index f4a6acb..57a6c33 100644
--- a/media/libstagefright/mpeg2ts/AnotherPacketSource.h
+++ b/media/libstagefright/mpeg2ts/AnotherPacketSource.h
@@ -85,6 +85,8 @@
void trimBuffersAfterMeta(const sp<AMessage> &meta);
sp<AMessage> trimBuffersBeforeMeta(const sp<AMessage> &meta);
+ void convertAudioPresentationInfoToMetadata(const AudioPresentationCollection &presentations);
+
protected:
virtual ~AnotherPacketSource();
diff --git a/media/ndk/NdkMediaFormat.cpp b/media/ndk/NdkMediaFormat.cpp
index b282ed8..bf9725c 100644
--- a/media/ndk/NdkMediaFormat.cpp
+++ b/media/ndk/NdkMediaFormat.cpp
@@ -272,6 +272,7 @@
EXPORT const char* AMEDIAFORMAT_KEY_ALBUMART = "albumart";
EXPORT const char* AMEDIAFORMAT_KEY_ALBUMARTIST = "albumartist";
EXPORT const char* AMEDIAFORMAT_KEY_ARTIST = "artist";
+EXPORT const char* AMEDIAFORMAT_KEY_AUDIO_PRESENTATION_INFO = "audio-presentation-info";
EXPORT const char* AMEDIAFORMAT_KEY_AUDIO_SESSION_ID = "audio-session-id";
EXPORT const char* AMEDIAFORMAT_KEY_AUTHOR = "author";
EXPORT const char* AMEDIAFORMAT_KEY_BITRATE_MODE = "bitrate-mode";
diff --git a/media/ndk/include/media/NdkMediaFormat.h b/media/ndk/include/media/NdkMediaFormat.h
index 89cfd5e..658cbac 100644
--- a/media/ndk/include/media/NdkMediaFormat.h
+++ b/media/ndk/include/media/NdkMediaFormat.h
@@ -180,6 +180,7 @@
extern const char* AMEDIAFORMAT_KEY_ALBUMART __INTRODUCED_IN(29);
extern const char* AMEDIAFORMAT_KEY_ALBUMARTIST __INTRODUCED_IN(29);
extern const char* AMEDIAFORMAT_KEY_ARTIST __INTRODUCED_IN(29);
+extern const char* AMEDIAFORMAT_KEY_AUDIO_PRESENTATION_INFO __INTRODUCED_IN(29);
extern const char* AMEDIAFORMAT_KEY_AUTHOR __INTRODUCED_IN(29);
extern const char* AMEDIAFORMAT_KEY_BITS_PER_SAMPLE __INTRODUCED_IN(29);
extern const char* AMEDIAFORMAT_KEY_CDTRACKNUMBER __INTRODUCED_IN(29);