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