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