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