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