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

Commit f3236777 authored by Srinu Gorle's avatar Srinu Gorle Committed by Arne Coucheron
Browse files

libstagefright: Fix for Software MP3Decoder to handle Partial frames

    Software MP3 decoder runs into error on receiving partial frames,
    as it does not handle partial frames. The fix is to store the
    partial frame in the MP3Decoder  and complete the partial frame on
    receiving the next buffer. Also on Sync lost error by software
    decoder, MP3Decoder checks for frame header in the input
    buffer and does not quit the decoding.

CRs-fixed: 271010

Change-Id: I1db5b025d4ae4cbba91f19fb965f5dbce3d498fb

Conflicts:

	media/libstagefright/codecs/mp3dec/src/pvmp3_decode_header.cpp
parent 07914a40
Loading
Loading
Loading
Loading
+378 −10
Original line number Original line Diff line number Diff line
@@ -22,9 +22,183 @@
#include <media/stagefright/MediaDebug.h>
#include <media/stagefright/MediaDebug.h>
#include <media/stagefright/MediaDefs.h>
#include <media/stagefright/MediaDefs.h>
#include <media/stagefright/MetaData.h>
#include <media/stagefright/MetaData.h>
#include <media/stagefright/Utils.h>


namespace android {
namespace android {


// Everything must match except for
// protection, bitrate, padding, private bits, mode extension,
// copyright bit, original bit and emphasis.
// Yes ... there are things that must indeed match...
static const uint32_t kMask = 0xfffe0cc0;

static bool get_mp3_frame_size(
        uint32_t header, size_t *frame_size,
        int *out_sampling_rate = NULL, int *out_channels = NULL,
        int *out_bitrate = NULL) {
    *frame_size = 0;

    if (out_sampling_rate) {
        *out_sampling_rate = 0;
    }

    if (out_channels) {
        *out_channels = 0;
    }

    if (out_bitrate) {
        *out_bitrate = 0;
    }

    if ((header & 0xffe00000) != 0xffe00000) {
        return false;
    }

    unsigned version = (header >> 19) & 3;

    if (version == 0x01) {
        return false;
    }

    unsigned layer = (header >> 17) & 3;

    if (layer == 0x00) {
        return false;
    }

    unsigned protection = (header >> 16) & 1;

    unsigned bitrate_index = (header >> 12) & 0x0f;

    if (bitrate_index == 0 || bitrate_index == 0x0f) {
        // Disallow "free" bitrate.
        return false;
    }

    unsigned sampling_rate_index = (header >> 10) & 3;

    if (sampling_rate_index == 3) {
        return false;
    }

    static const int kSamplingRateV1[] = { 44100, 48000, 32000 };
    int sampling_rate = kSamplingRateV1[sampling_rate_index];
    if (version == 2 /* V2 */) {
        sampling_rate /= 2;
    } else if (version == 0 /* V2.5 */) {
        sampling_rate /= 4;
    }

    unsigned padding = (header >> 9) & 1;

    if (layer == 3) {
        // layer I

        static const int kBitrateV1[] = {
            32, 64, 96, 128, 160, 192, 224, 256,
            288, 320, 352, 384, 416, 448
        };

        static const int kBitrateV2[] = {
            32, 48, 56, 64, 80, 96, 112, 128,
            144, 160, 176, 192, 224, 256
        };

        int bitrate =
            (version == 3 /* V1 */)
                ? kBitrateV1[bitrate_index - 1]
                : kBitrateV2[bitrate_index - 1];

        if (out_bitrate) {
            *out_bitrate = bitrate;
        }

        *frame_size = (12000 * bitrate / sampling_rate + padding) * 4;
    } else {
        // layer II or III

        static const int kBitrateV1L2[] = {
            32, 48, 56, 64, 80, 96, 112, 128,
            160, 192, 224, 256, 320, 384
        };

        static const int kBitrateV1L3[] = {
            32, 40, 48, 56, 64, 80, 96, 112,
            128, 160, 192, 224, 256, 320
        };

        static const int kBitrateV2[] = {
            8, 16, 24, 32, 40, 48, 56, 64,
            80, 96, 112, 128, 144, 160
        };

        int bitrate;
        if (version == 3 /* V1 */) {
            bitrate = (layer == 2 /* L2 */)
                ? kBitrateV1L2[bitrate_index - 1]
                : kBitrateV1L3[bitrate_index - 1];
        } else {
            // V2 (or 2.5)

            bitrate = kBitrateV2[bitrate_index - 1];
        }

        if (out_bitrate) {
            *out_bitrate = bitrate;
        }

        if (version == 3 /* V1 */) {
            *frame_size = 144000 * bitrate / sampling_rate + padding;
        } else {
            // V2 or V2.5
            *frame_size = 72000 * bitrate / sampling_rate + padding;
        }
    }

    if (out_sampling_rate) {
        *out_sampling_rate = sampling_rate;
    }

    if (out_channels) {
        int channel_mode = (header >> 6) & 3;

        *out_channels = (channel_mode == 3) ? 1 : 2;
    }

    return true;
}

static bool resync(
        uint8_t *data, uint32_t size, uint32_t match_header, off_t *out_pos) {

    bool valid = false;
    off_t pos = 0;
    *out_pos = 0;
    do {
        if (pos + 4 > size) {
            // Don't scan forever.
            LOGV("no dice, no valid sequence of frames found.");
            break;
        }

        uint32_t header = U32_AT(data + pos);

        if (match_header != 0 && (header & kMask) != (match_header & kMask)) {
            ++pos;
            continue;
        }

        LOGV("found possible frame at %ld (header = 0x%08x)", pos, header);

        // We found what looks like a valid frame,
        valid = true;
        *out_pos = pos;
    } while (!valid);

    return valid;
}


MP3Decoder::MP3Decoder(const sp<MediaSource> &source)
MP3Decoder::MP3Decoder(const sp<MediaSource> &source)
    : mSource(source),
    : mSource(source),
      mNumChannels(0),
      mNumChannels(0),
@@ -34,7 +208,9 @@ MP3Decoder::MP3Decoder(const sp<MediaSource> &source)
      mDecoderBuf(NULL),
      mDecoderBuf(NULL),
      mAnchorTimeUs(0),
      mAnchorTimeUs(0),
      mNumFramesOutput(0),
      mNumFramesOutput(0),
      mInputBuffer(NULL) {
      mInputBuffer(NULL),
      mPartialBuffer(NULL),
      mFixedHeader(0) {
    init();
    init();
}
}


@@ -115,11 +291,120 @@ sp<MetaData> MP3Decoder::getFormat() {
    return mMeta;
    return mMeta;
}
}


status_t MP3Decoder::updatePartialFrame() {
    status_t err = OK;
    if (mPartialBuffer == NULL) {
        return err;
    }

    size_t frameSize = 0;
    uint32_t partialBufLen = mPartialBuffer->range_length();
    uint32_t inputBufLen = mInputBuffer->range_length();
    uint8_t frameHeader[4];
    uint8_t *frmHdr;
    uint32_t header;


    // Look at the frame size and complete the partial frame
    // Also check if a vaild header is found after the partial frame
    if (partialBufLen < 4) { // check if partial frame has the 4 bytes header
        if (inputBufLen < (4 - partialBufLen)) {
            // input buffer does not have the frame header bytes
            // bail out TODO
            LOGE("MP3Decoder::updatePartialFrame buffer to small header not found"
                 " partial buffer len %d, input buffer len %d",
                 partialBufLen, inputBufLen);
            //mPartialBuffer->release();
            //mPartialBuffer = NULL;
            return UNKNOWN_ERROR;
        }

        // copy the header bytes to frameHeader
        memcpy (frameHeader, mPartialBuffer->data(), partialBufLen);
        memcpy (frameHeader + partialBufLen, mInputBuffer->data(), (4 - partialBufLen));
        // get the first 4 bytes of the buffer
        header = U32_AT((uint8_t *)frameHeader);
        frmHdr = frameHeader;
    } else {
        frmHdr = (uint8_t *)mPartialBuffer->data();
    }

    // check if its a good frame, and the frame size
    // get the first 4 bytes of the buffer
    header = U32_AT(frmHdr);
    bool curFrame = get_mp3_frame_size(header,&frameSize);
    if (!curFrame) {
        LOGE("MP3Decoder::read - partial frame does not have a vaild header 0x%x",
             header);
        return UNKNOWN_ERROR;
    }

    // check if the following frame is good
    uint32_t nextFrameOffset = frameSize - partialBufLen;
    if ((nextFrameOffset + 4) <= inputBufLen) {
        header = U32_AT((uint8_t *)mInputBuffer->data() + nextFrameOffset);
        if ((header & 0xffe00000) != 0xffe00000) {
            // next frame does not have a valid header,
            // this may not be the next buffer, bail out.
            LOGE("MP3Decoder::read - next frame does not have a vaild header 0x%x",
                 header);
            return UNKNOWN_ERROR;
        }
    } else {
        // next frame header is out of range
        // assume good header for now
        LOGE("MP3Decoder::read - assuming next frame is good");
    }

    // check if the input buffer has the remaining partial frame
    if (frameSize > (partialBufLen + inputBufLen)) {
        // input buffer does not have the remaining partial frame,
        // discard data here as frame split in 3 buffers not supported
        LOGE("MP3Decoder::updatePartialFrame - input buffer does not have the complete frame."
             " frame size %d, saved partial buffer len %d,"
             " input buffer len %d", frameSize, partialBufLen, inputBufLen);
        return UNKNOWN_ERROR;
    }

    // check if the mPartialBuffer can fit the remaining frame
    if ((mPartialBuffer->size() - partialBufLen) < (frameSize - partialBufLen)) {
        // mPartialBuffer is small to hold the reaming frame
        //TODO
        LOGE("MP3Decoder::updatePartialFrame - mPartialBuffer is small, size %d, required &d",
             (mPartialBuffer->size() - partialBufLen), (frameSize - partialBufLen));
        return UNKNOWN_ERROR;
    }

    // done with error checks
    // copy the partial frames to from a complete frame
    // Copy the remaining frame from input buffer
    uint32_t bytesRemaining = frameSize - mPartialBuffer->range_length();
    memcpy ((uint8_t *)mPartialBuffer->data() + mPartialBuffer->range_length(),
            (uint8_t *)mInputBuffer->data() + mInputBuffer->range_offset(),
            bytesRemaining);

    // mark the bytes as consumed from input buffer
    mInputBuffer->set_range(
                           mInputBuffer->range_offset() + bytesRemaining,
                           mInputBuffer->range_length() - bytesRemaining);

    // set the range and length of mPartialBuffer
    mPartialBuffer->set_range(0,
                              mPartialBuffer->range_length() + bytesRemaining);

    LOGE("MP3Decoder::updatePartialFrame - copied the partial frame %d, input buffer length %d",
         bytesRemaining, mInputBuffer->range_length());

    return err;
}

status_t MP3Decoder::read(
status_t MP3Decoder::read(
        MediaBuffer **out, const ReadOptions *options) {
        MediaBuffer **out, const ReadOptions *options) {
    status_t err;
    status_t err;


    *out = NULL;
    *out = NULL;
    bool usedPartialFrame = false;
    bool seekSource = false;


    int64_t seekTimeUs;
    int64_t seekTimeUs;
    ReadOptions::SeekMode mode;
    ReadOptions::SeekMode mode;
@@ -127,12 +412,18 @@ status_t MP3Decoder::read(
        CHECK(seekTimeUs >= 0);
        CHECK(seekTimeUs >= 0);


        mNumFramesOutput = 0;
        mNumFramesOutput = 0;
        seekSource = true;


        if (mInputBuffer) {
        if (mInputBuffer) {
            mInputBuffer->release();
            mInputBuffer->release();
            mInputBuffer = NULL;
            mInputBuffer = NULL;
        }
        }


        if (mPartialBuffer) {
            mPartialBuffer->release();
            mPartialBuffer = NULL;
        }

        // Make sure that the next buffer output does not still
        // Make sure that the next buffer output does not still
        // depend on fragments from the last one decoded.
        // depend on fragments from the last one decoded.
        pvmp3_InitDecoder(mConfig, mDecoderBuf);
        pvmp3_InitDecoder(mConfig, mDecoderBuf);
@@ -147,6 +438,26 @@ status_t MP3Decoder::read(
            return err;
            return err;
        }
        }


        if ((mFixedHeader == 0) && (mInputBuffer->range_length() > 4)) {
            //save the first 4 bytes as fixed header for the reset of the file
            mFixedHeader = U32_AT((uint8_t *)mInputBuffer->data());
        }

        if (seekSource == true) {
            off_t syncOffset = 0;
            bool valid = resync((uint8_t *)mInputBuffer->data() + mInputBuffer->range_offset()
                                ,mInputBuffer->range_length(), mFixedHeader, &syncOffset);
            if (valid) {
                // consume these bytes, we might find a frame header in next buffer
                mInputBuffer->set_range(
                    mInputBuffer->range_offset() + syncOffset,
                    mInputBuffer->range_length() - syncOffset);
                LOGV("mp3 decoder found a sync point after seek syncOffset %d", syncOffset);
            } else {
                LOGV("NO SYNC POINT found, buffer length %d",mInputBuffer->range_length());
            }
        }

        int64_t timeUs;
        int64_t timeUs;
        if (mInputBuffer->meta_data()->findInt64(kKeyTime, &timeUs)) {
        if (mInputBuffer->meta_data()->findInt64(kKeyTime, &timeUs)) {
            mAnchorTimeUs = timeUs;
            mAnchorTimeUs = timeUs;
@@ -155,15 +466,33 @@ status_t MP3Decoder::read(
            // We must have a new timestamp after seeking.
            // We must have a new timestamp after seeking.
            CHECK(seekTimeUs < 0);
            CHECK(seekTimeUs < 0);
        }
        }
        // check for partial frame
        if (mPartialBuffer != NULL) {
            err = updatePartialFrame();
            if (err != OK) {
                // updating partial frame failed, discard the previously
                // saved partial frame and continue
                mPartialBuffer->release();
                mPartialBuffer = NULL;
                err = OK;
            }
        }
    }
    }


    MediaBuffer *buffer;
    MediaBuffer *buffer;
    CHECK_EQ(mBufferGroup->acquire_buffer(&buffer), OK);
    CHECK_EQ(mBufferGroup->acquire_buffer(&buffer), OK);


    if (mPartialBuffer != NULL) {
        mConfig->pInputBuffer =
        (uint8_t *)mPartialBuffer->data() + mPartialBuffer->range_offset();
        mConfig->inputBufferCurrentLength = mPartialBuffer->range_length();
        usedPartialFrame = true;
    } else {
        mConfig->pInputBuffer =
        mConfig->pInputBuffer =
            (uint8_t *)mInputBuffer->data() + mInputBuffer->range_offset();
            (uint8_t *)mInputBuffer->data() + mInputBuffer->range_offset();

        mConfig->inputBufferCurrentLength = mInputBuffer->range_length();
        mConfig->inputBufferCurrentLength = mInputBuffer->range_length();
    }

    mConfig->inputBufferMaxLength = 0;
    mConfig->inputBufferMaxLength = 0;
    mConfig->inputBufferUsedLength = 0;
    mConfig->inputBufferUsedLength = 0;


@@ -175,28 +504,67 @@ status_t MP3Decoder::read(
            != NO_DECODING_ERROR) {
            != NO_DECODING_ERROR) {
        LOGV("mp3 decoder returned error %d", decoderErr);
        LOGV("mp3 decoder returned error %d", decoderErr);


        if (decoderErr != NO_ENOUGH_MAIN_DATA_ERROR) {
        if ((decoderErr != NO_ENOUGH_MAIN_DATA_ERROR) &&
            (decoderErr != SYNCH_LOST_ERROR)) {
            buffer->release();
            buffer->release();
            buffer = NULL;
            buffer = NULL;


            mInputBuffer->release();
            mInputBuffer->release();
            mInputBuffer = NULL;
            mInputBuffer = NULL;
            if (mPartialBuffer) {
                mPartialBuffer->release();
                mPartialBuffer = NULL;
            }
            LOGE("mp3 decoder returned UNKNOWN_ERROR");


            return UNKNOWN_ERROR;
            return UNKNOWN_ERROR;
        }
        }


        if ((mPartialBuffer == NULL) && (decoderErr == NO_ENOUGH_MAIN_DATA_ERROR)) {
            // Might be a partial frame, save it
            mPartialBuffer = new MediaBuffer(mInputBuffer->size());
            memcpy ((uint8_t *)mPartialBuffer->data(),
                    mConfig->pInputBuffer, mConfig->inputBufferCurrentLength);
            mPartialBuffer->set_range(0, mConfig->inputBufferCurrentLength);
            // set output buffer to 0
            mConfig->outputFrameSize = 0;
            // consume the copied bytes from input
            mConfig->inputBufferUsedLength = mConfig->inputBufferCurrentLength;
        } else if(decoderErr == SYNCH_LOST_ERROR) {
            // Try to find the mp3 frame header in the current buffer
            off_t syncOffset = 0;
            bool valid = resync(mConfig->pInputBuffer, mConfig->inputBufferCurrentLength,
                                mFixedHeader, &syncOffset);
            if (!valid) {
                // consume these bytes, we might find a frame header in next buffer
                syncOffset = mConfig->inputBufferCurrentLength;
            }
            // set output buffer to 0
            mConfig->outputFrameSize = 0;
            // consume the junk bytes from input buffer
            mConfig->inputBufferUsedLength = syncOffset;
        } else {
            // This is recoverable, just ignore the current frame and
            // This is recoverable, just ignore the current frame and
            // play silence instead.
            // play silence instead.
            memset(buffer->data(), 0, mConfig->outputFrameSize * sizeof(int16_t));
            memset(buffer->data(), 0, mConfig->outputFrameSize * sizeof(int16_t));
            mConfig->inputBufferUsedLength = mInputBuffer->range_length();
            mConfig->inputBufferUsedLength = mInputBuffer->range_length();
        }
        }
    }


