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

Commit 688ff9a7 authored by Andreas Huber's avatar Andreas Huber Committed by Android (Google) Code Review
Browse files

Merge "Support new HLS byte-range extensions"

parents 9fcc5ce7 796da703
Loading
Loading
Loading
Loading
+36 −5
Original line number Diff line number Diff line
@@ -215,7 +215,9 @@ void LiveSession::onDisconnect() {
    mDisconnectPending = false;
}

status_t LiveSession::fetchFile(const char *url, sp<ABuffer> *out) {
status_t LiveSession::fetchFile(
        const char *url, sp<ABuffer> *out,
        int64_t range_offset, int64_t range_length) {
    *out = NULL;

    sp<DataSource> source;
@@ -234,8 +236,18 @@ status_t LiveSession::fetchFile(const char *url, sp<ABuffer> *out) {
            }
        }

        status_t err = mHTTPDataSource->connect(
                url, mExtraHeaders.isEmpty() ? NULL : &mExtraHeaders);
        KeyedVector<String8, String8> headers = mExtraHeaders;
        if (range_offset > 0 || range_length >= 0) {
            headers.add(
                    String8("Range"),
                    String8(
                        StringPrintf(
                            "bytes=%lld-%s",
                            range_offset,
                            range_length < 0
                                ? "" : StringPrintf("%lld", range_offset + range_length - 1).c_str()).c_str()));
        }
        status_t err = mHTTPDataSource->connect(url, &headers);

        if (err != OK) {
            return err;
@@ -270,9 +282,21 @@ status_t LiveSession::fetchFile(const char *url, sp<ABuffer> *out) {
            buffer = copy;
        }

        size_t maxBytesToRead = bufferRemaining;
        if (range_length >= 0) {
            int64_t bytesLeftInRange = range_length - buffer->size();
            if (bytesLeftInRange < maxBytesToRead) {
                maxBytesToRead = bytesLeftInRange;

                if (bytesLeftInRange == 0) {
                    break;
                }
            }
        }

        ssize_t n = source->readAt(
                buffer->size(), buffer->data() + buffer->size(),
                bufferRemaining);
                maxBytesToRead);

        if (n < 0) {
            return n;
@@ -659,8 +683,15 @@ rinse_repeat:
        explicitDiscontinuity = true;
    }

    int64_t range_offset, range_length;
    if (!itemMeta->findInt64("range-offset", &range_offset)
            || !itemMeta->findInt64("range-length", &range_length)) {
        range_offset = 0;
        range_length = -1;
    }

    sp<ABuffer> buffer;
    status_t err = fetchFile(uri.c_str(), &buffer);
    status_t err = fetchFile(uri.c_str(), &buffer, range_offset, range_length);
    if (err != OK) {
        LOGE("failed to fetch .ts segment at url '%s'", uri.c_str());
        mDataSource->queueEOS(err);
+65 −0
Original line number Diff line number Diff line
@@ -152,6 +152,7 @@ status_t M3UParser::parse(const void *_data, size_t size) {

    const char *data = (const char *)_data;
    size_t offset = 0;
    uint64_t segmentRangeOffset = 0;
    while (offset < size) {
        size_t offsetLF = offset;
        while (offsetLF < size && data[offsetLF] != '\n') {
@@ -218,6 +219,24 @@ status_t M3UParser::parse(const void *_data, size_t size) {
                }
                mIsVariantPlaylist = true;
                err = parseStreamInf(line, &itemMeta);
            } else if (line.startsWith("#EXT-X-BYTERANGE")) {
                if (mIsVariantPlaylist) {
                    return ERROR_MALFORMED;
                }

                uint64_t length, offset;
                err = parseByteRange(line, segmentRangeOffset, &length, &offset);

                if (err == OK) {
                    if (itemMeta == NULL) {
                        itemMeta = new AMessage;
                    }

                    itemMeta->setInt64("range-offset", offset);
                    itemMeta->setInt64("range-length", length);

                    segmentRangeOffset = offset + length;
                }
            }

            if (err != OK) {
@@ -446,6 +465,52 @@ status_t M3UParser::parseCipherInfo(
    return OK;
}

// static
status_t M3UParser::parseByteRange(
        const AString &line, uint64_t curOffset,
        uint64_t *length, uint64_t *offset) {
    ssize_t colonPos = line.find(":");

    if (colonPos < 0) {
        return ERROR_MALFORMED;
    }

    ssize_t atPos = line.find("@", colonPos + 1);

    AString lenStr;
    if (atPos < 0) {
        lenStr = AString(line, colonPos + 1, line.size() - colonPos - 1);
    } else {
        lenStr = AString(line, colonPos + 1, atPos - colonPos - 1);
    }

    lenStr.trim();

    const char *s = lenStr.c_str();
    char *end;
    *length = strtoull(s, &end, 10);

    if (s == end || *end != '\0') {
        return ERROR_MALFORMED;
    }

    if (atPos >= 0) {
        AString offStr = AString(line, atPos + 1, line.size() - atPos - 1);
        offStr.trim();

        const char *s = offStr.c_str();
        *offset = strtoull(s, &end, 10);

        if (s == end || *end != '\0') {
            return ERROR_MALFORMED;
        }
    } else {
        *offset = curOffset;
    }

    return OK;
}

// static
status_t M3UParser::ParseInt32(const char *s, int32_t *x) {
    char *end;
+4 −1
Original line number Diff line number Diff line
@@ -120,7 +120,10 @@ private:
    void onMonitorQueue();
    void onSeek(const sp<AMessage> &msg);

    status_t fetchFile(const char *url, sp<ABuffer> *out);
    status_t fetchFile(
            const char *url, sp<ABuffer> *out,
            int64_t range_offset = 0, int64_t range_length = -1);

    sp<M3UParser> fetchPlaylist(const char *url, bool *unchanged);
    size_t getBandwidthIndex();

+4 −0
Original line number Diff line number Diff line
@@ -72,6 +72,10 @@ private:
    static status_t parseCipherInfo(
            const AString &line, sp<AMessage> *meta, const AString &baseURI);

    static status_t parseByteRange(
            const AString &line, uint64_t curOffset,
            uint64_t *length, uint64_t *offset);

    static status_t ParseInt32(const char *s, int32_t *x);
    static status_t ParseDouble(const char *s, double *x);