summaryrefslogtreecommitdiffstats
path: root/media/libstagefright/httplive
diff options
context:
space:
mode:
authorAndreas Huber <andih@google.com>2012-11-27 15:02:53 -0800
committerAndreas Huber <andih@google.com>2012-11-27 15:50:08 -0800
commitb7c8e91880463ff4981e3e53e98e45d68e2fe374 (patch)
tree3de921dd21aa2f4899487d3c56e4bfd28f4c004f /media/libstagefright/httplive
parent41829f30e60cdb7ae8eb1f0266834d245164f70e (diff)
downloadframeworks_av-b7c8e91880463ff4981e3e53e98e45d68e2fe374.zip
frameworks_av-b7c8e91880463ff4981e3e53e98e45d68e2fe374.tar.gz
frameworks_av-b7c8e91880463ff4981e3e53e98e45d68e2fe374.tar.bz2
Add support for HLS playlists of type 'event'.
related-to-bug: 6870049 Squashed commit of the following: commit eee2f3ba6bb7335f4e285632726db85645669929 Author: Andreas Huber <andih@google.com> Date: Tue Nov 27 15:02:01 2012 -0800 Make everything a lot less verbose by default. Change-Id: I884d7a7901aa1e7d4ff590f065ca57a79d2af8b3 commit 6bbdb837ed5bd88008e45efb8faf595e4051ba26 Author: Andreas Huber <andih@google.com> Date: Tue Nov 27 14:34:46 2012 -0800 HLS now properly signals media time changes at discontinuities including the start of playback (which may not necessarily be at time 0 if the playlist is of type 'event' and hasn't completed yet). Change-Id: I5ab747d024f9b8d0df72a4e06a12ebb29f62802e commit 1555589832b1878a144a976a643e1af4d61f877c Author: Andreas Huber <andih@google.com> Date: Tue Nov 27 14:32:28 2012 -0800 As part of a time discontinuity, clients of IStreamListener can now signal the corresponding media time after the discontinuity, i.e. the first PTS timestamp following the discontinuity will be considered equivalent to the specified media time and media buffers timestamped accordingly. Change-Id: Id7db7679b7faa6efd6270620ff52e34e884f3e92 commit 5c24c605c073a11c426d025b1e7478fc1ad8365a Author: Andreas Huber <andih@google.com> Date: Tue Nov 27 13:00:56 2012 -0800 NuPlayer sources now expose flags() and can announce that duration may change (increase) dynamically, in which case duration will be polled at 1 second intervals and communicated to the upper layers. Change-Id: I45102909b7a19eed0dda576747e3814d742a0eea commit ecb71de8e281e61971a2cd73e7161a97540bc357 Author: Andreas Huber <andih@google.com> Date: Tue Nov 27 12:57:47 2012 -0800 Stop caching duration in MediaPlayer, duration could increase dynamically. Change-Id: I7bb2f16c0abe49debdf45c776d2266aa069d7791 commit 544aec5823e6d7a3e97e15b6b23546616bcd343e Author: Andreas Huber <andih@google.com> Date: Tue Nov 27 08:46:28 2012 -0800 An attempt to add support for "event" style HLS playlists. Change-Id: I3dfb2e801ecaff8f5d8bdb3a4fca1b18aeeb2c60 Change-Id: I48cf7f65a654d33f2f49ded74f8be22aed9e3b98
Diffstat (limited to 'media/libstagefright/httplive')
-rw-r--r--media/libstagefright/httplive/LiveSession.cpp92
-rw-r--r--media/libstagefright/httplive/M3UParser.cpp9
2 files changed, 88 insertions, 13 deletions
diff --git a/media/libstagefright/httplive/LiveSession.cpp b/media/libstagefright/httplive/LiveSession.cpp
index 93d6429..733753b 100644
--- a/media/libstagefright/httplive/LiveSession.cpp
+++ b/media/libstagefright/httplive/LiveSession.cpp
@@ -55,7 +55,9 @@ LiveSession::LiveSession(uint32_t flags, bool uidValid, uid_t uid)
mSeqNumber(-1),
mSeekTimeUs(-1),
mNumRetries(0),
+ mStartOfPlayback(true),
mDurationUs(-1),
+ mDurationFixed(false),
mSeekDone(false),
mDisconnectPending(false),
mMonitorQueueGeneration(0),
@@ -311,6 +313,8 @@ status_t LiveSession::fetchFile(
}
sp<M3UParser> LiveSession::fetchPlaylist(const char *url, bool *unchanged) {
+ ALOGV("fetchPlaylist '%s'", url);
+
*unchanged = false;
sp<ABuffer> buffer;
@@ -364,6 +368,37 @@ sp<M3UParser> LiveSession::fetchPlaylist(const char *url, bool *unchanged) {
return playlist;
}
+int64_t LiveSession::getSegmentStartTimeUs(int32_t seqNumber) const {
+ CHECK(mPlaylist != NULL);
+
+ int32_t firstSeqNumberInPlaylist;
+ if (mPlaylist->meta() == NULL || !mPlaylist->meta()->findInt32(
+ "media-sequence", &firstSeqNumberInPlaylist)) {
+ firstSeqNumberInPlaylist = 0;
+ }
+
+ int32_t lastSeqNumberInPlaylist =
+ firstSeqNumberInPlaylist + (int32_t)mPlaylist->size() - 1;
+
+ CHECK_GE(seqNumber, firstSeqNumberInPlaylist);
+ CHECK_LE(seqNumber, lastSeqNumberInPlaylist);
+
+ int64_t segmentStartUs = 0ll;
+ for (int32_t index = 0;
+ index < seqNumber - firstSeqNumberInPlaylist; ++index) {
+ sp<AMessage> itemMeta;
+ CHECK(mPlaylist->itemAt(
+ index, NULL /* uri */, &itemMeta));
+
+ int64_t itemDurationUs;
+ CHECK(itemMeta->findInt64("durationUs", &itemDurationUs));
+
+ segmentStartUs += itemDurationUs;
+ }
+
+ return segmentStartUs;
+}
+
static double uniformRand() {
return (double)rand() / RAND_MAX;
}
@@ -512,8 +547,6 @@ rinse_repeat:
url = mMasterURL;
}
- bool firstTime = (mPlaylist == NULL);
-
if ((ssize_t)bandwidthIndex != mPrevBandwidthIndex) {
// If we switch bandwidths, do not pay any heed to whether
// playlists changed since the last time...
@@ -535,11 +568,12 @@ rinse_repeat:
mPlaylist = playlist;
}
- if (firstTime) {
+ if (!mDurationFixed) {
Mutex::Autolock autoLock(mLock);
- if (!mPlaylist->isComplete()) {
+ if (!mPlaylist->isComplete() && !mPlaylist->isEvent()) {
mDurationUs = -1;
+ mDurationFixed = true;
} else {
mDurationUs = 0;
for (size_t i = 0; i < mPlaylist->size(); ++i) {
@@ -552,6 +586,8 @@ rinse_repeat:
mDurationUs += itemDurationUs;
}
+
+ mDurationFixed = mPlaylist->isComplete();
}
}
@@ -569,7 +605,7 @@ rinse_repeat:
bool bandwidthChanged = false;
if (mSeekTimeUs >= 0) {
- if (mPlaylist->isComplete()) {
+ if (mPlaylist->isComplete() || mPlaylist->isEvent()) {
size_t index = 0;
int64_t segmentStartUs = 0;
while (index < mPlaylist->size()) {
@@ -617,13 +653,21 @@ rinse_repeat:
mCondition.broadcast();
}
+ const int32_t lastSeqNumberInPlaylist =
+ firstSeqNumberInPlaylist + (int32_t)mPlaylist->size() - 1;
+
if (mSeqNumber < 0) {
- mSeqNumber = firstSeqNumberInPlaylist;
+ if (mPlaylist->isComplete()) {
+ mSeqNumber = firstSeqNumberInPlaylist;
+ } else {
+ // If this is a live session, start 3 segments from the end.
+ mSeqNumber = lastSeqNumberInPlaylist - 3;
+ if (mSeqNumber < firstSeqNumberInPlaylist) {
+ mSeqNumber = firstSeqNumberInPlaylist;
+ }
+ }
}
- int32_t lastSeqNumberInPlaylist =
- firstSeqNumberInPlaylist + (int32_t)mPlaylist->size() - 1;
-
if (mSeqNumber < firstSeqNumberInPlaylist
|| mSeqNumber > lastSeqNumberInPlaylist) {
if (mPrevBandwidthIndex != (ssize_t)bandwidthIndex) {
@@ -686,6 +730,9 @@ rinse_repeat:
range_length = -1;
}
+ ALOGV("fetching segment %d from (%d .. %d)",
+ mSeqNumber, firstSeqNumberInPlaylist, lastSeqNumberInPlaylist);
+
sp<ABuffer> buffer;
status_t err = fetchFile(uri.c_str(), &buffer, range_offset, range_length);
if (err != OK) {
@@ -737,6 +784,11 @@ rinse_repeat:
bandwidthChanged = false;
}
+ if (mStartOfPlayback) {
+ seekDiscontinuity = true;
+ mStartOfPlayback = false;
+ }
+
if (seekDiscontinuity || explicitDiscontinuity || bandwidthChanged) {
// Signal discontinuity.
@@ -747,7 +799,19 @@ rinse_repeat:
memset(tmp->data(), 0, tmp->size());
// signal a 'hard' discontinuity for explicit or bandwidthChanged.
- tmp->data()[1] = (explicitDiscontinuity || bandwidthChanged) ? 1 : 0;
+ uint8_t type = (explicitDiscontinuity || bandwidthChanged) ? 1 : 0;
+
+ if (mPlaylist->isComplete() || mPlaylist->isEvent()) {
+ // If this was a live event this made no sense since
+ // we don't have access to all the segment before the current
+ // one.
+ int64_t segmentStartTimeUs = getSegmentStartTimeUs(mSeqNumber);
+ memcpy(tmp->data() + 2, &segmentStartTimeUs, sizeof(segmentStartTimeUs));
+
+ type |= 2;
+ }
+
+ tmp->data()[1] = type;
mDataSource->queueBuffer(tmp);
}
@@ -923,17 +987,21 @@ void LiveSession::onSeek(const sp<AMessage> &msg) {
postMonitorQueue();
}
-status_t LiveSession::getDuration(int64_t *durationUs) {
+status_t LiveSession::getDuration(int64_t *durationUs) const {
Mutex::Autolock autoLock(mLock);
*durationUs = mDurationUs;
return OK;
}
-bool LiveSession::isSeekable() {
+bool LiveSession::isSeekable() const {
int64_t durationUs;
return getDuration(&durationUs) == OK && durationUs >= 0;
}
+bool LiveSession::hasDynamicDuration() const {
+ return !mDurationFixed;
+}
+
} // namespace android
diff --git a/media/libstagefright/httplive/M3UParser.cpp b/media/libstagefright/httplive/M3UParser.cpp
index 7d3cf05..44e03dc 100644
--- a/media/libstagefright/httplive/M3UParser.cpp
+++ b/media/libstagefright/httplive/M3UParser.cpp
@@ -32,7 +32,8 @@ M3UParser::M3UParser(
mBaseURI(baseURI),
mIsExtM3U(false),
mIsVariantPlaylist(false),
- mIsComplete(false) {
+ mIsComplete(false),
+ mIsEvent(false) {
mInitCheck = parse(data, size);
}
@@ -55,6 +56,10 @@ bool M3UParser::isComplete() const {
return mIsComplete;
}
+bool M3UParser::isEvent() const {
+ return mIsEvent;
+}
+
sp<AMessage> M3UParser::meta() {
return mMeta;
}
@@ -200,6 +205,8 @@ status_t M3UParser::parse(const void *_data, size_t size) {
err = parseCipherInfo(line, &itemMeta, mBaseURI);
} else if (line.startsWith("#EXT-X-ENDLIST")) {
mIsComplete = true;
+ } else if (line.startsWith("#EXT-X-PLAYLIST-TYPE:EVENT")) {
+ mIsEvent = true;
} else if (line.startsWith("#EXTINF")) {
if (mIsVariantPlaylist) {
return ERROR_MALFORMED;