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
diff --git a/media/libmediaplayerservice/nuplayer/GenericSource.cpp b/media/libmediaplayerservice/nuplayer/GenericSource.cpp
index f0c3240..f281879 100644
--- a/media/libmediaplayerservice/nuplayer/GenericSource.cpp
+++ b/media/libmediaplayerservice/nuplayer/GenericSource.cpp
@@ -258,8 +258,8 @@
}
}
-bool NuPlayer::GenericSource::isSeekable() {
- return true;
+uint32_t NuPlayer::GenericSource::flags() const {
+ return FLAG_SEEKABLE;
}
} // namespace android
diff --git a/media/libmediaplayerservice/nuplayer/GenericSource.h b/media/libmediaplayerservice/nuplayer/GenericSource.h
index e50b855..e1ce2c1 100644
--- a/media/libmediaplayerservice/nuplayer/GenericSource.h
+++ b/media/libmediaplayerservice/nuplayer/GenericSource.h
@@ -47,7 +47,8 @@
virtual status_t getDuration(int64_t *durationUs);
virtual status_t seekTo(int64_t seekTimeUs);
- virtual bool isSeekable();
+
+ virtual uint32_t flags() const;
protected:
virtual ~GenericSource();
diff --git a/media/libmediaplayerservice/nuplayer/HTTPLiveSource.cpp b/media/libmediaplayerservice/nuplayer/HTTPLiveSource.cpp
index 1e98f35..5dcca12 100644
--- a/media/libmediaplayerservice/nuplayer/HTTPLiveSource.cpp
+++ b/media/libmediaplayerservice/nuplayer/HTTPLiveSource.cpp
@@ -121,9 +121,20 @@
} else {
if (buffer[0] == 0x00) {
// XXX legacy
- sp<AMessage> extra;
+
+ uint8_t type = buffer[1];
+
+ sp<AMessage> extra = new AMessage;
+
+ if (type & 2) {
+ int64_t mediaTimeUs;
+ memcpy(&mediaTimeUs, &buffer[2], sizeof(mediaTimeUs));
+
+ extra->setInt64(IStreamListener::kKeyMediaTimeUs, mediaTimeUs);
+ }
+
mTSParser->signalDiscontinuity(
- buffer[1] == 0x00
+ ((type & 1) == 0)
? ATSParser::DISCONTINUITY_SEEK
: ATSParser::DISCONTINUITY_FORMATCHANGE,
extra);
@@ -181,8 +192,17 @@
return OK;
}
-bool NuPlayer::HTTPLiveSource::isSeekable() {
- return mLiveSession->isSeekable();
+uint32_t NuPlayer::HTTPLiveSource::flags() const {
+ uint32_t flags = 0;
+ if (mLiveSession->isSeekable()) {
+ flags |= FLAG_SEEKABLE;
+ }
+
+ if (mLiveSession->hasDynamicDuration()) {
+ flags |= FLAG_DYNAMIC_DURATION;
+ }
+
+ return flags;
}
} // namespace android
diff --git a/media/libmediaplayerservice/nuplayer/HTTPLiveSource.h b/media/libmediaplayerservice/nuplayer/HTTPLiveSource.h
index 9950a9e..79f4ab8 100644
--- a/media/libmediaplayerservice/nuplayer/HTTPLiveSource.h
+++ b/media/libmediaplayerservice/nuplayer/HTTPLiveSource.h
@@ -41,7 +41,8 @@
virtual status_t getDuration(int64_t *durationUs);
virtual status_t seekTo(int64_t seekTimeUs);
- virtual bool isSeekable();
+
+ virtual uint32_t flags() const;
protected:
virtual ~HTTPLiveSource();
diff --git a/media/libmediaplayerservice/nuplayer/NuPlayer.cpp b/media/libmediaplayerservice/nuplayer/NuPlayer.cpp
index 1ddf775..ff27873 100644
--- a/media/libmediaplayerservice/nuplayer/NuPlayer.cpp
+++ b/media/libmediaplayerservice/nuplayer/NuPlayer.cpp
@@ -59,6 +59,7 @@
mVideoEOS(false),
mScanSourcesPending(false),
mScanSourcesGeneration(0),
+ mPollDurationGeneration(0),
mTimeDiscontinuityPending(false),
mFlushingAudio(NONE),
mFlushingVideo(NONE),
@@ -210,6 +211,28 @@
break;
}
+ case kWhatPollDuration:
+ {
+ int32_t generation;
+ CHECK(msg->findInt32("generation", &generation));
+
+ if (generation != mPollDurationGeneration) {
+ // stale
+ break;
+ }
+
+ int64_t durationUs;
+ if (mDriver != NULL && mSource->getDuration(&durationUs) == OK) {
+ sp<NuPlayerDriver> driver = mDriver.promote();
+ if (driver != NULL) {
+ driver->notifyDuration(durationUs);
+ }
+ }
+
+ msg->post(1000000ll); // poll again in a second.
+ break;
+ }
+
case kWhatSetVideoNativeWindow:
{
ALOGV("kWhatSetVideoNativeWindow");
@@ -274,6 +297,9 @@
ALOGV("scanning sources haveAudio=%d, haveVideo=%d",
mAudioDecoder != NULL, mVideoDecoder != NULL);
+ bool mHadAnySourcesBefore =
+ (mAudioDecoder != NULL) || (mVideoDecoder != NULL);
+
if (mNativeWindow != NULL) {
instantiateDecoder(false, &mVideoDecoder);
}
@@ -282,6 +308,17 @@
instantiateDecoder(true, &mAudioDecoder);
}
+ if (!mHadAnySourcesBefore
+ && (mAudioDecoder != NULL || mVideoDecoder != NULL)) {
+ // This is the first time we've found anything playable.
+
+ uint32_t flags = mSource->flags();
+
+ if (flags & Source::FLAG_DYNAMIC_DURATION) {
+ schedulePollDuration();
+ }
+ }
+
status_t err;
if ((err = mSource->feedMoreTSData()) != OK) {
if (mAudioDecoder == NULL && mVideoDecoder == NULL) {
@@ -534,6 +571,8 @@
{
ALOGV("kWhatReset");
+ cancelPollDuration();
+
if (mRenderer != NULL) {
// There's an edge case where the renderer owns all output
// buffers and is paused, therefore the decoder will not read
@@ -976,4 +1015,14 @@
return OK;
}
+void NuPlayer::schedulePollDuration() {
+ sp<AMessage> msg = new AMessage(kWhatPollDuration, id());
+ msg->setInt32("generation", mPollDurationGeneration);
+ msg->post();
+}
+
+void NuPlayer::cancelPollDuration() {
+ ++mPollDurationGeneration;
+}
+
} // namespace android
diff --git a/media/libmediaplayerservice/nuplayer/NuPlayer.h b/media/libmediaplayerservice/nuplayer/NuPlayer.h
index 36d3a9c..31efb2e 100644
--- a/media/libmediaplayerservice/nuplayer/NuPlayer.h
+++ b/media/libmediaplayerservice/nuplayer/NuPlayer.h
@@ -88,6 +88,7 @@
kWhatSeek = 'seek',
kWhatPause = 'paus',
kWhatResume = 'rsme',
+ kWhatPollDuration = 'polD',
};
wp<NuPlayerDriver> mDriver;
@@ -107,6 +108,8 @@
bool mScanSourcesPending;
int32_t mScanSourcesGeneration;
+ int32_t mPollDurationGeneration;
+
enum FlushStatus {
NONE,
AWAITING_DISCONTINUITY,
@@ -150,6 +153,9 @@
void finishReset();
void postScanSources();
+ void schedulePollDuration();
+ void cancelPollDuration();
+
DISALLOW_EVIL_CONSTRUCTORS(NuPlayer);
};
diff --git a/media/libmediaplayerservice/nuplayer/NuPlayerSource.h b/media/libmediaplayerservice/nuplayer/NuPlayerSource.h
index 66aeff3..a635340 100644
--- a/media/libmediaplayerservice/nuplayer/NuPlayerSource.h
+++ b/media/libmediaplayerservice/nuplayer/NuPlayerSource.h
@@ -25,6 +25,11 @@
struct ABuffer;
struct NuPlayer::Source : public RefBase {
+ enum Flags {
+ FLAG_SEEKABLE = 1,
+ FLAG_DYNAMIC_DURATION = 2,
+ };
+
Source() {}
virtual void start() = 0;
@@ -47,9 +52,7 @@
return INVALID_OPERATION;
}
- virtual bool isSeekable() {
- return false;
- }
+ virtual uint32_t flags() const = 0;
protected:
virtual ~Source() {}
diff --git a/media/libmediaplayerservice/nuplayer/RTSPSource.cpp b/media/libmediaplayerservice/nuplayer/RTSPSource.cpp
index 5a7a785..cf455bd 100644
--- a/media/libmediaplayerservice/nuplayer/RTSPSource.cpp
+++ b/media/libmediaplayerservice/nuplayer/RTSPSource.cpp
@@ -210,8 +210,8 @@
mHandler->seek(seekTimeUs);
}
-bool NuPlayer::RTSPSource::isSeekable() {
- return true;
+uint32_t NuPlayer::RTSPSource::flags() const {
+ return FLAG_SEEKABLE;
}
void NuPlayer::RTSPSource::onMessageReceived(const sp<AMessage> &msg) {
diff --git a/media/libmediaplayerservice/nuplayer/RTSPSource.h b/media/libmediaplayerservice/nuplayer/RTSPSource.h
index f07c724..779d791 100644
--- a/media/libmediaplayerservice/nuplayer/RTSPSource.h
+++ b/media/libmediaplayerservice/nuplayer/RTSPSource.h
@@ -46,7 +46,8 @@
virtual status_t getDuration(int64_t *durationUs);
virtual status_t seekTo(int64_t seekTimeUs);
- virtual bool isSeekable();
+
+ virtual uint32_t flags() const;
void onMessageReceived(const sp<AMessage> &msg);
diff --git a/media/libmediaplayerservice/nuplayer/StreamingSource.cpp b/media/libmediaplayerservice/nuplayer/StreamingSource.cpp
index a1fd2ed..7159404 100644
--- a/media/libmediaplayerservice/nuplayer/StreamingSource.cpp
+++ b/media/libmediaplayerservice/nuplayer/StreamingSource.cpp
@@ -93,8 +93,22 @@
} else {
if (buffer[0] == 0x00) {
// XXX legacy
+
+ if (extra == NULL) {
+ extra = new AMessage;
+ }
+
+ uint8_t type = buffer[1];
+
+ if (type & 2) {
+ int64_t mediaTimeUs;
+ memcpy(&mediaTimeUs, &buffer[2], sizeof(mediaTimeUs));
+
+ extra->setInt64(IStreamListener::kKeyMediaTimeUs, mediaTimeUs);
+ }
+
mTSParser->signalDiscontinuity(
- buffer[1] == 0x00
+ ((type & 1) == 0)
? ATSParser::DISCONTINUITY_SEEK
: ATSParser::DISCONTINUITY_FORMATCHANGE,
extra);
@@ -159,5 +173,9 @@
return err;
}
+uint32_t NuPlayer::StreamingSource::flags() const {
+ return 0;
+}
+
} // namespace android
diff --git a/media/libmediaplayerservice/nuplayer/StreamingSource.h b/media/libmediaplayerservice/nuplayer/StreamingSource.h
index 3971e2a..a27b58a 100644
--- a/media/libmediaplayerservice/nuplayer/StreamingSource.h
+++ b/media/libmediaplayerservice/nuplayer/StreamingSource.h
@@ -35,6 +35,8 @@
virtual status_t dequeueAccessUnit(bool audio, sp<ABuffer> *accessUnit);
+ virtual uint32_t flags() const;
+
protected:
virtual ~StreamingSource();
diff --git a/media/libmediaplayerservice/nuplayer/mp4/MP4Source.cpp b/media/libmediaplayerservice/nuplayer/mp4/MP4Source.cpp
index ffb3a65..a62d5a2 100644
--- a/media/libmediaplayerservice/nuplayer/mp4/MP4Source.cpp
+++ b/media/libmediaplayerservice/nuplayer/mp4/MP4Source.cpp
@@ -133,4 +133,8 @@
return mParser->dequeueAccessUnit(audio, accessUnit);
}
+uint32_t MP4Source::flags() const {
+ return 0;
+}
+
} // namespace android
diff --git a/media/libmediaplayerservice/nuplayer/mp4/MP4Source.h b/media/libmediaplayerservice/nuplayer/mp4/MP4Source.h
index 4e927af..abca236 100644
--- a/media/libmediaplayerservice/nuplayer/mp4/MP4Source.h
+++ b/media/libmediaplayerservice/nuplayer/mp4/MP4Source.h
@@ -35,6 +35,8 @@
virtual status_t dequeueAccessUnit(
bool audio, sp<ABuffer> *accessUnit);
+ virtual uint32_t flags() const;
+
protected:
virtual ~MP4Source();