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

Commit 93ea89f1 authored by Chong Zhang's avatar Chong Zhang Committed by Android (Google) Code Review
Browse files

Merge "MediaCas: return audio samples in scrambled form"

parents 74b113db e32a4130
Loading
Loading
Loading
Loading
+44 −0
Original line number Diff line number Diff line
@@ -16,8 +16,10 @@

//#define LOG_NDEBUG 0
#define LOG_TAG "MetaDataUtils"
#include <utils/Log.h>

#include <media/stagefright/foundation/avc_utils.h>
#include <media/stagefright/foundation/ABitReader.h>
#include <media/stagefright/foundation/ABuffer.h>
#include <media/stagefright/MediaDefs.h>
#include <media/stagefright/MetaDataUtils.h>
@@ -25,6 +27,10 @@
namespace android {

bool MakeAVCCodecSpecificData(MetaDataBase &meta, const uint8_t *data, size_t size) {
    if (data == nullptr || size == 0) {
        return false;
    }

    int32_t width;
    int32_t height;
    int32_t sarWidth;
@@ -46,6 +52,44 @@ bool MakeAVCCodecSpecificData(MetaDataBase &meta, const uint8_t *data, size_t si
    return true;
}

bool MakeAACCodecSpecificData(MetaDataBase &meta, const uint8_t *data, size_t size) {
    if (data == nullptr || size < 7) {
        return false;
    }

    ABitReader bits(data, size);

    // adts_fixed_header

    if (bits.getBits(12) != 0xfffu) {
        ALOGE("Wrong atds_fixed_header");
        return false;
    }

    bits.skipBits(4);  // ID, layer, protection_absent

    unsigned profile = bits.getBits(2);
    if (profile == 3u) {
        ALOGE("profile should not be 3");
        return false;
    }
    unsigned sampling_freq_index = bits.getBits(4);
    bits.getBits(1);  // private_bit
    unsigned channel_configuration = bits.getBits(3);
    if (channel_configuration == 0u) {
        ALOGE("channel_config should not be 0");
        return false;
    }

    if (!MakeAACCodecSpecificData(
            meta, profile, sampling_freq_index, channel_configuration)) {
        return false;
    }

    meta.setInt32(kKeyIsADTS, true);
    return true;
}

bool MakeAACCodecSpecificData(
        MetaDataBase &meta,
        unsigned profile, unsigned sampling_freq_index,
+1 −0
Original line number Diff line number Diff line
@@ -24,6 +24,7 @@ namespace android {

struct ABuffer;
bool MakeAVCCodecSpecificData(MetaDataBase &meta, const uint8_t *data, size_t size);
bool MakeAACCodecSpecificData(MetaDataBase &meta, const uint8_t *data, size_t size);
bool MakeAACCodecSpecificData(MetaDataBase &meta, unsigned profile, unsigned sampling_freq_index,
        unsigned channel_configuration);

+21 −10
Original line number Diff line number Diff line
@@ -775,10 +775,12 @@ ATSParser::Stream::Stream(
    ALOGV("new stream PID 0x%02x, type 0x%02x, scrambled %d, SampleEncrypted: %d",
            elementaryPID, streamType, mScrambled, mSampleEncrypted);

    uint32_t flags =
            (isVideo() && mScrambled) ? ElementaryStreamQueue::kFlag_ScrambledData :
            (mSampleEncrypted) ? ElementaryStreamQueue::kFlag_SampleEncryptedData :
            0;
    uint32_t flags = 0;
    if (((isVideo() || isAudio()) && mScrambled)) {
        flags = ElementaryStreamQueue::kFlag_ScrambledData;
    } else if (mSampleEncrypted) {
        flags = ElementaryStreamQueue::kFlag_SampleEncryptedData;
    }

    ElementaryStreamQueue::Mode mode = ElementaryStreamQueue::INVALID;

@@ -1504,7 +1506,13 @@ status_t ATSParser::Stream::flushScrambled(SyncEvent *event) {
        descrambleBytes = bytesWritten;
    }

    sp<ABuffer> buffer;
    // |buffer| points to the buffer from which we'd parse the PES header.
    // When the output stream is scrambled, it points to mDescrambledBuffer
    // (unless all packets in this PES are actually clear, in which case,
    // it points to mBuffer since we never copied into mDescrambledBuffer).
    // When the output stream is clear, it points to mBuffer, and we'll
    // copy all descrambled data back to mBuffer.
    sp<ABuffer> buffer = mBuffer;
    if (mQueue->isScrambled()) {
        // Queue subSample info for scrambled queue
        sp<ABuffer> clearSizesBuffer = new ABuffer(mSubSamples.size() * 4);
@@ -1533,15 +1541,18 @@ status_t ATSParser::Stream::flushScrambled(SyncEvent *event) {
        }
        // Pass the original TS subsample size now. The PES header adjust
        // will be applied when the scrambled AU is dequeued.
        // Note that if descrambleBytes is 0, it means this PES contains only
        // all ts packets, leadingClearBytes is entire buffer size.
        mQueue->appendScrambledData(
                mBuffer->data(), mBuffer->size(), sctrl,
                isSync, clearSizesBuffer, encSizesBuffer);
                mBuffer->data(), mBuffer->size(),
                (descrambleBytes > 0) ? descrambleBytes : mBuffer->size(),
                sctrl, isSync, clearSizesBuffer, encSizesBuffer);

        if (descrambleBytes > 0) {
            buffer = mDescrambledBuffer;
        }
    } else {
        memcpy(mBuffer->data(), mDescrambledBuffer->data(), descrambleBytes);

        buffer = mBuffer;
    }

    ABitReader br(buffer->data(), buffer->size());
+82 −64
Original line number Diff line number Diff line
@@ -439,7 +439,8 @@ status_t ElementaryStreamQueue::appendData(
        ALOGE("appending data after EOS");
        return ERROR_MALFORMED;
    }
    if (mBuffer == NULL || mBuffer->size() == 0) {

    if (!isScrambled() && (mBuffer == NULL || mBuffer->size() == 0)) {
        switch (mMode) {
            case H264:
            case MPEG_VIDEO:
@@ -698,6 +699,7 @@ status_t ElementaryStreamQueue::appendData(

void ElementaryStreamQueue::appendScrambledData(
        const void *data, size_t size,
        size_t leadingClearBytes,
        int32_t keyId, bool isSync,
        sp<ABuffer> clearSizes, sp<ABuffer> encSizes) {
    if (!isScrambled()) {
@@ -725,6 +727,7 @@ void ElementaryStreamQueue::appendScrambledData(

    ScrambledRangeInfo scrambledInfo;
    scrambledInfo.mLength = size;
    scrambledInfo.mLeadingClearBytes = leadingClearBytes;
    scrambledInfo.mKeyId = keyId;
    scrambledInfo.mIsSync = isSync;
    scrambledInfo.mClearSizes = clearSizes;
@@ -737,7 +740,6 @@ void ElementaryStreamQueue::appendScrambledData(

sp<ABuffer> ElementaryStreamQueue::dequeueScrambledAccessUnit() {
    size_t nextScan = mBuffer->size();
    mBuffer->setRange(0, 0);
    int32_t pesOffset = 0, pesScramblingControl = 0;
    int64_t timeUs = fetchTimestamp(nextScan, &pesOffset, &pesScramblingControl);
    if (timeUs < 0ll) {
@@ -748,6 +750,7 @@ sp<ABuffer> ElementaryStreamQueue::dequeueScrambledAccessUnit() {
    // return scrambled unit
    int32_t keyId = pesScramblingControl, isSync = 0, scrambledLength = 0;
    sp<ABuffer> clearSizes, encSizes;
    size_t leadingClearBytes;
    while (mScrambledRangeInfos.size() > mRangeInfos.size()) {
        auto it = mScrambledRangeInfos.begin();
        ALOGV("[stream %d] fetching scrambled range: size=%zu", mMode, it->mLength);
@@ -765,6 +768,7 @@ sp<ABuffer> ElementaryStreamQueue::dequeueScrambledAccessUnit() {
        clearSizes = it->mClearSizes;
        encSizes = it->mEncSizes;
        isSync = it->mIsSync;
        leadingClearBytes = it->mLeadingClearBytes;
        mScrambledRangeInfos.erase(it);
    }
    if (scrambledLength == 0) {
@@ -772,6 +776,70 @@ sp<ABuffer> ElementaryStreamQueue::dequeueScrambledAccessUnit() {
        return NULL;
    }

    // Retrieve the leading clear bytes info, and use it to set the clear
    // range on mBuffer. Note that the leading clear bytes includes the
    // PES header portion, while mBuffer doesn't.
    if ((int32_t)leadingClearBytes > pesOffset) {
        mBuffer->setRange(0, leadingClearBytes - pesOffset);
    } else {
        mBuffer->setRange(0, 0);
    }

    // Try to parse formats, and if unavailable set up a dummy format.
    // Only support the following modes for scrambled content for now.
    // (will be expanded later).
    if (mFormat == NULL) {
        mFormat = new MetaData;
        switch (mMode) {
            case H264:
            {
                if (!MakeAVCCodecSpecificData(
                        *mFormat, mBuffer->data(), mBuffer->size())) {
                    ALOGI("Creating dummy AVC format for scrambled content");

                    mFormat->setCString(kKeyMIMEType, MEDIA_MIMETYPE_VIDEO_AVC);
                    mFormat->setInt32(kKeyWidth, 1280);
                    mFormat->setInt32(kKeyHeight, 720);
                }
                break;
            }
            case AAC:
            {
                if (!MakeAACCodecSpecificData(
                        *mFormat, mBuffer->data(), mBuffer->size())) {
                    ALOGI("Creating dummy AAC format for scrambled content");

                    MakeAACCodecSpecificData(*mFormat,
                            1 /*profile*/, 7 /*sampling_freq_index*/, 1 /*channel_config*/);
                    mFormat->setInt32(kKeyIsADTS, true);
                }

                break;
            }
            case MPEG_VIDEO:
            {
                ALOGI("Creating dummy MPEG format for scrambled content");

                mFormat->setCString(kKeyMIMEType, MEDIA_MIMETYPE_VIDEO_MPEG2);
                mFormat->setInt32(kKeyWidth, 1280);
                mFormat->setInt32(kKeyHeight, 720);
                break;
            }
            default:
            {
                ALOGE("Unknown mode for scrambled content");
                return NULL;
            }
        }

        // for MediaExtractor.CasInfo
        mFormat->setInt32(kKeyCASystemID, mCASystemId);
        mFormat->setData(kKeyCASessionID,
                0, mCasSessionId.data(), mCasSessionId.size());
    }

    mBuffer->setRange(0, 0);

    // copy into scrambled access unit
    sp<ABuffer> scrambledAccessUnit = ABuffer::CreateAsCopy(
            mScrambledBuffer->data(), scrambledLength);
@@ -803,7 +871,11 @@ sp<ABuffer> ElementaryStreamQueue::dequeueScrambledAccessUnit() {
}

sp<ABuffer> ElementaryStreamQueue::dequeueAccessUnit() {
    if ((mFlags & kFlag_AlignedData) && mMode == H264 && !isScrambled()) {
    if (isScrambled()) {
        return dequeueScrambledAccessUnit();
    }

    if ((mFlags & kFlag_AlignedData) && mMode == H264) {
        if (mRangeInfos.empty()) {
            return NULL;
        }
@@ -1114,25 +1186,11 @@ sp<ABuffer> ElementaryStreamQueue::dequeueAccessUnitAAC() {
        bool protection_absent = bits.getBits(1) != 0;

        if (mFormat == NULL) {
            unsigned profile = bits.getBits(2);
            if (profile == 3u) {
                ALOGE("profile should not be 3");
                return NULL;
            }
            unsigned sampling_freq_index = bits.getBits(4);
            bits.getBits(1);  // private_bit
            unsigned channel_configuration = bits.getBits(3);
            if (channel_configuration == 0u) {
                ALOGE("channel_config should not be 0");
            mFormat = new MetaData;
            if (!MakeAACCodecSpecificData(
                    *mFormat, mBuffer->data() + offset, mBuffer->size() - offset)) {
                return NULL;
            }
            bits.skipBits(2);  // original_copy, home

            mFormat = new MetaData;
            MakeAACCodecSpecificData(*mFormat,
                    profile, sampling_freq_index, channel_configuration);

            mFormat->setInt32(kKeyIsADTS, true);

            int32_t sampleRate;
            int32_t numChannels;
@@ -1147,11 +1205,11 @@ sp<ABuffer> ElementaryStreamQueue::dequeueAccessUnitAAC() {

            ALOGI("found AAC codec config (%d Hz, %d channels)",
                 sampleRate, numChannels);
        } else {
        }

        // profile_ObjectType, sampling_frequency_index, private_bits,
        // channel_configuration, original_copy, home
        bits.skipBits(12);
        }

        // adts_variable_header

@@ -1267,27 +1325,6 @@ int64_t ElementaryStreamQueue::fetchTimestamp(
}

sp<ABuffer> ElementaryStreamQueue::dequeueAccessUnitH264() {
    if (isScrambled()) {
        if (mBuffer == NULL || mBuffer->size() == 0) {
            return NULL;
        }
        if (mFormat == NULL) {
            mFormat = new MetaData;
            if (!MakeAVCCodecSpecificData(*mFormat, mBuffer->data(), mBuffer->size())) {
                ALOGW("Creating dummy AVC format for scrambled content");
                mFormat = new MetaData;
                mFormat->setCString(kKeyMIMEType, MEDIA_MIMETYPE_VIDEO_AVC);
                mFormat->setInt32(kKeyWidth, 1280);
                mFormat->setInt32(kKeyHeight, 720);
            }
            // for MediaExtractor.CasInfo
            mFormat->setInt32(kKeyCASystemID, mCASystemId);
            mFormat->setData(kKeyCASessionID, 0,
                    mCasSessionId.data(), mCasSessionId.size());
        }
        return dequeueScrambledAccessUnit();
    }

    const uint8_t *data = mBuffer->data();

    size_t size = mBuffer->size();
@@ -1587,25 +1624,6 @@ static sp<ABuffer> MakeMPEGVideoESDS(const sp<ABuffer> &csd) {
}

sp<ABuffer> ElementaryStreamQueue::dequeueAccessUnitMPEGVideo() {
    if (isScrambled()) {
        if (mBuffer == NULL || mBuffer->size() == 0) {
            return NULL;
        }
        if (mFormat == NULL) {
            ALOGI("Creating dummy MPEG format for scrambled content");
            mFormat = new MetaData;
            mFormat->setCString(kKeyMIMEType, MEDIA_MIMETYPE_VIDEO_MPEG2);
            mFormat->setInt32(kKeyWidth, 1280);
            mFormat->setInt32(kKeyHeight, 720);

            // for MediaExtractor.CasInfo
            mFormat->setInt32(kKeyCASystemID, mCASystemId);
            mFormat->setData(kKeyCASessionID, 0,
                    mCasSessionId.data(), mCasSessionId.size());
        }
        return dequeueScrambledAccessUnit();
    }

    const uint8_t *data = mBuffer->data();
    size_t size = mBuffer->size();

+2 −1
Original line number Diff line number Diff line
@@ -61,6 +61,7 @@ struct ElementaryStreamQueue {

    void appendScrambledData(
            const void *data, size_t size,
            size_t leadingClearBytes,
            int32_t keyId, bool isSync,
            sp<ABuffer> clearSizes, sp<ABuffer> encSizes);

@@ -86,8 +87,8 @@ private:
    };

    struct ScrambledRangeInfo {
        //int64_t mTimestampUs;
        size_t mLength;
        size_t mLeadingClearBytes;
        int32_t mKeyId;
        int32_t mIsSync;
        sp<ABuffer> mClearSizes;