diff options
-rw-r--r-- | media/libmediaplayerservice/MediaPlayerFactory.cpp | 4 | ||||
-rw-r--r-- | media/libmediaplayerservice/nuplayer/NuPlayer.cpp | 6 | ||||
-rw-r--r-- | media/libmediaplayerservice/nuplayer/RTSPSource.cpp | 74 | ||||
-rw-r--r-- | media/libmediaplayerservice/nuplayer/RTSPSource.h | 7 | ||||
-rw-r--r-- | media/libstagefright/include/SDPLoader.h | 70 | ||||
-rw-r--r-- | media/libstagefright/rtsp/Android.mk | 1 | ||||
-rw-r--r-- | media/libstagefright/rtsp/MyHandler.h | 53 | ||||
-rw-r--r-- | media/libstagefright/rtsp/SDPLoader.cpp | 154 |
8 files changed, 362 insertions, 7 deletions
diff --git a/media/libmediaplayerservice/MediaPlayerFactory.cpp b/media/libmediaplayerservice/MediaPlayerFactory.cpp index 3f69c11..bb441cc 100644 --- a/media/libmediaplayerservice/MediaPlayerFactory.cpp +++ b/media/libmediaplayerservice/MediaPlayerFactory.cpp @@ -215,6 +215,10 @@ class NuPlayerFactory : public MediaPlayerFactory::IFactory { if (strstr(url,"m3u8")) { return kOurScore; } + + if ((len >= 4 && !strcasecmp(".sdp", &url[len - 4])) || strstr(url, ".sdp?")) { + return kOurScore; + } } if (!strncasecmp("rtsp://", url, 7)) { diff --git a/media/libmediaplayerservice/nuplayer/NuPlayer.cpp b/media/libmediaplayerservice/nuplayer/NuPlayer.cpp index 9585aba..0736fbe 100644 --- a/media/libmediaplayerservice/nuplayer/NuPlayer.cpp +++ b/media/libmediaplayerservice/nuplayer/NuPlayer.cpp @@ -177,6 +177,7 @@ static bool IsHTTPLiveURL(const char *url) { void NuPlayer::setDataSource( const char *url, const KeyedVector<String8, String8> *headers) { sp<AMessage> msg = new AMessage(kWhatSetDataSource, id()); + size_t len = strlen(url); sp<AMessage> notify = new AMessage(kWhatSourceNotify, id()); @@ -185,6 +186,11 @@ void NuPlayer::setDataSource( source = new HTTPLiveSource(notify, url, headers, mUIDValid, mUID); } else if (!strncasecmp(url, "rtsp://", 7)) { source = new RTSPSource(notify, url, headers, mUIDValid, mUID); + } else if ((!strncasecmp(url, "http://", 7) + || !strncasecmp(url, "https://", 8)) + && ((len >= 4 && !strcasecmp(".sdp", &url[len - 4])) + || strstr(url, ".sdp?"))) { + source = new RTSPSource(notify, url, headers, mUIDValid, mUID, true); } else { source = new GenericSource(notify, url, headers, mUIDValid, mUID); } diff --git a/media/libmediaplayerservice/nuplayer/RTSPSource.cpp b/media/libmediaplayerservice/nuplayer/RTSPSource.cpp index e402115..3035589 100644 --- a/media/libmediaplayerservice/nuplayer/RTSPSource.cpp +++ b/media/libmediaplayerservice/nuplayer/RTSPSource.cpp @@ -22,6 +22,7 @@ #include "AnotherPacketSource.h" #include "MyHandler.h" +#include "SDPLoader.h" #include <media/stagefright/MediaDefs.h> #include <media/stagefright/MetaData.h> @@ -33,12 +34,14 @@ NuPlayer::RTSPSource::RTSPSource( const char *url, const KeyedVector<String8, String8> *headers, bool uidValid, - uid_t uid) + uid_t uid, + bool isSDP) : Source(notify), mURL(url), mUIDValid(uidValid), mUID(uid), mFlags(0), + mIsSDP(isSDP), mState(DISCONNECTED), mFinalResult(OK), mDisconnectReplyID(0), @@ -73,16 +76,25 @@ void NuPlayer::RTSPSource::start() { } CHECK(mHandler == NULL); + CHECK(mSDPLoader == NULL); sp<AMessage> notify = new AMessage(kWhatNotify, mReflector->id()); - mHandler = new MyHandler(mURL.c_str(), notify, mUIDValid, mUID); - mLooper->registerHandler(mHandler); - CHECK_EQ(mState, (int)DISCONNECTED); mState = CONNECTING; - mHandler->connect(); + if (mIsSDP) { + mSDPLoader = new SDPLoader(notify, + (mFlags & kFlagIncognito) ? SDPLoader::kFlagIncognito : 0, + mUIDValid, mUID); + + mSDPLoader->load(mURL.c_str(), mExtraHeaders.isEmpty() ? NULL : &mExtraHeaders); + } else { + mHandler = new MyHandler(mURL.c_str(), notify, mUIDValid, mUID); + mLooper->registerHandler(mHandler); + + mHandler->connect(); + } } void NuPlayer::RTSPSource::stop() { @@ -408,6 +420,12 @@ void NuPlayer::RTSPSource::onMessageReceived(const sp<AMessage> &msg) { break; } + case SDPLoader::kWhatSDPLoaded: + { + onSDPLoaded(msg); + break; + } + default: TRESPASS(); } @@ -461,6 +479,46 @@ void NuPlayer::RTSPSource::onConnected() { mState = CONNECTED; } +void NuPlayer::RTSPSource::onSDPLoaded(const sp<AMessage> &msg) { + status_t err; + CHECK(msg->findInt32("result", &err)); + + mSDPLoader.clear(); + + if (mDisconnectReplyID != 0) { + err = UNKNOWN_ERROR; + } + + if (err == OK) { + sp<ASessionDescription> desc; + sp<RefBase> obj; + CHECK(msg->findObject("description", &obj)); + desc = static_cast<ASessionDescription *>(obj.get()); + + AString rtspUri; + if (!desc->findAttribute(0, "a=control", &rtspUri)) { + ALOGE("Unable to find url in SDP"); + err = UNKNOWN_ERROR; + } else { + sp<AMessage> notify = new AMessage(kWhatNotify, mReflector->id()); + + mHandler = new MyHandler(rtspUri.c_str(), notify, mUIDValid, mUID); + mLooper->registerHandler(mHandler); + + mHandler->loadSDP(desc); + } + } + + if (err != OK) { + mState = DISCONNECTED; + mFinalResult = err; + + if (mDisconnectReplyID != 0) { + finishDisconnectIfPossible(); + } + } +} + void NuPlayer::RTSPSource::onDisconnected(const sp<AMessage> &msg) { status_t err; CHECK(msg->findInt32("result", &err)); @@ -479,7 +537,11 @@ void NuPlayer::RTSPSource::onDisconnected(const sp<AMessage> &msg) { void NuPlayer::RTSPSource::finishDisconnectIfPossible() { if (mState != DISCONNECTED) { - mHandler->disconnect(); + if (mHandler != NULL) { + mHandler->disconnect(); + } else if (mSDPLoader != NULL) { + mSDPLoader->cancel(); + } return; } diff --git a/media/libmediaplayerservice/nuplayer/RTSPSource.h b/media/libmediaplayerservice/nuplayer/RTSPSource.h index 033b3e8..b2a7dae 100644 --- a/media/libmediaplayerservice/nuplayer/RTSPSource.h +++ b/media/libmediaplayerservice/nuplayer/RTSPSource.h @@ -29,6 +29,7 @@ namespace android { struct ALooper; struct AnotherPacketSource; struct MyHandler; +struct SDPLoader; struct NuPlayer::RTSPSource : public NuPlayer::Source { RTSPSource( @@ -36,7 +37,8 @@ struct NuPlayer::RTSPSource : public NuPlayer::Source { const char *url, const KeyedVector<String8, String8> *headers, bool uidValid = false, - uid_t uid = 0); + uid_t uid = 0, + bool isSDP = false); virtual void start(); virtual void stop(); @@ -90,6 +92,7 @@ private: bool mUIDValid; uid_t mUID; uint32_t mFlags; + bool mIsSDP; State mState; status_t mFinalResult; uint32_t mDisconnectReplyID; @@ -98,6 +101,7 @@ private: sp<ALooper> mLooper; sp<AHandlerReflector<RTSPSource> > mReflector; sp<MyHandler> mHandler; + sp<SDPLoader> mSDPLoader; Vector<TrackInfo> mTracks; sp<AnotherPacketSource> mAudioTrack; @@ -110,6 +114,7 @@ private: sp<AnotherPacketSource> getSource(bool audio); void onConnected(); + void onSDPLoaded(const sp<AMessage> &msg); void onDisconnected(const sp<AMessage> &msg); void finishDisconnectIfPossible(); diff --git a/media/libstagefright/include/SDPLoader.h b/media/libstagefright/include/SDPLoader.h new file mode 100644 index 0000000..ca59dc0 --- /dev/null +++ b/media/libstagefright/include/SDPLoader.h @@ -0,0 +1,70 @@ +/* + * Copyright (C) 2012 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef SDP_LOADER_H_ + +#define SDP_LOADER_H_ + +#include <media/stagefright/foundation/AMessage.h> +#include <media/stagefright/foundation/AHandler.h> +#include <utils/String8.h> + +namespace android { + +struct HTTPBase; + +struct SDPLoader : public AHandler { + enum Flags { + // Don't log any URLs. + kFlagIncognito = 1, + }; + enum { + kWhatSDPLoaded = 'sdpl' + }; + SDPLoader(const sp<AMessage> ¬ify, uint32_t flags = 0, bool uidValid = false, uid_t uid = 0); + + void load(const char* url, const KeyedVector<String8, String8> *headers); + + void cancel(); + +protected: + virtual ~SDPLoader() {} + + virtual void onMessageReceived(const sp<AMessage> &msg); + +private: + enum { + kWhatLoad = 'load', + }; + + void onLoad(const sp<AMessage> &msg); + + sp<AMessage> mNotify; + const char* mUrl; + uint32_t mFlags; + bool mUIDValid; + uid_t mUID; + sp<ALooper> mNetLooper; + bool mCancelled; + + sp<HTTPBase> mHTTPDataSource; + + DISALLOW_EVIL_CONSTRUCTORS(SDPLoader); +}; + +} // namespace android + +#endif // SDP_LOADER_H_ diff --git a/media/libstagefright/rtsp/Android.mk b/media/libstagefright/rtsp/Android.mk index 49e2daf..9e2724d 100644 --- a/media/libstagefright/rtsp/Android.mk +++ b/media/libstagefright/rtsp/Android.mk @@ -17,6 +17,7 @@ LOCAL_SRC_FILES:= \ ARTPWriter.cpp \ ARTSPConnection.cpp \ ASessionDescription.cpp \ + SDPLoader.cpp \ LOCAL_C_INCLUDES:= \ $(TOP)/frameworks/av/media/libstagefright/include \ diff --git a/media/libstagefright/rtsp/MyHandler.h b/media/libstagefright/rtsp/MyHandler.h index 96c7683..b7183b1 100644 --- a/media/libstagefright/rtsp/MyHandler.h +++ b/media/libstagefright/rtsp/MyHandler.h @@ -173,6 +173,18 @@ struct MyHandler : public AHandler { mConn->connect(mOriginalSessionURL.c_str(), reply); } + void loadSDP(const sp<ASessionDescription>& desc) { + looper()->registerHandler(mConn); + (1 ? mNetLooper : looper())->registerHandler(mRTPConn); + + sp<AMessage> notify = new AMessage('biny', id()); + mConn->observeBinaryData(notify); + + sp<AMessage> reply = new AMessage('sdpl', id()); + reply->setObject("description", desc); + mConn->connect(mOriginalSessionURL.c_str(), reply); + } + void disconnect() { (new AMessage('abor', id()))->post(); } @@ -486,6 +498,47 @@ struct MyHandler : public AHandler { break; } + case 'sdpl': + { + int32_t result; + CHECK(msg->findInt32("result", &result)); + + ALOGI("SDP connection request completed with result %d (%s)", + result, strerror(-result)); + + if (result == OK) { + sp<RefBase> obj; + CHECK(msg->findObject("description", &obj)); + mSessionDesc = + static_cast<ASessionDescription *>(obj.get()); + + if (!mSessionDesc->isValid()) { + ALOGE("Failed to parse session description."); + result = ERROR_MALFORMED; + } else { + mBaseURL = mSessionURL; + + if (mSessionDesc->countTracks() < 2) { + // There's no actual tracks in this session. + // The first "track" is merely session meta + // data. + + ALOGW("Session doesn't contain any playable " + "tracks. Aborting."); + result = ERROR_UNSUPPORTED; + } else { + setupTrack(1); + } + } + } + + if (result != OK) { + sp<AMessage> reply = new AMessage('disc', id()); + mConn->disconnect(reply); + } + break; + } + case 'setu': { size_t index; diff --git a/media/libstagefright/rtsp/SDPLoader.cpp b/media/libstagefright/rtsp/SDPLoader.cpp new file mode 100644 index 0000000..ed3fa7e --- /dev/null +++ b/media/libstagefright/rtsp/SDPLoader.cpp @@ -0,0 +1,154 @@ +/* + * Copyright (C) 2012 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +//#define LOG_NDEBUG 0 +#define LOG_TAG "SDPLoader" +#include <utils/Log.h> + +#include "SDPLoader.h" + +#include "ASessionDescription.h" +#include "HTTPBase.h" + +#include <media/stagefright/foundation/ABuffer.h> +#include <media/stagefright/foundation/ADebug.h> + +#define DEFAULT_SDP_SIZE 100000 + +namespace android { + +SDPLoader::SDPLoader(const sp<AMessage> ¬ify, uint32_t flags, bool uidValid, uid_t uid) + : mNotify(notify), + mFlags(flags), + mUIDValid(uidValid), + mUID(uid), + mNetLooper(new ALooper), + mCancelled(false), + mHTTPDataSource( + HTTPBase::Create( + (mFlags & kFlagIncognito) + ? HTTPBase::kFlagIncognito + : 0)) { + if (mUIDValid) { + mHTTPDataSource->setUID(mUID); + } + + mNetLooper->setName("sdp net"); + mNetLooper->start(false /* runOnCallingThread */, + false /* canCallJava */, + PRIORITY_HIGHEST); +} + +void SDPLoader::load(const char *url, const KeyedVector<String8, String8> *headers) { + mNetLooper->registerHandler(this); + + sp<AMessage> msg = new AMessage(kWhatLoad, id()); + msg->setString("url", url); + + if (headers != NULL) { + msg->setPointer( + "headers", + new KeyedVector<String8, String8>(*headers)); + } + + msg->post(); +} + +void SDPLoader::cancel() { + mCancelled = true; + sp<HTTPBase> HTTPDataSource = mHTTPDataSource; + HTTPDataSource->disconnect(); +} + +void SDPLoader::onMessageReceived(const sp<AMessage> &msg) { + switch (msg->what()) { + case kWhatLoad: + onLoad(msg); + break; + + default: + TRESPASS(); + break; + } +} + +void SDPLoader::onLoad(const sp<AMessage> &msg) { + status_t err = OK; + sp<ASessionDescription> desc = NULL; + AString url; + CHECK(msg->findString("url", &url)); + + KeyedVector<String8, String8> *headers = NULL; + msg->findPointer("headers", (void **)&headers); + + if (!(mFlags & kFlagIncognito)) { + ALOGI("onLoad '%s'", url.c_str()); + } else { + ALOGI("onLoad <URL suppressed>"); + } + + if (!mCancelled) { + err = mHTTPDataSource->connect(url.c_str(), headers); + + if (err != OK) { + ALOGE("connect() returned %d", err); + } + } + + if (headers != NULL) { + delete headers; + headers = NULL; + } + + off64_t sdpSize; + if (err == OK && !mCancelled) { + err = mHTTPDataSource->getSize(&sdpSize); + + if (err != OK) { + //We did not get the size of the sdp file, default to a large value + sdpSize = DEFAULT_SDP_SIZE; + err = OK; + } + } + + sp<ABuffer> buffer = new ABuffer(sdpSize); + + if (err == OK && !mCancelled) { + ssize_t readSize = mHTTPDataSource->readAt(0, buffer->data(), sdpSize); + + if (readSize < 0) { + ALOGE("Failed to read SDP, error code = %ld", readSize); + err = UNKNOWN_ERROR; + } else { + desc = new ASessionDescription; + + if (desc == NULL || !desc->setTo(buffer->data(), (size_t)readSize)) { + err = UNKNOWN_ERROR; + ALOGE("Failed to parse SDP"); + } + } + } + + mHTTPDataSource.clear(); + + sp<AMessage> notify = mNotify->dup(); + notify->setInt32("what", kWhatSDPLoaded); + notify->setInt32("result", err); + notify->setObject("description", desc); + notify->post(); +} + +} // namespace android |