From 822a489e595336be447f47f5c2a051e8fdd1cdff Mon Sep 17 00:00:00 2001 From: Robert Shih Date: Thu, 6 Feb 2014 14:01:30 -0800 Subject: LiveSession: Add support for block-by-block fetchFile. Bug: 11854054 Change-Id: I4025ba7fab8fab2e0c720f73894e908fd98a43d8 --- media/libstagefright/httplive/LiveSession.cpp | 97 +++++++++++++++++---------- media/libstagefright/httplive/LiveSession.h | 18 ++++- 2 files changed, 80 insertions(+), 35 deletions(-) (limited to 'media/libstagefright/httplive') diff --git a/media/libstagefright/httplive/LiveSession.cpp b/media/libstagefright/httplive/LiveSession.cpp index bd12ddc..0333a2a 100644 --- a/media/libstagefright/httplive/LiveSession.cpp +++ b/media/libstagefright/httplive/LiveSession.cpp @@ -512,53 +512,80 @@ sp LiveSession::addFetcher(const char *uri) { return info.mFetcher; } +/* + * Illustration of parameters: + * + * 0 `range_offset` + * +------------+-------------------------------------------------------+--+--+ + * | | | next block to fetch | | | + * | | `source` handle => `out` buffer | | | | + * | `url` file |<--------- buffer size --------->|<--- `block_size` -->| | | + * | |<----------- `range_length` / buffer capacity ----------->| | + * |<------------------------------ file_size ------------------------------->| + * + * Special parameter values: + * - range_length == -1 means entire file + * - block_size == 0 means entire range + * + */ status_t LiveSession::fetchFile( const char *url, sp *out, - int64_t range_offset, int64_t range_length) { - *out = NULL; + int64_t range_offset, int64_t range_length, + uint32_t block_size, /* download block size */ + sp *source /* to return and reuse source */) { + off64_t size; + sp temp_source; + if (source == NULL) { + source = &temp_source; + } - sp source; + if (*source == NULL) { + if (!strncasecmp(url, "file://", 7)) { + *source = new FileSource(url + 7); + } else if (strncasecmp(url, "http://", 7) + && strncasecmp(url, "https://", 8)) { + return ERROR_UNSUPPORTED; + } else { + KeyedVector 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 (!strncasecmp(url, "file://", 7)) { - source = new FileSource(url + 7); - } else if (strncasecmp(url, "http://", 7) - && strncasecmp(url, "https://", 8)) { - return ERROR_UNSUPPORTED; - } else { - KeyedVector 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; + } - if (err != OK) { - return err; + *source = mHTTPDataSource; } - - source = mHTTPDataSource; } - off64_t size; - status_t err = source->getSize(&size); - - if (err != OK) { + status_t getSizeErr = (*source)->getSize(&size); + if (getSizeErr != OK) { size = 65536; } - sp buffer = new ABuffer(size); - buffer->setRange(0, 0); + sp buffer = *out != NULL ? *out : new ABuffer(size); + if (*out == NULL) { + buffer->setRange(0, 0); + } + // adjust range_length if only reading partial block + if (block_size > 0 && (range_length == -1 || buffer->size() + block_size < range_length)) { + range_length = buffer->size() + block_size; + } for (;;) { + // Only resize when we don't know the size. size_t bufferRemaining = buffer->capacity() - buffer->size(); - - if (bufferRemaining == 0) { + if (bufferRemaining == 0 && getSizeErr != OK) { bufferRemaining = 32768; ALOGV("increasing download buffer to %d bytes", @@ -583,7 +610,9 @@ status_t LiveSession::fetchFile( } } - ssize_t n = source->readAt( + // The DataSource is responsible for informing us of error (n < 0) or eof (n == 0) + // to help us break out of the loop. + ssize_t n = (*source)->readAt( buffer->size(), buffer->data() + buffer->size(), maxBytesToRead); diff --git a/media/libstagefright/httplive/LiveSession.h b/media/libstagefright/httplive/LiveSession.h index 99b480a8..f42d7ae 100644 --- a/media/libstagefright/httplive/LiveSession.h +++ b/media/libstagefright/httplive/LiveSession.h @@ -145,9 +145,25 @@ private: status_t onSeek(const sp &msg); void onFinishDisconnect2(); + // If given a non-zero block_size (default 0), it is used to cap the number of + // bytes read in from the DataSource. If given a non-NULL buffer, new content + // is read into the end. + // + // The DataSource we read from is responsible for signaling error or EOF to help us + // break out of the read loop. The DataSource can be returned to the caller, so + // that the caller can reuse it for subsequent fetches (within the initially + // requested range). + // + // For reused HTTP sources, the caller must download a file sequentially without + // any overlaps or gaps to prevent reconnection. status_t fetchFile( const char *url, sp *out, - int64_t range_offset = 0, int64_t range_length = -1); + /* request/open a file starting at range_offset for range_length bytes */ + int64_t range_offset = 0, int64_t range_length = -1, + /* download block size */ + uint32_t block_size = 0, + /* reuse DataSource if doing partial fetch */ + sp *source = NULL); sp fetchPlaylist( const char *url, uint8_t *curPlaylistHash, bool *unchanged); -- cgit v1.1