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

Commit 2833eaf0 authored by Marco Nelissen's avatar Marco Nelissen Committed by Android (Google) Code Review
Browse files

Merge "Skip XING/VBRI frame when decoding"

parents 3e6038dd 4fc769e9
Loading
Loading
Loading
Loading
+7 −0
Original line number Diff line number Diff line
@@ -317,6 +317,13 @@ MP3Extractor::MP3Extractor(
        mSeeker = VBRISeeker::CreateFromSource(mDataSource, post_id3_pos);
    }

    if (mSeeker != NULL) {
        // While it is safe to send the XING/VBRI frame to the decoder, this will
        // result in an extra 1152 samples being output. The real first frame to
        // decode is after the XING/VBRI frame, so skip there.
        mFirstFramePos += frame_size;
    }

    int64_t durationUs;

    if (mSeeker == NULL || !mSeeker->getDuration(&durationUs)) {
+1 −1
Original line number Diff line number Diff line
@@ -92,7 +92,7 @@ sp<VBRISeeker> VBRISeeker::CreateFromSource(
    }

    sp<VBRISeeker> seeker = new VBRISeeker;
    seeker->mBasePos = post_id3_pos;
    seeker->mBasePos = post_id3_pos + frameSize;
    seeker->mDurationUs = durationUs;

    off64_t offset = post_id3_pos;
+51 −106
Original line number Diff line number Diff line
@@ -15,35 +15,13 @@
 */

#include "include/XINGSeeker.h"
#include "include/avc_utils.h"

#include <media/stagefright/DataSource.h>
#include <media/stagefright/Utils.h>

namespace android {

static bool parse_xing_header(
        const sp<DataSource> &source, off64_t first_frame_pos,
        int32_t *frame_number = NULL, int32_t *byte_number = NULL,
        unsigned char *table_of_contents = NULL, bool *toc_is_valid = NULL,
        int32_t *quality_indicator = NULL, int64_t *duration = NULL);

// static
sp<XINGSeeker> XINGSeeker::CreateFromSource(
        const sp<DataSource> &source, off64_t first_frame_pos) {
    sp<XINGSeeker> seeker = new XINGSeeker;

    seeker->mFirstFramePos = first_frame_pos;

    if (!parse_xing_header(
                source, first_frame_pos,
                NULL, &seeker->mSizeBytes, seeker->mTOC, &seeker->mTOCValid,
                NULL, &seeker->mDurationUs)) {
        return NULL;
    }

    return seeker;
}

XINGSeeker::XINGSeeker()
    : mDurationUs(-1),
      mSizeBytes(0) {
@@ -91,60 +69,50 @@ bool XINGSeeker::getOffsetForTime(int64_t *timeUs, off64_t *pos) {
    return true;
}

static bool parse_xing_header(
        const sp<DataSource> &source, off64_t first_frame_pos,
        int32_t *frame_number, int32_t *byte_number,
        unsigned char *table_of_contents, bool *toc_valid,
        int32_t *quality_indicator,
        int64_t *duration) {
    if (frame_number) {
        *frame_number = 0;
    }
    if (byte_number) {
        *byte_number = 0;
    }
    if (toc_valid) {
        *toc_valid = false;
    }
    if (quality_indicator) {
        *quality_indicator = 0;
    }
    if (duration) {
        *duration = 0;
    }
// static
sp<XINGSeeker> XINGSeeker::CreateFromSource(
        const sp<DataSource> &source, off64_t first_frame_pos) {
    sp<XINGSeeker> seeker = new XINGSeeker;

    seeker->mFirstFramePos = first_frame_pos;

    ALOGI("xingseeker first frame pos: %lld", first_frame_pos);

    seeker->mSizeBytes = 0;
    seeker->mTOCValid = false;
    seeker->mDurationUs = 0;

    uint8_t buffer[4];
    int offset = first_frame_pos;
    if (source->readAt(offset, &buffer, 4) < 4) { // get header
        return false;
        return NULL;
    }
    offset += 4;

    uint8_t id, layer, sr_index, mode;
    layer = (buffer[1] >> 1) & 3;
    id = (buffer[1] >> 3) & 3;
    sr_index = (buffer[2] >> 2) & 3;
    mode = (buffer[3] >> 6) & 3;
    if (layer == 0) {
        return false;
    }
    if (id == 1) {
        return false;
    }
    if (sr_index == 3) {
        return false;
    int header = U32_AT(buffer);;
    size_t xingframesize = 0;
    int sampling_rate = 0;
    int num_channels;
    int samples_per_frame = 0;
    if (!GetMPEGAudioFrameSize(header, &xingframesize, &sampling_rate, &num_channels,
                               NULL, &samples_per_frame)) {
        return NULL;
    }
    seeker->mFirstFramePos += xingframesize;

    uint8_t version = (buffer[1] >> 3) & 3;

    // determine offset of XING header
    if(id&1) { // mpeg1
        if (mode != 3) offset += 32;
    if(version & 1) { // mpeg1
        if (num_channels != 1) offset += 32;
        else offset += 17;
    } else { // mpeg2
        if (mode != 3) offset += 17;
    } else { // mpeg 2 or 2.5
        if (num_channels != 1) offset += 17;
        else offset += 9;
    }

    if (source->readAt(offset, &buffer, 4) < 4) { // XING header ID
        return false;
        return NULL;
    }
    offset += 4;
    // Check XING ID
@@ -152,73 +120,50 @@ static bool parse_xing_header(
                || (buffer[2] != 'n') || (buffer[3] != 'g')) {
        if ((buffer[0] != 'I') || (buffer[1] != 'n')
                    || (buffer[2] != 'f') || (buffer[3] != 'o')) {
            return false;
            return NULL;
        }
    }

    if (source->readAt(offset, &buffer, 4) < 4) { // flags
        return false;
        return NULL;
    }
    offset += 4;
    uint32_t flags = U32_AT(buffer);

    if (flags & 0x0001) {  // Frames field is present
        if (source->readAt(offset, buffer, 4) < 4) {
             return false;
        }
        if (frame_number) {
           *frame_number = U32_AT(buffer);
        }
        int32_t frame = U32_AT(buffer);
        // Samples per Frame: 1. index = MPEG Version ID, 2. index = Layer
        const int samplesPerFrames[2][3] =
        {
            { 384, 1152, 576  }, // MPEG 2, 2.5: layer1, layer2, layer3
            { 384, 1152, 1152 }, // MPEG 1: layer1, layer2, layer3
        };
        // sampling rates in hertz: 1. index = MPEG Version ID, 2. index = sampling rate index
        const int samplingRates[4][3] =
        {
            { 11025, 12000, 8000,  },    // MPEG 2.5
            { 0,     0,     0,     },    // reserved
            { 22050, 24000, 16000, },    // MPEG 2
            { 44100, 48000, 32000, }     // MPEG 1
        };
        if (duration) {
            *duration = (int64_t)frame * samplesPerFrames[id&1][3-layer] * 1000000LL
                / samplingRates[id][sr_index];
             return NULL;
        }
        int32_t frames = U32_AT(buffer);
        seeker->mDurationUs = (int64_t)frames * samples_per_frame * 1000000LL / sampling_rate;
        offset += 4;
    }
    if (flags & 0x0002) {  // Bytes field is present
        if (byte_number) {
        if (source->readAt(offset, buffer, 4) < 4) {
                return false;
            }
            *byte_number = U32_AT(buffer);
            return NULL;
        }
        seeker->mSizeBytes = U32_AT(buffer);
        offset += 4;
    }
    if (flags & 0x0004) {  // TOC field is present
        if (table_of_contents) {
            if (source->readAt(offset + 1, table_of_contents, 99) < 99) {
                return false;
            }
            if (toc_valid) {
                *toc_valid = true;
            }
        if (source->readAt(offset + 1, seeker->mTOC, 99) < 99) {
            return NULL;
        }
        seeker->mTOCValid = true;
        offset += 100;
    }

#if 0
    if (flags & 0x0008) {  // Quality indicator field is present
        if (quality_indicator) {
        if (source->readAt(offset, buffer, 4) < 4) {
                return false;
            }
            *quality_indicator = U32_AT(buffer);
            return NULL;
        }
        // do something with the quality indicator
        offset += 4;
    }
    return true;
#endif

    return seeker;
}

}  // namespace android