RTSPSource.cpp revision 57cea553cb19235553463412db5ad04c99835411
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#include "SDPLoader.h" 26 27#include <media/stagefright/MediaDefs.h> 28#include <media/stagefright/MetaData.h> 29 30namespace android { 31 32NuPlayer::RTSPSource::RTSPSource( 33 const sp<AMessage> ¬ify, 34 const char *url, 35 const KeyedVector<String8, String8> *headers, 36 bool uidValid, 37 uid_t uid, 38 bool isSDP) 39 : Source(notify), 40 mURL(url), 41 mUIDValid(uidValid), 42 mUID(uid), 43 mFlags(0), 44 mIsSDP(isSDP), 45 mState(DISCONNECTED), 46 mFinalResult(OK), 47 mDisconnectReplyID(0), 48 mStartingUp(true), 49 mSeekGeneration(0) { 50 if (headers) { 51 mExtraHeaders = *headers; 52 53 ssize_t index = 54 mExtraHeaders.indexOfKey(String8("x-hide-urls-from-log")); 55 56 if (index >= 0) { 57 mFlags |= kFlagIncognito; 58 59 mExtraHeaders.removeItemsAt(index); 60 } 61 } 62} 63 64NuPlayer::RTSPSource::~RTSPSource() { 65 mLooper->stop(); 66} 67 68void NuPlayer::RTSPSource::prepareAsync() { 69 if (mLooper == NULL) { 70 mLooper = new ALooper; 71 mLooper->setName("rtsp"); 72 mLooper->start(); 73 74 mReflector = new AHandlerReflector<RTSPSource>(this); 75 mLooper->registerHandler(mReflector); 76 } 77 78 CHECK(mHandler == NULL); 79 CHECK(mSDPLoader == NULL); 80 81 sp<AMessage> notify = new AMessage(kWhatNotify, mReflector->id()); 82 83 CHECK_EQ(mState, (int)DISCONNECTED); 84 mState = CONNECTING; 85 86 if (mIsSDP) { 87 mSDPLoader = new SDPLoader(notify, 88 (mFlags & kFlagIncognito) ? SDPLoader::kFlagIncognito : 0, 89 mUIDValid, mUID); 90 91 mSDPLoader->load( 92 mURL.c_str(), mExtraHeaders.isEmpty() ? NULL : &mExtraHeaders); 93 } else { 94 mHandler = new MyHandler(mURL.c_str(), notify, mUIDValid, mUID); 95 mLooper->registerHandler(mHandler); 96 97 mHandler->connect(); 98 } 99 100 notifyVideoSizeChanged(0, 0); 101 102 notifyFlagsChanged( 103 FLAG_CAN_PAUSE 104 | FLAG_CAN_SEEK_BACKWARD 105 | FLAG_CAN_SEEK_FORWARD 106 | FLAG_CAN_SEEK); 107 108 notifyPrepared(); 109} 110 111void NuPlayer::RTSPSource::start() { 112} 113 114void NuPlayer::RTSPSource::stop() { 115 if (mLooper == NULL) { 116 return; 117 } 118 sp<AMessage> msg = new AMessage(kWhatDisconnect, mReflector->id()); 119 120 sp<AMessage> dummy; 121 msg->postAndAwaitResponse(&dummy); 122} 123 124status_t NuPlayer::RTSPSource::feedMoreTSData() { 125 return mFinalResult; 126} 127 128sp<MetaData> NuPlayer::RTSPSource::getFormatMeta(bool audio) { 129 sp<AnotherPacketSource> source = getSource(audio); 130 131 if (source == NULL) { 132 return NULL; 133 } 134 135 return source->getFormat(); 136} 137 138bool NuPlayer::RTSPSource::haveSufficientDataOnAllTracks() { 139 // We're going to buffer at least 2 secs worth data on all tracks before 140 // starting playback (both at startup and after a seek). 141 142 static const int64_t kMinDurationUs = 2000000ll; 143 144 status_t err; 145 int64_t durationUs; 146 if (mAudioTrack != NULL 147 && (durationUs = mAudioTrack->getBufferedDurationUs(&err)) 148 < kMinDurationUs 149 && err == OK) { 150 ALOGV("audio track doesn't have enough data yet. (%.2f secs buffered)", 151 durationUs / 1E6); 152 return false; 153 } 154 155 if (mVideoTrack != NULL 156 && (durationUs = mVideoTrack->getBufferedDurationUs(&err)) 157 < kMinDurationUs 158 && err == OK) { 159 ALOGV("video track doesn't have enough data yet. (%.2f secs buffered)", 160 durationUs / 1E6); 161 return false; 162 } 163 164 return true; 165} 166 167status_t NuPlayer::RTSPSource::dequeueAccessUnit( 168 bool audio, sp<ABuffer> *accessUnit) { 169 if (mStartingUp) { 170 if (!haveSufficientDataOnAllTracks()) { 171 return -EWOULDBLOCK; 172 } 173 174 mStartingUp = false; 175 } 176 177 sp<AnotherPacketSource> source = getSource(audio); 178 179 if (source == NULL) { 180 return -EWOULDBLOCK; 181 } 182 183 status_t finalResult; 184 if (!source->hasBufferAvailable(&finalResult)) { 185 return finalResult == OK ? -EWOULDBLOCK : finalResult; 186 } 187 188 return source->dequeueAccessUnit(accessUnit); 189} 190 191sp<AnotherPacketSource> NuPlayer::RTSPSource::getSource(bool audio) { 192 if (mTSParser != NULL) { 193 sp<MediaSource> source = mTSParser->getSource( 194 audio ? ATSParser::AUDIO : ATSParser::VIDEO); 195 196 return static_cast<AnotherPacketSource *>(source.get()); 197 } 198 199 return audio ? mAudioTrack : mVideoTrack; 200} 201 202status_t NuPlayer::RTSPSource::getDuration(int64_t *durationUs) { 203 *durationUs = 0ll; 204 205 int64_t audioDurationUs; 206 if (mAudioTrack != NULL 207 && mAudioTrack->getFormat()->findInt64( 208 kKeyDuration, &audioDurationUs) 209 && audioDurationUs > *durationUs) { 210 *durationUs = audioDurationUs; 211 } 212 213 int64_t videoDurationUs; 214 if (mVideoTrack != NULL 215 && mVideoTrack->getFormat()->findInt64( 216 kKeyDuration, &videoDurationUs) 217 && videoDurationUs > *durationUs) { 218 *durationUs = videoDurationUs; 219 } 220 221 return OK; 222} 223 224status_t NuPlayer::RTSPSource::seekTo(int64_t seekTimeUs) { 225 sp<AMessage> msg = new AMessage(kWhatPerformSeek, mReflector->id()); 226 msg->setInt32("generation", ++mSeekGeneration); 227 msg->setInt64("timeUs", seekTimeUs); 228 msg->post(200000ll); 229 230 return OK; 231} 232 233void NuPlayer::RTSPSource::performSeek(int64_t seekTimeUs) { 234 if (mState != CONNECTED) { 235 return; 236 } 237 238 mState = SEEKING; 239 mHandler->seek(seekTimeUs); 240} 241 242void NuPlayer::RTSPSource::onMessageReceived(const sp<AMessage> &msg) { 243 if (msg->what() == kWhatDisconnect) { 244 uint32_t replyID; 245 CHECK(msg->senderAwaitsResponse(&replyID)); 246 247 mDisconnectReplyID = replyID; 248 finishDisconnectIfPossible(); 249 return; 250 } else if (msg->what() == kWhatPerformSeek) { 251 int32_t generation; 252 CHECK(msg->findInt32("generation", &generation)); 253 254 if (generation != mSeekGeneration) { 255 // obsolete. 256 return; 257 } 258 259 int64_t seekTimeUs; 260 CHECK(msg->findInt64("timeUs", &seekTimeUs)); 261 262 performSeek(seekTimeUs); 263 return; 264 } 265 266 CHECK_EQ(msg->what(), (int)kWhatNotify); 267 268 int32_t what; 269 CHECK(msg->findInt32("what", &what)); 270 271 switch (what) { 272 case MyHandler::kWhatConnected: 273 onConnected(); 274 break; 275 276 case MyHandler::kWhatDisconnected: 277 onDisconnected(msg); 278 break; 279 280 case MyHandler::kWhatSeekDone: 281 { 282 mState = CONNECTED; 283 mStartingUp = true; 284 break; 285 } 286 287 case MyHandler::kWhatAccessUnit: 288 { 289 size_t trackIndex; 290 CHECK(msg->findSize("trackIndex", &trackIndex)); 291 292 if (mTSParser == NULL) { 293 CHECK_LT(trackIndex, mTracks.size()); 294 } else { 295 CHECK_EQ(trackIndex, 0u); 296 } 297 298 sp<ABuffer> accessUnit; 299 CHECK(msg->findBuffer("accessUnit", &accessUnit)); 300 301 int32_t damaged; 302 if (accessUnit->meta()->findInt32("damaged", &damaged) 303 && damaged) { 304 ALOGI("dropping damaged access unit."); 305 break; 306 } 307 308 if (mTSParser != NULL) { 309 size_t offset = 0; 310 status_t err = OK; 311 while (offset + 188 <= accessUnit->size()) { 312 err = mTSParser->feedTSPacket( 313 accessUnit->data() + offset, 188); 314 if (err != OK) { 315 break; 316 } 317 318 offset += 188; 319 } 320 321 if (offset < accessUnit->size()) { 322 err = ERROR_MALFORMED; 323 } 324 325 if (err != OK) { 326 sp<AnotherPacketSource> source = getSource(false /* audio */); 327 if (source != NULL) { 328 source->signalEOS(err); 329 } 330 331 source = getSource(true /* audio */); 332 if (source != NULL) { 333 source->signalEOS(err); 334 } 335 } 336 break; 337 } 338 339 TrackInfo *info = &mTracks.editItemAt(trackIndex); 340 341 sp<AnotherPacketSource> source = info->mSource; 342 if (source != NULL) { 343 uint32_t rtpTime; 344 CHECK(accessUnit->meta()->findInt32("rtp-time", (int32_t *)&rtpTime)); 345 346 if (!info->mNPTMappingValid) { 347 // This is a live stream, we didn't receive any normal 348 // playtime mapping. We won't map to npt time. 349 source->queueAccessUnit(accessUnit); 350 break; 351 } 352 353 int64_t nptUs = 354 ((double)rtpTime - (double)info->mRTPTime) 355 / info->mTimeScale 356 * 1000000ll 357 + info->mNormalPlaytimeUs; 358 359 accessUnit->meta()->setInt64("timeUs", nptUs); 360 361 source->queueAccessUnit(accessUnit); 362 } 363 break; 364 } 365 366 case MyHandler::kWhatEOS: 367 { 368 int32_t finalResult; 369 CHECK(msg->findInt32("finalResult", &finalResult)); 370 CHECK_NE(finalResult, (status_t)OK); 371 372 if (mTSParser != NULL) { 373 sp<AnotherPacketSource> source = getSource(false /* audio */); 374 if (source != NULL) { 375 source->signalEOS(finalResult); 376 } 377 378 source = getSource(true /* audio */); 379 if (source != NULL) { 380 source->signalEOS(finalResult); 381 } 382 383 return; 384 } 385 386 size_t trackIndex; 387 CHECK(msg->findSize("trackIndex", &trackIndex)); 388 CHECK_LT(trackIndex, mTracks.size()); 389 390 TrackInfo *info = &mTracks.editItemAt(trackIndex); 391 sp<AnotherPacketSource> source = info->mSource; 392 if (source != NULL) { 393 source->signalEOS(finalResult); 394 } 395 396 break; 397 } 398 399 case MyHandler::kWhatSeekDiscontinuity: 400 { 401 size_t trackIndex; 402 CHECK(msg->findSize("trackIndex", &trackIndex)); 403 CHECK_LT(trackIndex, mTracks.size()); 404 405 TrackInfo *info = &mTracks.editItemAt(trackIndex); 406 sp<AnotherPacketSource> source = info->mSource; 407 if (source != NULL) { 408 source->queueDiscontinuity(ATSParser::DISCONTINUITY_SEEK, NULL); 409 } 410 411 break; 412 } 413 414 case MyHandler::kWhatNormalPlayTimeMapping: 415 { 416 size_t trackIndex; 417 CHECK(msg->findSize("trackIndex", &trackIndex)); 418 CHECK_LT(trackIndex, mTracks.size()); 419 420 uint32_t rtpTime; 421 CHECK(msg->findInt32("rtpTime", (int32_t *)&rtpTime)); 422 423 int64_t nptUs; 424 CHECK(msg->findInt64("nptUs", &nptUs)); 425 426 TrackInfo *info = &mTracks.editItemAt(trackIndex); 427 info->mRTPTime = rtpTime; 428 info->mNormalPlaytimeUs = nptUs; 429 info->mNPTMappingValid = true; 430 break; 431 } 432 433 case SDPLoader::kWhatSDPLoaded: 434 { 435 onSDPLoaded(msg); 436 break; 437 } 438 439 default: 440 TRESPASS(); 441 } 442} 443 444void NuPlayer::RTSPSource::onConnected() { 445 CHECK(mAudioTrack == NULL); 446 CHECK(mVideoTrack == NULL); 447 448 size_t numTracks = mHandler->countTracks(); 449 for (size_t i = 0; i < numTracks; ++i) { 450 int32_t timeScale; 451 sp<MetaData> format = mHandler->getTrackFormat(i, &timeScale); 452 453 const char *mime; 454 CHECK(format->findCString(kKeyMIMEType, &mime)); 455 456 if (!strcasecmp(mime, MEDIA_MIMETYPE_CONTAINER_MPEG2TS)) { 457 // Very special case for MPEG2 Transport Streams. 458 CHECK_EQ(numTracks, 1u); 459 460 mTSParser = new ATSParser; 461 return; 462 } 463 464 bool isAudio = !strncasecmp(mime, "audio/", 6); 465 bool isVideo = !strncasecmp(mime, "video/", 6); 466 467 TrackInfo info; 468 info.mTimeScale = timeScale; 469 info.mRTPTime = 0; 470 info.mNormalPlaytimeUs = 0ll; 471 info.mNPTMappingValid = false; 472 473 if ((isAudio && mAudioTrack == NULL) 474 || (isVideo && mVideoTrack == NULL)) { 475 sp<AnotherPacketSource> source = new AnotherPacketSource(format); 476 477 if (isAudio) { 478 mAudioTrack = source; 479 } else { 480 mVideoTrack = source; 481 } 482 483 info.mSource = source; 484 } 485 486 mTracks.push(info); 487 } 488 489 mState = CONNECTED; 490} 491 492void NuPlayer::RTSPSource::onSDPLoaded(const sp<AMessage> &msg) { 493 status_t err; 494 CHECK(msg->findInt32("result", &err)); 495 496 mSDPLoader.clear(); 497 498 if (mDisconnectReplyID != 0) { 499 err = UNKNOWN_ERROR; 500 } 501 502 if (err == OK) { 503 sp<ASessionDescription> desc; 504 sp<RefBase> obj; 505 CHECK(msg->findObject("description", &obj)); 506 desc = static_cast<ASessionDescription *>(obj.get()); 507 508 AString rtspUri; 509 if (!desc->findAttribute(0, "a=control", &rtspUri)) { 510 ALOGE("Unable to find url in SDP"); 511 err = UNKNOWN_ERROR; 512 } else { 513 sp<AMessage> notify = new AMessage(kWhatNotify, mReflector->id()); 514 515 mHandler = new MyHandler(rtspUri.c_str(), notify, mUIDValid, mUID); 516 mLooper->registerHandler(mHandler); 517 518 mHandler->loadSDP(desc); 519 } 520 } 521 522 if (err != OK) { 523 mState = DISCONNECTED; 524 mFinalResult = err; 525 526 if (mDisconnectReplyID != 0) { 527 finishDisconnectIfPossible(); 528 } 529 } 530} 531 532void NuPlayer::RTSPSource::onDisconnected(const sp<AMessage> &msg) { 533 status_t err; 534 CHECK(msg->findInt32("result", &err)); 535 CHECK_NE(err, (status_t)OK); 536 537 mLooper->unregisterHandler(mHandler->id()); 538 mHandler.clear(); 539 540 mState = DISCONNECTED; 541 mFinalResult = err; 542 543 if (mDisconnectReplyID != 0) { 544 finishDisconnectIfPossible(); 545 } 546} 547 548void NuPlayer::RTSPSource::finishDisconnectIfPossible() { 549 if (mState != DISCONNECTED) { 550 if (mHandler != NULL) { 551 mHandler->disconnect(); 552 } else if (mSDPLoader != NULL) { 553 mSDPLoader->cancel(); 554 } 555 return; 556 } 557 558 (new AMessage)->postReply(mDisconnectReplyID); 559 mDisconnectReplyID = 0; 560} 561 562} // namespace android 563