diff options
-rw-r--r-- | media/libstagefright/httplive/LiveSession.cpp | 41 | ||||
-rw-r--r-- | media/libstagefright/httplive/M3UParser.cpp | 65 | ||||
-rw-r--r-- | media/libstagefright/include/LiveSession.h | 5 | ||||
-rw-r--r-- | media/libstagefright/include/M3UParser.h | 4 |
4 files changed, 109 insertions, 6 deletions
diff --git a/media/libstagefright/httplive/LiveSession.cpp b/media/libstagefright/httplive/LiveSession.cpp index 422850d..6f4b875 100644 --- a/media/libstagefright/httplive/LiveSession.cpp +++ b/media/libstagefright/httplive/LiveSession.cpp @@ -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); diff --git a/media/libstagefright/httplive/M3UParser.cpp b/media/libstagefright/httplive/M3UParser.cpp index 0d84c83..a50970e 100644 --- a/media/libstagefright/httplive/M3UParser.cpp +++ b/media/libstagefright/httplive/M3UParser.cpp @@ -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) { @@ -447,6 +466,52 @@ status_t M3UParser::parseCipherInfo( } // 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; long lval = strtol(s, &end, 10); diff --git a/media/libstagefright/include/LiveSession.h b/media/libstagefright/include/LiveSession.h index 116ed0e..3a11612 100644 --- a/media/libstagefright/include/LiveSession.h +++ b/media/libstagefright/include/LiveSession.h @@ -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(); diff --git a/media/libstagefright/include/M3UParser.h b/media/libstagefright/include/M3UParser.h index 478582d..e30d6fd 100644 --- a/media/libstagefright/include/M3UParser.h +++ b/media/libstagefright/include/M3UParser.h @@ -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); |