blob: 6df2ddd5a26059a8c3a902709c3d10754adc3069 [file] [log] [blame]
Andreas Huber2bfdd422011-10-11 15:24:07 -07001/*
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
Andreas Hubercfaeeec2012-08-31 10:27:46 -070026#include <media/stagefright/MediaDefs.h>
Andreas Huber2bfdd422011-10-11 15:24:07 -070027#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),
Andreas Huberee736e92011-12-08 13:04:50 -080042 mDisconnectReplyID(0),
Andreas Huberbfd4d0d2012-05-17 14:18:50 -070043 mStartingUp(true),
Andreas Huberee736e92011-12-08 13:04:50 -080044 mSeekGeneration(0) {
Andreas Huber2bfdd422011-10-11 15:24:07 -070045 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() {
James Dongf6f0f0e2012-11-16 14:31:15 -080060 mLooper->stop();
Andreas Huber2bfdd422011-10-11 15:24:07 -070061}
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() {
James Dongf6f0f0e2012-11-16 14:31:15 -080087 if (mLooper == NULL) {
88 return;
89 }
Andreas Huber2bfdd422011-10-11 15:24:07 -070090 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
Andreas Huber84066782011-08-16 09:34:26 -0700100sp<MetaData> NuPlayer::RTSPSource::getFormatMeta(bool audio) {
Andreas Huber2bfdd422011-10-11 15:24:07 -0700101 sp<AnotherPacketSource> source = getSource(audio);
102
103 if (source == NULL) {
104 return NULL;
105 }
106
107 return source->getFormat();
108}
109
Andreas Huberbfd4d0d2012-05-17 14:18:50 -0700110bool 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
Andreas Huber2bfdd422011-10-11 15:24:07 -0700139status_t NuPlayer::RTSPSource::dequeueAccessUnit(
140 bool audio, sp<ABuffer> *accessUnit) {
Andreas Huberbfd4d0d2012-05-17 14:18:50 -0700141 if (mStartingUp) {
142 if (!haveSufficientDataOnAllTracks()) {
143 return -EWOULDBLOCK;
144 }
145
146 mStartingUp = false;
147 }
148
Andreas Huber2bfdd422011-10-11 15:24:07 -0700149 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) {
Andreas Hubercfaeeec2012-08-31 10:27:46 -0700164 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
Andreas Huber2bfdd422011-10-11 15:24:07 -0700171 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) {
Andreas Huberee736e92011-12-08 13:04:50 -0800197 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) {
Andreas Huber2bfdd422011-10-11 15:24:07 -0700206 if (mState != CONNECTED) {
Andreas Huberee736e92011-12-08 13:04:50 -0800207 return;
Andreas Huber2bfdd422011-10-11 15:24:07 -0700208 }
209
210 mState = SEEKING;
211 mHandler->seek(seekTimeUs);
Andreas Huber2bfdd422011-10-11 15:24:07 -0700212}
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;
Andreas Huberee736e92011-12-08 13:04:50 -0800226 } 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;
Andreas Huber2bfdd422011-10-11 15:24:07 -0700240 }
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;
Andreas Huberbfd4d0d2012-05-17 14:18:50 -0700259 mStartingUp = true;
Andreas Huber2bfdd422011-10-11 15:24:07 -0700260 break;
261 }
262
263 case MyHandler::kWhatAccessUnit:
264 {
265 size_t trackIndex;
266 CHECK(msg->findSize("trackIndex", &trackIndex));
Andreas Hubercfaeeec2012-08-31 10:27:46 -0700267
268 if (mTSParser == NULL) {
269 CHECK_LT(trackIndex, mTracks.size());
270 } else {
271 CHECK_EQ(trackIndex, 0u);
272 }
Andreas Huber2bfdd422011-10-11 15:24:07 -0700273
Andreas Huber2d8bedd2012-02-21 14:38:23 -0800274 sp<ABuffer> accessUnit;
275 CHECK(msg->findBuffer("accessUnit", &accessUnit));
Andreas Huber2bfdd422011-10-11 15:24:07 -0700276
277 int32_t damaged;
278 if (accessUnit->meta()->findInt32("damaged", &damaged)
279 && damaged) {
Steve Blockdf64d152012-01-04 20:05:49 +0000280 ALOGI("dropping damaged access unit.");
Andreas Huber2bfdd422011-10-11 15:24:07 -0700281 break;
282 }
283
Andreas Hubercfaeeec2012-08-31 10:27:46 -0700284 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
Andreas Huber1906e5c2011-12-08 12:27:47 -0800315 TrackInfo *info = &mTracks.editItemAt(trackIndex);
316
317 sp<AnotherPacketSource> source = info->mSource;
Andreas Huber2bfdd422011-10-11 15:24:07 -0700318 if (source != NULL) {
Andreas Huber2bfdd422011-10-11 15:24:07 -0700319 uint32_t rtpTime;
320 CHECK(accessUnit->meta()->findInt32("rtp-time", (int32_t *)&rtpTime));
321
Andreas Huber1906e5c2011-12-08 12:27:47 -0800322 if (!info->mNPTMappingValid) {
323 // This is a live stream, we didn't receive any normal
Andreas Huberc9d16962012-05-21 11:12:40 -0700324 // playtime mapping. We won't map to npt time.
325 source->queueAccessUnit(accessUnit);
326 break;
Andreas Huber1906e5c2011-12-08 12:27:47 -0800327 }
328
Andreas Huber2bfdd422011-10-11 15:24:07 -0700329 int64_t nptUs =
Andreas Huber1906e5c2011-12-08 12:27:47 -0800330 ((double)rtpTime - (double)info->mRTPTime)
331 / info->mTimeScale
Andreas Huber2bfdd422011-10-11 15:24:07 -0700332 * 1000000ll
Andreas Huber1906e5c2011-12-08 12:27:47 -0800333 + info->mNormalPlaytimeUs;
Andreas Huber2bfdd422011-10-11 15:24:07 -0700334
335 accessUnit->meta()->setInt64("timeUs", nptUs);
Andreas Huber2bfdd422011-10-11 15:24:07 -0700336
337 source->queueAccessUnit(accessUnit);
338 }
339 break;
340 }
341
342 case MyHandler::kWhatEOS:
343 {
Andreas Huber2bfdd422011-10-11 15:24:07 -0700344 int32_t finalResult;
345 CHECK(msg->findInt32("finalResult", &finalResult));
346 CHECK_NE(finalResult, (status_t)OK);
347
Andreas Hubercfaeeec2012-08-31 10:27:46 -0700348 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
Andreas Huber2bfdd422011-10-11 15:24:07 -0700366 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;
Andreas Huber1906e5c2011-12-08 12:27:47 -0800405 info->mNPTMappingValid = true;
Andreas Huber2bfdd422011-10-11 15:24:07 -0700406 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
Andreas Hubercfaeeec2012-08-31 10:27:46 -0700426 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
Andreas Huber2bfdd422011-10-11 15:24:07 -0700434 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;
Andreas Huber1906e5c2011-12-08 12:27:47 -0800441 info.mNPTMappingValid = false;
Andreas Huber2bfdd422011-10-11 15:24:07 -0700442
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