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

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

Merge "Add EAC3 support to MediaExtractor"

parents 05357b12 68e6fe1f
Loading
Loading
Loading
Loading
+2 −1
Original line number Diff line number Diff line
@@ -650,7 +650,8 @@ static void dumpCodecProfiles(bool queryDecoders) {
        MEDIA_MIMETYPE_AUDIO_MPEG, MEDIA_MIMETYPE_AUDIO_G711_MLAW,
        MEDIA_MIMETYPE_AUDIO_G711_ALAW, MEDIA_MIMETYPE_AUDIO_VORBIS,
        MEDIA_MIMETYPE_VIDEO_VP8, MEDIA_MIMETYPE_VIDEO_VP9,
        MEDIA_MIMETYPE_VIDEO_DOLBY_VISION, MEDIA_MIMETYPE_AUDIO_AC4
        MEDIA_MIMETYPE_VIDEO_DOLBY_VISION,
        MEDIA_MIMETYPE_AUDIO_EAC3, MEDIA_MIMETYPE_AUDIO_AC4
    };

    const char *codecType = queryDecoders? "decoder" : "encoder";
+196 −44
Original line number Diff line number Diff line
@@ -313,6 +313,9 @@ static const char *FourCC2MIME(uint32_t fourcc) {
        case FOURCC('s', 'a', 'w', 'b'):
            return MEDIA_MIMETYPE_AUDIO_AMR_WB;

        case FOURCC('e', 'c', '-', '3'):
            return MEDIA_MIMETYPE_AUDIO_EAC3;

        case FOURCC('m', 'p', '4', 'v'):
            return MEDIA_MIMETYPE_VIDEO_MPEG4;

@@ -2438,13 +2441,19 @@ status_t MPEG4Extractor::parseChunk(off64_t *offset, int depth) {
        case FOURCC('a', 'c', '-', '3'):
        {
            *offset += chunk_size;
            return parseAC3SampleEntry(data_offset);
            return parseAC3SpecificBox(data_offset);
        }

        case FOURCC('e', 'c', '-', '3'):
        {
            *offset += chunk_size;
            return parseEAC3SpecificBox(data_offset);
        }

        case FOURCC('a', 'c', '-', '4'):
        {
            *offset += chunk_size;
            return parseAC4SampleEntry(data_offset);
            return parseAC4SpecificBox(data_offset);
        }

        case FOURCC('f', 't', 'y', 'p'):
@@ -2518,43 +2527,43 @@ status_t MPEG4Extractor::parseChunk(off64_t *offset, int depth) {
    return OK;
}

status_t MPEG4Extractor::parseAC4SampleEntry(off64_t offset) {
status_t MPEG4Extractor::parseChannelCountSampleRate(
        off64_t *offset, uint16_t *channelCount, uint16_t *sampleRate) {
    // skip 16 bytes:
    //  + 6-byte reserved,
    //  + 2-byte data reference index,
    //  + 8-byte reserved
    offset += 16;
    uint16_t channelCount;
    if (!mDataSource->getUInt16(offset, &channelCount)) {
        ALOGE("MPEG4Extractor: error while reading ac-4 block: cannot read channel count");
    *offset += 16;
    if (!mDataSource->getUInt16(*offset, channelCount)) {
        ALOGE("MPEG4Extractor: error while reading sample entry box: cannot read channel count");
        return ERROR_MALFORMED;
    }
    // skip 8 bytes:
    //  + 2-byte channelCount,
    //  + 2-byte sample size,
    //  + 4-byte reserved
    offset += 8;
    uint16_t sampleRate;
    if (!mDataSource->getUInt16(offset, &sampleRate)) {
        ALOGE("MPEG4Extractor: error while reading ac-4 block: cannot read sample rate");
    *offset += 8;
    if (!mDataSource->getUInt16(*offset, sampleRate)) {
        ALOGE("MPEG4Extractor: error while reading sample entry box: cannot read sample rate");
        return ERROR_MALFORMED;
    }

    // skip 4 bytes:
    //  + 2-byte sampleRate,
    //  + 2-byte reserved
    offset += 4;
    *offset += 4;
    return OK;
}

status_t MPEG4Extractor::parseAC4SpecificBox(off64_t offset) {
    if (mLastTrack == NULL) {
        return ERROR_MALFORMED;
    }
    mLastTrack->meta.setCString(kKeyMIMEType, MEDIA_MIMETYPE_AUDIO_AC4);
    mLastTrack->meta.setInt32(kKeyChannelCount, channelCount);
    mLastTrack->meta.setInt32(kKeySampleRate, sampleRate);
    return parseAC4SpecificBox(offset);
}

status_t MPEG4Extractor::parseAC4SpecificBox(off64_t offset) {
    uint16_t sampleRate, channelCount;
    status_t status;
    if ((status = parseChannelCountSampleRate(&offset, &channelCount, &sampleRate)) != OK) {
        return status;
    }
    uint32_t size;
    // + 4-byte size
    // + 4-byte type
@@ -2593,39 +2602,185 @@ status_t MPEG4Extractor::parseAC4SpecificBox(off64_t offset) {
        return ERROR_MALFORMED;
    }

    mLastTrack->meta.setCString(kKeyMIMEType, MEDIA_MIMETYPE_AUDIO_AC4);
    mLastTrack->meta.setInt32(kKeyChannelCount, channelCount);
    mLastTrack->meta.setInt32(kKeySampleRate, sampleRate);
    return OK;
}

status_t MPEG4Extractor::parseAC3SampleEntry(off64_t offset) {
    // skip 16 bytes:
    //  + 6-byte reserved,
    //  + 2-byte data reference index,
    //  + 8-byte reserved
    offset += 16;
    uint16_t channelCount;
    if (!mDataSource->getUInt16(offset, &channelCount)) {
status_t MPEG4Extractor::parseEAC3SpecificBox(off64_t offset) {
    if (mLastTrack == NULL) {
        return ERROR_MALFORMED;
    }
    // skip 8 bytes:
    //  + 2-byte channelCount,
    //  + 2-byte sample size,
    //  + 4-byte reserved
    offset += 8;
    uint16_t sampleRate;
    if (!mDataSource->getUInt16(offset, &sampleRate)) {
        ALOGE("MPEG4Extractor: error while reading ac-3 block: cannot read sample rate");

    uint16_t sampleRate, channels;
    status_t status;
    if ((status = parseChannelCountSampleRate(&offset, &channels, &sampleRate)) != OK) {
        return status;
    }
    uint32_t size;
    // + 4-byte size
    // + 4-byte type
    // + 3-byte payload
    const uint32_t kEAC3SpecificBoxMinSize = 11;
    // 13 + 3 + (8 * (2 + 5 + 5 + 3 + 1 + 3 + 4 + (14 * 9 + 1))) bits == 152 bytes theoretical max
    // calculated from the required bits read below as well as the maximum number of independent
    // and dependant sub streams you can have
    const uint32_t kEAC3SpecificBoxMaxSize = 152;
    if (!mDataSource->getUInt32(offset, &size) ||
        size < kEAC3SpecificBoxMinSize ||
        size > kEAC3SpecificBoxMaxSize) {
        ALOGE("MPEG4Extractor: error while reading eac-3 block: cannot read specific box size");
        return ERROR_MALFORMED;
    }

    // skip 4 bytes:
    //  + 2-byte sampleRate,
    //  + 2-byte reserved
    offset += 4;
    return parseAC3SpecificBox(offset, sampleRate);
    uint32_t type;
    if (!mDataSource->getUInt32(offset, &type) || type != FOURCC('d', 'e', 'c', '3')) {
        ALOGE("MPEG4Extractor: error while reading eac-3 specific block: header not dec3");
        return ERROR_MALFORMED;
    }

    offset += 4;
    uint8_t* chunk = new (std::nothrow) uint8_t[size];
    if (chunk == NULL) {
        return ERROR_MALFORMED;
    }

    if (mDataSource->readAt(offset, chunk, size) != (ssize_t)size) {
        ALOGE("MPEG4Extractor: error while reading eac-3 specific block: bitstream fields");
        delete[] chunk;
        return ERROR_MALFORMED;
    }

    ABitReader br(chunk, size);
    static const unsigned channelCountTable[] = {2, 1, 2, 3, 3, 4, 4, 5};
    static const unsigned sampleRateTable[] = {48000, 44100, 32000};

    if (br.numBitsLeft() < 16) {
        delete[] chunk;
        return ERROR_MALFORMED;
    }
    unsigned data_rate = br.getBits(13);
    ALOGV("EAC3 data rate = %d", data_rate);

status_t MPEG4Extractor::parseAC3SpecificBox(
        off64_t offset, uint16_t sampleRate) {
    unsigned num_ind_sub = br.getBits(3) + 1;
    ALOGV("EAC3 independant substreams = %d", num_ind_sub);
    if (br.numBitsLeft() < (num_ind_sub * 23)) {
        delete[] chunk;
        return ERROR_MALFORMED;
    }

    unsigned channelCount = 0;
    for (unsigned i = 0; i < num_ind_sub; i++) {
        unsigned fscod = br.getBits(2);
        if (fscod == 3) {
            ALOGE("Incorrect fscod (3) in EAC3 header");
            delete[] chunk;
            return ERROR_MALFORMED;
        }
        unsigned boxSampleRate = sampleRateTable[fscod];
        if (boxSampleRate != sampleRate) {
            ALOGE("sample rate mismatch: boxSampleRate = %d, sampleRate = %d",
                boxSampleRate, sampleRate);
            delete[] chunk;
            return ERROR_MALFORMED;
        }

        unsigned bsid = br.getBits(5);
        if (bsid < 8) {
            ALOGW("Incorrect bsid in EAC3 header. Possibly AC-3?");
            delete[] chunk;
            return ERROR_MALFORMED;
        }

        // skip
        br.skipBits(2);
        unsigned bsmod = br.getBits(3);
        unsigned acmod = br.getBits(3);
        unsigned lfeon = br.getBits(1);
        // we currently only support the first stream
        if (i == 0)
            channelCount = channelCountTable[acmod] + lfeon;
        ALOGV("bsmod = %d, acmod = %d, lfeon = %d", bsmod, acmod, lfeon);

        br.skipBits(3);
        unsigned num_dep_sub = br.getBits(4);
        ALOGV("EAC3 dependant substreams = %d", num_dep_sub);
        if (num_dep_sub != 0) {
            if (br.numBitsLeft() < 9) {
                delete[] chunk;
                return ERROR_MALFORMED;
            }
            static const char* chan_loc_tbl[] = { "Lc/Rc","Lrs/Rrs","Cs","Ts","Lsd/Rsd",
                "Lw/Rw","Lvh/Rvh","Cvh","Lfe2" };
            unsigned chan_loc = br.getBits(9);
            unsigned mask = 1;
            for (unsigned j = 0; j < 9; j++, mask <<= 1) {
                if ((chan_loc & mask) != 0) {
                    // we currently only support the first stream
                    if (i == 0) {
                        channelCount++;
                        // these are 2 channels in the mask
                        if (j == 0 || j == 1 || j == 4 || j == 5 || j == 6) {
                            channelCount++;
                        }
                    }
                    ALOGV(" %s", chan_loc_tbl[j]);
                }
            }
        } else {
            if (br.numBitsLeft() == 0) {
                delete[] chunk;
                return ERROR_MALFORMED;
            }
            br.skipBits(1);
        }
    }

    if (br.numBitsLeft() != 0) {
        if (br.numBitsLeft() < 8) {
            delete[] chunk;
            return ERROR_MALFORMED;
        }
        unsigned mask = br.getBits(8);
        for (unsigned i = 0; i < 8; i++) {
            if (((0x1 << i) && mask) == 0)
                continue;

            if (br.numBitsLeft() < 8) {
                delete[] chunk;
                return ERROR_MALFORMED;
            }
            switch (i) {
                case 0: {
                    unsigned complexity = br.getBits(8);
                    ALOGV("Found a JOC stream with complexity = %d", complexity);
                }break;
                default: {
                    br.skipBits(8);
                }break;
            }
        }
    }
    mLastTrack->meta.setCString(kKeyMIMEType, MEDIA_MIMETYPE_AUDIO_EAC3);
    mLastTrack->meta.setInt32(kKeyChannelCount, channelCount);
    mLastTrack->meta.setInt32(kKeySampleRate, sampleRate);

    delete[] chunk;
    return OK;
}

status_t MPEG4Extractor::parseAC3SpecificBox(off64_t offset) {
    if (mLastTrack == NULL) {
        return ERROR_MALFORMED;
    }

    uint16_t sampleRate, channels;
    status_t status;
    if ((status = parseChannelCountSampleRate(&offset, &channels, &sampleRate)) != OK) {
        return status;
    }
    uint32_t size;
    // + 4-byte size
    // + 4-byte type
@@ -2680,9 +2835,6 @@ status_t MPEG4Extractor::parseAC3SpecificBox(
    unsigned lfeon = br.getBits(1);
    unsigned channelCount = channelCountTable[acmod] + lfeon;

    if (mLastTrack == NULL) {
        return ERROR_MALFORMED;
    }
    mLastTrack->meta.setCString(kKeyMIMEType, MEDIA_MIMETYPE_AUDIO_AC3);
    mLastTrack->meta.setInt32(kKeyChannelCount, channelCount);
    mLastTrack->meta.setInt32(kKeySampleRate, sampleRate);
+4 −3
Original line number Diff line number Diff line
@@ -139,9 +139,10 @@ private:

    Track *findTrackByMimePrefix(const char *mimePrefix);

    status_t parseAC3SampleEntry(off64_t offset);
    status_t parseAC3SpecificBox(off64_t offset, uint16_t sampleRate);
    status_t parseAC4SampleEntry(off64_t offset);
    status_t parseChannelCountSampleRate(
            off64_t *offset, uint16_t *channelCount, uint16_t *sampleRate);
    status_t parseAC3SpecificBox(off64_t offset);
    status_t parseEAC3SpecificBox(off64_t offset);
    status_t parseAC4SpecificBox(off64_t offset);

    MPEG4Extractor(const MPEG4Extractor &);
+1 −1
Original line number Diff line number Diff line
@@ -1577,6 +1577,7 @@ static const struct mime_conv_t mimeLookup[] = {
    { MEDIA_MIMETYPE_AUDIO_VORBIS,      AUDIO_FORMAT_VORBIS },
    { MEDIA_MIMETYPE_AUDIO_OPUS,        AUDIO_FORMAT_OPUS},
    { MEDIA_MIMETYPE_AUDIO_AC3,         AUDIO_FORMAT_AC3},
    { MEDIA_MIMETYPE_AUDIO_EAC3,        AUDIO_FORMAT_E_AC3},
    { MEDIA_MIMETYPE_AUDIO_AC4,         AUDIO_FORMAT_AC4},
    { MEDIA_MIMETYPE_AUDIO_FLAC,        AUDIO_FORMAT_FLAC},
    { 0, AUDIO_FORMAT_INVALID }
@@ -1868,4 +1869,3 @@ AString nameForFd(int fd) {
}

}  // namespace android
+5 −0
Original line number Diff line number Diff line
@@ -815,6 +815,10 @@ ATSParser::Stream::Stream(
            mode = ElementaryStreamQueue::AC3;
            break;

        case STREAMTYPE_EAC3:
            mode = ElementaryStreamQueue::EAC3;
            break;

        case STREAMTYPE_PES_PRIVATE_DATA:
            if (mStreamTypeExt == EXT_DESCRIPTOR_DVB_AC4) {
                mode = ElementaryStreamQueue::AC4;
@@ -1026,6 +1030,7 @@ bool ATSParser::Stream::isAudio() const {
        case STREAMTYPE_MPEG2_AUDIO_ADTS:
        case STREAMTYPE_LPCM_AC3:
        case STREAMTYPE_AC3:
        case STREAMTYPE_EAC3:
        case STREAMTYPE_AAC_ENCRYPTED:
        case STREAMTYPE_AC3_ENCRYPTED:
            return true;
Loading