diff options
Diffstat (limited to 'media/libstagefright/httplive/LiveSession.cpp')
-rw-r--r-- | media/libstagefright/httplive/LiveSession.cpp | 303 |
1 files changed, 138 insertions, 165 deletions
diff --git a/media/libstagefright/httplive/LiveSession.cpp b/media/libstagefright/httplive/LiveSession.cpp index fc1353a..95779c4 100644 --- a/media/libstagefright/httplive/LiveSession.cpp +++ b/media/libstagefright/httplive/LiveSession.cpp @@ -27,6 +27,8 @@ #include "mpeg2ts/AnotherPacketSource.h" #include <cutils/properties.h> +#include <media/IMediaHTTPConnection.h> +#include <media/IMediaHTTPService.h> #include <media/stagefright/foundation/hexdump.h> #include <media/stagefright/foundation/ABuffer.h> #include <media/stagefright/foundation/ADebug.h> @@ -34,6 +36,7 @@ #include <media/stagefright/DataSource.h> #include <media/stagefright/FileSource.h> #include <media/stagefright/MediaErrors.h> +#include <media/stagefright/MediaHTTP.h> #include <media/stagefright/MetaData.h> #include <media/stagefright/Utils.h> @@ -44,17 +47,13 @@ namespace android { LiveSession::LiveSession( - const sp<AMessage> ¬ify, uint32_t flags, bool uidValid, uid_t uid) + const sp<AMessage> ¬ify, uint32_t flags, + const sp<IMediaHTTPService> &httpService) : mNotify(notify), mFlags(flags), - mUIDValid(uidValid), - mUID(uid), + mHTTPService(httpService), mInPreparationPhase(true), - mHTTPDataSource( - HTTPBase::Create( - (mFlags & kFlagIncognito) - ? HTTPBase::kFlagIncognito - : 0)), + mHTTPDataSource(new MediaHTTP(mHTTPService->makeHTTPConnection())), mPrevBandwidthIndex(-1), mStreamMask(0), mCheckBandwidthGeneration(0), @@ -62,18 +61,14 @@ LiveSession::LiveSession( mRealTimeBaseUs(0ll), mReconfigurationInProgress(false), mDisconnectReplyID(0) { - if (mUIDValid) { - mHTTPDataSource->setUID(mUID); - } - - mPacketSources.add( - STREAMTYPE_AUDIO, new AnotherPacketSource(NULL /* meta */)); - mPacketSources.add( - STREAMTYPE_VIDEO, new AnotherPacketSource(NULL /* meta */)); + mStreams[kAudioIndex] = StreamItem("audio"); + mStreams[kVideoIndex] = StreamItem("video"); + mStreams[kSubtitleIndex] = StreamItem("subtitle"); - mPacketSources.add( - STREAMTYPE_SUBTITLES, new AnotherPacketSource(NULL /* meta */)); + for (size_t i = 0; i < kMaxStreams; ++i) { + mPacketSources.add(indexToType(i), new AnotherPacketSource(NULL /* meta */)); + } } LiveSession::~LiveSession() { @@ -374,6 +369,12 @@ int LiveSession::SortByBandwidth(const BandwidthItem *a, const BandwidthItem *b) return 1; } +// static +LiveSession::StreamType LiveSession::indexToType(int idx) { + CHECK(idx >= 0 && idx < kMaxStreams); + return (StreamType)(1 << idx); +} + void LiveSession::onConnect(const sp<AMessage> &msg) { AString url; CHECK(msg->findString("url", &url)); @@ -512,54 +513,81 @@ sp<PlaylistFetcher> 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<ABuffer> *out, int64_t range_offset, int64_t range_length, + uint32_t block_size, /* download block size */ + sp<DataSource> *source, /* to return and reuse source */ String8 *actualUrl) { - *out = NULL; + off64_t size; + sp<DataSource> temp_source; + if (source == NULL) { + source = &temp_source; + } - sp<DataSource> 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<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 (!strncasecmp(url, "file://", 7)) { - source = new FileSource(url + 7); - } else if (strncasecmp(url, "http://", 7) - && strncasecmp(url, "https://", 8)) { - return ERROR_UNSUPPORTED; - } else { - 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; + } - 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<ABuffer> buffer = new ABuffer(size); - buffer->setRange(0, 0); + sp<ABuffer> 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", @@ -584,7 +612,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); @@ -601,7 +631,7 @@ status_t LiveSession::fetchFile( *out = buffer; if (actualUrl != NULL) { - *actualUrl = source->getUri(); + *actualUrl = (*source)->getUri(); if (actualUrl->isEmpty()) { *actualUrl = url; } @@ -618,7 +648,7 @@ sp<M3UParser> LiveSession::fetchPlaylist( sp<ABuffer> buffer; String8 actualUrl; - status_t err = fetchFile(url, &buffer, 0, -1, &actualUrl); + status_t err = fetchFile(url, &buffer, 0, -1, 0, NULL, &actualUrl); if (err != OK) { return NULL; @@ -834,19 +864,11 @@ void LiveSession::changeConfiguration( uint32_t streamMask = 0; - AString audioURI; - if (mPlaylist->getAudioURI(item.mPlaylistIndex, &audioURI)) { - streamMask |= STREAMTYPE_AUDIO; - } - - AString videoURI; - if (mPlaylist->getVideoURI(item.mPlaylistIndex, &videoURI)) { - streamMask |= STREAMTYPE_VIDEO; - } - - AString subtitleURI; - if (mPlaylist->getSubtitleURI(item.mPlaylistIndex, &subtitleURI)) { - streamMask |= STREAMTYPE_SUBTITLES; + AString URIs[kMaxStreams]; + for (size_t i = 0; i < kMaxStreams; ++i) { + if (mPlaylist->getTypeURI(item.mPlaylistIndex, mStreams[i].mType, &URIs[i])) { + streamMask |= indexToType(i); + } } // Step 1, stop and discard fetchers that are no longer needed. @@ -858,10 +880,10 @@ void LiveSession::changeConfiguration( // If we're seeking all current fetchers are discarded. if (timeUs < 0ll) { - if (((streamMask & STREAMTYPE_AUDIO) && uri == audioURI) - || ((streamMask & STREAMTYPE_VIDEO) && uri == videoURI) - || ((streamMask & STREAMTYPE_SUBTITLES) && uri == subtitleURI)) { - discardFetcher = false; + for (size_t j = 0; j < kMaxStreams; ++j) { + if ((streamMask & indexToType(j)) && uri == URIs[j]) { + discardFetcher = false; + } } } @@ -875,14 +897,10 @@ void LiveSession::changeConfiguration( sp<AMessage> msg = new AMessage(kWhatChangeConfiguration2, id()); msg->setInt32("streamMask", streamMask); msg->setInt64("timeUs", timeUs); - if (streamMask & STREAMTYPE_AUDIO) { - msg->setString("audioURI", audioURI.c_str()); - } - if (streamMask & STREAMTYPE_VIDEO) { - msg->setString("videoURI", videoURI.c_str()); - } - if (streamMask & STREAMTYPE_SUBTITLES) { - msg->setString("subtitleURI", subtitleURI.c_str()); + for (size_t i = 0; i < kMaxStreams; ++i) { + if (streamMask & indexToType(i)) { + msg->setString(mStreams[i].uriKey().c_str(), URIs[i].c_str()); + } } // Every time a fetcher acknowledges the stopAsync or pauseAsync request @@ -913,18 +931,13 @@ void LiveSession::onChangeConfiguration2(const sp<AMessage> &msg) { uint32_t streamMask; CHECK(msg->findInt32("streamMask", (int32_t *)&streamMask)); - AString audioURI, videoURI, subtitleURI; - if (streamMask & STREAMTYPE_AUDIO) { - CHECK(msg->findString("audioURI", &audioURI)); - ALOGV("audioURI = '%s'", audioURI.c_str()); - } - if (streamMask & STREAMTYPE_VIDEO) { - CHECK(msg->findString("videoURI", &videoURI)); - ALOGV("videoURI = '%s'", videoURI.c_str()); - } - if (streamMask & STREAMTYPE_SUBTITLES) { - CHECK(msg->findString("subtitleURI", &subtitleURI)); - ALOGV("subtitleURI = '%s'", subtitleURI.c_str()); + AString URIs[kMaxStreams]; + for (size_t i = 0; i < kMaxStreams; ++i) { + if (streamMask & indexToType(i)) { + const AString &uriKey = mStreams[i].uriKey(); + CHECK(msg->findString(uriKey.c_str(), &URIs[i])); + ALOGV("%s = '%s'", uriKey.c_str(), URIs[i].c_str()); + } } // Determine which decoders to shutdown on the player side, @@ -934,15 +947,12 @@ void LiveSession::onChangeConfiguration2(const sp<AMessage> &msg) { // 2) its streamtype was already active and still is but the URI // has changed. uint32_t changedMask = 0; - if (((mStreamMask & streamMask & STREAMTYPE_AUDIO) - && !(audioURI == mAudioURI)) - || (mStreamMask & ~streamMask & STREAMTYPE_AUDIO)) { - changedMask |= STREAMTYPE_AUDIO; - } - if (((mStreamMask & streamMask & STREAMTYPE_VIDEO) - && !(videoURI == mVideoURI)) - || (mStreamMask & ~streamMask & STREAMTYPE_VIDEO)) { - changedMask |= STREAMTYPE_VIDEO; + for (size_t i = 0; i < kMaxStreams && i != kSubtitleIndex; ++i) { + if (((mStreamMask & streamMask & indexToType(i)) + && !(URIs[i] == mStreams[i].mUri)) + || (mStreamMask & ~streamMask & indexToType(i))) { + changedMask |= indexToType(i); + } } if (changedMask == 0) { @@ -974,15 +984,10 @@ void LiveSession::onChangeConfiguration3(const sp<AMessage> &msg) { uint32_t streamMask; CHECK(msg->findInt32("streamMask", (int32_t *)&streamMask)); - AString audioURI, videoURI, subtitleURI; - if (streamMask & STREAMTYPE_AUDIO) { - CHECK(msg->findString("audioURI", &audioURI)); - } - if (streamMask & STREAMTYPE_VIDEO) { - CHECK(msg->findString("videoURI", &videoURI)); - } - if (streamMask & STREAMTYPE_SUBTITLES) { - CHECK(msg->findString("subtitleURI", &subtitleURI)); + for (size_t i = 0; i < kMaxStreams; ++i) { + if (streamMask & indexToType(i)) { + CHECK(msg->findString(mStreams[i].uriKey().c_str(), &mStreams[i].mUri)); + } } int64_t timeUs; @@ -994,9 +999,6 @@ void LiveSession::onChangeConfiguration3(const sp<AMessage> &msg) { mRealTimeBaseUs = ALooper::GetNowUs() - timeUs; mStreamMask = streamMask; - mAudioURI = audioURI; - mVideoURI = videoURI; - mSubtitleURI = subtitleURI; // Resume all existing fetchers and assign them packet sources. for (size_t i = 0; i < mFetcherInfos.size(); ++i) { @@ -1004,22 +1006,12 @@ void LiveSession::onChangeConfiguration3(const sp<AMessage> &msg) { uint32_t resumeMask = 0; - sp<AnotherPacketSource> audioSource; - if ((streamMask & STREAMTYPE_AUDIO) && uri == audioURI) { - audioSource = mPacketSources.valueFor(STREAMTYPE_AUDIO); - resumeMask |= STREAMTYPE_AUDIO; - } - - sp<AnotherPacketSource> videoSource; - if ((streamMask & STREAMTYPE_VIDEO) && uri == videoURI) { - videoSource = mPacketSources.valueFor(STREAMTYPE_VIDEO); - resumeMask |= STREAMTYPE_VIDEO; - } - - sp<AnotherPacketSource> subtitleSource; - if ((streamMask & STREAMTYPE_SUBTITLES) && uri == subtitleURI) { - subtitleSource = mPacketSources.valueFor(STREAMTYPE_SUBTITLES); - resumeMask |= STREAMTYPE_SUBTITLES; + sp<AnotherPacketSource> sources[kMaxStreams]; + for (size_t j = 0; j < kMaxStreams; ++j) { + if ((streamMask & indexToType(j)) && uri == mStreams[j].mUri) { + sources[j] = mPacketSources.valueFor(indexToType(j)); + resumeMask |= indexToType(j); + } } CHECK_NE(resumeMask, 0u); @@ -1029,7 +1021,7 @@ void LiveSession::onChangeConfiguration3(const sp<AMessage> &msg) { streamMask &= ~resumeMask; mFetcherInfos.valueAt(i).mFetcher->startAsync( - audioSource, videoSource, subtitleSource); + sources[kAudioIndex], sources[kVideoIndex], sources[kSubtitleIndex]); } // streamMask now only contains the types that need a new fetcher created. @@ -1038,52 +1030,33 @@ void LiveSession::onChangeConfiguration3(const sp<AMessage> &msg) { ALOGV("creating new fetchers for mask 0x%08x", streamMask); } - while (streamMask != 0) { - StreamType streamType = (StreamType)(streamMask & ~(streamMask - 1)); + for (size_t i = 0; i < kMaxStreams; i++) { + if (!(indexToType(i) & streamMask)) { + continue; + } AString uri; - switch (streamType) { - case STREAMTYPE_AUDIO: - uri = audioURI; - break; - case STREAMTYPE_VIDEO: - uri = videoURI; - break; - case STREAMTYPE_SUBTITLES: - uri = subtitleURI; - break; - default: - TRESPASS(); - } + uri = mStreams[i].mUri; sp<PlaylistFetcher> fetcher = addFetcher(uri.c_str()); CHECK(fetcher != NULL); - sp<AnotherPacketSource> audioSource; - if ((streamMask & STREAMTYPE_AUDIO) && uri == audioURI) { - audioSource = mPacketSources.valueFor(STREAMTYPE_AUDIO); - audioSource->clear(); + sp<AnotherPacketSource> sources[kMaxStreams]; + // TRICKY: looping from i as earlier streams are already removed from streamMask + for (size_t j = i; j < kMaxStreams; ++j) { + if ((streamMask & indexToType(j)) && uri == mStreams[j].mUri) { + sources[j] = mPacketSources.valueFor(indexToType(j)); + sources[j]->clear(); - streamMask &= ~STREAMTYPE_AUDIO; - } - - sp<AnotherPacketSource> videoSource; - if ((streamMask & STREAMTYPE_VIDEO) && uri == videoURI) { - videoSource = mPacketSources.valueFor(STREAMTYPE_VIDEO); - videoSource->clear(); - - streamMask &= ~STREAMTYPE_VIDEO; - } - - sp<AnotherPacketSource> subtitleSource; - if ((streamMask & STREAMTYPE_SUBTITLES) && uri == subtitleURI) { - subtitleSource = mPacketSources.valueFor(STREAMTYPE_SUBTITLES); - subtitleSource->clear(); - - streamMask &= ~STREAMTYPE_SUBTITLES; + streamMask &= ~indexToType(j); + } } - fetcher->startAsync(audioSource, videoSource, subtitleSource, timeUs); + fetcher->startAsync( + sources[kAudioIndex], + sources[kVideoIndex], + sources[kSubtitleIndex], + timeUs); } // All fetchers have now been started, the configuration change |