Merge "Camera2: Add flush support" into klp-dev
diff --git a/camera/camera2/ICameraDeviceUser.cpp b/camera/camera2/ICameraDeviceUser.cpp
index ae4cf69..1e5822f 100644
--- a/camera/camera2/ICameraDeviceUser.cpp
+++ b/camera/camera2/ICameraDeviceUser.cpp
@@ -44,6 +44,19 @@
FLUSH
};
+namespace {
+ // Read empty strings without printing a false error message.
+ String16 readMaybeEmptyString16(const Parcel& parcel) {
+ size_t len;
+ const char16_t* str = parcel.readString16Inplace(&len);
+ if (str != NULL) {
+ return String16(str, len);
+ } else {
+ return String16();
+ }
+ }
+};
+
class BpCameraDeviceUser : public BpInterface<ICameraDeviceUser>
{
public:
@@ -261,7 +274,7 @@
sp<IGraphicBufferProducer> bp;
if (data.readInt32() != 0) {
- String16 name = data.readString16();
+ String16 name = readMaybeEmptyString16(data);
bp = interface_cast<IGraphicBufferProducer>(
data.readStrongBinder());
diff --git a/drm/common/DrmInfoEvent.cpp b/drm/common/DrmInfoEvent.cpp
index 27a5a2d..2315aa9 100644
--- a/drm/common/DrmInfoEvent.cpp
+++ b/drm/common/DrmInfoEvent.cpp
@@ -16,16 +16,29 @@
#include <utils/String8.h>
#include <drm/DrmInfoEvent.h>
+#include <stdlib.h>
using namespace android;
DrmInfoEvent::DrmInfoEvent(int uniqueId, int infoType, const String8 message)
: mUniqueId(uniqueId),
mInfoType(infoType),
- mMessage(message) {
+ mMessage(message),
+ mDrmBuffer() {
}
+DrmInfoEvent::DrmInfoEvent(int uniqueId, int infoType, const String8 message,
+ const DrmBuffer& drmBuffer)
+ : mUniqueId(uniqueId), mInfoType(infoType), mMessage(message), mDrmBuffer() {
+ setData(drmBuffer);
+}
+
+DrmInfoEvent::~DrmInfoEvent() {
+ delete [] mDrmBuffer.data;
+}
+
+
int DrmInfoEvent::getUniqueId() const {
return mUniqueId;
}
@@ -38,3 +51,80 @@
return mMessage;
}
+int DrmInfoEvent::getCount() const {
+ return mAttributes.size();
+}
+
+status_t DrmInfoEvent::put(const String8& key, String8& value) {
+ mAttributes.add(key, value);
+ return DRM_NO_ERROR;
+}
+
+const String8 DrmInfoEvent::get(const String8& key) const {
+ if (mAttributes.indexOfKey(key) != NAME_NOT_FOUND) {
+ return mAttributes.valueFor(key);
+ }
+ return String8("");
+}
+
+const DrmBuffer& DrmInfoEvent::getData() const {
+ return mDrmBuffer;
+}
+
+void DrmInfoEvent::setData(const DrmBuffer& drmBuffer) {
+ delete [] mDrmBuffer.data;
+ mDrmBuffer.data = new char[drmBuffer.length];;
+ mDrmBuffer.length = drmBuffer.length;
+ memcpy(mDrmBuffer.data, drmBuffer.data, drmBuffer.length);
+}
+
+DrmInfoEvent::KeyIterator DrmInfoEvent::keyIterator() const {
+ return KeyIterator(this);
+}
+
+DrmInfoEvent::Iterator DrmInfoEvent::iterator() const {
+ return Iterator(this);
+}
+
+// KeyIterator implementation
+DrmInfoEvent::KeyIterator::KeyIterator(const DrmInfoEvent::KeyIterator& keyIterator)
+ : mDrmInfoEvent(keyIterator.mDrmInfoEvent), mIndex(keyIterator.mIndex) {
+}
+
+bool DrmInfoEvent::KeyIterator::hasNext() {
+ return (mIndex < mDrmInfoEvent->mAttributes.size());
+}
+
+const String8& DrmInfoEvent::KeyIterator::next() {
+ const String8& key = mDrmInfoEvent->mAttributes.keyAt(mIndex);
+ mIndex++;
+ return key;
+}
+
+DrmInfoEvent::KeyIterator& DrmInfoEvent::KeyIterator::operator=(
+ const DrmInfoEvent::KeyIterator& keyIterator) {
+ mDrmInfoEvent = keyIterator.mDrmInfoEvent;
+ mIndex = keyIterator.mIndex;
+ return *this;
+}
+
+// Iterator implementation
+DrmInfoEvent::Iterator::Iterator(const DrmInfoEvent::Iterator& iterator)
+ : mDrmInfoEvent(iterator.mDrmInfoEvent), mIndex(iterator.mIndex) {
+}
+
+DrmInfoEvent::Iterator& DrmInfoEvent::Iterator::operator=(const DrmInfoEvent::Iterator& iterator) {
+ mDrmInfoEvent = iterator.mDrmInfoEvent;
+ mIndex = iterator.mIndex;
+ return *this;
+}
+
+bool DrmInfoEvent::Iterator::hasNext() {
+ return mIndex < mDrmInfoEvent->mAttributes.size();
+}
+
+const String8& DrmInfoEvent::Iterator::next() {
+ const String8& value = mDrmInfoEvent->mAttributes.editValueAt(mIndex);
+ mIndex++;
+ return value;
+}
diff --git a/drm/common/IDrmServiceListener.cpp b/drm/common/IDrmServiceListener.cpp
index 6eeea40..d825afb 100644
--- a/drm/common/IDrmServiceListener.cpp
+++ b/drm/common/IDrmServiceListener.cpp
@@ -32,6 +32,19 @@
data.writeInt32(event.getType());
data.writeString8(event.getMessage());
+ data.writeInt32(event.getCount());
+ DrmInfoEvent::KeyIterator keyIt = event.keyIterator();
+ while (keyIt.hasNext()) {
+ String8 key = keyIt.next();
+ data.writeString8(key);
+ data.writeString8(event.get(key));
+ }
+ const DrmBuffer& value = event.getData();
+ data.writeInt32(value.length);
+ if (value.length > 0) {
+ data.write(value.data, value.length);
+ }
+
remote()->transact(NOTIFY, data, &reply);
return reply.readInt32();
}
@@ -49,7 +62,24 @@
int type = data.readInt32();
const String8& message = data.readString8();
- status_t status = notify(DrmInfoEvent(uniqueId, type, message));
+ DrmInfoEvent event(uniqueId, type, message);
+ int size = data.readInt32();
+ for (int index = 0; index < size; index++) {
+ String8 key(data.readString8());
+ String8 value(data.readString8());
+ event.put(key, value);
+ }
+ int valueSize = data.readInt32();
+ if (valueSize > 0) {
+ char* valueData = new char[valueSize];
+ data.read(valueData, valueSize);
+ DrmBuffer drmBuffer(valueData, valueSize);
+ event.setData(drmBuffer);
+ delete[] valueData;
+ }
+
+ status_t status = notify(event);
+
reply->writeInt32(status);
return DRM_NO_ERROR;
diff --git a/include/drm/DrmInfoEvent.h b/include/drm/DrmInfoEvent.h
index dfca228..23b2950 100644
--- a/include/drm/DrmInfoEvent.h
+++ b/include/drm/DrmInfoEvent.h
@@ -17,6 +17,8 @@
#ifndef __DRM_INFO_EVENT_H__
#define __DRM_INFO_EVENT_H__
+#include "drm_framework_common.h"
+
namespace android {
class String8;
@@ -71,18 +73,70 @@
public:
/**
- * Constructor for DrmInfoEvent
+ * Constructor for DrmInfoEvent.
+ * Data in drmBuffer are copied to newly allocated buffer.
*
* @param[in] uniqueId Unique session identifier
* @param[in] infoType Type of information
* @param[in] message Message description
+ * @param[in] drmBuffer Binary information
*/
DrmInfoEvent(int uniqueId, int infoType, const String8 message);
+ DrmInfoEvent(int uniqueId, int infoType, const String8 message, const DrmBuffer& drmBuffer);
/**
* Destructor for DrmInfoEvent
*/
- virtual ~DrmInfoEvent() {}
+ ~DrmInfoEvent();
+
+public:
+ /**
+ * Iterator for key
+ */
+ class KeyIterator {
+ friend class DrmInfoEvent;
+
+ private:
+ KeyIterator(const DrmInfoEvent* drmInfoEvent)
+ : mDrmInfoEvent(const_cast <DrmInfoEvent*> (drmInfoEvent)), mIndex(0) {}
+
+ public:
+ KeyIterator(const KeyIterator& keyIterator);
+ KeyIterator& operator=(const KeyIterator& keyIterator);
+ virtual ~KeyIterator() {}
+
+ public:
+ bool hasNext();
+ const String8& next();
+
+ private:
+ DrmInfoEvent* mDrmInfoEvent;
+ unsigned int mIndex;
+ };
+
+ /**
+ * Iterator
+ */
+ class Iterator {
+ friend class DrmInfoEvent;
+
+ private:
+ Iterator(const DrmInfoEvent* drmInfoEvent)
+ : mDrmInfoEvent(const_cast <DrmInfoEvent*> (drmInfoEvent)), mIndex(0) {}
+
+ public:
+ Iterator(const Iterator& iterator);
+ Iterator& operator=(const Iterator& iterator);
+ virtual ~Iterator() {}
+
+ public:
+ bool hasNext();
+ const String8& next();
+
+ private:
+ DrmInfoEvent* mDrmInfoEvent;
+ unsigned int mIndex;
+ };
public:
/**
@@ -106,10 +160,69 @@
*/
const String8 getMessage() const;
+ /**
+ * Returns the number of attributes contained in this instance
+ *
+ * @return Number of attributes
+ */
+ int getCount() const;
+
+ /**
+ * Adds optional information as <key, value> pair to this instance
+ *
+ * @param[in] key Key to add
+ * @param[in] value Value to add
+ * @return Returns the error code
+ */
+ status_t put(const String8& key, String8& value);
+
+ /**
+ * Retrieves the value of given key
+ *
+ * @param key Key whose value to be retrieved
+ * @return The value
+ */
+ const String8 get(const String8& key) const;
+
+ /**
+ * Returns KeyIterator object to walk through the keys associated with this instance
+ *
+ * @return KeyIterator object
+ */
+ KeyIterator keyIterator() const;
+
+ /**
+ * Returns Iterator object to walk through the values associated with this instance
+ *
+ * @return Iterator object
+ */
+ Iterator iterator() const;
+
+ /**
+ * Returns the Binary information associated with this instance
+ *
+ * @return Binary information
+ */
+ const DrmBuffer& getData() const;
+
+ /**
+ * Sets the Binary information associated with this instance.
+ * Data in drmBuffer are copied to newly allocated buffer.
+ *
+ * @param[in] drmBuffer Binary information associated with this instance
+ */
+ void setData(const DrmBuffer& drmBuffer);
+
+private:
+ DrmInfoEvent(const DrmInfoEvent& ref);
+ const DrmInfoEvent& operator=(const DrmInfoEvent& ref);
+
private:
int mUniqueId;
int mInfoType;
const String8 mMessage;
+ KeyedVector<String8, String8> mAttributes;
+ DrmBuffer mDrmBuffer;
};
};
diff --git a/include/media/IRemoteDisplayClient.h b/include/media/IRemoteDisplayClient.h
index 7b0fa9e..0e6d55d 100644
--- a/include/media/IRemoteDisplayClient.h
+++ b/include/media/IRemoteDisplayClient.h
@@ -49,7 +49,7 @@
// Provides a surface texture that the client should use to stream buffers to
// the remote display.
virtual void onDisplayConnected(const sp<IGraphicBufferProducer>& bufferProducer,
- uint32_t width, uint32_t height, uint32_t flags) = 0; // one-way
+ uint32_t width, uint32_t height, uint32_t flags, uint32_t session) = 0; // one-way
// Indicates that the remote display has been disconnected normally.
// This method should only be called once the client has called 'dispose()'
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 @@
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 @@
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/IRemoteDisplayClient.cpp b/media/libmedia/IRemoteDisplayClient.cpp
index 5c494b3..7190879 100644
--- a/media/libmedia/IRemoteDisplayClient.cpp
+++ b/media/libmedia/IRemoteDisplayClient.cpp
@@ -38,7 +38,7 @@
}
void onDisplayConnected(const sp<IGraphicBufferProducer>& bufferProducer,
- uint32_t width, uint32_t height, uint32_t flags)
+ uint32_t width, uint32_t height, uint32_t flags, uint32_t session)
{
Parcel data, reply;
data.writeInterfaceToken(IRemoteDisplayClient::getInterfaceDescriptor());
@@ -46,6 +46,7 @@
data.writeInt32(width);
data.writeInt32(height);
data.writeInt32(flags);
+ data.writeInt32(session);
remote()->transact(ON_DISPLAY_CONNECTED, data, &reply, IBinder::FLAG_ONEWAY);
}
@@ -80,7 +81,8 @@
uint32_t width = data.readInt32();
uint32_t height = data.readInt32();
uint32_t flags = data.readInt32();
- onDisplayConnected(surfaceTexture, width, height, flags);
+ uint32_t session = data.readInt32();
+ onDisplayConnected(surfaceTexture, width, height, flags, session);
return NO_ERROR;
}
case ON_DISPLAY_DISCONNECTED: {
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 @@
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 @@
mUID(uid),
mFlags(0),
mFinalResult(OK),
- mOffset(0) {
+ mOffset(0),
+ mFetchSubtitleDataGeneration(0) {
if (headers) {
mExtraHeaders = *headers;
@@ -120,6 +121,28 @@
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 @@
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 @@
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 @@
enum {
kWhatSessionNotify,
+ kWhatFetchSubtitleData,
};
AString mURL;
@@ -67,6 +70,7 @@
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 @@
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 @@
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 @@
return;
}
- driver->notifyListener(msg, ext1, ext2);
+ driver->notifyListener(msg, ext1, ext2, in);
}
void NuPlayer::flushDecoder(bool audio, bool needShutdown) {
@@ -1132,6 +1172,26 @@
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 @@
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 @@
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 @@
kWhatResume = 'rsme',
kWhatPollDuration = 'polD',
kWhatSourceNotify = 'srcN',
+ kWhatGetTrackInfo = 'gTrI',
+ kWhatSelectTrack = 'selT',
};
wp<NuPlayerDriver> mDriver;
@@ -157,7 +161,7 @@
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 @@
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 @@
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 @@
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 @@
kWhatVideoSizeChanged,
kWhatBufferingStart,
kWhatBufferingEnd,
+ kWhatSubtitleData,
kWhatQueueDecoderShutdown,
};
@@ -71,6 +72,14 @@
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 @@
$(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 @@
mStreamMask(0),
mCheckBandwidthGeneration(0),
mLastDequeuedTimeUs(0ll),
+ mRealTimeBaseUs(0ll),
mReconfigurationInProgress(false),
mDisconnectReplyID(0) {
if (mUIDValid) {
@@ -122,11 +123,18 @@
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);
+ 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;
+ 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 @@
break;
}
+ case kWhatChangeConfiguration:
+ {
+ onChangeConfiguration(msg);
+ break;
+ }
+
case kWhatChangeConfiguration2:
{
onChangeConfiguration2(msg);
@@ -438,7 +452,8 @@
mBandwidthItems.push(item);
}
- changeConfiguration(0ll /* timeUs */, initialBandwidthIndex);
+ changeConfiguration(
+ 0ll /* timeUs */, initialBandwidthIndex, true /* pickTrack */);
}
void LiveSession::finishDisconnect() {
@@ -783,16 +798,31 @@
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::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 @@
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 LiveDataSource;
struct M3UParser;
struct PlaylistFetcher;
+struct Parcel;
struct LiveSession : public AHandler {
enum Flags {
@@ -60,6 +61,8 @@
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 @@
kWhatSeek = 'seek',
kWhatFetcherNotify = 'notf',
kWhatCheckBandwidth = 'bndw',
+ kWhatChangeConfiguration = 'chC0',
kWhatChangeConfiguration2 = 'chC2',
kWhatChangeConfiguration3 = 'chC3',
kWhatFinishDisconnect2 = 'fin2',
@@ -130,6 +134,7 @@
sp<AMessage> mContinuation;
int64_t mLastDequeuedTimeUs;
+ int64_t mRealTimeBaseUs;
bool mReconfigurationInProgress;
uint32_t mDisconnectReplyID;
@@ -151,7 +156,9 @@
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 @@
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 @@
#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 @@
mIsExtM3U(false),
mIsVariantPlaylist(false),
mIsComplete(false),
- mIsEvent(false) {
+ mIsEvent(false),
+ mSelectedIndex(-1) {
mInitCheck = parse(data, size);
}
@@ -237,6 +295,39 @@
}
}
+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 @@
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 @@
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 @@
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 @@
}
}
- err = extractAndQueueAccessUnits(buffer);
+ err = extractAndQueueAccessUnits(buffer, itemMeta);
if (err != OK) {
notifyError(err);
@@ -706,7 +710,7 @@
}
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 @@
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 @@
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);
diff --git a/media/libstagefright/wifi-display/source/WifiDisplaySource.cpp b/media/libstagefright/wifi-display/source/WifiDisplaySource.cpp
index 4b59e62..d72349d 100644
--- a/media/libstagefright/wifi-display/source/WifiDisplaySource.cpp
+++ b/media/libstagefright/wifi-display/source/WifiDisplaySource.cpp
@@ -416,7 +416,8 @@
0, // height,
mUsingHDCP
? IRemoteDisplayClient::kDisplayFlagSecure
- : 0);
+ : 0,
+ 0);
} else {
size_t width, height;
@@ -435,7 +436,8 @@
height,
mUsingHDCP
? IRemoteDisplayClient::kDisplayFlagSecure
- : 0);
+ : 0,
+ playbackSessionID);
}
}
diff --git a/media/libstagefright/wifi-display/wfd.cpp b/media/libstagefright/wifi-display/wfd.cpp
index 04cb319..52e4e26 100644
--- a/media/libstagefright/wifi-display/wfd.cpp
+++ b/media/libstagefright/wifi-display/wfd.cpp
@@ -55,7 +55,8 @@
const sp<IGraphicBufferProducer> &bufferProducer,
uint32_t width,
uint32_t height,
- uint32_t flags);
+ uint32_t flags,
+ uint32_t session);
virtual void onDisplayDisconnected();
virtual void onDisplayError(int32_t error);
@@ -91,9 +92,10 @@
const sp<IGraphicBufferProducer> &bufferProducer,
uint32_t width,
uint32_t height,
- uint32_t flags) {
- ALOGI("onDisplayConnected width=%u, height=%u, flags = 0x%08x",
- width, height, flags);
+ uint32_t flags,
+ uint32_t session) {
+ ALOGI("onDisplayConnected width=%u, height=%u, flags = 0x%08x, session = %d",
+ width, height, flags, session);
if (bufferProducer != NULL) {
mSurfaceTexture = bufferProducer;