diff options
32 files changed, 412 insertions, 92 deletions
diff --git a/camera/Camera.cpp b/camera/Camera.cpp index 22016a9..22199fa 100644 --- a/camera/Camera.cpp +++ b/camera/Camera.cpp @@ -100,13 +100,13 @@ status_t Camera::unlock() } // pass the buffered IGraphicBufferProducer to the camera service -status_t Camera::setPreviewTexture(const sp<IGraphicBufferProducer>& bufferProducer) +status_t Camera::setPreviewTarget(const sp<IGraphicBufferProducer>& bufferProducer) { - ALOGV("setPreviewTexture(%p)", bufferProducer.get()); + ALOGV("setPreviewTarget(%p)", bufferProducer.get()); sp <ICamera> c = mCamera; if (c == 0) return NO_INIT; ALOGD_IF(bufferProducer == 0, "app passed NULL surface"); - return c->setPreviewTexture(bufferProducer); + return c->setPreviewTarget(bufferProducer); } // start preview mode @@ -127,7 +127,7 @@ status_t Camera::storeMetaDataInBuffers(bool enabled) return c->storeMetaDataInBuffers(enabled); } -// start recording mode, must call setPreviewDisplay first +// start recording mode, must call setPreviewTarget first status_t Camera::startRecording() { ALOGV("startRecording"); diff --git a/camera/ICamera.cpp b/camera/ICamera.cpp index 12356f0..8c6e1f7 100644 --- a/camera/ICamera.cpp +++ b/camera/ICamera.cpp @@ -29,7 +29,7 @@ namespace android { enum { DISCONNECT = IBinder::FIRST_CALL_TRANSACTION, - SET_PREVIEW_TEXTURE, + SET_PREVIEW_TARGET, SET_PREVIEW_CALLBACK_FLAG, SET_PREVIEW_CALLBACK_TARGET, START_PREVIEW, @@ -70,14 +70,14 @@ public: } // pass the buffered IGraphicBufferProducer to the camera service - status_t setPreviewTexture(const sp<IGraphicBufferProducer>& bufferProducer) + status_t setPreviewTarget(const sp<IGraphicBufferProducer>& bufferProducer) { - ALOGV("setPreviewTexture"); + ALOGV("setPreviewTarget"); Parcel data, reply; data.writeInterfaceToken(ICamera::getInterfaceDescriptor()); sp<IBinder> b(bufferProducer->asBinder()); data.writeStrongBinder(b); - remote()->transact(SET_PREVIEW_TEXTURE, data, &reply); + remote()->transact(SET_PREVIEW_TARGET, data, &reply); return reply.readInt32(); } @@ -104,7 +104,7 @@ public: return reply.readInt32(); } - // start preview mode, must call setPreviewDisplay first + // start preview mode, must call setPreviewTarget first status_t startPreview() { ALOGV("startPreview"); @@ -114,7 +114,7 @@ public: return reply.readInt32(); } - // start recording mode, must call setPreviewDisplay first + // start recording mode, must call setPreviewTarget first status_t startRecording() { ALOGV("startRecording"); @@ -285,12 +285,12 @@ status_t BnCamera::onTransact( reply->writeNoException(); return NO_ERROR; } break; - case SET_PREVIEW_TEXTURE: { - ALOGV("SET_PREVIEW_TEXTURE"); + case SET_PREVIEW_TARGET: { + ALOGV("SET_PREVIEW_TARGET"); CHECK_INTERFACE(ICamera, data, reply); sp<IGraphicBufferProducer> st = interface_cast<IGraphicBufferProducer>(data.readStrongBinder()); - reply->writeInt32(setPreviewTexture(st)); + reply->writeInt32(setPreviewTarget(st)); return NO_ERROR; } break; case SET_PREVIEW_CALLBACK_FLAG: { diff --git a/drm/mediadrm/plugins/mock/MockDrmCryptoPlugin.cpp b/drm/mediadrm/plugins/mock/MockDrmCryptoPlugin.cpp index 06fc29d..4770db0 100644 --- a/drm/mediadrm/plugins/mock/MockDrmCryptoPlugin.cpp +++ b/drm/mediadrm/plugins/mock/MockDrmCryptoPlugin.cpp @@ -48,6 +48,14 @@ namespace android { return (!memcmp(uuid, mock_uuid, sizeof(uuid))); } + bool MockDrmFactory::isContentTypeSupported(const String8 &mimeType) + { + if (mimeType != "" && mimeType != "video/mp4") { + return false; + } + return true; + } + status_t MockDrmFactory::createDrmPlugin(const uint8_t uuid[16], DrmPlugin **plugin) { *plugin = new MockDrmPlugin(); diff --git a/drm/mediadrm/plugins/mock/MockDrmCryptoPlugin.h b/drm/mediadrm/plugins/mock/MockDrmCryptoPlugin.h index ca9eac7..2297f9b 100644 --- a/drm/mediadrm/plugins/mock/MockDrmCryptoPlugin.h +++ b/drm/mediadrm/plugins/mock/MockDrmCryptoPlugin.h @@ -32,6 +32,7 @@ namespace android { virtual ~MockDrmFactory() {} bool isCryptoSchemeSupported(const uint8_t uuid[16]); + bool isContentTypeSupported(const String8 &mimeType); status_t createDrmPlugin(const uint8_t uuid[16], DrmPlugin **plugin); }; diff --git a/include/camera/Camera.h b/include/camera/Camera.h index 81848b3..79682b8 100644 --- a/include/camera/Camera.h +++ b/include/camera/Camera.h @@ -81,9 +81,9 @@ public: status_t unlock(); // pass the buffered IGraphicBufferProducer to the camera service - status_t setPreviewTexture(const sp<IGraphicBufferProducer>& bufferProducer); + status_t setPreviewTarget(const sp<IGraphicBufferProducer>& bufferProducer); - // start preview mode, must call setPreviewDisplay first + // start preview mode, must call setPreviewTarget first status_t startPreview(); // stop preview mode @@ -92,7 +92,7 @@ public: // get preview state bool previewEnabled(); - // start recording mode, must call setPreviewDisplay first + // start recording mode, must call setPreviewTarget first status_t startRecording(); // stop recording mode diff --git a/include/camera/ICamera.h b/include/camera/ICamera.h index f3a186e..b025735 100644 --- a/include/camera/ICamera.h +++ b/include/camera/ICamera.h @@ -50,7 +50,7 @@ public: virtual status_t unlock() = 0; // pass the buffered IGraphicBufferProducer to the camera service - virtual status_t setPreviewTexture( + virtual status_t setPreviewTarget( const sp<IGraphicBufferProducer>& bufferProducer) = 0; // set the preview callback flag to affect how the received frames from @@ -64,7 +64,7 @@ public: virtual status_t setPreviewCallbackTarget( const sp<IGraphicBufferProducer>& callbackProducer) = 0; - // start preview mode, must call setPreviewDisplay first + // start preview mode, must call setPreviewTarget first virtual status_t startPreview() = 0; // stop preview mode diff --git a/include/media/IDrm.h b/include/media/IDrm.h index d630c40..5ef26af 100644 --- a/include/media/IDrm.h +++ b/include/media/IDrm.h @@ -32,7 +32,7 @@ struct IDrm : public IInterface { virtual status_t initCheck() const = 0; - virtual bool isCryptoSchemeSupported(const uint8_t uuid[16]) = 0; + virtual bool isCryptoSchemeSupported(const uint8_t uuid[16], const String8 &mimeType) = 0; virtual status_t createPlugin(const uint8_t uuid[16]) = 0; 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/IDrm.cpp b/media/libmedia/IDrm.cpp index 902aeb2..f7a9a75 100644 --- a/media/libmedia/IDrm.cpp +++ b/media/libmedia/IDrm.cpp @@ -68,10 +68,11 @@ struct BpDrm : public BpInterface<IDrm> { return reply.readInt32(); } - virtual bool isCryptoSchemeSupported(const uint8_t uuid[16]) { + virtual bool isCryptoSchemeSupported(const uint8_t uuid[16], const String8 &mimeType) { Parcel data, reply; data.writeInterfaceToken(IDrm::getInterfaceDescriptor()); data.write(uuid, 16); + data.writeString8(mimeType); remote()->transact(IS_CRYPTO_SUPPORTED, data, &reply); return reply.readInt32() != 0; @@ -438,7 +439,9 @@ status_t BnDrm::onTransact( CHECK_INTERFACE(IDrm, data, reply); uint8_t uuid[16]; data.read(uuid, sizeof(uuid)); - reply->writeInt32(isCryptoSchemeSupported(uuid)); + String8 mimeType = data.readString8(); + reply->writeInt32(isCryptoSchemeSupported(uuid, mimeType)); + return OK; } 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/Drm.cpp b/media/libmediaplayerservice/Drm.cpp index f00f488..4b527d0 100644 --- a/media/libmediaplayerservice/Drm.cpp +++ b/media/libmediaplayerservice/Drm.cpp @@ -211,15 +211,18 @@ bool Drm::loadLibraryForScheme(const String8 &path, const uint8_t uuid[16]) { return true; } -bool Drm::isCryptoSchemeSupported(const uint8_t uuid[16]) { +bool Drm::isCryptoSchemeSupported(const uint8_t uuid[16], const String8 &mimeType) { + Mutex::Autolock autoLock(mLock); - if (mFactory && mFactory->isCryptoSchemeSupported(uuid)) { - return true; + if (!mFactory || !mFactory->isCryptoSchemeSupported(uuid)) { + findFactoryForScheme(uuid); + if (mInitCheck != OK) { + return false; + } } - findFactoryForScheme(uuid); - return (mInitCheck == OK); + return mFactory->isContentTypeSupported(mimeType); } status_t Drm::createPlugin(const uint8_t uuid[16]) { diff --git a/media/libmediaplayerservice/Drm.h b/media/libmediaplayerservice/Drm.h index 3f460f1..119fd50 100644 --- a/media/libmediaplayerservice/Drm.h +++ b/media/libmediaplayerservice/Drm.h @@ -37,7 +37,7 @@ struct Drm : public BnDrm, virtual status_t initCheck() const; - virtual bool isCryptoSchemeSupported(const uint8_t uuid[16]); + virtual bool isCryptoSchemeSupported(const uint8_t uuid[16], const String8 &mimeType); virtual status_t createPlugin(const uint8_t uuid[16]); 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/CameraSource.cpp b/media/libstagefright/CameraSource.cpp index 5a26b06..3017fe7 100644 --- a/media/libstagefright/CameraSource.cpp +++ b/media/libstagefright/CameraSource.cpp @@ -536,7 +536,7 @@ status_t CameraSource::initWithCameraAccess( if (mSurface != NULL) { // This CHECK is good, since we just passed the lock/unlock // check earlier by calling mCamera->setParameters(). - CHECK_EQ((status_t)OK, mCamera->setPreviewTexture(mSurface)); + CHECK_EQ((status_t)OK, mCamera->setPreviewTarget(mSurface)); } // By default, do not store metadata in video buffers 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); diff --git a/services/camera/libcameraservice/CameraService.h b/services/camera/libcameraservice/CameraService.h index 3921cbd..b34a0f6 100644 --- a/services/camera/libcameraservice/CameraService.h +++ b/services/camera/libcameraservice/CameraService.h @@ -212,8 +212,7 @@ public: virtual status_t connect(const sp<ICameraClient>& client) = 0; virtual status_t lock() = 0; virtual status_t unlock() = 0; - virtual status_t setPreviewDisplay(const sp<Surface>& surface) = 0; - virtual status_t setPreviewTexture(const sp<IGraphicBufferProducer>& bufferProducer)=0; + virtual status_t setPreviewTarget(const sp<IGraphicBufferProducer>& bufferProducer)=0; virtual void setPreviewCallbackFlag(int flag) = 0; virtual status_t setPreviewCallbackTarget( const sp<IGraphicBufferProducer>& callbackProducer) = 0; diff --git a/services/camera/libcameraservice/api1/Camera2Client.cpp b/services/camera/libcameraservice/api1/Camera2Client.cpp index 46aa60c..3d9fe01 100644 --- a/services/camera/libcameraservice/api1/Camera2Client.cpp +++ b/services/camera/libcameraservice/api1/Camera2Client.cpp @@ -491,25 +491,7 @@ status_t Camera2Client::unlock() { return EBUSY; } -status_t Camera2Client::setPreviewDisplay( - const sp<Surface>& surface) { - ATRACE_CALL(); - ALOGV("%s: E", __FUNCTION__); - Mutex::Autolock icl(mBinderSerializationLock); - status_t res; - if ( (res = checkPid(__FUNCTION__) ) != OK) return res; - - sp<IBinder> binder; - sp<ANativeWindow> window; - if (surface != 0) { - binder = surface->getIGraphicBufferProducer()->asBinder(); - window = surface; - } - - return setPreviewWindowL(binder,window); -} - -status_t Camera2Client::setPreviewTexture( +status_t Camera2Client::setPreviewTarget( const sp<IGraphicBufferProducer>& bufferProducer) { ATRACE_CALL(); ALOGV("%s: E", __FUNCTION__); @@ -521,7 +503,10 @@ status_t Camera2Client::setPreviewTexture( sp<ANativeWindow> window; if (bufferProducer != 0) { binder = bufferProducer->asBinder(); - window = new Surface(bufferProducer); + // Using controlledByApp flag to ensure that the buffer queue remains in + // async mode for the old camera API, where many applications depend + // on that behavior. + window = new Surface(bufferProducer, /*controlledByApp*/ true); } return setPreviewWindowL(binder, window); } diff --git a/services/camera/libcameraservice/api1/Camera2Client.h b/services/camera/libcameraservice/api1/Camera2Client.h index ed448f3..53629a1 100644 --- a/services/camera/libcameraservice/api1/Camera2Client.h +++ b/services/camera/libcameraservice/api1/Camera2Client.h @@ -57,8 +57,7 @@ public: virtual status_t connect(const sp<ICameraClient>& client); virtual status_t lock(); virtual status_t unlock(); - virtual status_t setPreviewDisplay(const sp<Surface>& surface); - virtual status_t setPreviewTexture( + virtual status_t setPreviewTarget( const sp<IGraphicBufferProducer>& bufferProducer); virtual void setPreviewCallbackFlag(int flag); virtual status_t setPreviewCallbackTarget( diff --git a/services/camera/libcameraservice/api1/CameraClient.cpp b/services/camera/libcameraservice/api1/CameraClient.cpp index ad8856b..bd6805d 100644 --- a/services/camera/libcameraservice/api1/CameraClient.cpp +++ b/services/camera/libcameraservice/api1/CameraClient.cpp @@ -308,26 +308,20 @@ status_t CameraClient::setPreviewWindow(const sp<IBinder>& binder, return result; } -// set the Surface that the preview will use -status_t CameraClient::setPreviewDisplay(const sp<Surface>& surface) { - LOG1("setPreviewDisplay(%p) (pid %d)", surface.get(), getCallingPid()); - - sp<IBinder> binder(surface != 0 ? surface->getIGraphicBufferProducer()->asBinder() : 0); - sp<ANativeWindow> window(surface); - return setPreviewWindow(binder, window); -} - -// set the SurfaceTextureClient that the preview will use -status_t CameraClient::setPreviewTexture( +// set the buffer consumer that the preview will use +status_t CameraClient::setPreviewTarget( const sp<IGraphicBufferProducer>& bufferProducer) { - LOG1("setPreviewTexture(%p) (pid %d)", bufferProducer.get(), + LOG1("setPreviewTarget(%p) (pid %d)", bufferProducer.get(), getCallingPid()); sp<IBinder> binder; sp<ANativeWindow> window; if (bufferProducer != 0) { binder = bufferProducer->asBinder(); - window = new Surface(bufferProducer); + // Using controlledByApp flag to ensure that the buffer queue remains in + // async mode for the old camera API, where many applications depend + // on that behavior. + window = new Surface(bufferProducer, /*controlledByApp*/ true); } return setPreviewWindow(binder, window); } diff --git a/services/camera/libcameraservice/api1/CameraClient.h b/services/camera/libcameraservice/api1/CameraClient.h index abde75a..4b89564 100644 --- a/services/camera/libcameraservice/api1/CameraClient.h +++ b/services/camera/libcameraservice/api1/CameraClient.h @@ -37,8 +37,7 @@ public: virtual status_t connect(const sp<ICameraClient>& client); virtual status_t lock(); virtual status_t unlock(); - virtual status_t setPreviewDisplay(const sp<Surface>& surface); - virtual status_t setPreviewTexture(const sp<IGraphicBufferProducer>& bufferProducer); + virtual status_t setPreviewTarget(const sp<IGraphicBufferProducer>& bufferProducer); virtual void setPreviewCallbackFlag(int flag); virtual status_t setPreviewCallbackTarget( const sp<IGraphicBufferProducer>& callbackProducer); |