diff options
author | Andreas Huber <andih@google.com> | 2011-10-11 15:24:07 -0700 |
---|---|---|
committer | Andreas Huber <andih@google.com> | 2011-10-13 11:31:06 -0700 |
commit | 2bfdd428c56c7524d1a11979f200a1762866032d (patch) | |
tree | 83bb72ba82f689cc704010c06a51a9963479bab4 /media/libmediaplayerservice/nuplayer/RTSPSource.cpp | |
parent | f337772630b0a1b48d7828647d1079ebdc22919d (diff) | |
download | frameworks_av-2bfdd428c56c7524d1a11979f200a1762866032d.zip frameworks_av-2bfdd428c56c7524d1a11979f200a1762866032d.tar.gz frameworks_av-2bfdd428c56c7524d1a11979f200a1762866032d.tar.bz2 |
NuPlayer is now taking on the task of streaming over RTSP.
Change-Id: Ie204db8810807f1e7981959e34dc0149e5d9563a
Diffstat (limited to 'media/libmediaplayerservice/nuplayer/RTSPSource.cpp')
-rw-r--r-- | media/libmediaplayerservice/nuplayer/RTSPSource.cpp | 354 |
1 files changed, 354 insertions, 0 deletions
diff --git a/media/libmediaplayerservice/nuplayer/RTSPSource.cpp b/media/libmediaplayerservice/nuplayer/RTSPSource.cpp new file mode 100644 index 0000000..e72adc4 --- /dev/null +++ b/media/libmediaplayerservice/nuplayer/RTSPSource.cpp @@ -0,0 +1,354 @@ +/* + * Copyright (C) 2010 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 "RTSPSource" +#include <utils/Log.h> + +#include "RTSPSource.h" + +#include "AnotherPacketSource.h" +#include "MyHandler.h" + +#include <media/stagefright/MetaData.h> + +namespace android { + +NuPlayer::RTSPSource::RTSPSource( + const char *url, + const KeyedVector<String8, String8> *headers, + bool uidValid, + uid_t uid) + : mURL(url), + mUIDValid(uidValid), + mUID(uid), + mFlags(0), + mState(DISCONNECTED), + mFinalResult(OK), + mDisconnectReplyID(0) { + if (headers) { + mExtraHeaders = *headers; + + ssize_t index = + mExtraHeaders.indexOfKey(String8("x-hide-urls-from-log")); + + if (index >= 0) { + mFlags |= kFlagIncognito; + + mExtraHeaders.removeItemsAt(index); + } + } +} + +NuPlayer::RTSPSource::~RTSPSource() { + if (mLooper != NULL) { + mLooper->stop(); + } +} + +void NuPlayer::RTSPSource::start() { + if (mLooper == NULL) { + mLooper = new ALooper; + mLooper->setName("rtsp"); + mLooper->start(); + + mReflector = new AHandlerReflector<RTSPSource>(this); + mLooper->registerHandler(mReflector); + } + + CHECK(mHandler == 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(); +} + +void NuPlayer::RTSPSource::stop() { + sp<AMessage> msg = new AMessage(kWhatDisconnect, mReflector->id()); + + sp<AMessage> dummy; + msg->postAndAwaitResponse(&dummy); +} + +status_t NuPlayer::RTSPSource::feedMoreTSData() { + return mFinalResult; +} + +sp<MetaData> NuPlayer::RTSPSource::getFormat(bool audio) { + sp<AnotherPacketSource> source = getSource(audio); + + if (source == NULL) { + return NULL; + } + + return source->getFormat(); +} + +status_t NuPlayer::RTSPSource::dequeueAccessUnit( + bool audio, sp<ABuffer> *accessUnit) { + sp<AnotherPacketSource> source = getSource(audio); + + if (source == NULL) { + return -EWOULDBLOCK; + } + + status_t finalResult; + if (!source->hasBufferAvailable(&finalResult)) { + return finalResult == OK ? -EWOULDBLOCK : finalResult; + } + + return source->dequeueAccessUnit(accessUnit); +} + +sp<AnotherPacketSource> NuPlayer::RTSPSource::getSource(bool audio) { + return audio ? mAudioTrack : mVideoTrack; +} + +status_t NuPlayer::RTSPSource::getDuration(int64_t *durationUs) { + *durationUs = 0ll; + + int64_t audioDurationUs; + if (mAudioTrack != NULL + && mAudioTrack->getFormat()->findInt64( + kKeyDuration, &audioDurationUs) + && audioDurationUs > *durationUs) { + *durationUs = audioDurationUs; + } + + int64_t videoDurationUs; + if (mVideoTrack != NULL + && mVideoTrack->getFormat()->findInt64( + kKeyDuration, &videoDurationUs) + && videoDurationUs > *durationUs) { + *durationUs = videoDurationUs; + } + + return OK; +} + +status_t NuPlayer::RTSPSource::seekTo(int64_t seekTimeUs) { + if (mState != CONNECTED) { + return UNKNOWN_ERROR; + } + + mState = SEEKING; + mHandler->seek(seekTimeUs); + + return OK; +} + +bool NuPlayer::RTSPSource::isSeekable() { + return true; +} + +void NuPlayer::RTSPSource::onMessageReceived(const sp<AMessage> &msg) { + if (msg->what() == kWhatDisconnect) { + uint32_t replyID; + CHECK(msg->senderAwaitsResponse(&replyID)); + + mDisconnectReplyID = replyID; + finishDisconnectIfPossible(); + return; + } + + CHECK_EQ(msg->what(), (int)kWhatNotify); + + int32_t what; + CHECK(msg->findInt32("what", &what)); + + switch (what) { + case MyHandler::kWhatConnected: + onConnected(); + break; + + case MyHandler::kWhatDisconnected: + onDisconnected(msg); + break; + + case MyHandler::kWhatSeekDone: + { + mState = CONNECTED; + break; + } + + case MyHandler::kWhatAccessUnit: + { + size_t trackIndex; + CHECK(msg->findSize("trackIndex", &trackIndex)); + CHECK_LT(trackIndex, mTracks.size()); + + sp<RefBase> obj; + CHECK(msg->findObject("accessUnit", &obj)); + + sp<ABuffer> accessUnit = static_cast<ABuffer *>(obj.get()); + + int32_t damaged; + if (accessUnit->meta()->findInt32("damaged", &damaged) + && damaged) { + LOGI("dropping damaged access unit."); + break; + } + + const TrackInfo &info = mTracks.editItemAt(trackIndex); + sp<AnotherPacketSource> source = info.mSource; + if (source != NULL) { +#if 1 + uint32_t rtpTime; + CHECK(accessUnit->meta()->findInt32("rtp-time", (int32_t *)&rtpTime)); + + int64_t nptUs = + ((double)rtpTime - (double)info.mRTPTime) + / info.mTimeScale + * 1000000ll + + info.mNormalPlaytimeUs; + + accessUnit->meta()->setInt64("timeUs", nptUs); +#endif + + source->queueAccessUnit(accessUnit); + } + break; + } + + case MyHandler::kWhatEOS: + { + size_t trackIndex; + CHECK(msg->findSize("trackIndex", &trackIndex)); + CHECK_LT(trackIndex, mTracks.size()); + + int32_t finalResult; + CHECK(msg->findInt32("finalResult", &finalResult)); + CHECK_NE(finalResult, (status_t)OK); + + TrackInfo *info = &mTracks.editItemAt(trackIndex); + sp<AnotherPacketSource> source = info->mSource; + if (source != NULL) { + source->signalEOS(finalResult); + } + + break; + } + + case MyHandler::kWhatSeekDiscontinuity: + { + size_t trackIndex; + CHECK(msg->findSize("trackIndex", &trackIndex)); + CHECK_LT(trackIndex, mTracks.size()); + + TrackInfo *info = &mTracks.editItemAt(trackIndex); + sp<AnotherPacketSource> source = info->mSource; + if (source != NULL) { + source->queueDiscontinuity(ATSParser::DISCONTINUITY_SEEK, NULL); + } + + break; + } + + case MyHandler::kWhatNormalPlayTimeMapping: + { + size_t trackIndex; + CHECK(msg->findSize("trackIndex", &trackIndex)); + CHECK_LT(trackIndex, mTracks.size()); + + uint32_t rtpTime; + CHECK(msg->findInt32("rtpTime", (int32_t *)&rtpTime)); + + int64_t nptUs; + CHECK(msg->findInt64("nptUs", &nptUs)); + + TrackInfo *info = &mTracks.editItemAt(trackIndex); + info->mRTPTime = rtpTime; + info->mNormalPlaytimeUs = nptUs; + break; + } + + default: + TRESPASS(); + } +} + +void NuPlayer::RTSPSource::onConnected() { + CHECK(mAudioTrack == NULL); + CHECK(mVideoTrack == NULL); + + size_t numTracks = mHandler->countTracks(); + for (size_t i = 0; i < numTracks; ++i) { + int32_t timeScale; + sp<MetaData> format = mHandler->getTrackFormat(i, &timeScale); + + const char *mime; + CHECK(format->findCString(kKeyMIMEType, &mime)); + + bool isAudio = !strncasecmp(mime, "audio/", 6); + bool isVideo = !strncasecmp(mime, "video/", 6); + + TrackInfo info; + info.mTimeScale = timeScale; + info.mRTPTime = 0; + info.mNormalPlaytimeUs = 0ll; + + if ((isAudio && mAudioTrack == NULL) + || (isVideo && mVideoTrack == NULL)) { + sp<AnotherPacketSource> source = new AnotherPacketSource(format); + + if (isAudio) { + mAudioTrack = source; + } else { + mVideoTrack = source; + } + + info.mSource = source; + } + + mTracks.push(info); + } + + mState = CONNECTED; +} + +void NuPlayer::RTSPSource::onDisconnected(const sp<AMessage> &msg) { + status_t err; + CHECK(msg->findInt32("result", &err)); + CHECK_NE(err, (status_t)OK); + + mLooper->unregisterHandler(mHandler->id()); + mHandler.clear(); + + mState = DISCONNECTED; + mFinalResult = err; + + if (mDisconnectReplyID != 0) { + finishDisconnectIfPossible(); + } +} + +void NuPlayer::RTSPSource::finishDisconnectIfPossible() { + if (mState != DISCONNECTED) { + mHandler->disconnect(); + return; + } + + (new AMessage)->postReply(mDisconnectReplyID); + mDisconnectReplyID = 0; +} + +} // namespace android |