RTSPSource.cpp revision 1906e5c7492b9cbc88601365536a69e9a490c963
1/* 2 * Copyright (C) 2010 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17//#define LOG_NDEBUG 0 18#define LOG_TAG "RTSPSource" 19#include <utils/Log.h> 20 21#include "RTSPSource.h" 22 23#include "AnotherPacketSource.h" 24#include "MyHandler.h" 25 26#include <media/stagefright/MetaData.h> 27 28namespace android { 29 30NuPlayer::RTSPSource::RTSPSource( 31 const char *url, 32 const KeyedVector<String8, String8> *headers, 33 bool uidValid, 34 uid_t uid) 35 : mURL(url), 36 mUIDValid(uidValid), 37 mUID(uid), 38 mFlags(0), 39 mState(DISCONNECTED), 40 mFinalResult(OK), 41 mDisconnectReplyID(0) { 42 if (headers) { 43 mExtraHeaders = *headers; 44 45 ssize_t index = 46 mExtraHeaders.indexOfKey(String8("x-hide-urls-from-log")); 47 48 if (index >= 0) { 49 mFlags |= kFlagIncognito; 50 51 mExtraHeaders.removeItemsAt(index); 52 } 53 } 54} 55 56NuPlayer::RTSPSource::~RTSPSource() { 57 if (mLooper != NULL) { 58 mLooper->stop(); 59 } 60} 61 62void NuPlayer::RTSPSource::start() { 63 if (mLooper == NULL) { 64 mLooper = new ALooper; 65 mLooper->setName("rtsp"); 66 mLooper->start(); 67 68 mReflector = new AHandlerReflector<RTSPSource>(this); 69 mLooper->registerHandler(mReflector); 70 } 71 72 CHECK(mHandler == NULL); 73 74 sp<AMessage> notify = new AMessage(kWhatNotify, mReflector->id()); 75 76 mHandler = new MyHandler(mURL.c_str(), notify, mUIDValid, mUID); 77 mLooper->registerHandler(mHandler); 78 79 CHECK_EQ(mState, (int)DISCONNECTED); 80 mState = CONNECTING; 81 82 mHandler->connect(); 83} 84 85void NuPlayer::RTSPSource::stop() { 86 sp<AMessage> msg = new AMessage(kWhatDisconnect, mReflector->id()); 87 88 sp<AMessage> dummy; 89 msg->postAndAwaitResponse(&dummy); 90} 91 92status_t NuPlayer::RTSPSource::feedMoreTSData() { 93 return mFinalResult; 94} 95 96sp<MetaData> NuPlayer::RTSPSource::getFormat(bool audio) { 97 sp<AnotherPacketSource> source = getSource(audio); 98 99 if (source == NULL) { 100 return NULL; 101 } 102 103 return source->getFormat(); 104} 105 106status_t NuPlayer::RTSPSource::dequeueAccessUnit( 107 bool audio, sp<ABuffer> *accessUnit) { 108 sp<AnotherPacketSource> source = getSource(audio); 109 110 if (source == NULL) { 111 return -EWOULDBLOCK; 112 } 113 114 status_t finalResult; 115 if (!source->hasBufferAvailable(&finalResult)) { 116 return finalResult == OK ? -EWOULDBLOCK : finalResult; 117 } 118 119 return source->dequeueAccessUnit(accessUnit); 120} 121 122sp<AnotherPacketSource> NuPlayer::RTSPSource::getSource(bool audio) { 123 return audio ? mAudioTrack : mVideoTrack; 124} 125 126status_t NuPlayer::RTSPSource::getDuration(int64_t *durationUs) { 127 *durationUs = 0ll; 128 129 int64_t audioDurationUs; 130 if (mAudioTrack != NULL 131 && mAudioTrack->getFormat()->findInt64( 132 kKeyDuration, &audioDurationUs) 133 && audioDurationUs > *durationUs) { 134 *durationUs = audioDurationUs; 135 } 136 137 int64_t videoDurationUs; 138 if (mVideoTrack != NULL 139 && mVideoTrack->getFormat()->findInt64( 140 kKeyDuration, &videoDurationUs) 141 && videoDurationUs > *durationUs) { 142 *durationUs = videoDurationUs; 143 } 144 145 return OK; 146} 147 148status_t NuPlayer::RTSPSource::seekTo(int64_t seekTimeUs) { 149 if (mState != CONNECTED) { 150 return UNKNOWN_ERROR; 151 } 152 153 mState = SEEKING; 154 mHandler->seek(seekTimeUs); 155 156 return OK; 157} 158 159bool NuPlayer::RTSPSource::isSeekable() { 160 return true; 161} 162 163void NuPlayer::RTSPSource::onMessageReceived(const sp<AMessage> &msg) { 164 if (msg->what() == kWhatDisconnect) { 165 uint32_t replyID; 166 CHECK(msg->senderAwaitsResponse(&replyID)); 167 168 mDisconnectReplyID = replyID; 169 finishDisconnectIfPossible(); 170 return; 171 } 172 173 CHECK_EQ(msg->what(), (int)kWhatNotify); 174 175 int32_t what; 176 CHECK(msg->findInt32("what", &what)); 177 178 switch (what) { 179 case MyHandler::kWhatConnected: 180 onConnected(); 181 break; 182 183 case MyHandler::kWhatDisconnected: 184 onDisconnected(msg); 185 break; 186 187 case MyHandler::kWhatSeekDone: 188 { 189 mState = CONNECTED; 190 break; 191 } 192 193 case MyHandler::kWhatAccessUnit: 194 { 195 size_t trackIndex; 196 CHECK(msg->findSize("trackIndex", &trackIndex)); 197 CHECK_LT(trackIndex, mTracks.size()); 198 199 sp<RefBase> obj; 200 CHECK(msg->findObject("accessUnit", &obj)); 201 202 sp<ABuffer> accessUnit = static_cast<ABuffer *>(obj.get()); 203 204 int32_t damaged; 205 if (accessUnit->meta()->findInt32("damaged", &damaged) 206 && damaged) { 207 LOGI("dropping damaged access unit."); 208 break; 209 } 210 211 TrackInfo *info = &mTracks.editItemAt(trackIndex); 212 213 sp<AnotherPacketSource> source = info->mSource; 214 if (source != NULL) { 215 uint32_t rtpTime; 216 CHECK(accessUnit->meta()->findInt32("rtp-time", (int32_t *)&rtpTime)); 217 218 if (!info->mNPTMappingValid) { 219 // This is a live stream, we didn't receive any normal 220 // playtime mapping. Assume the first packets correspond 221 // to time 0. 222 223 LOGV("This is a live stream, assuming time = 0"); 224 225 info->mRTPTime = rtpTime; 226 info->mNormalPlaytimeUs = 0ll; 227 info->mNPTMappingValid = true; 228 } 229 230 int64_t nptUs = 231 ((double)rtpTime - (double)info->mRTPTime) 232 / info->mTimeScale 233 * 1000000ll 234 + info->mNormalPlaytimeUs; 235 236 accessUnit->meta()->setInt64("timeUs", nptUs); 237 238 source->queueAccessUnit(accessUnit); 239 } 240 break; 241 } 242 243 case MyHandler::kWhatEOS: 244 { 245 size_t trackIndex; 246 CHECK(msg->findSize("trackIndex", &trackIndex)); 247 CHECK_LT(trackIndex, mTracks.size()); 248 249 int32_t finalResult; 250 CHECK(msg->findInt32("finalResult", &finalResult)); 251 CHECK_NE(finalResult, (status_t)OK); 252 253 TrackInfo *info = &mTracks.editItemAt(trackIndex); 254 sp<AnotherPacketSource> source = info->mSource; 255 if (source != NULL) { 256 source->signalEOS(finalResult); 257 } 258 259 break; 260 } 261 262 case MyHandler::kWhatSeekDiscontinuity: 263 { 264 size_t trackIndex; 265 CHECK(msg->findSize("trackIndex", &trackIndex)); 266 CHECK_LT(trackIndex, mTracks.size()); 267 268 TrackInfo *info = &mTracks.editItemAt(trackIndex); 269 sp<AnotherPacketSource> source = info->mSource; 270 if (source != NULL) { 271 source->queueDiscontinuity(ATSParser::DISCONTINUITY_SEEK, NULL); 272 } 273 274 break; 275 } 276 277 case MyHandler::kWhatNormalPlayTimeMapping: 278 { 279 size_t trackIndex; 280 CHECK(msg->findSize("trackIndex", &trackIndex)); 281 CHECK_LT(trackIndex, mTracks.size()); 282 283 uint32_t rtpTime; 284 CHECK(msg->findInt32("rtpTime", (int32_t *)&rtpTime)); 285 286 int64_t nptUs; 287 CHECK(msg->findInt64("nptUs", &nptUs)); 288 289 TrackInfo *info = &mTracks.editItemAt(trackIndex); 290 info->mRTPTime = rtpTime; 291 info->mNormalPlaytimeUs = nptUs; 292 info->mNPTMappingValid = true; 293 break; 294 } 295 296 default: 297 TRESPASS(); 298 } 299} 300 301void NuPlayer::RTSPSource::onConnected() { 302 CHECK(mAudioTrack == NULL); 303 CHECK(mVideoTrack == NULL); 304 305 size_t numTracks = mHandler->countTracks(); 306 for (size_t i = 0; i < numTracks; ++i) { 307 int32_t timeScale; 308 sp<MetaData> format = mHandler->getTrackFormat(i, &timeScale); 309 310 const char *mime; 311 CHECK(format->findCString(kKeyMIMEType, &mime)); 312 313 bool isAudio = !strncasecmp(mime, "audio/", 6); 314 bool isVideo = !strncasecmp(mime, "video/", 6); 315 316 TrackInfo info; 317 info.mTimeScale = timeScale; 318 info.mRTPTime = 0; 319 info.mNormalPlaytimeUs = 0ll; 320 info.mNPTMappingValid = false; 321 322 if ((isAudio && mAudioTrack == NULL) 323 || (isVideo && mVideoTrack == NULL)) { 324 sp<AnotherPacketSource> source = new AnotherPacketSource(format); 325 326 if (isAudio) { 327 mAudioTrack = source; 328 } else { 329 mVideoTrack = source; 330 } 331 332 info.mSource = source; 333 } 334 335 mTracks.push(info); 336 } 337 338 mState = CONNECTED; 339} 340 341void NuPlayer::RTSPSource::onDisconnected(const sp<AMessage> &msg) { 342 status_t err; 343 CHECK(msg->findInt32("result", &err)); 344 CHECK_NE(err, (status_t)OK); 345 346 mLooper->unregisterHandler(mHandler->id()); 347 mHandler.clear(); 348 349 mState = DISCONNECTED; 350 mFinalResult = err; 351 352 if (mDisconnectReplyID != 0) { 353 finishDisconnectIfPossible(); 354 } 355} 356 357void NuPlayer::RTSPSource::finishDisconnectIfPossible() { 358 if (mState != DISCONNECTED) { 359 mHandler->disconnect(); 360 return; 361 } 362 363 (new AMessage)->postReply(mDisconnectReplyID); 364 mDisconnectReplyID = 0; 365} 366 367} // namespace android 368