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

Commit 51c684bd authored by Robert Shih's avatar Robert Shih Committed by Android (Google) Code Review
Browse files

Merge "MKV handles MP3 audio whose frame is not complete"

parents 60c73a44 d9b70d53
Loading
Loading
Loading
Loading
+212 −1
Original line number Diff line number Diff line
@@ -32,6 +32,7 @@
#include <media/stagefright/MediaDefs.h>
#include <media/stagefright/MediaErrors.h>
#include <media/stagefright/MetaDataUtils.h>
#include <media/stagefright/foundation/avc_utils.h>
#include <utils/String8.h>

#include <arpa/inet.h>
@@ -147,6 +148,7 @@ private:
        AVC,
        AAC,
        HEVC,
        MP3,
        OTHER
    };

@@ -159,6 +161,15 @@ private:

    List<MediaBufferHelper *> mPendingFrames;

    int64_t mCurrentTS; // add for mp3
    uint32_t mMP3Header;

    media_status_t findMP3Header(uint32_t * header,
        const uint8_t *dataSource, int length, int *outStartPos);
    media_status_t mp3FrameRead(
            MediaBufferHelper **out, const ReadOptions *options,
            int64_t targetSampleTimeUs);

    status_t advance();

    status_t setWebmBlockCryptoInfo(MediaBufferHelper *mbuf);
