blob: cf455bd4b76f5b88b05c6c28c16ef50db4552588 [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 Huber49694682012-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() {
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
Andreas Huber84066782011-08-16 09:34:26 -070099sp<MetaData> NuPlayer::RTSPSource::getFormatMeta(bool audio) {
Andreas Huber2bfdd422011-10-11 15:24:07 -0700100 sp<AnotherPacketSource> source = getSource(audio);
101
102 if (source == NULL) {
103 return NULL;
104 }
105
106 return source->getFormat();
107}
108
Andreas Huberbfd4d0d2012-05-17 14:18:50 -0700109bool 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
Andreas Huber2bfdd422011-10-11 15:24:07 -0700138status_t NuPlayer::RTSPSource::dequeueAccessUnit(
139 bool audio, sp<ABuffer> *accessUnit) {
Andreas Huberbfd4d0d2012-05-17 14:18:50 -0700140 if (mStartingUp) {
141 if (!haveSufficientDataOnAllTracks()) {
142 return -EWOULDBLOCK;
143 }
144
145 mStartingUp = false;
146 }
147
Andreas Huber2bfdd422011-10-11 15:24:07 -0700148 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) {
Andreas Huber49694682012-08-31 10:27:46 -0700163 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
Andreas Huber2bfdd422011-10-11 15:24:07 -0700170 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) {
Andreas Huberee736e92011-12-08 13:04:50 -0800196 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) {
Andreas Huber2bfdd422011-10-11 15:24:07 -0700205 if (mState != CONNECTED) {
Andreas Huberee736e92011-12-08 13:04:50 -0800206 return;
Andreas Huber2bfdd422011-10-11 15:24:07 -0700207 }
208
209 mState = SEEKING;
210 mHandler->seek(seekTimeUs);
Andreas Huber2bfdd422011-10-11 15:24:07 -0700211}
212
Andreas Hubera4c5bc02012-11-27 15:02:53 -0800213uint32_t NuPlayer::RTSPSource::flags() const {
214 return FLAG_SEEKABLE;
Andreas Huber2bfdd422011-10-11 15:24:07 -0700215}
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;
Andreas Huberee736e92011-12-08 13:04:50 -0800225 } 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;
Andreas Huber2bfdd422011-10-11 15:24:07 -0700239 }
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;
Andreas Huberbfd4d0d2012-05-17 14:18:50 -0700258 mStartingUp = true;
Andreas Huber2bfdd422011-10-11 15:24:07 -0700259 break;
260 }
261
262 case MyHandler::kWhatAccessUnit:
263 {
264 size_t trackIndex;
265 CHECK(msg->findSize("trackIndex", &trackIndex));
Andreas Huber49694682012-08-31 10:27:46 -0700266
267 if (mTSParser == NULL) {
268 CHECK_LT(trackIndex, mTracks.size());
269 } else {
270 CHECK_EQ(trackIndex, 0u);
271 }
Andreas Huber2bfdd422011-10-11 15:24:07 -0700272
Andreas Huber2d8bedd2012-02-21 14:38:23 -0800273 sp<ABuffer> accessUnit;
274 CHECK(msg->findBuffer("accessUnit", &accessUnit));
Andreas Huber2bfdd422011-10-11 15:24:07 -0700275
276 int32_t damaged;
277 if (accessUnit->meta()->findInt32("damaged", &damaged)
278 && damaged) {
Steve Blockdf64d152012-01-04 20:05:49 +0000279 ALOGI("dropping damaged access unit.");
Andreas Huber2bfdd422011-10-11 15:24:07 -0700280 break;
281 }
282
Andreas Huber49694682012-08-31 10:27:46 -0700283 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
Andreas Huber1906e5c2011-12-08 12:27:47 -0800314 TrackInfo *info = &mTracks.editItemAt(trackIndex);
315
316 sp<AnotherPacketSource> source = info->mSource;
Andreas Huber2bfdd422011-10-11 15:24:07 -0700317 if (source != NULL) {
Andreas Huber2bfdd422011-10-11 15:24:07 -0700318 uint32_t rtpTime;
319 CHECK(accessUnit->meta()->findInt32("rtp-time", (int32_t *)&rtpTime));
320
Andreas Huber1906e5c2011-12-08 12:27:47 -0800321 if (!info->mNPTMappingValid) {
322 // This is a live stream, we didn't receive any normal
Andreas Huberc9d16962012-05-21 11:12:40 -0700323 // playtime mapping. We won't map to npt time.
324 source->queueAccessUnit(accessUnit);
325 break;
Andreas Huber1906e5c2011-12-08 12:27:47 -0800326 }
327
Andreas Huber2bfdd422011-10-11 15:24:07 -0700328 int64_t nptUs =
Andreas Huber1906e5c2011-12-08 12:27:47 -0800329 ((double)rtpTime - (double)info->mRTPTime)
330 / info->mTimeScale
Andreas Huber2bfdd422011-10-11 15:24:07 -0700331 * 1000000ll
Andreas Huber1906e5c2011-12-08 12:27:47 -0800332 + info->mNormalPlaytimeUs;
Andreas Huber2bfdd422011-10-11 15:24:07 -0700333
334 accessUnit->meta()->setInt64("timeUs", nptUs);
Andreas Huber2bfdd422011-10-11 15:24:07 -0700335
336 source->queueAccessUnit(accessUnit);
337 }
338 break;
339 }
340
341 case MyHandler::kWhatEOS:
342 {
Andreas Huber2bfdd422011-10-11 15:24:07 -0700343 int32_t finalResult;
344 CHECK(msg->findInt32("finalResult", &finalResult));
345 CHECK_NE(finalResult, (status_t)OK);
346
Andreas Huber49694682012-08-31 10:27:46 -0700347 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
Andreas Huber2bfdd422011-10-11 15:24:07 -0700365 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;
Andreas Huber1906e5c2011-12-08 12:27:47 -0800404 info->mNPTMappingValid = true;
Andreas Huber2bfdd422011-10-11 15:24:07 -0700405 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
Andreas Huber49694682012-08-31 10:27:46 -0700425 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
Andreas Huber2bfdd422011-10-11 15:24:07 -0700433 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;
Andreas Huber1906e5c2011-12-08 12:27:47 -0800440 info.mNPTMappingValid = false;
Andreas Huber2bfdd422011-10-11 15:24:07 -0700441
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