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

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

Merge changes from topic "opus_finale"

* changes:
  stagefright_foundation: Fix parsing seek pre roll in Opus
  stagefright: Updates to Opus unified CSD syntax
parents fd11daa9 630dda97
Loading
Loading
Loading
Loading
+15 −10
Original line number Diff line number Diff line
@@ -252,20 +252,25 @@ void C2SoftOpusDec::process(
    const uint8_t *data = rView.data() + inOffset;
    if (mInputBufferCount < 3) {
        if (mInputBufferCount == 0) {
            size_t opusHeadSize = inSize;
            size_t opusHeadSize = 0;
            size_t codecDelayBufSize = 0;
            size_t seekPreRollBufSize = 0;
            void *opusHeadBuf = (void *)data;
            void *opusHeadBuf = NULL;
            void *codecDelayBuf = NULL;
            void *seekPreRollBuf = NULL;

            GetOpusHeaderBuffers(data, inSize, &opusHeadBuf,
            if (!GetOpusHeaderBuffers(data, inSize, &opusHeadBuf,
                                     &opusHeadSize, &codecDelayBuf,
                                     &codecDelayBufSize, &seekPreRollBuf,
                                &seekPreRollBufSize);
                                     &seekPreRollBufSize)) {
                ALOGE("%s encountered error in GetOpusHeaderBuffers", __func__);
                mSignalledError = true;
                work->result = C2_CORRUPTED;
                return;
            }

            if (!ParseOpusHeader((uint8_t *)opusHeadBuf, opusHeadSize, &mHeader)) {
                ALOGE("Encountered error while Parsing Opus Header.");
                ALOGE("%s Encountered error while Parsing Opus Header.", __func__);
                mSignalledError = true;
                work->result = C2_CORRUPTED;
                return;
@@ -304,16 +309,16 @@ void C2SoftOpusDec::process(
                return;
            }

            if (codecDelayBuf && codecDelayBufSize == 8) {
            if (codecDelayBuf && codecDelayBufSize == sizeof(uint64_t)) {
                uint64_t value;
                memcpy(&value, codecDelayBuf, sizeof(uint64_t));
                mCodecDelay = ns_to_samples(value, kRate);
                mSamplesToDiscard = mCodecDelay;
                ++mInputBufferCount;
            }
            if (seekPreRollBuf && seekPreRollBufSize == 8) {
            if (seekPreRollBuf && seekPreRollBufSize == sizeof(uint64_t)) {
                uint64_t value;
                memcpy(&value, codecDelayBuf, sizeof(uint64_t));
                memcpy(&value, seekPreRollBuf, sizeof(uint64_t));
                mSeekPreRoll = ns_to_samples(value, kRate);
                ++mInputBufferCount;
            }
+12 −0
Original line number Diff line number Diff line
@@ -295,6 +295,18 @@ status_t OggWriter::threadFunc() {
                  mEstimatedSizeBytes, mMaxFileSizeLimitBytes);
            break;
        }

        int32_t isCodecSpecific;
        if ((buffer->meta_data().findInt32(kKeyIsCodecConfig, &isCodecSpecific)
             && isCodecSpecific)
            || IsOpusHeader((uint8_t*)buffer->data() + buffer->range_offset(),
                         buffer->range_length())) {
            ALOGV("Drop codec specific info buffer");
            buffer->release();
            buffer = nullptr;
            continue;
        }

        int64_t timestampUs;
        CHECK(buffer->meta_data().findInt64(kKeyTime, &timestampUs));
        if (timestampUs > mEstimatedDurationUs) {
+120 −31
Original line number Diff line number Diff line
@@ -15,9 +15,9 @@
 */

//#define LOG_NDEBUG 0
#define LOG_TAG "SoftOpus"
#include <algorithm>
#define LOG_TAG "OpusHeader"
#include <cstring>
#include <inttypes.h>
#include <stdint.h>

#include <log/log.h>
@@ -91,6 +91,9 @@ static uint16_t ReadLE16(const uint8_t* data, size_t data_size, uint32_t read_of

// Parses Opus Header. Header spec: http://wiki.xiph.org/OggOpus#ID_Header
bool ParseOpusHeader(const uint8_t* data, size_t data_size, OpusHeader* header) {
    if (data == NULL) {
        return false;
    }
    if (data_size < kOpusHeaderSize) {
        ALOGV("Header size is too small.");
        return false;
@@ -183,53 +186,88 @@ int WriteOpusHeaders(const OpusHeader &header, int inputSampleRate,
        ALOGD("Buffer not large enough to hold unified OPUS CSD");
        return -1;
    }
    int headerLen = 0;

    // Add opus header
    /*
      Following is the CSD syntax for signalling OpusHeader
      (http://wiki.xiph.org/OggOpus#ID_Header)

      Marker (8 bytes) | Length (8 bytes) | OpusHeader

      Markers supported:
      AOPUS_CSD_OPUS_HEADER_MARKER - Signals Opus Header

      Length should be a value within AOPUS_OPUSHEAD_MINSIZE and AOPUS_OPUSHEAD_MAXSIZE.
    */

    memcpy(output + headerLen, AOPUS_CSD_OPUS_HEADER_MARKER, AOPUS_MARKER_SIZE);
    headerLen += AOPUS_MARKER_SIZE;

    int headerLen = WriteOpusHeader(header, inputSampleRate, output,
    // Place holder for opusHeader Size
    headerLen += AOPUS_LENGTH_SIZE;

    int headerSize = WriteOpusHeader(header, inputSampleRate, output + headerLen,
        outputSize);
    if (headerLen < 0) {
        ALOGD("WriteOpusHeader failed");
        return -1;
    }
    if (headerLen >= (outputSize - 2 * AOPUS_TOTAL_CSD_SIZE)) {
        ALOGD("Buffer not large enough to hold codec delay and seek pre roll");
    if (headerSize < 0) {
        ALOGD("%s: WriteOpusHeader failed", __func__);
        return -1;
    }
    headerLen += headerSize;

    uint64_t length = AOPUS_LENGTH;
    // Update opus headerSize after AOPUS_CSD_OPUS_HEADER_MARKER
    uint64_t length = headerSize;
    memcpy(output + AOPUS_MARKER_SIZE, &length, AOPUS_LENGTH_SIZE);

    /*
      Following is the CSD syntax for signalling codec delay and
      seek pre-roll which is to be appended after OpusHeader

      Marker (8 bytes) | Length (8 bytes) | Samples (8 bytes)
      Marker (8 bytes) | Length (8 bytes) | Samples in ns (8 bytes)

      Markers supported:
      AOPUSDLY - Signals Codec Delay
      AOPUSPRL - Signals seek pre roll
      AOPUS_CSD_CODEC_DELAY_MARKER - codec delay as samples in ns, represented in 8 bytes
      AOPUS_CSD_SEEK_PREROLL_MARKER - preroll adjustment as samples in ns, represented in 8 bytes

      Length should be 8.
    */

    length = sizeof(codecDelay);
    if (headerLen > (outputSize - AOPUS_MARKER_SIZE - AOPUS_LENGTH_SIZE - length)) {
        ALOGD("Buffer not large enough to hold codec delay");
        return -1;
    }
    // Add codec delay
    memcpy(output + headerLen, AOPUS_CSD_CODEC_DELAY_MARKER, AOPUS_MARKER_SIZE);
    headerLen += AOPUS_MARKER_SIZE;
    memcpy(output + headerLen, &length, AOPUS_LENGTH_SIZE);
    headerLen += AOPUS_LENGTH_SIZE;
    memcpy(output + headerLen, &codecDelay, AOPUS_CSD_SIZE);
    headerLen += AOPUS_CSD_SIZE;
    memcpy(output + headerLen, &codecDelay, length);
    headerLen += length;

    length = sizeof(seekPreRoll);
    if (headerLen > (outputSize - AOPUS_MARKER_SIZE - AOPUS_LENGTH_SIZE - length)) {
        ALOGD("Buffer not large enough to hold seek pre roll");
        return -1;
    }
    // Add skip pre roll
    memcpy(output + headerLen, AOPUS_CSD_SEEK_PREROLL_MARKER, AOPUS_MARKER_SIZE);
    headerLen += AOPUS_MARKER_SIZE;
    memcpy(output + headerLen, &length, AOPUS_LENGTH_SIZE);
    headerLen += AOPUS_LENGTH_SIZE;
    memcpy(output + headerLen, &seekPreRoll, AOPUS_CSD_SIZE);
    headerLen += AOPUS_CSD_SIZE;
    memcpy(output + headerLen, &seekPreRoll, length);
    headerLen += length;

    return headerLen;
}

void GetOpusHeaderBuffers(const uint8_t *data, size_t data_size,
bool IsOpusHeader(const uint8_t *data, size_t data_size) {
    if (data_size < AOPUS_MARKER_SIZE) {
        return false;
    }

    return !memcmp(data, AOPUS_CSD_OPUS_HEADER_MARKER, AOPUS_MARKER_SIZE);
}

bool GetOpusHeaderBuffers(const uint8_t *data, size_t data_size,
                          void **opusHeadBuf, size_t *opusHeadSize,
                          void **codecDelayBuf, size_t *codecDelaySize,
                          void **seekPreRollBuf, size_t *seekPreRollSize) {
@@ -237,26 +275,77 @@ void GetOpusHeaderBuffers(const uint8_t *data, size_t data_size,
    *codecDelaySize = 0;
    *seekPreRollBuf = NULL;
    *seekPreRollSize = 0;
    *opusHeadBuf = NULL;
    *opusHeadSize = 0;

    // AOPUS_MARKER_SIZE is 8 "OpusHead" is of size 8
    if (data_size < 8)
        return false;

    // Check if the CSD is in legacy format
    if (!memcmp("OpusHead", data, 8)) {
        if (data_size < AOPUS_OPUSHEAD_MINSIZE || data_size > AOPUS_OPUSHEAD_MAXSIZE) {
            ALOGD("Unexpected size for opusHeadSize %zu", data_size);
            return false;
        }
        *opusHeadBuf = (void *)data;
        *opusHeadSize = data_size;
    if (data_size >= AOPUS_UNIFIED_CSD_MINSIZE) {
        return true;
    } else if (memcmp(AOPUS_CSD_MARKER_PREFIX, data, AOPUS_CSD_MARKER_PREFIX_SIZE) == 0) {
        size_t i = 0;
        while (i < data_size - AOPUS_TOTAL_CSD_SIZE) {
        bool found = false;
        while (i <= data_size - AOPUS_MARKER_SIZE - AOPUS_LENGTH_SIZE) {
            uint8_t *csdBuf = (uint8_t *)data + i;
            if (!memcmp(csdBuf, AOPUS_CSD_CODEC_DELAY_MARKER, AOPUS_MARKER_SIZE)) {
                *opusHeadSize = std::min(*opusHeadSize, i);
            if (!memcmp(csdBuf, AOPUS_CSD_OPUS_HEADER_MARKER, AOPUS_MARKER_SIZE)) {
                uint64_t value;
                memcpy(&value, csdBuf + AOPUS_MARKER_SIZE, sizeof(value));
                if (value < AOPUS_OPUSHEAD_MINSIZE || value > AOPUS_OPUSHEAD_MAXSIZE) {
                    ALOGD("Unexpected size for opusHeadSize %" PRIu64, value);
                    return false;
                }
                i += AOPUS_MARKER_SIZE + AOPUS_LENGTH_SIZE + value;
                if (i > data_size) {
                    ALOGD("Marker signals a header that is larger than input");
                    return false;
                }
                *opusHeadBuf = csdBuf + AOPUS_MARKER_SIZE + AOPUS_LENGTH_SIZE;
                *opusHeadSize = value;
                found = true;
            } else if (!memcmp(csdBuf, AOPUS_CSD_CODEC_DELAY_MARKER, AOPUS_MARKER_SIZE)) {
                uint64_t value;
                memcpy(&value, csdBuf + AOPUS_MARKER_SIZE, sizeof(value));
                if (value != sizeof(uint64_t)) {
                    ALOGD("Unexpected size for codecDelay %" PRIu64, value);
                    return false;
                }
                i += AOPUS_MARKER_SIZE + AOPUS_LENGTH_SIZE + value;
                if (i > data_size) {
                    ALOGD("Marker signals a header that is larger than input");
                    return false;
                }
                *codecDelayBuf = csdBuf + AOPUS_MARKER_SIZE + AOPUS_LENGTH_SIZE;
                *codecDelaySize = AOPUS_CSD_SIZE;
                i += AOPUS_TOTAL_CSD_SIZE;
                *codecDelaySize = value;
            } else if (!memcmp(csdBuf, AOPUS_CSD_SEEK_PREROLL_MARKER, AOPUS_MARKER_SIZE)) {
                *opusHeadSize = std::min(*opusHeadSize, i);
                uint64_t value;
                memcpy(&value, csdBuf + AOPUS_MARKER_SIZE, sizeof(value));
                if (value != sizeof(uint64_t)) {
                    ALOGD("Unexpected size for seekPreRollSize %" PRIu64, value);
                    return false;
                }
                i += AOPUS_MARKER_SIZE + AOPUS_LENGTH_SIZE + value;
                if (i > data_size) {
                    ALOGD("Marker signals a header that is larger than input");
                    return false;
                }
                *seekPreRollBuf = csdBuf + AOPUS_MARKER_SIZE + AOPUS_LENGTH_SIZE;
                *seekPreRollSize = AOPUS_CSD_SIZE;
                i += AOPUS_TOTAL_CSD_SIZE;
                *seekPreRollSize = value;
            } else {
                i++;
            }
        }
        return found;
    } else {
        return false;  // it isn't in either format
    }
}

+29 −13
Original line number Diff line number Diff line
@@ -25,22 +25,37 @@
namespace android {

/* Constants used for delimiting Opus CSD */
#define AOPUS_CSD_CODEC_DELAY_MARKER "AOPUSDLY"
#define AOPUS_CSD_SEEK_PREROLL_MARKER "AOPUSPRL"
#define AOPUS_CSD_SIZE 8
#define AOPUS_LENGTH 8
#define AOPUS_CSD_MARKER_PREFIX "AOPUS"
#define AOPUS_CSD_MARKER_PREFIX_SIZE (sizeof(AOPUS_CSD_MARKER_PREFIX) - 1)
#define AOPUS_CSD_OPUS_HEADER_MARKER AOPUS_CSD_MARKER_PREFIX "HDR"
#define AOPUS_CSD_CODEC_DELAY_MARKER AOPUS_CSD_MARKER_PREFIX "DLY"
#define AOPUS_CSD_SEEK_PREROLL_MARKER AOPUS_CSD_MARKER_PREFIX "PRL"
#define AOPUS_MARKER_SIZE 8
#define AOPUS_LENGTH_SIZE 8
#define AOPUS_TOTAL_CSD_SIZE \
    ((AOPUS_MARKER_SIZE) + (AOPUS_LENGTH_SIZE) + (AOPUS_CSD_SIZE))
#define AOPUS_CSD0_MINSIZE 19
#define AOPUS_LENGTH_SIZE sizeof(uint64_t)
#define AOPUS_CSD_CODEC_DELAY_SIZE \
     (AOPUS_MARKER_SIZE) + (AOPUS_LENGTH_SIZE) + sizeof(uint64_t)
#define AOPUS_CSD_SEEK_PREROLL_SIZE \
     (AOPUS_MARKER_SIZE) + (AOPUS_LENGTH_SIZE) + sizeof(uint64_t)

/* OpusHead csd minimum size is 19 */
#define AOPUS_OPUSHEAD_MINSIZE 19
#define AOPUS_CSD_OPUSHEAD_MINSIZE \
    (AOPUS_MARKER_SIZE) + (AOPUS_LENGTH_SIZE) + (AOPUS_OPUSHEAD_MINSIZE)

#define AOPUS_UNIFIED_CSD_MINSIZE \
    ((AOPUS_CSD0_MINSIZE) + 2 * (AOPUS_TOTAL_CSD_SIZE))
    ((AOPUS_CSD_OPUSHEAD_MINSIZE) + \
     (AOPUS_CSD_CODEC_DELAY_SIZE) + \
     (AOPUS_CSD_SEEK_PREROLL_SIZE))

/* OpusHead csd at max can be AOPUS_CSD_OPUSHEAD_MINSIZE + 2 + max number of channels (255) */
#define AOPUS_OPUSHEAD_MAXSIZE ((AOPUS_OPUSHEAD_MINSIZE) + 2 + 255)
#define AOPUS_CSD_OPUSHEAD_MAXSIZE \
    (AOPUS_MARKER_SIZE) + (AOPUS_LENGTH_SIZE) + (AOPUS_OPUSHEAD_MAXSIZE)

/* CSD0 at max can be 22 bytes + max number of channels (255) */
#define AOPUS_CSD0_MAXSIZE 277
#define AOPUS_UNIFIED_CSD_MAXSIZE \
    ((AOPUS_CSD0_MAXSIZE) + 2 * (AOPUS_TOTAL_CSD_SIZE))
    ((AOPUS_CSD_OPUSHEAD_MAXSIZE) + \
     (AOPUS_CSD_CODEC_DELAY_SIZE) + \
     (AOPUS_CSD_SEEK_PREROLL_SIZE))

struct OpusHeader {
    int channels;
@@ -54,13 +69,14 @@ struct OpusHeader {

bool ParseOpusHeader(const uint8_t* data, size_t data_size, OpusHeader* header);
int WriteOpusHeader(const OpusHeader &header, int input_sample_rate, uint8_t* output, size_t output_size);
void GetOpusHeaderBuffers(const uint8_t *data, size_t data_size,
bool GetOpusHeaderBuffers(const uint8_t *data, size_t data_size,
                          void **opusHeadBuf, size_t *opusHeadSize,
                          void **codecDelayBuf, size_t *codecDelaySize,
                          void **seekPreRollBuf, size_t *seekPreRollSize);
int WriteOpusHeaders(const OpusHeader &header, int inputSampleRate,
                     uint8_t* output, size_t outputSize, uint64_t codecDelay,
                     uint64_t seekPreRoll);
bool IsOpusHeader(const uint8_t *data, size_t data_size);
}  // namespace android

#endif  // OPUS_HEADER_H_