@@ -225,7 +236,9 @@ MatroskaSource::MatroskaSource(
      mBlockIter(mExtractor,
                 mExtractor->mTracks.itemAt(index).mTrackNum,
                 index),
      mNALSizeLen(-1) {
      mNALSizeLen(-1),
      mCurrentTS(0),
      mMP3Header(0) {
    MatroskaExtractor::TrackInfo &trackInfo = mExtractor->mTracks.editItemAt(index);
    AMediaFormat *meta = trackInfo.mMeta;

@@ -254,6 +267,8 @@ MatroskaSource::MatroskaSource(
        }
    } else if (!strcasecmp(mime, MEDIA_MIMETYPE_AUDIO_AAC)) {
        mType = AAC;
    } else if (!strcasecmp(mime, MEDIA_MIMETYPE_AUDIO_MPEG)) {
        mType = MP3;
    }
}

@@ -270,6 +285,16 @@ media_status_t MatroskaSource::start() {
    mBufferGroup->init(1 /* number of buffers */, 1024 /* buffer size */, 64 /* growth limit */);
    mBlockIter.reset();

    if (mType == MP3 && mMP3Header == 0) {
        int start = -1;
        media_status_t err = findMP3Header(&mMP3Header, NULL, 0, &start);
        if (err != OK) {
            ALOGE("No mp3 header found");
            clearPendingFrames();
            return err;
        }
    }

    return AMEDIA_OK;
}

@@ -796,6 +821,188 @@ media_status_t MatroskaSource::readBlock() {
    return AMEDIA_OK;
}

//the value of kMP3HeaderMask is from MP3Extractor
static const uint32_t kMP3HeaderMask = 0xfffe0c00;

media_status_t MatroskaSource::findMP3Header(uint32_t * header,
        const uint8_t *dataSource, int length, int *outStartPos) {
    if (NULL == header) {
        ALOGE("header is null!");
        return AMEDIA_ERROR_END_OF_STREAM;
    }

    //to find header start position
    if (0 != *header) {
        if (NULL == dataSource) {
            *outStartPos = -1;
            return AMEDIA_OK;
        }
        uint32_t tmpCode = 0;
        for (int i = 0; i < length; i++) {
            tmpCode = (tmpCode << 8) + dataSource[i];
            if ((tmpCode & kMP3HeaderMask) == (*header & kMP3HeaderMask)) {
                *outStartPos = i - 3;
                return AMEDIA_OK;
            }
        }
        *outStartPos = -1;
        return AMEDIA_OK;
    }

    //to find mp3 header
    uint32_t code = 0;
    while (0 == *header) {
        while (mPendingFrames.empty()) {
            media_status_t err = readBlock();
            if (err != OK) {
                clearPendingFrames();
                return err;
            }
        }
        MediaBufferHelper *frame = *mPendingFrames.begin();
        size_t size = frame->range_length();
        size_t offset = frame->range_offset();
        size_t i;
        size_t frame_size;
        for (i = 0; i < size; i++) {
            ALOGV("data[%zu]=%x", i, *((uint8_t*)frame->data() + offset + i));
            code = (code << 8) + *((uint8_t*)frame->data() + offset + i);
            if (GetMPEGAudioFrameSize(code, &frame_size, NULL, NULL, NULL)) {
                *header = code;
                mBlockIter.reset();
                clearPendingFrames();
                return AMEDIA_OK;
            }
        }
    }

    return AMEDIA_ERROR_END_OF_STREAM;
}

media_status_t MatroskaSource::mp3FrameRead(
        MediaBufferHelper **out, const ReadOptions *options,
        int64_t targetSampleTimeUs) {
    MediaBufferHelper *frame = *mPendingFrames.begin();
    int64_t seekTimeUs;
    ReadOptions::SeekMode mode;
    if (options && options->getSeekTo(&seekTimeUs, &mode)) {
        CHECK(AMediaFormat_getInt64(frame->meta_data(),
                    AMEDIAFORMAT_KEY_TIME_US, &mCurrentTS));
        if (mCurrentTS < 0) {
            mCurrentTS = 0;
            AMediaFormat_setInt64(frame->meta_data(),
                    AMEDIAFORMAT_KEY_TIME_US, mCurrentTS);
        }
    }

    int32_t start = -1;
    while (start < 0) {
        //find header start position
        findMP3Header(&mMP3Header,
            (const uint8_t*)frame->data() + frame->range_offset(),
            frame->range_length(), &start);
        ALOGV("start=%d, frame->range_length() = %zu, frame->range_offset() =%zu",
                      start, frame->range_length(), frame->range_offset());
        if (start >= 0)
            break;
        frame->release();
        mPendingFrames.erase(mPendingFrames.begin());
        while (mPendingFrames.empty()) {
            media_status_t err = readBlock();
            if (err != OK) {
                clearPendingFrames();
                return err;
            }
        }
        frame = *mPendingFrames.begin();
    }

    frame->set_range(frame->range_offset() + start, frame->range_length() - start);

    uint32_t header = *(uint32_t*)((uint8_t*)frame->data() + frame->range_offset());
    header = ((header >> 24) & 0xff) | ((header >> 8) & 0xff00) |
                    ((header << 8) & 0xff0000) | ((header << 24) & 0xff000000);
    size_t frame_size;
    int out_sampling_rate;
    int out_channels;
    int out_bitrate;
    if (!GetMPEGAudioFrameSize(header, &frame_size,
                               &out_sampling_rate, &out_channels, &out_bitrate)) {
        ALOGE("MP3 Header read fail!!");
        return AMEDIA_ERROR_UNSUPPORTED;
    }

    MediaBufferHelper *buffer;
    mBufferGroup->acquire_buffer(&buffer, false /* nonblocking */, frame_size /* requested size */);
    buffer->set_range(0, frame_size);

    uint8_t *data = static_cast<uint8_t *>(buffer->data());
    ALOGV("MP3 frame %zu frame->range_length() %zu", frame_size, frame->range_length());

    if (frame_size > frame->range_length()) {
        memcpy(data, (uint8_t*)(frame->data()) + frame->range_offset(), frame->range_length());
        size_t sumSize = 0;
        sumSize += frame->range_length();
        size_t needSize = frame_size - frame->range_length();
        frame->release();
        mPendingFrames.erase(mPendingFrames.begin());
        while (mPendingFrames.empty()) {
            media_status_t err = readBlock();
            if (err != OK) {
                clearPendingFrames();
                return err;
            }
        }
        frame = *mPendingFrames.begin();
        size_t offset = frame->range_offset();
        size_t size = frame->range_length();

        // the next buffer frame is not enough to fullfill mp3 frame,
        // we have to read until mp3 frame is completed.
        while (size < needSize) {
            memcpy(data + sumSize, (uint8_t*)(frame->data()) + offset, size);
            needSize -= size;
            sumSize += size;
            frame->release();
            mPendingFrames.erase(mPendingFrames.begin());
            while (mPendingFrames.empty()) {
                media_status_t err = readBlock();
                if (err != OK) {
                    clearPendingFrames();
                    return err;
                }
            }
            frame = *mPendingFrames.begin();
            offset = frame->range_offset();
            size = frame->range_length();
        }
        memcpy(data + sumSize, (uint8_t*)(frame->data()) + offset, needSize);
        frame->set_range(offset + needSize, size - needSize);
     } else {
        size_t offset = frame->range_offset();
        size_t size = frame->range_length();
        memcpy(data, (uint8_t*)(frame->data()) + offset, frame_size);
        frame->set_range(offset + frame_size, size - frame_size);
    }
    if (frame->range_length() < 4) {
        frame->release();
        frame = NULL;
        mPendingFrames.erase(mPendingFrames.begin());
    }
    ALOGV("MatroskaSource::read MP3 frame kKeyTime=%lld,kKeyTargetTime=%lld",
                    (long long)mCurrentTS, (long long)targetSampleTimeUs);
    AMediaFormat_setInt64(buffer->meta_data(),
            AMEDIAFORMAT_KEY_TIME_US, mCurrentTS);
    mCurrentTS += (int64_t)frame_size * 8000ll / out_bitrate;

    if (targetSampleTimeUs >= 0ll)
        AMediaFormat_setInt64(buffer->meta_data(),
                AMEDIAFORMAT_KEY_TARGET_TIME, targetSampleTimeUs);
    *out = buffer;
    ALOGV("MatroskaSource::read MP3, keyTime=%lld for next frame", (long long)mCurrentTS);
    return AMEDIA_OK;
}

media_status_t MatroskaSource::read(
        MediaBufferHelper **out, const ReadOptions *options) {
    *out = NULL;
@@ -833,6 +1040,10 @@ media_status_t MatroskaSource::read(
        }
    }

    if (mType == MP3) {
        return mp3FrameRead(out, options, targetSampleTimeUs);
    }

    MediaBufferHelper *frame = *mPendingFrames.begin();
    mPendingFrames.erase(mPendingFrames.begin());