summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--include/media/mediaplayer.h2
-rw-r--r--media/libmedia/mediaplayer.cpp3
-rw-r--r--media/libmediaplayerservice/nuplayer/HTTPLiveSource.cpp58
-rw-r--r--media/libmediaplayerservice/nuplayer/HTTPLiveSource.h4
-rw-r--r--media/libmediaplayerservice/nuplayer/NuPlayer.cpp87
-rw-r--r--media/libmediaplayerservice/nuplayer/NuPlayer.h6
-rw-r--r--media/libmediaplayerservice/nuplayer/NuPlayerDriver.cpp22
-rw-r--r--media/libmediaplayerservice/nuplayer/NuPlayerDriver.h2
-rw-r--r--media/libmediaplayerservice/nuplayer/NuPlayerSource.h9
-rw-r--r--media/libstagefright/httplive/Android.mk1
-rw-r--r--media/libstagefright/httplive/LiveSession.cpp59
-rw-r--r--media/libstagefright/httplive/LiveSession.h9
-rw-r--r--media/libstagefright/httplive/M3UParser.cpp95
-rw-r--r--media/libstagefright/httplive/M3UParser.h4
-rw-r--r--media/libstagefright/httplive/PlaylistFetcher.cpp15
-rw-r--r--media/libstagefright/httplive/PlaylistFetcher.h3
16 files changed, 354 insertions, 25 deletions
diff --git a/include/media/mediaplayer.h b/include/media/mediaplayer.h
index 1afd7f7..923c8b2 100644
--- a/include/media/mediaplayer.h
+++ b/include/media/mediaplayer.h
@@ -48,6 +48,7 @@ enum media_event_type {
MEDIA_TIMED_TEXT = 99,
MEDIA_ERROR = 100,
MEDIA_INFO = 200,
+ MEDIA_SUBTITLE_DATA = 201,
};
// Generic error codes for the media player framework. Errors are fatal, the
@@ -176,6 +177,7 @@ enum media_track_type {
MEDIA_TRACK_TYPE_VIDEO = 1,
MEDIA_TRACK_TYPE_AUDIO = 2,
MEDIA_TRACK_TYPE_TIMEDTEXT = 3,
+ MEDIA_TRACK_TYPE_SUBTITLE = 4,
};
// ----------------------------------------------------------------------------
diff --git a/media/libmedia/mediaplayer.cpp b/media/libmedia/mediaplayer.cpp
index 056cc0a..4323d0c 100644
--- a/media/libmedia/mediaplayer.cpp
+++ b/media/libmedia/mediaplayer.cpp
@@ -756,6 +756,9 @@ void MediaPlayer::notify(int msg, int ext1, int ext2, const Parcel *obj)
case MEDIA_TIMED_TEXT:
ALOGV("Received timed text message");
break;
+ case MEDIA_SUBTITLE_DATA:
+ ALOGV("Received subtitle data message");
+ break;
default:
ALOGV("unrecognized message: (%d, %d, %d)", msg, ext1, ext2);
break;
diff --git a/media/libmediaplayerservice/nuplayer/HTTPLiveSource.cpp b/media/libmediaplayerservice/nuplayer/HTTPLiveSource.cpp
index c8901ce..d8b35d7 100644
--- a/media/libmediaplayerservice/nuplayer/HTTPLiveSource.cpp
+++ b/media/libmediaplayerservice/nuplayer/HTTPLiveSource.cpp
@@ -43,7 +43,8 @@ NuPlayer::HTTPLiveSource::HTTPLiveSource(
mUID(uid),
mFlags(0),
mFinalResult(OK),
- mOffset(0) {
+ mOffset(0),
+ mFetchSubtitleDataGeneration(0) {
if (headers) {
mExtraHeaders = *headers;
@@ -120,6 +121,28 @@ status_t NuPlayer::HTTPLiveSource::getDuration(int64_t *durationUs) {
return mLiveSession->getDuration(durationUs);
}
+status_t NuPlayer::HTTPLiveSource::getTrackInfo(Parcel *reply) const {
+ return mLiveSession->getTrackInfo(reply);
+}
+
+status_t NuPlayer::HTTPLiveSource::selectTrack(size_t trackIndex, bool select) {
+ status_t err = mLiveSession->selectTrack(trackIndex, select);
+
+ if (err == OK) {
+ mFetchSubtitleDataGeneration++;
+ if (select) {
+ sp<AMessage> msg = new AMessage(kWhatFetchSubtitleData, id());
+ msg->setInt32("generation", mFetchSubtitleDataGeneration);
+ msg->post();
+ }
+ }
+
+ // LiveSession::selectTrack returns BAD_VALUE when selecting the currently
+ // selected track, or unselecting a non-selected track. In this case it's an
+ // no-op so we return OK.
+ return (err == OK || err == BAD_VALUE) ? OK : err;
+}
+
status_t NuPlayer::HTTPLiveSource::seekTo(int64_t seekTimeUs) {
return mLiveSession->seekTo(seekTimeUs);
}
@@ -132,6 +155,39 @@ void NuPlayer::HTTPLiveSource::onMessageReceived(const sp<AMessage> &msg) {
break;
}
+ case kWhatFetchSubtitleData:
+ {
+ int32_t generation;
+ CHECK(msg->findInt32("generation", &generation));
+
+ if (generation != mFetchSubtitleDataGeneration) {
+ // stale
+ break;
+ }
+
+ sp<ABuffer> buffer;
+ if (mLiveSession->dequeueAccessUnit(
+ LiveSession::STREAMTYPE_SUBTITLES, &buffer) == OK) {
+ sp<AMessage> notify = dupNotify();
+ notify->setInt32("what", kWhatSubtitleData);
+ notify->setBuffer("buffer", buffer);
+ notify->post();
+
+ int64_t timeUs, baseUs, durationUs, delayUs;
+ CHECK(buffer->meta()->findInt64("baseUs", &baseUs));
+ CHECK(buffer->meta()->findInt64("timeUs", &timeUs));
+ CHECK(buffer->meta()->findInt64("durationUs", &durationUs));
+ delayUs = baseUs + timeUs - ALooper::GetNowUs();
+
+ msg->post(delayUs > 0ll ? delayUs : 0ll);
+ } else {
+ // try again in 1 second
+ msg->post(1000000ll);
+ }
+
+ break;
+ }
+
default:
Source::onMessageReceived(msg);
break;
diff --git a/media/libmediaplayerservice/nuplayer/HTTPLiveSource.h b/media/libmediaplayerservice/nuplayer/HTTPLiveSource.h
index aa9434b..bcc3f8b 100644
--- a/media/libmediaplayerservice/nuplayer/HTTPLiveSource.h
+++ b/media/libmediaplayerservice/nuplayer/HTTPLiveSource.h
@@ -41,6 +41,8 @@ struct NuPlayer::HTTPLiveSource : public NuPlayer::Source {
virtual status_t feedMoreTSData();
virtual status_t getDuration(int64_t *durationUs);
+ virtual status_t getTrackInfo(Parcel *reply) const;
+ virtual status_t selectTrack(size_t trackIndex, bool select);
virtual status_t seekTo(int64_t seekTimeUs);
protected:
@@ -56,6 +58,7 @@ private:
enum {
kWhatSessionNotify,
+ kWhatFetchSubtitleData,
};
AString mURL;
@@ -67,6 +70,7 @@ private:
off64_t mOffset;
sp<ALooper> mLiveLooper;
sp<LiveSession> mLiveSession;
+ int32_t mFetchSubtitleDataGeneration;
void onSessionNotify(const sp<AMessage> &msg);
diff --git a/media/libmediaplayerservice/nuplayer/NuPlayer.cpp b/media/libmediaplayerservice/nuplayer/NuPlayer.cpp
index b411f34..e1735fa 100644
--- a/media/libmediaplayerservice/nuplayer/NuPlayer.cpp
+++ b/media/libmediaplayerservice/nuplayer/NuPlayer.cpp
@@ -340,6 +340,46 @@ void NuPlayer::onMessageReceived(const sp<AMessage> &msg) {
break;
}
+ case kWhatGetTrackInfo:
+ {
+ uint32_t replyID;
+ CHECK(msg->senderAwaitsResponse(&replyID));
+
+ status_t err = INVALID_OPERATION;
+ if (mSource != NULL) {
+ Parcel* reply;
+ CHECK(msg->findPointer("reply", (void**)&reply));
+ err = mSource->getTrackInfo(reply);
+ }
+
+ sp<AMessage> response = new AMessage;
+ response->setInt32("err", err);
+
+ response->postReply(replyID);
+ break;
+ }
+
+ case kWhatSelectTrack:
+ {
+ uint32_t replyID;
+ CHECK(msg->senderAwaitsResponse(&replyID));
+
+ status_t err = INVALID_OPERATION;
+ if (mSource != NULL) {
+ size_t trackIndex;
+ int32_t select;
+ CHECK(msg->findSize("trackIndex", &trackIndex));
+ CHECK(msg->findInt32("select", &select));
+ err = mSource->selectTrack(trackIndex, select);
+ }
+
+ sp<AMessage> response = new AMessage;
+ response->setInt32("err", err);
+
+ response->postReply(replyID);
+ break;
+ }
+
case kWhatPollDuration:
{
int32_t generation;
@@ -1045,7 +1085,7 @@ void NuPlayer::renderBuffer(bool audio, const sp<AMessage> &msg) {
mRenderer->queueBuffer(audio, buffer, reply);
}
-void NuPlayer::notifyListener(int msg, int ext1, int ext2) {
+void NuPlayer::notifyListener(int msg, int ext1, int ext2, const Parcel *in) {
if (mDriver == NULL) {
return;
}
@@ -1056,7 +1096,7 @@ void NuPlayer::notifyListener(int msg, int ext1, int ext2) {
return;
}
- driver->notifyListener(msg, ext1, ext2);
+ driver->notifyListener(msg, ext1, ext2, in);
}
void NuPlayer::flushDecoder(bool audio, bool needShutdown) {
@@ -1132,6 +1172,26 @@ status_t NuPlayer::setVideoScalingMode(int32_t mode) {
return OK;
}
+status_t NuPlayer::getTrackInfo(Parcel* reply) const {
+ sp<AMessage> msg = new AMessage(kWhatGetTrackInfo, id());
+ msg->setPointer("reply", reply);
+
+ sp<AMessage> response;
+ status_t err = msg->postAndAwaitResponse(&response);
+ return err;
+}
+
+status_t NuPlayer::selectTrack(size_t trackIndex, bool select) {
+ sp<AMessage> msg = new AMessage(kWhatSelectTrack, id());
+ msg->setSize("trackIndex", trackIndex);
+ msg->setInt32("select", select);
+
+ sp<AMessage> response;
+ status_t err = msg->postAndAwaitResponse(&response);
+
+ return err;
+}
+
void NuPlayer::schedulePollDuration() {
sp<AMessage> msg = new AMessage(kWhatPollDuration, id());
msg->setInt32("generation", mPollDurationGeneration);
@@ -1371,6 +1431,29 @@ void NuPlayer::onSourceNotify(const sp<AMessage> &msg) {
break;
}
+ case Source::kWhatSubtitleData:
+ {
+ sp<ABuffer> buffer;
+ CHECK(msg->findBuffer("buffer", &buffer));
+
+ int32_t trackIndex;
+ int64_t timeUs, durationUs;
+ CHECK(buffer->meta()->findInt32("trackIndex", &trackIndex));
+ CHECK(buffer->meta()->findInt64("timeUs", &timeUs));
+ CHECK(buffer->meta()->findInt64("durationUs", &durationUs));
+
+ Parcel in;
+ in.writeInt32(trackIndex);
+ in.writeInt64(timeUs);
+ in.writeInt64(durationUs);
+ in.writeInt32(buffer->size());
+ in.writeInt32(buffer->size());
+ in.write(buffer->data(), buffer->size());
+
+ notifyListener(MEDIA_SUBTITLE_DATA, 0, 0, &in);
+ break;
+ }
+
case Source::kWhatQueueDecoderShutdown:
{
int32_t audio, video;
diff --git a/media/libmediaplayerservice/nuplayer/NuPlayer.h b/media/libmediaplayerservice/nuplayer/NuPlayer.h
index 8b6c8c1..13350f3 100644
--- a/media/libmediaplayerservice/nuplayer/NuPlayer.h
+++ b/media/libmediaplayerservice/nuplayer/NuPlayer.h
@@ -60,6 +60,8 @@ struct NuPlayer : public AHandler {
void seekToAsync(int64_t seekTimeUs);
status_t setVideoScalingMode(int32_t mode);
+ status_t getTrackInfo(Parcel* reply) const;
+ status_t selectTrack(size_t trackIndex, bool select);
protected:
virtual ~NuPlayer();
@@ -101,6 +103,8 @@ private:
kWhatResume = 'rsme',
kWhatPollDuration = 'polD',
kWhatSourceNotify = 'srcN',
+ kWhatGetTrackInfo = 'gTrI',
+ kWhatSelectTrack = 'selT',
};
wp<NuPlayerDriver> mDriver;
@@ -157,7 +161,7 @@ private:
status_t feedDecoderInputData(bool audio, const sp<AMessage> &msg);
void renderBuffer(bool audio, const sp<AMessage> &msg);
- void notifyListener(int msg, int ext1, int ext2);
+ void notifyListener(int msg, int ext1, int ext2, const Parcel *in = NULL);
void finishFlushIfPossible();
diff --git a/media/libmediaplayerservice/nuplayer/NuPlayerDriver.cpp b/media/libmediaplayerservice/nuplayer/NuPlayerDriver.cpp
index cf0373c..47834fd 100644
--- a/media/libmediaplayerservice/nuplayer/NuPlayerDriver.cpp
+++ b/media/libmediaplayerservice/nuplayer/NuPlayerDriver.cpp
@@ -392,6 +392,23 @@ status_t NuPlayerDriver::invoke(const Parcel &request, Parcel *reply) {
return mPlayer->setVideoScalingMode(mode);
}
+ case INVOKE_ID_GET_TRACK_INFO:
+ {
+ return mPlayer->getTrackInfo(reply);
+ }
+
+ case INVOKE_ID_SELECT_TRACK:
+ {
+ int trackIndex = request.readInt32();
+ return mPlayer->selectTrack(trackIndex, true /* select */);
+ }
+
+ case INVOKE_ID_UNSELECT_TRACK:
+ {
+ int trackIndex = request.readInt32();
+ return mPlayer->selectTrack(trackIndex, false /* select */);
+ }
+
default:
{
return INVALID_OPERATION;
@@ -495,12 +512,13 @@ status_t NuPlayerDriver::dump(int fd, const Vector<String16> &args) const {
return OK;
}
-void NuPlayerDriver::notifyListener(int msg, int ext1, int ext2) {
+void NuPlayerDriver::notifyListener(
+ int msg, int ext1, int ext2, const Parcel *in) {
if (msg == MEDIA_PLAYBACK_COMPLETE || msg == MEDIA_ERROR) {
mAtEOS = true;
}
- sendEvent(msg, ext1, ext2);
+ sendEvent(msg, ext1, ext2, in);
}
void NuPlayerDriver::notifySetDataSourceCompleted(status_t err) {
diff --git a/media/libmediaplayerservice/nuplayer/NuPlayerDriver.h b/media/libmediaplayerservice/nuplayer/NuPlayerDriver.h
index 5df0cfb..99f72a6 100644
--- a/media/libmediaplayerservice/nuplayer/NuPlayerDriver.h
+++ b/media/libmediaplayerservice/nuplayer/NuPlayerDriver.h
@@ -69,7 +69,7 @@ struct NuPlayerDriver : public MediaPlayerInterface {
void notifyPosition(int64_t positionUs);
void notifySeekComplete();
void notifyFrameStats(int64_t numFramesTotal, int64_t numFramesDropped);
- void notifyListener(int msg, int ext1 = 0, int ext2 = 0);
+ void notifyListener(int msg, int ext1 = 0, int ext2 = 0, const Parcel *in = NULL);
void notifyFlagsChanged(uint32_t flags);
protected:
diff --git a/media/libmediaplayerservice/nuplayer/NuPlayerSource.h b/media/libmediaplayerservice/nuplayer/NuPlayerSource.h
index 81ffd21..e50533a 100644
--- a/media/libmediaplayerservice/nuplayer/NuPlayerSource.h
+++ b/media/libmediaplayerservice/nuplayer/NuPlayerSource.h
@@ -42,6 +42,7 @@ struct NuPlayer::Source : public AHandler {
kWhatVideoSizeChanged,
kWhatBufferingStart,
kWhatBufferingEnd,
+ kWhatSubtitleData,
kWhatQueueDecoderShutdown,
};
@@ -71,6 +72,14 @@ struct NuPlayer::Source : public AHandler {
return INVALID_OPERATION;
}
+ virtual status_t getTrackInfo(Parcel* reply) const {
+ return INVALID_OPERATION;
+ }
+
+ virtual status_t selectTrack(size_t trackIndex, bool select) {
+ return INVALID_OPERATION;
+ }
+
virtual status_t seekTo(int64_t seekTimeUs) {
return INVALID_OPERATION;
}
diff --git a/media/libstagefright/httplive/Android.mk b/media/libstagefright/httplive/Android.mk
index 85bd492..f3529f9 100644
--- a/media/libstagefright/httplive/Android.mk
+++ b/media/libstagefright/httplive/Android.mk
@@ -14,6 +14,7 @@ LOCAL_C_INCLUDES:= \
$(TOP)/external/openssl/include
LOCAL_SHARED_LIBRARIES := \
+ libbinder \
libcrypto \
libcutils \
libmedia \
diff --git a/media/libstagefright/httplive/LiveSession.cpp b/media/libstagefright/httplive/LiveSession.cpp
index e91c60b..bd12ddc 100644
--- a/media/libstagefright/httplive/LiveSession.cpp
+++ b/media/libstagefright/httplive/LiveSession.cpp
@@ -59,6 +59,7 @@ LiveSession::LiveSession(
mStreamMask(0),
mCheckBandwidthGeneration(0),
mLastDequeuedTimeUs(0ll),
+ mRealTimeBaseUs(0ll),
mReconfigurationInProgress(false),
mDisconnectReplyID(0) {
if (mUIDValid) {
@@ -122,11 +123,18 @@ status_t LiveSession::dequeueAccessUnit(
type,
extra == NULL ? "NULL" : extra->debugString().c_str());
} else if (err == OK) {
- int64_t timeUs;
- CHECK((*accessUnit)->meta()->findInt64("timeUs", &timeUs));
- ALOGV("[%s] read buffer at time %lld us", streamStr, timeUs);
-
- mLastDequeuedTimeUs = timeUs;
+ if (stream == STREAMTYPE_AUDIO || stream == STREAMTYPE_VIDEO) {
+ int64_t timeUs;
+ CHECK((*accessUnit)->meta()->findInt64("timeUs", &timeUs));
+ ALOGV("[%s] read buffer at time %lld us", streamStr, timeUs);
+
+ mLastDequeuedTimeUs = timeUs;
+ mRealTimeBaseUs = ALooper::GetNowUs() - timeUs;
+ } else if (stream == STREAMTYPE_SUBTITLES) {
+ (*accessUnit)->meta()->setInt32(
+ "trackIndex", mPlaylist->getSelectedIndex());
+ (*accessUnit)->meta()->setInt64("baseUs", mRealTimeBaseUs);
+ }
} else {
ALOGI("[%s] encountered error %d", streamStr, err);
}
@@ -325,6 +333,12 @@ void LiveSession::onMessageReceived(const sp<AMessage> &msg) {
break;
}
+ case kWhatChangeConfiguration:
+ {
+ onChangeConfiguration(msg);
+ break;
+ }
+
case kWhatChangeConfiguration2:
{
onChangeConfiguration2(msg);
@@ -438,7 +452,8 @@ void LiveSession::onConnect(const sp<AMessage> &msg) {
mBandwidthItems.push(item);
}
- changeConfiguration(0ll /* timeUs */, initialBandwidthIndex);
+ changeConfiguration(
+ 0ll /* timeUs */, initialBandwidthIndex, true /* pickTrack */);
}
void LiveSession::finishDisconnect() {
@@ -783,16 +798,31 @@ bool LiveSession::hasDynamicDuration() const {
return false;
}
-void LiveSession::changeConfiguration(int64_t timeUs, size_t bandwidthIndex) {
+status_t LiveSession::getTrackInfo(Parcel *reply) const {
+ return mPlaylist->getTrackInfo(reply);
+}
+
+status_t LiveSession::selectTrack(size_t index, bool select) {
+ status_t err = mPlaylist->selectTrack(index, select);
+ if (err == OK) {
+ (new AMessage(kWhatChangeConfiguration, id()))->post();
+ }
+ return err;
+}
+
+void LiveSession::changeConfiguration(
+ int64_t timeUs, size_t bandwidthIndex, bool pickTrack) {
CHECK(!mReconfigurationInProgress);
mReconfigurationInProgress = true;
mPrevBandwidthIndex = bandwidthIndex;
- ALOGV("changeConfiguration => timeUs:%lld us, bwIndex:%d",
- timeUs, bandwidthIndex);
+ ALOGV("changeConfiguration => timeUs:%lld us, bwIndex:%d, pickTrack:%d",
+ timeUs, bandwidthIndex, pickTrack);
- mPlaylist->pickRandomMediaItems();
+ if (pickTrack) {
+ mPlaylist->pickRandomMediaItems();
+ }
CHECK_LT(bandwidthIndex, mBandwidthItems.size());
const BandwidthItem &item = mBandwidthItems.itemAt(bandwidthIndex);
@@ -862,6 +892,14 @@ void LiveSession::changeConfiguration(int64_t timeUs, size_t bandwidthIndex) {
}
}
+void LiveSession::onChangeConfiguration(const sp<AMessage> &msg) {
+ if (!mReconfigurationInProgress) {
+ changeConfiguration(-1ll /* timeUs */, getBandwidthIndex());
+ } else {
+ msg->post(1000000ll); // retry in 1 sec
+ }
+}
+
void LiveSession::onChangeConfiguration2(const sp<AMessage> &msg) {
mContinuation.clear();
@@ -948,6 +986,7 @@ void LiveSession::onChangeConfiguration3(const sp<AMessage> &msg) {
if (timeUs < 0ll) {
timeUs = mLastDequeuedTimeUs;
}
+ mRealTimeBaseUs = ALooper::GetNowUs() - timeUs;
mStreamMask = streamMask;
mAudioURI = audioURI;
diff --git a/media/libstagefright/httplive/LiveSession.h b/media/libstagefright/httplive/LiveSession.h
index b134725..99b480a8 100644
--- a/media/libstagefright/httplive/LiveSession.h
+++ b/media/libstagefright/httplive/LiveSession.h
@@ -31,6 +31,7 @@ struct HTTPBase;
struct LiveDataSource;
struct M3UParser;
struct PlaylistFetcher;
+struct Parcel;
struct LiveSession : public AHandler {
enum Flags {
@@ -60,6 +61,8 @@ struct LiveSession : public AHandler {
status_t seekTo(int64_t timeUs);
status_t getDuration(int64_t *durationUs) const;
+ status_t getTrackInfo(Parcel *reply) const;
+ status_t selectTrack(size_t index, bool select);
bool isSeekable() const;
bool hasDynamicDuration() const;
@@ -85,6 +88,7 @@ private:
kWhatSeek = 'seek',
kWhatFetcherNotify = 'notf',
kWhatCheckBandwidth = 'bndw',
+ kWhatChangeConfiguration = 'chC0',
kWhatChangeConfiguration2 = 'chC2',
kWhatChangeConfiguration3 = 'chC3',
kWhatFinishDisconnect2 = 'fin2',
@@ -130,6 +134,7 @@ private:
sp<AMessage> mContinuation;
int64_t mLastDequeuedTimeUs;
+ int64_t mRealTimeBaseUs;
bool mReconfigurationInProgress;
uint32_t mDisconnectReplyID;
@@ -151,7 +156,9 @@ private:
static int SortByBandwidth(const BandwidthItem *, const BandwidthItem *);
- void changeConfiguration(int64_t timeUs, size_t bandwidthIndex);
+ void changeConfiguration(
+ int64_t timeUs, size_t bandwidthIndex, bool pickTrack = false);
+ void onChangeConfiguration(const sp<AMessage> &msg);
void onChangeConfiguration2(const sp<AMessage> &msg);
void onChangeConfiguration3(const sp<AMessage> &msg);
diff --git a/media/libstagefright/httplive/M3UParser.cpp b/media/libstagefright/httplive/M3UParser.cpp
index be66252..bc6d629 100644
--- a/media/libstagefright/httplive/M3UParser.cpp
+++ b/media/libstagefright/httplive/M3UParser.cpp
@@ -19,11 +19,12 @@
#include <utils/Log.h>
#include "M3UParser.h"
-
+#include <binder/Parcel.h>
#include <cutils/properties.h>
#include <media/stagefright/foundation/ADebug.h>
#include <media/stagefright/foundation/AMessage.h>
#include <media/stagefright/MediaErrors.h>
+#include <media/mediaplayer.h>
namespace android {
@@ -55,6 +56,9 @@ struct M3UParser::MediaGroup : public RefBase {
bool getActiveURI(AString *uri) const;
void pickRandomMediaItems();
+ status_t selectTrack(size_t index, bool select);
+ void getTrackInfo(Parcel* reply) const;
+ size_t countTracks() const;
protected:
virtual ~MediaGroup();
@@ -150,6 +154,59 @@ void M3UParser::MediaGroup::pickRandomMediaItems() {
#endif
}
+status_t M3UParser::MediaGroup::selectTrack(size_t index, bool select) {
+ if (mType != TYPE_SUBS) {
+ ALOGE("only select subtitile tracks for now!");
+ return INVALID_OPERATION;
+ }
+
+ if (select) {
+ if (index >= mMediaItems.size()) {
+ ALOGE("track %d does not exist", index);
+ return INVALID_OPERATION;
+ }
+ if (mSelectedIndex == index) {
+ ALOGE("track %d already selected", index);
+ return BAD_VALUE;
+ }
+ ALOGV("selected track %d", index);
+ mSelectedIndex = index;
+ } else {
+ if (mSelectedIndex != index) {
+ ALOGE("track %d is not selected", index);
+ return BAD_VALUE;
+ }
+ ALOGV("unselected track %d", index);
+ mSelectedIndex = -1;
+ }
+
+ return OK;
+}
+
+void M3UParser::MediaGroup::getTrackInfo(Parcel* reply) const {
+ for (size_t i = 0; i < mMediaItems.size(); ++i) {
+ reply->writeInt32(2); // 2 fields
+
+ if (mType == TYPE_AUDIO) {
+ reply->writeInt32(MEDIA_TRACK_TYPE_AUDIO);
+ } else if (mType == TYPE_VIDEO) {
+ reply->writeInt32(MEDIA_TRACK_TYPE_VIDEO);
+ } else if (mType == TYPE_SUBS) {
+ reply->writeInt32(MEDIA_TRACK_TYPE_SUBTITLE);
+ } else {
+ reply->writeInt32(MEDIA_TRACK_TYPE_UNKNOWN);
+ }
+
+ const Media &item = mMediaItems.itemAt(i);
+ const char *lang = item.mLanguage.empty() ? "und" : item.mLanguage.c_str();
+ reply->writeString16(String16(lang));
+ }
+}
+
+size_t M3UParser::MediaGroup::countTracks() const {
+ return mMediaItems.size();
+}
+
bool M3UParser::MediaGroup::getActiveURI(AString *uri) const {
for (size_t i = 0; i < mMediaItems.size(); ++i) {
if (mSelectedIndex >= 0 && i == (size_t)mSelectedIndex) {
@@ -172,7 +229,8 @@ M3UParser::M3UParser(
mIsExtM3U(false),
mIsVariantPlaylist(false),
mIsComplete(false),
- mIsEvent(false) {
+ mIsEvent(false),
+ mSelectedIndex(-1) {
mInitCheck = parse(data, size);
}
@@ -237,6 +295,39 @@ void M3UParser::pickRandomMediaItems() {
}
}
+status_t M3UParser::selectTrack(size_t index, bool select) {
+ for (size_t i = 0, ii = index; i < mMediaGroups.size(); ++i) {
+ sp<MediaGroup> group = mMediaGroups.valueAt(i);
+ size_t tracks = group->countTracks();
+ if (ii < tracks) {
+ status_t err = group->selectTrack(ii, select);
+ if (err == OK) {
+ mSelectedIndex = select ? index : -1;
+ }
+ return err;
+ }
+ ii -= tracks;
+ }
+ return INVALID_OPERATION;
+}
+
+status_t M3UParser::getTrackInfo(Parcel* reply) const {
+ size_t trackCount = 0;
+ for (size_t i = 0; i < mMediaGroups.size(); ++i) {
+ trackCount += mMediaGroups.valueAt(i)->countTracks();
+ }
+ reply->writeInt32(trackCount);
+
+ for (size_t i = 0; i < mMediaGroups.size(); ++i) {
+ mMediaGroups.valueAt(i)->getTrackInfo(reply);
+ }
+ return OK;
+}
+
+ssize_t M3UParser::getSelectedIndex() const {
+ return mSelectedIndex;
+}
+
bool M3UParser::getTypeURI(size_t index, const char *key, AString *uri) const {
if (!mIsVariantPlaylist) {
*uri = mBaseURI;
diff --git a/media/libstagefright/httplive/M3UParser.h b/media/libstagefright/httplive/M3UParser.h
index abea286..5248004 100644
--- a/media/libstagefright/httplive/M3UParser.h
+++ b/media/libstagefright/httplive/M3UParser.h
@@ -41,6 +41,9 @@ struct M3UParser : public RefBase {
bool itemAt(size_t index, AString *uri, sp<AMessage> *meta = NULL);
void pickRandomMediaItems();
+ status_t selectTrack(size_t index, bool select);
+ status_t getTrackInfo(Parcel* reply) const;
+ ssize_t getSelectedIndex() const;
bool getAudioURI(size_t index, AString *uri) const;
bool getVideoURI(size_t index, AString *uri) const;
@@ -67,6 +70,7 @@ private:
sp<AMessage> mMeta;
Vector<Item> mItems;
+ ssize_t mSelectedIndex;
// Media groups keyed by group ID.
KeyedVector<AString, sp<MediaGroup> > mMediaGroups;
diff --git a/media/libstagefright/httplive/PlaylistFetcher.cpp b/media/libstagefright/httplive/PlaylistFetcher.cpp
index 8ae70b7..973b779 100644
--- a/media/libstagefright/httplive/PlaylistFetcher.cpp
+++ b/media/libstagefright/httplive/PlaylistFetcher.cpp
@@ -462,7 +462,11 @@ void PlaylistFetcher::onMonitorQueue() {
sp<AnotherPacketSource> packetSource =
mPacketSources.valueFor(LiveSession::STREAMTYPE_SUBTITLES);
- downloadMore = packetSource->hasBufferAvailable(&finalResult);
+ int64_t bufferedDurationUs =
+ packetSource->getBufferedDurationUs(&finalResult);
+
+ downloadMore = (bufferedDurationUs < kMinBufferedDurationUs);
+ finalResult = OK;
} else {
bool first = true;
int64_t minBufferedDurationUs = 0ll;
@@ -659,7 +663,7 @@ void PlaylistFetcher::onDownloadNext() {
}
}
- err = extractAndQueueAccessUnits(buffer);
+ err = extractAndQueueAccessUnits(buffer, itemMeta);
if (err != OK) {
notifyError(err);
@@ -706,7 +710,7 @@ int32_t PlaylistFetcher::getSeqNumberForTime(int64_t timeUs) const {
}
status_t PlaylistFetcher::extractAndQueueAccessUnits(
- const sp<ABuffer> &buffer) {
+ const sp<ABuffer> &buffer, const sp<AMessage> &itemMeta) {
if (buffer->size() > 0 && buffer->data()[0] == 0x47) {
// Let's assume this is an MPEG2 transport stream.
@@ -802,7 +806,10 @@ status_t PlaylistFetcher::extractAndQueueAccessUnits(
const sp<AnotherPacketSource> packetSource =
mPacketSources.valueFor(LiveSession::STREAMTYPE_SUBTITLES);
- buffer->meta()->setInt64("timeUs", 0ll);
+ int64_t durationUs;
+ CHECK(itemMeta->findInt64("durationUs", &durationUs));
+ buffer->meta()->setInt64("timeUs", getSegmentStartTimeUs(mSeqNumber));
+ buffer->meta()->setInt64("durationUs", durationUs);
packetSource->queueAccessUnit(buffer);
return OK;
diff --git a/media/libstagefright/httplive/PlaylistFetcher.h b/media/libstagefright/httplive/PlaylistFetcher.h
index 5a2b901..1648e02 100644
--- a/media/libstagefright/httplive/PlaylistFetcher.h
+++ b/media/libstagefright/httplive/PlaylistFetcher.h
@@ -135,7 +135,8 @@ private:
void onMonitorQueue();
void onDownloadNext();
- status_t extractAndQueueAccessUnits(const sp<ABuffer> &buffer);
+ status_t extractAndQueueAccessUnits(
+ const sp<ABuffer> &buffer, const sp<AMessage> &itemMeta);
void notifyError(status_t err);