    buffer->set_range(
    buffer->set_range(
            0, mConfig->outputFrameSize * sizeof(int16_t));
            0, mConfig->outputFrameSize * sizeof(int16_t));


    if ((mPartialBuffer != NULL) && usedPartialFrame) {
        mPartialBuffer->set_range(
            mPartialBuffer->range_offset() + mConfig->inputBufferUsedLength,
            mPartialBuffer->range_length() - mConfig->inputBufferUsedLength);
        mPartialBuffer->release();
        mPartialBuffer = NULL;
    } else {
        mInputBuffer->set_range(
        mInputBuffer->set_range(
            mInputBuffer->range_offset() + mConfig->inputBufferUsedLength,
            mInputBuffer->range_offset() + mConfig->inputBufferUsedLength,
            mInputBuffer->range_length() - mConfig->inputBufferUsedLength);
            mInputBuffer->range_length() - mConfig->inputBufferUsedLength);
    }


    if (mInputBuffer->range_length() == 0) {
    if (mInputBuffer->range_length() == 0) {
        mInputBuffer->release();
        mInputBuffer->release();
+1 −1
Original line number Original line Diff line number Diff line
@@ -125,7 +125,7 @@ ERROR_CODE pvmp3_decode_header(tmp3Bits *inputStream,
     * Note that SYNC_WORD_LNGTH is in unit of bits, but inputBufferCurrentLength
     * Note that SYNC_WORD_LNGTH is in unit of bits, but inputBufferCurrentLength
     * is in unit of bytes.
     * is in unit of bytes.
     */
     */
    if (inputStream->inputBufferCurrentLength < ((SYNC_WORD_LNGTH + 21) >> 3))
    if (inputStream->inputBufferCurrentLength < ((SYNC_WORD_LNGTH + 25) >> 3))
    {
    {
        return NO_ENOUGH_MAIN_DATA_ERROR;
        return NO_ENOUGH_MAIN_DATA_ERROR;
    }
    }
+3 −0
Original line number Original line Diff line number Diff line
@@ -53,13 +53,16 @@ private:
    void *mDecoderBuf;
    void *mDecoderBuf;
    int64_t mAnchorTimeUs;
    int64_t mAnchorTimeUs;
    int64_t mNumFramesOutput;
    int64_t mNumFramesOutput;
    uint32_t mFixedHeader;


    MediaBuffer *mInputBuffer;
    MediaBuffer *mInputBuffer;
    MediaBuffer *mPartialBuffer;


    void init();
    void init();


    MP3Decoder(const MP3Decoder &);
    MP3Decoder(const MP3Decoder &);
    MP3Decoder &operator=(const MP3Decoder &);
    MP3Decoder &operator=(const MP3Decoder &);
    status_t updatePartialFrame();
};
};


}  // namespace android
}  // namespace android