summaryrefslogtreecommitdiffstats
path: root/media/libstagefright
diff options
context:
space:
mode:
Diffstat (limited to 'media/libstagefright')
-rw-r--r--media/libstagefright/chromium_http/ChromiumHTTPDataSource.cpp7
-rw-r--r--media/libstagefright/httplive/LiveSession.cpp92
-rw-r--r--media/libstagefright/httplive/M3UParser.cpp9
-rw-r--r--media/libstagefright/include/LiveSession.h14
-rw-r--r--media/libstagefright/include/M3UParser.h2
-rw-r--r--media/libstagefright/mpeg2ts/ATSParser.cpp16
6 files changed, 122 insertions, 18 deletions
diff --git a/media/libstagefright/chromium_http/ChromiumHTTPDataSource.cpp b/media/libstagefright/chromium_http/ChromiumHTTPDataSource.cpp
index 32a0ec8..91ce175 100644
--- a/media/libstagefright/chromium_http/ChromiumHTTPDataSource.cpp
+++ b/media/libstagefright/chromium_http/ChromiumHTTPDataSource.cpp
@@ -65,7 +65,10 @@ status_t ChromiumHTTPDataSource::connect(
if (getUID(&uid)) {
mDelegate->setUID(uid);
}
+
+#if defined(LOG_NDEBUG) && !LOG_NDEBUG
LOG_PRI(ANDROID_LOG_VERBOSE, LOG_TAG, "connect on behalf of uid %d", uid);
+#endif
return connect_l(uri, headers, offset);
}
@@ -78,8 +81,10 @@ status_t ChromiumHTTPDataSource::connect_l(
disconnect_l();
}
- LOG_PRI(ANDROID_LOG_INFO, LOG_TAG,
+#if defined(LOG_NDEBUG) && !LOG_NDEBUG
+ LOG_PRI(ANDROID_LOG_VERBOSE, LOG_TAG,
"connect to <URL suppressed> @%lld", offset);
+#endif
mURI = uri;
mContentType = String8("application/octet-stream");
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;
diff --git a/media/libstagefright/include/LiveSession.h b/media/libstagefright/include/LiveSession.h
index 3a11612..f329cc9 100644
--- a/media/libstagefright/include/LiveSession.h
+++ b/media/libstagefright/include/LiveSession.h
@@ -48,8 +48,10 @@ struct LiveSession : public AHandler {
// Blocks until seek is complete.
void seekTo(int64_t timeUs);
- status_t getDuration(int64_t *durationUs);
- bool isSeekable();
+ status_t getDuration(int64_t *durationUs) const;
+
+ bool isSeekable() const;
+ bool hasDynamicDuration() const;
protected:
virtual ~LiveSession();
@@ -95,10 +97,12 @@ private:
int32_t mSeqNumber;
int64_t mSeekTimeUs;
int32_t mNumRetries;
+ bool mStartOfPlayback;
- Mutex mLock;
+ mutable Mutex mLock;
Condition mCondition;
int64_t mDurationUs;
+ bool mDurationFixed; // Duration has been determined once and for all.
bool mSeekDone;
bool mDisconnectPending;
@@ -136,6 +140,10 @@ private:
static int SortByBandwidth(const BandwidthItem *, const BandwidthItem *);
+ // Returns the media time in us of the segment specified by seqNumber.
+ // This is computed by summing the durations of all segments before it.
+ int64_t getSegmentStartTimeUs(int32_t seqNumber) const;
+
DISALLOW_EVIL_CONSTRUCTORS(LiveSession);
};
diff --git a/media/libstagefright/include/M3UParser.h b/media/libstagefright/include/M3UParser.h
index e30d6fd..2d2f50f 100644
--- a/media/libstagefright/include/M3UParser.h
+++ b/media/libstagefright/include/M3UParser.h
@@ -33,6 +33,7 @@ struct M3UParser : public RefBase {
bool isExtM3U() const;
bool isVariantPlaylist() const;
bool isComplete() const;
+ bool isEvent() const;
sp<AMessage> meta();
@@ -54,6 +55,7 @@ private:
bool mIsExtM3U;
bool mIsVariantPlaylist;
bool mIsComplete;
+ bool mIsEvent;
sp<AMessage> mMeta;
Vector<Item> mItems;
diff --git a/media/libstagefright/mpeg2ts/ATSParser.cpp b/media/libstagefright/mpeg2ts/ATSParser.cpp
index 9faa6bc..4f6c4b2 100644
--- a/media/libstagefright/mpeg2ts/ATSParser.cpp
+++ b/media/libstagefright/mpeg2ts/ATSParser.cpp
@@ -215,6 +215,14 @@ bool ATSParser::Program::parsePID(
void ATSParser::Program::signalDiscontinuity(
DiscontinuityType type, const sp<AMessage> &extra) {
+ int64_t mediaTimeUs;
+ if ((type & DISCONTINUITY_TIME)
+ && extra != NULL
+ && extra->findInt64(
+ IStreamListener::kKeyMediaTimeUs, &mediaTimeUs)) {
+ mFirstPTSValid = false;
+ }
+
for (size_t i = 0; i < mStreams.size(); ++i) {
mStreams.editValueAt(i)->signalDiscontinuity(type, extra);
}
@@ -929,7 +937,13 @@ status_t ATSParser::feedTSPacket(const void *data, size_t size) {
void ATSParser::signalDiscontinuity(
DiscontinuityType type, const sp<AMessage> &extra) {
- if (type == DISCONTINUITY_ABSOLUTE_TIME) {
+ int64_t mediaTimeUs;
+ if ((type & DISCONTINUITY_TIME)
+ && extra != NULL
+ && extra->findInt64(
+ IStreamListener::kKeyMediaTimeUs, &mediaTimeUs)) {
+ mAbsoluteTimeAnchorUs = mediaTimeUs;
+ } else if (type == DISCONTINUITY_ABSOLUTE_TIME) {
int64_t timeUs;
CHECK(extra->findInt64("timeUs", &timeUs));