Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 516d8447 authored by TreeHugger Robot's avatar TreeHugger Robot Committed by Android (Google) Code Review
Browse files

Merge "Extract AudioPresentations from AC4 in MP4 and TS"

parents 010ef929 0ac73a5d
Loading
Loading
Loading
Loading
+70 −0
Original line number Diff line number Diff line
@@ -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 @@ status_t MPEG4Extractor::parseAC4SpecificBox(off64_t offset) {
    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;
}

+3 −0
Original line number Diff line number Diff line
@@ -225,6 +225,9 @@ enum {

    // Key for ALAC Magic Cookie
    kKeyAlacMagicCookie  = 'almc', // raw data

    // AC-4 AudioPresentationInfo
    kKeyAudioPresentationInfo = 'audP',  // raw data
};

enum {
+0 −1
Original line number Diff line number Diff line
@@ -96,7 +96,6 @@ cc_library_shared {
        "AHierarchicalStateMachine.cpp",
        "AMRWriter.cpp",
        "AudioPlayer.cpp",
        "AudioPresentationInfo.cpp",
        "AudioSource.cpp",
        "BufferImpl.cpp",
        "CallbackDataSource.cpp",
+0 −45
Original line number Diff line number Diff line
/*
 * 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
+28 −0
Original line number Diff line number Diff line
@@ -794,4 +794,32 @@ bool NuMediaExtractor::getCachedDuration(
    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
Loading