blob: ff28f3b86769c3b9c7925e5bdb4beb0bc0da0ecf [file] [log] [blame]
Andreas Huber27366fc2009-11-20 09:32:46 -08001/*
2 * Copyright (C) 2009 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 "AwesomePlayer"
19#include <utils/Log.h>
20
Andreas Huber4ab5a6f2010-02-11 11:00:26 -080021#include <dlfcn.h>
22
Andreas Huber7a747b82010-06-07 15:19:40 -070023#include "include/ARTSPController.h"
Andreas Huber27366fc2009-11-20 09:32:46 -080024#include "include/AwesomePlayer.h"
Andreas Huber7a747b82010-06-07 15:19:40 -070025#include "include/LiveSource.h"
Andreas Huber1314e732009-12-14 14:18:22 -080026#include "include/SoftwareRenderer.h"
Andreas Huber4d61f602010-06-10 11:17:50 -070027#include "include/NuCachedSource2.h"
28#include "include/ThrottledSource.h"
Andreas Huber27366fc2009-11-20 09:32:46 -080029
Andreas Huber57648e42010-08-04 10:14:30 -070030#include "ARTPSession.h"
31#include "APacketSource.h"
32#include "ASessionDescription.h"
33#include "UDPPusher.h"
34
Andreas Hubera67d5382009-12-10 15:32:12 -080035#include <binder/IPCThreadState.h>
Andreas Huber27366fc2009-11-20 09:32:46 -080036#include <media/stagefright/AudioPlayer.h>
37#include <media/stagefright/DataSource.h>
38#include <media/stagefright/FileSource.h>
39#include <media/stagefright/MediaBuffer.h>
Andreas Huberc79827a2010-01-05 10:54:55 -080040#include <media/stagefright/MediaDefs.h>
Andreas Huber27366fc2009-11-20 09:32:46 -080041#include <media/stagefright/MediaExtractor.h>
42#include <media/stagefright/MediaDebug.h>
43#include <media/stagefright/MediaSource.h>
44#include <media/stagefright/MetaData.h>
45#include <media/stagefright/OMXCodec.h>
Andreas Huberc79827a2010-01-05 10:54:55 -080046
Mathias Agopian000479f2010-02-09 17:46:37 -080047#include <surfaceflinger/ISurface.h>
48
Andreas Huber7a747b82010-06-07 15:19:40 -070049#include <media/stagefright/foundation/ALooper.h>
Andreas Huber202348e2010-06-07 14:35:29 -070050
Andreas Huber27366fc2009-11-20 09:32:46 -080051namespace android {
52
Andreas Huber87ab9cd2010-09-03 13:20:33 -070053static int64_t kLowWaterMarkUs = 2000000ll; // 2secs
54static int64_t kHighWaterMarkUs = 10000000ll; // 10secs
55
Andreas Huber27366fc2009-11-20 09:32:46 -080056struct AwesomeEvent : public TimedEventQueue::Event {
Andreas Huber6be780e2010-02-08 14:40:30 -080057 AwesomeEvent(
58 AwesomePlayer *player,
59 void (AwesomePlayer::*method)())
Andreas Huber27366fc2009-11-20 09:32:46 -080060 : mPlayer(player),
Andreas Huber6be780e2010-02-08 14:40:30 -080061 mMethod(method) {
Andreas Huber27366fc2009-11-20 09:32:46 -080062 }
63
64protected:
65 virtual ~AwesomeEvent() {}
66
67 virtual void fire(TimedEventQueue *queue, int64_t /* now_us */) {
Andreas Huber6be780e2010-02-08 14:40:30 -080068 (mPlayer->*mMethod)();
Andreas Huber27366fc2009-11-20 09:32:46 -080069 }
70
71private:
72 AwesomePlayer *mPlayer;
Andreas Huber6be780e2010-02-08 14:40:30 -080073 void (AwesomePlayer::*mMethod)();
Andreas Huber27366fc2009-11-20 09:32:46 -080074
75 AwesomeEvent(const AwesomeEvent &);
76 AwesomeEvent &operator=(const AwesomeEvent &);
77};
78
Andreas Huber1314e732009-12-14 14:18:22 -080079struct AwesomeRemoteRenderer : public AwesomeRenderer {
80 AwesomeRemoteRenderer(const sp<IOMXRenderer> &target)
81 : mTarget(target) {
82 }
83
84 virtual void render(MediaBuffer *buffer) {
85 void *id;
86 if (buffer->meta_data()->findPointer(kKeyBufferID, &id)) {
87 mTarget->render((IOMX::buffer_id)id);
88 }
89 }
90
91private:
92 sp<IOMXRenderer> mTarget;
93
94 AwesomeRemoteRenderer(const AwesomeRemoteRenderer &);
95 AwesomeRemoteRenderer &operator=(const AwesomeRemoteRenderer &);
96};
97
98struct AwesomeLocalRenderer : public AwesomeRenderer {
99 AwesomeLocalRenderer(
Andreas Huber7b73cfc2010-02-12 14:40:08 -0800100 bool previewOnly,
Andreas Huber4ab5a6f2010-02-11 11:00:26 -0800101 const char *componentName,
Andreas Huber1314e732009-12-14 14:18:22 -0800102 OMX_COLOR_FORMATTYPE colorFormat,
103 const sp<ISurface> &surface,
104 size_t displayWidth, size_t displayHeight,
105 size_t decodedWidth, size_t decodedHeight)
Andreas Huber4ab5a6f2010-02-11 11:00:26 -0800106 : mTarget(NULL),
107 mLibHandle(NULL) {
Andreas Huber7b73cfc2010-02-12 14:40:08 -0800108 init(previewOnly, componentName,
Andreas Huber4ab5a6f2010-02-11 11:00:26 -0800109 colorFormat, surface, displayWidth,
110 displayHeight, decodedWidth, decodedHeight);
Andreas Huber1314e732009-12-14 14:18:22 -0800111 }
112
113 virtual void render(MediaBuffer *buffer) {
Andreas Huber7b73cfc2010-02-12 14:40:08 -0800114 render((const uint8_t *)buffer->data() + buffer->range_offset(),
115 buffer->range_length());
116 }
117
118 void render(const void *data, size_t size) {
119 mTarget->render(data, size, NULL);
Andreas Huber1314e732009-12-14 14:18:22 -0800120 }
121
122protected:
123 virtual ~AwesomeLocalRenderer() {
124 delete mTarget;
125 mTarget = NULL;
Andreas Huber4ab5a6f2010-02-11 11:00:26 -0800126
127 if (mLibHandle) {
128 dlclose(mLibHandle);
129 mLibHandle = NULL;
130 }
Andreas Huber1314e732009-12-14 14:18:22 -0800131 }
132
133private:
Andreas Huber4ab5a6f2010-02-11 11:00:26 -0800134 VideoRenderer *mTarget;
135 void *mLibHandle;
136
137 void init(
Andreas Huber7b73cfc2010-02-12 14:40:08 -0800138 bool previewOnly,
Andreas Huber4ab5a6f2010-02-11 11:00:26 -0800139 const char *componentName,
140 OMX_COLOR_FORMATTYPE colorFormat,
141 const sp<ISurface> &surface,
142 size_t displayWidth, size_t displayHeight,
143 size_t decodedWidth, size_t decodedHeight);
Andreas Huber1314e732009-12-14 14:18:22 -0800144
145 AwesomeLocalRenderer(const AwesomeLocalRenderer &);
146 AwesomeLocalRenderer &operator=(const AwesomeLocalRenderer &);;
147};
148
Andreas Huber4ab5a6f2010-02-11 11:00:26 -0800149void AwesomeLocalRenderer::init(
Andreas Huber7b73cfc2010-02-12 14:40:08 -0800150 bool previewOnly,
Andreas Huber4ab5a6f2010-02-11 11:00:26 -0800151 const char *componentName,
152 OMX_COLOR_FORMATTYPE colorFormat,
153 const sp<ISurface> &surface,
154 size_t displayWidth, size_t displayHeight,
155 size_t decodedWidth, size_t decodedHeight) {
Andreas Huber7b73cfc2010-02-12 14:40:08 -0800156 if (!previewOnly) {
157 // We will stick to the vanilla software-color-converting renderer
158 // for "previewOnly" mode, to avoid unneccessarily switching overlays
159 // more often than necessary.
Andreas Huber4ab5a6f2010-02-11 11:00:26 -0800160
Andreas Huber7b73cfc2010-02-12 14:40:08 -0800161 mLibHandle = dlopen("libstagefrighthw.so", RTLD_NOW);
Andreas Huber4ab5a6f2010-02-11 11:00:26 -0800162
Andreas Huber7b73cfc2010-02-12 14:40:08 -0800163 if (mLibHandle) {
164 typedef VideoRenderer *(*CreateRendererFunc)(
165 const sp<ISurface> &surface,
166 const char *componentName,
167 OMX_COLOR_FORMATTYPE colorFormat,
168 size_t displayWidth, size_t displayHeight,
169 size_t decodedWidth, size_t decodedHeight);
Andreas Huber4ab5a6f2010-02-11 11:00:26 -0800170
Andreas Huber7b73cfc2010-02-12 14:40:08 -0800171 CreateRendererFunc func =
172 (CreateRendererFunc)dlsym(
173 mLibHandle,
174 "_Z14createRendererRKN7android2spINS_8ISurfaceEEEPKc20"
175 "OMX_COLOR_FORMATTYPEjjjj");
176
177 if (func) {
178 mTarget =
179 (*func)(surface, componentName, colorFormat,
180 displayWidth, displayHeight,
181 decodedWidth, decodedHeight);
182 }
Andreas Huber4ab5a6f2010-02-11 11:00:26 -0800183 }
184 }
185
186 if (mTarget == NULL) {
187 mTarget = new SoftwareRenderer(
188 colorFormat, surface, displayWidth, displayHeight,
189 decodedWidth, decodedHeight);
190 }
191}
192
Andreas Huber27366fc2009-11-20 09:32:46 -0800193AwesomePlayer::AwesomePlayer()
Andreas Huber406a18b2010-02-18 16:45:13 -0800194 : mQueueStarted(false),
195 mTimeSource(NULL),
Andreas Huber7b73cfc2010-02-12 14:40:08 -0800196 mVideoRendererIsPreview(false),
Andreas Huber27366fc2009-11-20 09:32:46 -0800197 mAudioPlayer(NULL),
Andreas Huberffdf4782010-02-09 14:05:43 -0800198 mFlags(0),
Andreas Huber62f7ffe2010-05-06 10:18:05 -0700199 mExtractorFlags(0),
Andreas Huber27366fc2009-11-20 09:32:46 -0800200 mLastVideoBuffer(NULL),
Andreas Huberba7ec912010-02-12 10:42:02 -0800201 mVideoBuffer(NULL),
202 mSuspensionState(NULL) {
Andreas Huber27366fc2009-11-20 09:32:46 -0800203 CHECK_EQ(mClient.connect(), OK);
204
205 DataSource::RegisterDefaultSniffers();
206
Andreas Huber6be780e2010-02-08 14:40:30 -0800207 mVideoEvent = new AwesomeEvent(this, &AwesomePlayer::onVideoEvent);
Andreas Huber27366fc2009-11-20 09:32:46 -0800208 mVideoEventPending = false;
Andreas Huber6be780e2010-02-08 14:40:30 -0800209 mStreamDoneEvent = new AwesomeEvent(this, &AwesomePlayer::onStreamDone);
Andreas Huber27366fc2009-11-20 09:32:46 -0800210 mStreamDoneEventPending = false;
Andreas Huber6be780e2010-02-08 14:40:30 -0800211 mBufferingEvent = new AwesomeEvent(this, &AwesomePlayer::onBufferingUpdate);
Andreas Huberb9e63832010-01-26 16:20:10 -0800212 mBufferingEventPending = false;
Andreas Huber6be780e2010-02-08 14:40:30 -0800213
214 mCheckAudioStatusEvent = new AwesomeEvent(
215 this, &AwesomePlayer::onCheckAudioStatus);
216
Andreas Huber70d10c02010-02-03 11:37:29 -0800217 mAudioStatusEventPending = false;
Andreas Huber27366fc2009-11-20 09:32:46 -0800218
Andreas Huber27366fc2009-11-20 09:32:46 -0800219 reset();
220}
221
222AwesomePlayer::~AwesomePlayer() {
Andreas Huber406a18b2010-02-18 16:45:13 -0800223 if (mQueueStarted) {
224 mQueue.stop();
225 }
Andreas Huber27366fc2009-11-20 09:32:46 -0800226
227 reset();
228
229 mClient.disconnect();
230}
231
Andreas Huberb9e63832010-01-26 16:20:10 -0800232void AwesomePlayer::cancelPlayerEvents(bool keepBufferingGoing) {
Andreas Huber27366fc2009-11-20 09:32:46 -0800233 mQueue.cancelEvent(mVideoEvent->eventID());
234 mVideoEventPending = false;
235 mQueue.cancelEvent(mStreamDoneEvent->eventID());
236 mStreamDoneEventPending = false;
Andreas Huber70d10c02010-02-03 11:37:29 -0800237 mQueue.cancelEvent(mCheckAudioStatusEvent->eventID());
238 mAudioStatusEventPending = false;
Andreas Huberb9e63832010-01-26 16:20:10 -0800239
240 if (!keepBufferingGoing) {
241 mQueue.cancelEvent(mBufferingEvent->eventID());
242 mBufferingEventPending = false;
243 }
Andreas Huber27366fc2009-11-20 09:32:46 -0800244}
245
Andreas Hubera3f43842010-01-21 10:28:45 -0800246void AwesomePlayer::setListener(const wp<MediaPlayerBase> &listener) {
Andreas Huber27366fc2009-11-20 09:32:46 -0800247 Mutex::Autolock autoLock(mLock);
248 mListener = listener;
249}
250
Andreas Huber433c9ac2010-01-27 16:49:05 -0800251status_t AwesomePlayer::setDataSource(
252 const char *uri, const KeyedVector<String8, String8> *headers) {
Andreas Huber27366fc2009-11-20 09:32:46 -0800253 Mutex::Autolock autoLock(mLock);
Andreas Huberba7ec912010-02-12 10:42:02 -0800254 return setDataSource_l(uri, headers);
255}
Andreas Huber27366fc2009-11-20 09:32:46 -0800256
Andreas Huberba7ec912010-02-12 10:42:02 -0800257status_t AwesomePlayer::setDataSource_l(
258 const char *uri, const KeyedVector<String8, String8> *headers) {
Andreas Huber27366fc2009-11-20 09:32:46 -0800259 reset_l();
260
Andreas Huberffdf4782010-02-09 14:05:43 -0800261 mUri = uri;
Andreas Huberb9e63832010-01-26 16:20:10 -0800262
Andreas Huberffdf4782010-02-09 14:05:43 -0800263 if (headers) {
264 mUriHeaders = *headers;
Andreas Huberb9e63832010-01-26 16:20:10 -0800265 }
266
Andreas Huberffdf4782010-02-09 14:05:43 -0800267 // The actual work will be done during preparation in the call to
268 // ::finishSetDataSource_l to avoid blocking the calling thread in
269 // setDataSource for any significant time.
Andreas Huber27366fc2009-11-20 09:32:46 -0800270
Andreas Huberffdf4782010-02-09 14:05:43 -0800271 return OK;
Andreas Huber27366fc2009-11-20 09:32:46 -0800272}
273
274status_t AwesomePlayer::setDataSource(
275 int fd, int64_t offset, int64_t length) {
276 Mutex::Autolock autoLock(mLock);
277
278 reset_l();
279
Andreas Huberba7ec912010-02-12 10:42:02 -0800280 sp<DataSource> dataSource = new FileSource(fd, offset, length);
Andreas Huber27366fc2009-11-20 09:32:46 -0800281
Andreas Huberba7ec912010-02-12 10:42:02 -0800282 status_t err = dataSource->initCheck();
Andreas Huber27366fc2009-11-20 09:32:46 -0800283
284 if (err != OK) {
285 return err;
286 }
287
Andreas Huberba7ec912010-02-12 10:42:02 -0800288 mFileSource = dataSource;
289
290 return setDataSource_l(dataSource);
291}
292
293status_t AwesomePlayer::setDataSource_l(
294 const sp<DataSource> &dataSource) {
295 sp<MediaExtractor> extractor = MediaExtractor::Create(dataSource);
Andreas Huber27366fc2009-11-20 09:32:46 -0800296
297 if (extractor == NULL) {
298 return UNKNOWN_ERROR;
299 }
300
301 return setDataSource_l(extractor);
302}
303
304status_t AwesomePlayer::setDataSource_l(const sp<MediaExtractor> &extractor) {
Andreas Huber27366fc2009-11-20 09:32:46 -0800305 bool haveAudio = false;
306 bool haveVideo = false;
307 for (size_t i = 0; i < extractor->countTracks(); ++i) {
308 sp<MetaData> meta = extractor->getTrackMetaData(i);
309
310 const char *mime;
311 CHECK(meta->findCString(kKeyMIMEType, &mime));
312
313 if (!haveVideo && !strncasecmp(mime, "video/", 6)) {
Andreas Huber3ac94ef2010-03-05 10:42:10 -0800314 setVideoSource(extractor->getTrack(i));
315 haveVideo = true;
Andreas Huber27366fc2009-11-20 09:32:46 -0800316 } else if (!haveAudio && !strncasecmp(mime, "audio/", 6)) {
Andreas Huber3ac94ef2010-03-05 10:42:10 -0800317 setAudioSource(extractor->getTrack(i));
318 haveAudio = true;
Andreas Huber9fee0b22010-09-03 14:09:21 -0700319
Andreas Huber1913c1a2010-10-04 11:09:31 -0700320 if (!strcasecmp(mime, MEDIA_MIMETYPE_AUDIO_VORBIS)) {
321 // Only do this for vorbis audio, none of the other audio
322 // formats even support this ringtone specific hack and
323 // retrieving the metadata on some extractors may turn out
324 // to be very expensive.
325 sp<MetaData> fileMeta = extractor->getMetaData();
326 int32_t loop;
327 if (fileMeta != NULL
328 && fileMeta->findInt32(kKeyAutoLoop, &loop) && loop != 0) {
329 mFlags |= AUTO_LOOPING;
330 }
Andreas Huber9fee0b22010-09-03 14:09:21 -0700331 }
Andreas Huber27366fc2009-11-20 09:32:46 -0800332 }
333
334 if (haveAudio && haveVideo) {
335 break;
336 }
337 }
338
Andreas Huber62f7ffe2010-05-06 10:18:05 -0700339 if (!haveAudio && !haveVideo) {
340 return UNKNOWN_ERROR;
341 }
342
343 mExtractorFlags = extractor->flags();
344
345 return OK;
Andreas Huber27366fc2009-11-20 09:32:46 -0800346}
347
348void AwesomePlayer::reset() {
349 Mutex::Autolock autoLock(mLock);
350 reset_l();
351}
352
353void AwesomePlayer::reset_l() {
Andreas Huberedbb4d82010-03-12 08:59:22 -0800354 if (mFlags & PREPARING) {
355 mFlags |= PREPARE_CANCELLED;
356 if (mConnectingDataSource != NULL) {
357 LOGI("interrupting the connection process");
358 mConnectingDataSource->disconnect();
359 }
360 }
361
Andreas Huberffdf4782010-02-09 14:05:43 -0800362 while (mFlags & PREPARING) {
363 mPreparedCondition.wait(mLock);
364 }
365
Andreas Huber27366fc2009-11-20 09:32:46 -0800366 cancelPlayerEvents();
367
Andreas Huber4d61f602010-06-10 11:17:50 -0700368 mCachedSource.clear();
Andreas Huber3ac94ef2010-03-05 10:42:10 -0800369 mAudioTrack.clear();
370 mVideoTrack.clear();
371
Andreas Huberba7ec912010-02-12 10:42:02 -0800372 // Shutdown audio first, so that the respone to the reset request
373 // appears to happen instantaneously as far as the user is concerned
374 // If we did this later, audio would continue playing while we
375 // shutdown the video-related resources and the player appear to
376 // not be as responsive to a reset request.
Andreas Huberedbb4d82010-03-12 08:59:22 -0800377 if (mAudioPlayer == NULL && mAudioSource != NULL) {
378 // If we had an audio player, it would have effectively
379 // taken possession of the audio source and stopped it when
380 // _it_ is stopped. Otherwise this is still our responsibility.
381 mAudioSource->stop();
382 }
Andreas Huberba7ec912010-02-12 10:42:02 -0800383 mAudioSource.clear();
384
Andreas Huberba7ec912010-02-12 10:42:02 -0800385 mTimeSource = NULL;
386
387 delete mAudioPlayer;
388 mAudioPlayer = NULL;
389
Andreas Huber3522b5a52010-01-22 14:36:53 -0800390 mVideoRenderer.clear();
391
Andreas Huber27366fc2009-11-20 09:32:46 -0800392 if (mLastVideoBuffer) {
393 mLastVideoBuffer->release();
394 mLastVideoBuffer = NULL;
395 }
396
397 if (mVideoBuffer) {
398 mVideoBuffer->release();
399 mVideoBuffer = NULL;
400 }
401
Andreas Hubere0dd7d32010-08-24 14:33:58 -0700402 if (mRTSPController != NULL) {
403 mRTSPController->disconnect();
404 mRTSPController.clear();
405 }
406
Andreas Huber57648e42010-08-04 10:14:30 -0700407 mRTPPusher.clear();
408 mRTCPPusher.clear();
409 mRTPSession.clear();
Andreas Huber7a747b82010-06-07 15:19:40 -0700410
Andreas Huber27366fc2009-11-20 09:32:46 -0800411 if (mVideoSource != NULL) {
412 mVideoSource->stop();
Andreas Huber98b48de2010-01-29 10:10:22 -0800413
414 // The following hack is necessary to ensure that the OMX
415 // component is completely released by the time we may try
416 // to instantiate it again.
417 wp<MediaSource> tmp = mVideoSource;
Andreas Huber27366fc2009-11-20 09:32:46 -0800418 mVideoSource.clear();
Andreas Huber98b48de2010-01-29 10:10:22 -0800419 while (tmp.promote() != NULL) {
420 usleep(1000);
421 }
422 IPCThreadState::self()->flushCommands();
Andreas Huber27366fc2009-11-20 09:32:46 -0800423 }
424
Andreas Huber27366fc2009-11-20 09:32:46 -0800425 mDurationUs = -1;
426 mFlags = 0;
Andreas Huber62f7ffe2010-05-06 10:18:05 -0700427 mExtractorFlags = 0;
Andreas Huber27366fc2009-11-20 09:32:46 -0800428 mVideoWidth = mVideoHeight = -1;
429 mTimeSourceDeltaUs = 0;
430 mVideoTimeUs = 0;
431
432 mSeeking = false;
Andreas Huber8e2b9412010-03-31 09:40:15 -0700433 mSeekNotificationSent = false;
Andreas Huber27366fc2009-11-20 09:32:46 -0800434 mSeekTimeUs = 0;
Andreas Huberb9e63832010-01-26 16:20:10 -0800435
Andreas Huberffdf4782010-02-09 14:05:43 -0800436 mUri.setTo("");
437 mUriHeaders.clear();
Andreas Huberba7ec912010-02-12 10:42:02 -0800438
439 mFileSource.clear();
440
441 delete mSuspensionState;
442 mSuspensionState = NULL;
Andreas Huber27366fc2009-11-20 09:32:46 -0800443}
444
Andreas Huber6be780e2010-02-08 14:40:30 -0800445void AwesomePlayer::notifyListener_l(int msg, int ext1, int ext2) {
Andreas Hubera3f43842010-01-21 10:28:45 -0800446 if (mListener != NULL) {
447 sp<MediaPlayerBase> listener = mListener.promote();
448
449 if (listener != NULL) {
Andreas Huber6be780e2010-02-08 14:40:30 -0800450 listener->sendEvent(msg, ext1, ext2);
Andreas Hubera3f43842010-01-21 10:28:45 -0800451 }
452 }
453}
454
Andreas Huber87ab9cd2010-09-03 13:20:33 -0700455// Returns true iff cached duration is available/applicable.
456bool AwesomePlayer::getCachedDuration_l(int64_t *durationUs, bool *eos) {
457 off_t totalSize;
458
459 if (mRTSPController != NULL) {
460 *durationUs = mRTSPController->getQueueDurationUs(eos);
461 return true;
462 } else if (mCachedSource != NULL && mDurationUs >= 0
463 && mCachedSource->getSize(&totalSize) == OK) {
464 int64_t bitrate = totalSize * 8000000ll / mDurationUs; // in bits/sec
465
466 size_t cachedDataRemaining = mCachedSource->approxDataRemaining(eos);
467 *durationUs = cachedDataRemaining * 8000000ll / bitrate;
468 return true;
469 }
470
471 return false;
472}
473
Andreas Huberb9e63832010-01-26 16:20:10 -0800474void AwesomePlayer::onBufferingUpdate() {
475 Mutex::Autolock autoLock(mLock);
Andreas Huberc0178f12010-02-17 15:58:57 -0800476 if (!mBufferingEventPending) {
477 return;
478 }
Andreas Huberb9e63832010-01-26 16:20:10 -0800479 mBufferingEventPending = false;
480
Andreas Huber87ab9cd2010-09-03 13:20:33 -0700481 if (mCachedSource != NULL) {
Andreas Huber4d8f66b2010-09-01 15:05:28 -0700482 bool eos;
Andreas Huber87ab9cd2010-09-03 13:20:33 -0700483 size_t cachedDataRemaining = mCachedSource->approxDataRemaining(&eos);
Andreas Huber4d8f66b2010-09-01 15:05:28 -0700484
Andreas Huber87ab9cd2010-09-03 13:20:33 -0700485 if (eos) {
486 notifyListener_l(MEDIA_BUFFERING_UPDATE, 100);
Andreas Huber05f67872010-10-04 11:36:39 -0700487 if (mFlags & PREPARING) {
488 LOGV("cache has reached EOS, prepare is done.");
489 finishAsyncPrepare_l();
490 }
Andreas Huber87ab9cd2010-09-03 13:20:33 -0700491 } else {
492 off_t size;
493 if (mDurationUs >= 0 && mCachedSource->getSize(&size) == OK) {
494 int64_t bitrate = size * 8000000ll / mDurationUs; // in bits/sec
Andreas Huber4d8f66b2010-09-01 15:05:28 -0700495
Andreas Huber87ab9cd2010-09-03 13:20:33 -0700496 size_t cachedSize = mCachedSource->cachedSize();
497 int64_t cachedDurationUs = cachedSize * 8000000ll / bitrate;
498
499 int percentage = 100.0 * (double)cachedDurationUs / mDurationUs;
500 if (percentage > 100) {
501 percentage = 100;
502 }
503
504 notifyListener_l(MEDIA_BUFFERING_UPDATE, percentage);
505 } else {
506 // We don't know the bitrate of the stream, use absolute size
507 // limits to maintain the cache.
508
509 const size_t kLowWaterMarkBytes = 400000;
510 const size_t kHighWaterMarkBytes = 1000000;
511
512 if ((mFlags & PLAYING) && !eos
513 && (cachedDataRemaining < kLowWaterMarkBytes)) {
514 LOGI("cache is running low (< %d) , pausing.",
515 kLowWaterMarkBytes);
516 mFlags |= CACHE_UNDERRUN;
517 pause_l();
518 notifyListener_l(MEDIA_INFO, MEDIA_INFO_BUFFERING_START);
519 } else if (eos || cachedDataRemaining > kHighWaterMarkBytes) {
520 if (mFlags & CACHE_UNDERRUN) {
521 LOGI("cache has filled up (> %d), resuming.",
522 kHighWaterMarkBytes);
523 mFlags &= ~CACHE_UNDERRUN;
524 play_l();
525 notifyListener_l(MEDIA_INFO, MEDIA_INFO_BUFFERING_END);
526 } else if (mFlags & PREPARING) {
527 LOGV("cache has filled up (> %d), prepare is done",
528 kHighWaterMarkBytes);
529 finishAsyncPrepare_l();
530 }
531 }
532 }
533 }
534 }
535
536 int64_t cachedDurationUs;
537 bool eos;
538 if (getCachedDuration_l(&cachedDurationUs, &eos)) {
Andreas Huber4d8f66b2010-09-01 15:05:28 -0700539 if ((mFlags & PLAYING) && !eos
Andreas Huber87ab9cd2010-09-03 13:20:33 -0700540 && (cachedDurationUs < kLowWaterMarkUs)) {
541 LOGI("cache is running low (%.2f secs) , pausing.",
542 cachedDurationUs / 1E6);
Andreas Huber4d8f66b2010-09-01 15:05:28 -0700543 mFlags |= CACHE_UNDERRUN;
544 pause_l();
545 notifyListener_l(MEDIA_INFO, MEDIA_INFO_BUFFERING_START);
Andreas Huber87ab9cd2010-09-03 13:20:33 -0700546 } else if (eos || cachedDurationUs > kHighWaterMarkUs) {
547 if (mFlags & CACHE_UNDERRUN) {
548 LOGI("cache has filled up (%.2f secs), resuming.",
549 cachedDurationUs / 1E6);
550 mFlags &= ~CACHE_UNDERRUN;
551 play_l();
552 notifyListener_l(MEDIA_INFO, MEDIA_INFO_BUFFERING_END);
553 } else if (mFlags & PREPARING) {
554 LOGV("cache has filled up (%.2f secs), prepare is done",
555 cachedDurationUs / 1E6);
556 finishAsyncPrepare_l();
Andreas Huberc23296e2010-08-25 12:31:48 -0700557 }
Andreas Huberc23296e2010-08-25 12:31:48 -0700558 }
Andreas Huberb9e63832010-01-26 16:20:10 -0800559 }
Andreas Huber4d61f602010-06-10 11:17:50 -0700560
Andreas Huber4d61f602010-06-10 11:17:50 -0700561 postBufferingEvent_l();
Andreas Huberb9e63832010-01-26 16:20:10 -0800562}
563
Andreas Huber4c19bf92010-09-08 14:32:20 -0700564void AwesomePlayer::partial_reset_l() {
565 // Only reset the video renderer and shut down the video decoder.
566 // Then instantiate a new video decoder and resume video playback.
567
568 mVideoRenderer.clear();
569
570 if (mLastVideoBuffer) {
571 mLastVideoBuffer->release();
572 mLastVideoBuffer = NULL;
573 }
574
575 if (mVideoBuffer) {
576 mVideoBuffer->release();
577 mVideoBuffer = NULL;
578 }
579
580 {
581 mVideoSource->stop();
582
583 // The following hack is necessary to ensure that the OMX
584 // component is completely released by the time we may try
585 // to instantiate it again.
586 wp<MediaSource> tmp = mVideoSource;
587 mVideoSource.clear();
588 while (tmp.promote() != NULL) {
589 usleep(1000);
590 }
591 IPCThreadState::self()->flushCommands();
592 }
593
594 CHECK_EQ(OK, initVideoDecoder(OMXCodec::kIgnoreCodecSpecificData));
595}
596
Andreas Huber27366fc2009-11-20 09:32:46 -0800597void AwesomePlayer::onStreamDone() {
598 // Posted whenever any stream finishes playing.
599
600 Mutex::Autolock autoLock(mLock);
Andreas Huberc0178f12010-02-17 15:58:57 -0800601 if (!mStreamDoneEventPending) {
602 return;
603 }
Andreas Huber27366fc2009-11-20 09:32:46 -0800604 mStreamDoneEventPending = false;
605
Andreas Huber4c19bf92010-09-08 14:32:20 -0700606 if (mStreamDoneStatus == INFO_DISCONTINUITY) {
607 // This special status is returned because an http live stream's
608 // video stream switched to a different bandwidth at this point
609 // and future data may have been encoded using different parameters.
610 // This requires us to shutdown the video decoder and reinstantiate
611 // a fresh one.
612
613 LOGV("INFO_DISCONTINUITY");
614
615 CHECK(mVideoSource != NULL);
616
617 partial_reset_l();
618 postVideoEvent_l();
619 return;
620 } else if (mStreamDoneStatus != ERROR_END_OF_STREAM) {
Andreas Huber971305d2010-07-07 13:35:27 -0700621 LOGV("MEDIA_ERROR %d", mStreamDoneStatus);
622
623 notifyListener_l(
624 MEDIA_ERROR, MEDIA_ERROR_UNKNOWN, mStreamDoneStatus);
625
Andreas Huberc743f452010-10-05 10:25:34 -0700626 pause_l(true /* at eos */);
Andreas Huber971305d2010-07-07 13:35:27 -0700627
628 mFlags |= AT_EOS;
629 return;
630 }
631
632 const bool allDone =
633 (mVideoSource == NULL || (mFlags & VIDEO_AT_EOS))
634 && (mAudioSource == NULL || (mFlags & AUDIO_AT_EOS));
635
636 if (!allDone) {
637 return;
638 }
639
Andreas Huber9fee0b22010-09-03 14:09:21 -0700640 if (mFlags & (LOOPING | AUTO_LOOPING)) {
Andreas Huber27366fc2009-11-20 09:32:46 -0800641 seekTo_l(0);
642
Andreas Huber7085b6842010-02-03 16:02:02 -0800643 if (mVideoSource != NULL) {
Andreas Huber27366fc2009-11-20 09:32:46 -0800644 postVideoEvent_l();
645 }
646 } else {
Andreas Huber971305d2010-07-07 13:35:27 -0700647 LOGV("MEDIA_PLAYBACK_COMPLETE");
648 notifyListener_l(MEDIA_PLAYBACK_COMPLETE);
Andreas Huber27366fc2009-11-20 09:32:46 -0800649
Andreas Huberc743f452010-10-05 10:25:34 -0700650 pause_l(true /* at eos */);
Andreas Huber406a18b2010-02-18 16:45:13 -0800651
652 mFlags |= AT_EOS;
Andreas Huber27366fc2009-11-20 09:32:46 -0800653 }
654}
655
656status_t AwesomePlayer::play() {
657 Mutex::Autolock autoLock(mLock);
Andreas Huber4d61f602010-06-10 11:17:50 -0700658
659 mFlags &= ~CACHE_UNDERRUN;
660
Andreas Huberba7ec912010-02-12 10:42:02 -0800661 return play_l();
662}
Andreas Huber27366fc2009-11-20 09:32:46 -0800663
Andreas Huberba7ec912010-02-12 10:42:02 -0800664status_t AwesomePlayer::play_l() {
Andreas Huber27366fc2009-11-20 09:32:46 -0800665 if (mFlags & PLAYING) {
666 return OK;
667 }
668
Andreas Huberffdf4782010-02-09 14:05:43 -0800669 if (!(mFlags & PREPARED)) {
670 status_t err = prepare_l();
671
672 if (err != OK) {
673 return err;
674 }
675 }
676
Andreas Huber27366fc2009-11-20 09:32:46 -0800677 mFlags |= PLAYING;
678 mFlags |= FIRST_FRAME;
679
Andreas Huberc1d5c922009-12-10 15:49:04 -0800680 bool deferredAudioSeek = false;
681
Andreas Huber27366fc2009-11-20 09:32:46 -0800682 if (mAudioSource != NULL) {
683 if (mAudioPlayer == NULL) {
684 if (mAudioSink != NULL) {
Andreas Huber2b359ed2010-09-28 11:56:39 -0700685 mAudioPlayer = new AudioPlayer(mAudioSink, this);
Andreas Huber27366fc2009-11-20 09:32:46 -0800686 mAudioPlayer->setSource(mAudioSource);
Andreas Huberdc9927d2010-03-08 15:46:13 -0800687
688 // We've already started the MediaSource in order to enable
689 // the prefetcher to read its data.
690 status_t err = mAudioPlayer->start(
691 true /* sourceAlreadyStarted */);
Andreas Huber62eac002010-01-29 13:24:58 -0800692
693 if (err != OK) {
694 delete mAudioPlayer;
695 mAudioPlayer = NULL;
696
697 mFlags &= ~(PLAYING | FIRST_FRAME);
698
699 return err;
700 }
Andreas Huber27366fc2009-11-20 09:32:46 -0800701
Andreas Huber27366fc2009-11-20 09:32:46 -0800702 mTimeSource = mAudioPlayer;
703
Andreas Huberc1d5c922009-12-10 15:49:04 -0800704 deferredAudioSeek = true;
Andreas Huber70d10c02010-02-03 11:37:29 -0800705
706 mWatchForAudioSeekComplete = false;
707 mWatchForAudioEOS = true;
Andreas Huber27366fc2009-11-20 09:32:46 -0800708 }
709 } else {
710 mAudioPlayer->resume();
711 }
712 }
713
714 if (mTimeSource == NULL && mAudioPlayer == NULL) {
Andreas Huber971305d2010-07-07 13:35:27 -0700715 mTimeSource = &mSystemTimeSource;
Andreas Huber27366fc2009-11-20 09:32:46 -0800716 }
717
718 if (mVideoSource != NULL) {
Andreas Huber7085b6842010-02-03 16:02:02 -0800719 // Kick off video playback
720 postVideoEvent_l();
Andreas Huber27366fc2009-11-20 09:32:46 -0800721 }
722
Andreas Huberc1d5c922009-12-10 15:49:04 -0800723 if (deferredAudioSeek) {
724 // If there was a seek request while we were paused
725 // and we're just starting up again, honor the request now.
726 seekAudioIfNecessary_l();
727 }
728
Andreas Huber406a18b2010-02-18 16:45:13 -0800729 if (mFlags & AT_EOS) {
730 // Legacy behaviour, if a stream finishes playing and then
731 // is started again, we play from the start...
732 seekTo_l(0);
733 }
734
Andreas Huber27366fc2009-11-20 09:32:46 -0800735 return OK;
736}
737
738void AwesomePlayer::initRenderer_l() {
739 if (mISurface != NULL) {
740 sp<MetaData> meta = mVideoSource->getFormat();
741
742 int32_t format;
743 const char *component;
744 int32_t decodedWidth, decodedHeight;
745 CHECK(meta->findInt32(kKeyColorFormat, &format));
746 CHECK(meta->findCString(kKeyDecoderComponent, &component));
747 CHECK(meta->findInt32(kKeyWidth, &decodedWidth));
748 CHECK(meta->findInt32(kKeyHeight, &decodedHeight));
749
Andreas Hubera67d5382009-12-10 15:32:12 -0800750 mVideoRenderer.clear();
751
752 // Must ensure that mVideoRenderer's destructor is actually executed
753 // before creating a new one.
754 IPCThreadState::self()->flushCommands();
755
Andreas Huber1314e732009-12-14 14:18:22 -0800756 if (!strncmp("OMX.", component, 4)) {
757 // Our OMX codecs allocate buffers on the media_server side
758 // therefore they require a remote IOMXRenderer that knows how
759 // to display them.
760 mVideoRenderer = new AwesomeRemoteRenderer(
761 mClient.interface()->createRenderer(
762 mISurface, component,
763 (OMX_COLOR_FORMATTYPE)format,
764 decodedWidth, decodedHeight,
765 mVideoWidth, mVideoHeight));
766 } else {
767 // Other decoders are instantiated locally and as a consequence
768 // allocate their buffers in local address space.
769 mVideoRenderer = new AwesomeLocalRenderer(
Andreas Huber7b73cfc2010-02-12 14:40:08 -0800770 false, // previewOnly
Andreas Huber4ab5a6f2010-02-11 11:00:26 -0800771 component,
Andreas Huber1314e732009-12-14 14:18:22 -0800772 (OMX_COLOR_FORMATTYPE)format,
773 mISurface,
774 mVideoWidth, mVideoHeight,
775 decodedWidth, decodedHeight);
776 }
Andreas Huber27366fc2009-11-20 09:32:46 -0800777 }
778}
779
780status_t AwesomePlayer::pause() {
781 Mutex::Autolock autoLock(mLock);
Andreas Huber4d61f602010-06-10 11:17:50 -0700782
783 mFlags &= ~CACHE_UNDERRUN;
784
Andreas Huber27366fc2009-11-20 09:32:46 -0800785 return pause_l();
786}
787
Andreas Huberc743f452010-10-05 10:25:34 -0700788status_t AwesomePlayer::pause_l(bool at_eos) {
Andreas Huber27366fc2009-11-20 09:32:46 -0800789 if (!(mFlags & PLAYING)) {
790 return OK;
791 }
792
Andreas Huberb9e63832010-01-26 16:20:10 -0800793 cancelPlayerEvents(true /* keepBufferingGoing */);
Andreas Huber27366fc2009-11-20 09:32:46 -0800794
795 if (mAudioPlayer != NULL) {
Andreas Huberc743f452010-10-05 10:25:34 -0700796 if (at_eos) {
797 // If we played the audio stream to completion we
798 // want to make sure that all samples remaining in the audio
799 // track's queue are played out.
800 mAudioPlayer->pause(true /* playPendingSamples */);
801 } else {
802 mAudioPlayer->pause();
803 }
Andreas Huber27366fc2009-11-20 09:32:46 -0800804 }
805
806 mFlags &= ~PLAYING;
807
808 return OK;
809}
810
811bool AwesomePlayer::isPlaying() const {
Andreas Huber4d61f602010-06-10 11:17:50 -0700812 return (mFlags & PLAYING) || (mFlags & CACHE_UNDERRUN);
Andreas Huber27366fc2009-11-20 09:32:46 -0800813}
814
815void AwesomePlayer::setISurface(const sp<ISurface> &isurface) {
816 Mutex::Autolock autoLock(mLock);
817
818 mISurface = isurface;
819}
820
821void AwesomePlayer::setAudioSink(
822 const sp<MediaPlayerBase::AudioSink> &audioSink) {
823 Mutex::Autolock autoLock(mLock);
824
825 mAudioSink = audioSink;
826}
827
828status_t AwesomePlayer::setLooping(bool shouldLoop) {
829 Mutex::Autolock autoLock(mLock);
830
831 mFlags = mFlags & ~LOOPING;
832
833 if (shouldLoop) {
834 mFlags |= LOOPING;
835 }
836
837 return OK;
838}
839
840status_t AwesomePlayer::getDuration(int64_t *durationUs) {
Andreas Huber252573c2010-03-26 10:17:17 -0700841 Mutex::Autolock autoLock(mMiscStateLock);
Andreas Huber27366fc2009-11-20 09:32:46 -0800842
843 if (mDurationUs < 0) {
844 return UNKNOWN_ERROR;
845 }
846
847 *durationUs = mDurationUs;
848
849 return OK;
850}
851
852status_t AwesomePlayer::getPosition(int64_t *positionUs) {
Andreas Hubereeb97d92010-08-27 13:29:08 -0700853 if (mRTSPController != NULL) {
854 *positionUs = mRTSPController->getNormalPlayTimeUs();
855 }
856 else if (mSeeking) {
Andreas Huberddb709c2010-04-07 10:24:35 -0700857 *positionUs = mSeekTimeUs;
858 } else if (mVideoSource != NULL) {
Andreas Huber252573c2010-03-26 10:17:17 -0700859 Mutex::Autolock autoLock(mMiscStateLock);
Andreas Huber27366fc2009-11-20 09:32:46 -0800860 *positionUs = mVideoTimeUs;
861 } else if (mAudioPlayer != NULL) {
862 *positionUs = mAudioPlayer->getMediaTimeUs();
863 } else {
864 *positionUs = 0;
865 }
866
867 return OK;
868}
869
870status_t AwesomePlayer::seekTo(int64_t timeUs) {
Andreas Huber10b9b3f2010-10-08 10:16:24 -0700871 if (mExtractorFlags & MediaExtractor::CAN_SEEK) {
Andreas Huber62f7ffe2010-05-06 10:18:05 -0700872 Mutex::Autolock autoLock(mLock);
873 return seekTo_l(timeUs);
874 }
875
876 return OK;
Andreas Huber27366fc2009-11-20 09:32:46 -0800877}
878
Andreas Huber0c46b692010-10-08 15:21:08 -0700879// static
880void AwesomePlayer::OnRTSPSeekDoneWrapper(void *cookie) {
881 static_cast<AwesomePlayer *>(cookie)->onRTSPSeekDone();
882}
883
884void AwesomePlayer::onRTSPSeekDone() {
885 notifyListener_l(MEDIA_SEEK_COMPLETE);
886 mSeekNotificationSent = true;
887}
888
Andreas Huber27366fc2009-11-20 09:32:46 -0800889status_t AwesomePlayer::seekTo_l(int64_t timeUs) {
Andreas Hubere0dd7d32010-08-24 14:33:58 -0700890 if (mRTSPController != NULL) {
Andreas Huber0c46b692010-10-08 15:21:08 -0700891 mRTSPController->seekAsync(timeUs, OnRTSPSeekDoneWrapper, this);
Andreas Hubere0dd7d32010-08-24 14:33:58 -0700892 return OK;
893 }
894
Andreas Huber4d61f602010-06-10 11:17:50 -0700895 if (mFlags & CACHE_UNDERRUN) {
896 mFlags &= ~CACHE_UNDERRUN;
897 play_l();
898 }
899
Andreas Huber27366fc2009-11-20 09:32:46 -0800900 mSeeking = true;
Andreas Huber8e2b9412010-03-31 09:40:15 -0700901 mSeekNotificationSent = false;
Andreas Huber27366fc2009-11-20 09:32:46 -0800902 mSeekTimeUs = timeUs;
Andreas Huber971305d2010-07-07 13:35:27 -0700903 mFlags &= ~(AT_EOS | AUDIO_AT_EOS | VIDEO_AT_EOS);
Andreas Huber27366fc2009-11-20 09:32:46 -0800904
905 seekAudioIfNecessary_l();
906
Andreas Huber8e2b9412010-03-31 09:40:15 -0700907 if (!(mFlags & PLAYING)) {
908 LOGV("seeking while paused, sending SEEK_COMPLETE notification"
909 " immediately.");
910
911 notifyListener_l(MEDIA_SEEK_COMPLETE);
912 mSeekNotificationSent = true;
913 }
914
Andreas Huber27366fc2009-11-20 09:32:46 -0800915 return OK;
916}
917
918void AwesomePlayer::seekAudioIfNecessary_l() {
Andreas Huber7085b6842010-02-03 16:02:02 -0800919 if (mSeeking && mVideoSource == NULL && mAudioPlayer != NULL) {
Andreas Huber27366fc2009-11-20 09:32:46 -0800920 mAudioPlayer->seekTo(mSeekTimeUs);
921
Andreas Huber70d10c02010-02-03 11:37:29 -0800922 mWatchForAudioSeekComplete = true;
923 mWatchForAudioEOS = true;
Andreas Huber8e2b9412010-03-31 09:40:15 -0700924 mSeekNotificationSent = false;
Andreas Huber27366fc2009-11-20 09:32:46 -0800925 }
926}
927
928status_t AwesomePlayer::getVideoDimensions(
929 int32_t *width, int32_t *height) const {
930 Mutex::Autolock autoLock(mLock);
931
932 if (mVideoWidth < 0 || mVideoHeight < 0) {
933 return UNKNOWN_ERROR;
934 }
935
936 *width = mVideoWidth;
937 *height = mVideoHeight;
938
939 return OK;
940}
941
Andreas Huber3ac94ef2010-03-05 10:42:10 -0800942void AwesomePlayer::setAudioSource(sp<MediaSource> source) {
943 CHECK(source != NULL);
Andreas Huber27366fc2009-11-20 09:32:46 -0800944
Andreas Huber3ac94ef2010-03-05 10:42:10 -0800945 mAudioTrack = source;
946}
947
948status_t AwesomePlayer::initAudioDecoder() {
949 sp<MetaData> meta = mAudioTrack->getFormat();
Andreas Huberc79827a2010-01-05 10:54:55 -0800950
951 const char *mime;
952 CHECK(meta->findCString(kKeyMIMEType, &mime));
953
954 if (!strcasecmp(mime, MEDIA_MIMETYPE_AUDIO_RAW)) {
Andreas Huber3ac94ef2010-03-05 10:42:10 -0800955 mAudioSource = mAudioTrack;
Andreas Huberc79827a2010-01-05 10:54:55 -0800956 } else {
957 mAudioSource = OMXCodec::Create(
Andreas Huber3ac94ef2010-03-05 10:42:10 -0800958 mClient.interface(), mAudioTrack->getFormat(),
Andreas Huberc79827a2010-01-05 10:54:55 -0800959 false, // createEncoder
Andreas Huber3ac94ef2010-03-05 10:42:10 -0800960 mAudioTrack);
Andreas Huberc79827a2010-01-05 10:54:55 -0800961 }
Andreas Huber27366fc2009-11-20 09:32:46 -0800962
963 if (mAudioSource != NULL) {
964 int64_t durationUs;
Andreas Huber3ac94ef2010-03-05 10:42:10 -0800965 if (mAudioTrack->getFormat()->findInt64(kKeyDuration, &durationUs)) {
Andreas Huber252573c2010-03-26 10:17:17 -0700966 Mutex::Autolock autoLock(mMiscStateLock);
Andreas Huber27366fc2009-11-20 09:32:46 -0800967 if (mDurationUs < 0 || durationUs > mDurationUs) {
968 mDurationUs = durationUs;
969 }
970 }
Andreas Huber27366fc2009-11-20 09:32:46 -0800971
Andreas Huber3c78a1b2010-05-13 09:15:21 -0700972 status_t err = mAudioSource->start();
973
974 if (err != OK) {
975 mAudioSource.clear();
976 return err;
977 }
Andreas Huberd0332ad2010-04-12 16:05:57 -0700978 } else if (!strcasecmp(mime, MEDIA_MIMETYPE_AUDIO_QCELP)) {
979 // For legacy reasons we're simply going to ignore the absence
980 // of an audio decoder for QCELP instead of aborting playback
981 // altogether.
982 return OK;
983 }
Andreas Huberdc9927d2010-03-08 15:46:13 -0800984
Andreas Huber27366fc2009-11-20 09:32:46 -0800985 return mAudioSource != NULL ? OK : UNKNOWN_ERROR;
986}
987
Andreas Huber3ac94ef2010-03-05 10:42:10 -0800988void AwesomePlayer::setVideoSource(sp<MediaSource> source) {
989 CHECK(source != NULL);
Andreas Huber27366fc2009-11-20 09:32:46 -0800990
Andreas Huber3ac94ef2010-03-05 10:42:10 -0800991 mVideoTrack = source;
992}
993
Andreas Huber4c19bf92010-09-08 14:32:20 -0700994status_t AwesomePlayer::initVideoDecoder(uint32_t flags) {
Andreas Huber27366fc2009-11-20 09:32:46 -0800995 mVideoSource = OMXCodec::Create(
Andreas Huber3ac94ef2010-03-05 10:42:10 -0800996 mClient.interface(), mVideoTrack->getFormat(),
Andreas Huber27366fc2009-11-20 09:32:46 -0800997 false, // createEncoder
Andreas Huber57648e42010-08-04 10:14:30 -0700998 mVideoTrack,
999 NULL, flags);
Andreas Huber27366fc2009-11-20 09:32:46 -08001000
1001 if (mVideoSource != NULL) {
1002 int64_t durationUs;
Andreas Huber3ac94ef2010-03-05 10:42:10 -08001003 if (mVideoTrack->getFormat()->findInt64(kKeyDuration, &durationUs)) {
Andreas Huber252573c2010-03-26 10:17:17 -07001004 Mutex::Autolock autoLock(mMiscStateLock);
Andreas Huber27366fc2009-11-20 09:32:46 -08001005 if (mDurationUs < 0 || durationUs > mDurationUs) {
1006 mDurationUs = durationUs;
1007 }
1008 }
1009
Andreas Huber3ac94ef2010-03-05 10:42:10 -08001010 CHECK(mVideoTrack->getFormat()->findInt32(kKeyWidth, &mVideoWidth));
1011 CHECK(mVideoTrack->getFormat()->findInt32(kKeyHeight, &mVideoHeight));
Andreas Huber27366fc2009-11-20 09:32:46 -08001012
Andreas Huber1919e5a2010-05-20 10:37:06 -07001013 status_t err = mVideoSource->start();
1014
1015 if (err != OK) {
1016 mVideoSource.clear();
1017 return err;
1018 }
Andreas Huber27366fc2009-11-20 09:32:46 -08001019 }
1020
1021 return mVideoSource != NULL ? OK : UNKNOWN_ERROR;
1022}
1023
Andreas Huber6be780e2010-02-08 14:40:30 -08001024void AwesomePlayer::onVideoEvent() {
Andreas Huber27366fc2009-11-20 09:32:46 -08001025 Mutex::Autolock autoLock(mLock);
Andreas Huberba7ec912010-02-12 10:42:02 -08001026 if (!mVideoEventPending) {
1027 // The event has been cancelled in reset_l() but had already
1028 // been scheduled for execution at that time.
1029 return;
1030 }
Andreas Huber27366fc2009-11-20 09:32:46 -08001031 mVideoEventPending = false;
1032
1033 if (mSeeking) {
1034 if (mLastVideoBuffer) {
1035 mLastVideoBuffer->release();
1036 mLastVideoBuffer = NULL;
1037 }
1038
1039 if (mVideoBuffer) {
1040 mVideoBuffer->release();
1041 mVideoBuffer = NULL;
1042 }
Andreas Huber4d61f602010-06-10 11:17:50 -07001043
1044 if (mCachedSource != NULL && mAudioSource != NULL) {
1045 // We're going to seek the video source first, followed by
1046 // the audio source.
1047 // In order to avoid jumps in the DataSource offset caused by
1048 // the audio codec prefetching data from the old locations
1049 // while the video codec is already reading data from the new
1050 // locations, we'll "pause" the audio source, causing it to
1051 // stop reading input data until a subsequent seek.
1052
1053 if (mAudioPlayer != NULL) {
1054 mAudioPlayer->pause();
1055 }
1056 mAudioSource->pause();
1057 }
Andreas Huber27366fc2009-11-20 09:32:46 -08001058 }
1059
1060 if (!mVideoBuffer) {
1061 MediaSource::ReadOptions options;
1062 if (mSeeking) {
1063 LOGV("seeking to %lld us (%.2f secs)", mSeekTimeUs, mSeekTimeUs / 1E6);
1064
Andreas Huber6624c9f2010-07-20 15:04:28 -07001065 options.setSeekTo(
1066 mSeekTimeUs, MediaSource::ReadOptions::SEEK_CLOSEST_SYNC);
Andreas Huber27366fc2009-11-20 09:32:46 -08001067 }
1068 for (;;) {
1069 status_t err = mVideoSource->read(&mVideoBuffer, &options);
Andreas Huberb1f5ee42009-12-14 15:34:11 -08001070 options.clearSeekTo();
Andreas Huber27366fc2009-11-20 09:32:46 -08001071
1072 if (err != OK) {
1073 CHECK_EQ(mVideoBuffer, NULL);
1074
1075 if (err == INFO_FORMAT_CHANGED) {
1076 LOGV("VideoSource signalled format change.");
1077
Andreas Huber7085b6842010-02-03 16:02:02 -08001078 if (mVideoRenderer != NULL) {
Andreas Huber7b73cfc2010-02-12 14:40:08 -08001079 mVideoRendererIsPreview = false;
Andreas Huber7085b6842010-02-03 16:02:02 -08001080 initRenderer_l();
1081 }
Andreas Huber27366fc2009-11-20 09:32:46 -08001082 continue;
1083 }
1084
Andreas Huber971305d2010-07-07 13:35:27 -07001085 mFlags |= VIDEO_AT_EOS;
Andreas Huberd7d22eb2010-02-23 13:45:33 -08001086 postStreamDoneEvent_l(err);
Andreas Huber27366fc2009-11-20 09:32:46 -08001087 return;
1088 }
1089
Andreas Hubera67d5382009-12-10 15:32:12 -08001090 if (mVideoBuffer->range_length() == 0) {
Andreas Huber6ddcf012009-12-10 15:32:12 -08001091 // Some decoders, notably the PV AVC software decoder
1092 // return spurious empty buffers that we just want to ignore.
1093
Andreas Hubera67d5382009-12-10 15:32:12 -08001094 mVideoBuffer->release();
1095 mVideoBuffer = NULL;
1096 continue;
1097 }
1098
Andreas Huber27366fc2009-11-20 09:32:46 -08001099 break;
1100 }
1101 }
1102
1103 int64_t timeUs;
1104 CHECK(mVideoBuffer->meta_data()->findInt64(kKeyTime, &timeUs));
1105
Andreas Huber252573c2010-03-26 10:17:17 -07001106 {
1107 Mutex::Autolock autoLock(mMiscStateLock);
1108 mVideoTimeUs = timeUs;
1109 }
Andreas Huber27366fc2009-11-20 09:32:46 -08001110
1111 if (mSeeking) {
1112 if (mAudioPlayer != NULL) {
1113 LOGV("seeking audio to %lld us (%.2f secs).", timeUs, timeUs / 1E6);
1114
1115 mAudioPlayer->seekTo(timeUs);
Andreas Huber4d61f602010-06-10 11:17:50 -07001116 mAudioPlayer->resume();
Andreas Huber70d10c02010-02-03 11:37:29 -08001117 mWatchForAudioSeekComplete = true;
1118 mWatchForAudioEOS = true;
Andreas Huber8e2b9412010-03-31 09:40:15 -07001119 } else if (!mSeekNotificationSent) {
Andreas Huber27366fc2009-11-20 09:32:46 -08001120 // If we're playing video only, report seek complete now,
1121 // otherwise audio player will notify us later.
Andreas Hubera3f43842010-01-21 10:28:45 -08001122 notifyListener_l(MEDIA_SEEK_COMPLETE);
Andreas Huber27366fc2009-11-20 09:32:46 -08001123 }
1124
1125 mFlags |= FIRST_FRAME;
1126 mSeeking = false;
Andreas Huber8e2b9412010-03-31 09:40:15 -07001127 mSeekNotificationSent = false;
Andreas Huber27366fc2009-11-20 09:32:46 -08001128 }
1129
Andreas Huber971305d2010-07-07 13:35:27 -07001130 TimeSource *ts = (mFlags & AUDIO_AT_EOS) ? &mSystemTimeSource : mTimeSource;
1131
Andreas Huber27366fc2009-11-20 09:32:46 -08001132 if (mFlags & FIRST_FRAME) {
1133 mFlags &= ~FIRST_FRAME;
1134
Andreas Huber971305d2010-07-07 13:35:27 -07001135 mTimeSourceDeltaUs = ts->getRealTimeUs() - timeUs;
Andreas Huber27366fc2009-11-20 09:32:46 -08001136 }
1137
1138 int64_t realTimeUs, mediaTimeUs;
Andreas Huber971305d2010-07-07 13:35:27 -07001139 if (!(mFlags & AUDIO_AT_EOS) && mAudioPlayer != NULL
Andreas Huber27366fc2009-11-20 09:32:46 -08001140 && mAudioPlayer->getMediaTimeMapping(&realTimeUs, &mediaTimeUs)) {
1141 mTimeSourceDeltaUs = realTimeUs - mediaTimeUs;
1142 }
1143
Andreas Huber971305d2010-07-07 13:35:27 -07001144 int64_t nowUs = ts->getRealTimeUs() - mTimeSourceDeltaUs;
Andreas Huber27366fc2009-11-20 09:32:46 -08001145
1146 int64_t latenessUs = nowUs - timeUs;
1147
Andreas Huberf88f8442010-08-10 11:18:36 -07001148 if (mRTPSession != NULL) {
1149 // We'll completely ignore timestamps for gtalk videochat
1150 // and we'll play incoming video as fast as we get it.
1151 latenessUs = 0;
1152 }
1153
Andreas Huber24b0a952009-11-23 14:02:00 -08001154 if (latenessUs > 40000) {
1155 // We're more than 40ms late.
Andreas Huber4a9375e2010-02-09 11:54:33 -08001156 LOGV("we're late by %lld us (%.2f secs)", latenessUs, latenessUs / 1E6);
Andreas Huber27366fc2009-11-20 09:32:46 -08001157
1158 mVideoBuffer->release();
1159 mVideoBuffer = NULL;
1160
1161 postVideoEvent_l();
1162 return;
1163 }
1164
1165 if (latenessUs < -10000) {
1166 // We're more than 10ms early.
1167
1168 postVideoEvent_l(10000);
1169 return;
1170 }
1171
Andreas Huber7b73cfc2010-02-12 14:40:08 -08001172 if (mVideoRendererIsPreview || mVideoRenderer == NULL) {
1173 mVideoRendererIsPreview = false;
1174
Andreas Huber7085b6842010-02-03 16:02:02 -08001175 initRenderer_l();
1176 }
1177
1178 if (mVideoRenderer != NULL) {
1179 mVideoRenderer->render(mVideoBuffer);
1180 }
Andreas Huber27366fc2009-11-20 09:32:46 -08001181
1182 if (mLastVideoBuffer) {
1183 mLastVideoBuffer->release();
1184 mLastVideoBuffer = NULL;
1185 }
1186 mLastVideoBuffer = mVideoBuffer;
1187 mVideoBuffer = NULL;
1188
1189 postVideoEvent_l();
1190}
1191
1192void AwesomePlayer::postVideoEvent_l(int64_t delayUs) {
1193 if (mVideoEventPending) {
1194 return;
1195 }
1196
1197 mVideoEventPending = true;
1198 mQueue.postEventWithDelay(mVideoEvent, delayUs < 0 ? 10000 : delayUs);
1199}
1200
Andreas Huberd7d22eb2010-02-23 13:45:33 -08001201void AwesomePlayer::postStreamDoneEvent_l(status_t status) {
Andreas Huber27366fc2009-11-20 09:32:46 -08001202 if (mStreamDoneEventPending) {
1203 return;
1204 }
1205 mStreamDoneEventPending = true;
Andreas Huberd7d22eb2010-02-23 13:45:33 -08001206
1207 mStreamDoneStatus = status;
Andreas Huber27366fc2009-11-20 09:32:46 -08001208 mQueue.postEvent(mStreamDoneEvent);
1209}
1210
Andreas Huberb9e63832010-01-26 16:20:10 -08001211void AwesomePlayer::postBufferingEvent_l() {
Andreas Huberb9e63832010-01-26 16:20:10 -08001212 if (mBufferingEventPending) {
1213 return;
1214 }
1215 mBufferingEventPending = true;
1216 mQueue.postEventWithDelay(mBufferingEvent, 1000000ll);
1217}
1218
Andreas Huber70d10c02010-02-03 11:37:29 -08001219void AwesomePlayer::postCheckAudioStatusEvent_l() {
1220 if (mAudioStatusEventPending) {
1221 return;
1222 }
1223 mAudioStatusEventPending = true;
Andreas Huber2b359ed2010-09-28 11:56:39 -07001224 mQueue.postEvent(mCheckAudioStatusEvent);
Andreas Huber70d10c02010-02-03 11:37:29 -08001225}
1226
1227void AwesomePlayer::onCheckAudioStatus() {
1228 Mutex::Autolock autoLock(mLock);
Andreas Huberc0178f12010-02-17 15:58:57 -08001229 if (!mAudioStatusEventPending) {
1230 // Event was dispatched and while we were blocking on the mutex,
1231 // has already been cancelled.
1232 return;
1233 }
1234
Andreas Huber70d10c02010-02-03 11:37:29 -08001235 mAudioStatusEventPending = false;
1236
1237 if (mWatchForAudioSeekComplete && !mAudioPlayer->isSeeking()) {
1238 mWatchForAudioSeekComplete = false;
Andreas Huber8e2b9412010-03-31 09:40:15 -07001239
1240 if (!mSeekNotificationSent) {
1241 notifyListener_l(MEDIA_SEEK_COMPLETE);
1242 mSeekNotificationSent = true;
1243 }
Andreas Huberddb709c2010-04-07 10:24:35 -07001244
1245 mSeeking = false;
Andreas Huber70d10c02010-02-03 11:37:29 -08001246 }
1247
Andreas Huberd7d22eb2010-02-23 13:45:33 -08001248 status_t finalStatus;
1249 if (mWatchForAudioEOS && mAudioPlayer->reachedEOS(&finalStatus)) {
Andreas Huber70d10c02010-02-03 11:37:29 -08001250 mWatchForAudioEOS = false;
Andreas Huber971305d2010-07-07 13:35:27 -07001251 mFlags |= AUDIO_AT_EOS;
1252 mFlags |= FIRST_FRAME;
Andreas Huberd7d22eb2010-02-23 13:45:33 -08001253 postStreamDoneEvent_l(finalStatus);
Andreas Huber70d10c02010-02-03 11:37:29 -08001254 }
Andreas Huber70d10c02010-02-03 11:37:29 -08001255}
1256
Andreas Huber6be780e2010-02-08 14:40:30 -08001257status_t AwesomePlayer::prepare() {
1258 Mutex::Autolock autoLock(mLock);
Andreas Huberffdf4782010-02-09 14:05:43 -08001259 return prepare_l();
1260}
Andreas Huber6be780e2010-02-08 14:40:30 -08001261
Andreas Huberffdf4782010-02-09 14:05:43 -08001262status_t AwesomePlayer::prepare_l() {
1263 if (mFlags & PREPARED) {
1264 return OK;
1265 }
1266
1267 if (mFlags & PREPARING) {
1268 return UNKNOWN_ERROR;
1269 }
1270
1271 mIsAsyncPrepare = false;
Andreas Huber6be780e2010-02-08 14:40:30 -08001272 status_t err = prepareAsync_l();
1273
1274 if (err != OK) {
1275 return err;
1276 }
1277
Andreas Huberffdf4782010-02-09 14:05:43 -08001278 while (mFlags & PREPARING) {
Andreas Huber6be780e2010-02-08 14:40:30 -08001279 mPreparedCondition.wait(mLock);
1280 }
1281
Andreas Huberffdf4782010-02-09 14:05:43 -08001282 return mPrepareResult;
Andreas Huber6be780e2010-02-08 14:40:30 -08001283}
1284
1285status_t AwesomePlayer::prepareAsync() {
1286 Mutex::Autolock autoLock(mLock);
Andreas Huberffdf4782010-02-09 14:05:43 -08001287
1288 if (mFlags & PREPARING) {
1289 return UNKNOWN_ERROR; // async prepare already pending
1290 }
1291
1292 mIsAsyncPrepare = true;
Andreas Huber6be780e2010-02-08 14:40:30 -08001293 return prepareAsync_l();
1294}
1295
1296status_t AwesomePlayer::prepareAsync_l() {
Andreas Huberffdf4782010-02-09 14:05:43 -08001297 if (mFlags & PREPARING) {
1298 return UNKNOWN_ERROR; // async prepare already pending
Andreas Huber6be780e2010-02-08 14:40:30 -08001299 }
1300
Andreas Huber406a18b2010-02-18 16:45:13 -08001301 if (!mQueueStarted) {
1302 mQueue.start();
1303 mQueueStarted = true;
1304 }
1305
Andreas Huberffdf4782010-02-09 14:05:43 -08001306 mFlags |= PREPARING;
Andreas Huber6be780e2010-02-08 14:40:30 -08001307 mAsyncPrepareEvent = new AwesomeEvent(
1308 this, &AwesomePlayer::onPrepareAsyncEvent);
1309
1310 mQueue.postEvent(mAsyncPrepareEvent);
1311
1312 return OK;
1313}
1314
Andreas Huberffdf4782010-02-09 14:05:43 -08001315status_t AwesomePlayer::finishSetDataSource_l() {
Andreas Huberedbb4d82010-03-12 08:59:22 -08001316 sp<DataSource> dataSource;
1317
1318 if (!strncasecmp("http://", mUri.string(), 7)) {
Andreas Huber4d61f602010-06-10 11:17:50 -07001319 mConnectingDataSource = new NuHTTPDataSource;
Andreas Huberedbb4d82010-03-12 08:59:22 -08001320
1321 mLock.unlock();
Andreas Huber3a53dc52010-06-11 09:57:46 -07001322 status_t err = mConnectingDataSource->connect(mUri, &mUriHeaders);
Andreas Huberedbb4d82010-03-12 08:59:22 -08001323 mLock.lock();
1324
1325 if (err != OK) {
1326 mConnectingDataSource.clear();
1327
1328 LOGI("mConnectingDataSource->connect() returned %d", err);
1329 return err;
1330 }
1331
Andreas Huber4d61f602010-06-10 11:17:50 -07001332#if 0
1333 mCachedSource = new NuCachedSource2(
1334 new ThrottledSource(
1335 mConnectingDataSource, 50 * 1024 /* bytes/sec */));
1336#else
1337 mCachedSource = new NuCachedSource2(mConnectingDataSource);
1338#endif
Andreas Huberedbb4d82010-03-12 08:59:22 -08001339 mConnectingDataSource.clear();
Andreas Huber4d61f602010-06-10 11:17:50 -07001340
1341 dataSource = mCachedSource;
Andreas Huber202348e2010-06-07 14:35:29 -07001342 } else if (!strncasecmp(mUri.string(), "httplive://", 11)) {
1343 String8 uri("http://");
1344 uri.append(mUri.string() + 11);
1345
1346 dataSource = new LiveSource(uri.string());
1347
Andreas Huber4d61f602010-06-10 11:17:50 -07001348 mCachedSource = new NuCachedSource2(dataSource);
1349 dataSource = mCachedSource;
Andreas Huber202348e2010-06-07 14:35:29 -07001350
1351 sp<MediaExtractor> extractor =
1352 MediaExtractor::Create(dataSource, MEDIA_MIMETYPE_CONTAINER_MPEG2TS);
Andreas Huber4d61f602010-06-10 11:17:50 -07001353
1354 return setDataSource_l(extractor);
Mike Dodd8741dfa2010-08-12 16:04:35 -07001355 } else if (!strncmp("rtsp://gtalk/", mUri.string(), 13)) {
Andreas Huber57648e42010-08-04 10:14:30 -07001356 if (mLooper == NULL) {
1357 mLooper = new ALooper;
Andreas Huberc4e0b702010-08-27 15:21:07 -07001358 mLooper->setName("gtalk rtp");
Andreas Huber3eaa3002010-08-05 09:22:25 -07001359 mLooper->start(
1360 false /* runOnCallingThread */,
1361 false /* canCallJava */,
1362 PRIORITY_HIGHEST);
Andreas Huber57648e42010-08-04 10:14:30 -07001363 }
1364
Mike Dodd8741dfa2010-08-12 16:04:35 -07001365 const char *startOfCodecString = &mUri.string()[13];
1366 const char *startOfSlash1 = strchr(startOfCodecString, '/');
1367 if (startOfSlash1 == NULL) {
1368 return BAD_VALUE;
1369 }
1370 const char *startOfWidthString = &startOfSlash1[1];
1371 const char *startOfSlash2 = strchr(startOfWidthString, '/');
1372 if (startOfSlash2 == NULL) {
1373 return BAD_VALUE;
1374 }
1375 const char *startOfHeightString = &startOfSlash2[1];
1376
1377 String8 codecString(startOfCodecString, startOfSlash1 - startOfCodecString);
1378 String8 widthString(startOfWidthString, startOfSlash2 - startOfWidthString);
1379 String8 heightString(startOfHeightString);
1380
Andreas Huber57648e42010-08-04 10:14:30 -07001381#if 0
1382 mRTPPusher = new UDPPusher("/data/misc/rtpout.bin", 5434);
1383 mLooper->registerHandler(mRTPPusher);
1384
1385 mRTCPPusher = new UDPPusher("/data/misc/rtcpout.bin", 5435);
1386 mLooper->registerHandler(mRTCPPusher);
1387#endif
1388
1389 mRTPSession = new ARTPSession;
1390 mLooper->registerHandler(mRTPSession);
1391
1392#if 0
Andreas Huber57648e42010-08-04 10:14:30 -07001393 // My AMR SDP
1394 static const char *raw =
1395 "v=0\r\n"
1396 "o=- 64 233572944 IN IP4 127.0.0.0\r\n"
1397 "s=QuickTime\r\n"
1398 "t=0 0\r\n"
1399 "a=range:npt=0-315\r\n"
1400 "a=isma-compliance:2,2.0,2\r\n"
1401 "m=audio 5434 RTP/AVP 97\r\n"
1402 "c=IN IP4 127.0.0.1\r\n"
1403 "b=AS:30\r\n"
1404 "a=rtpmap:97 AMR/8000/1\r\n"
1405 "a=fmtp:97 octet-align\r\n";
1406#elif 1
Mike Dodd8741dfa2010-08-12 16:04:35 -07001407 String8 sdp;
1408 sdp.appendFormat(
Andreas Huber57648e42010-08-04 10:14:30 -07001409 "v=0\r\n"
1410 "o=- 64 233572944 IN IP4 127.0.0.0\r\n"
1411 "s=QuickTime\r\n"
1412 "t=0 0\r\n"
1413 "a=range:npt=0-315\r\n"
1414 "a=isma-compliance:2,2.0,2\r\n"
1415 "m=video 5434 RTP/AVP 97\r\n"
1416 "c=IN IP4 127.0.0.1\r\n"
1417 "b=AS:30\r\n"
Mike Dodd8741dfa2010-08-12 16:04:35 -07001418 "a=rtpmap:97 %s/90000\r\n"
1419 "a=cliprect:0,0,%s,%s\r\n"
1420 "a=framesize:97 %s-%s\r\n",
1421
1422 codecString.string(),
1423 heightString.string(), widthString.string(),
1424 widthString.string(), heightString.string()
1425 );
1426 const char *raw = sdp.string();
1427
Andreas Huber57648e42010-08-04 10:14:30 -07001428#endif
1429
1430 sp<ASessionDescription> desc = new ASessionDescription;
1431 CHECK(desc->setTo(raw, strlen(raw)));
1432
1433 CHECK_EQ(mRTPSession->setup(desc), (status_t)OK);
1434
1435 if (mRTPPusher != NULL) {
1436 mRTPPusher->start();
1437 }
1438
1439 if (mRTCPPusher != NULL) {
1440 mRTCPPusher->start();
1441 }
1442
1443 CHECK_EQ(mRTPSession->countTracks(), 1u);
1444 sp<MediaSource> source = mRTPSession->trackAt(0);
1445
1446#if 0
1447 bool eos;
1448 while (((APacketSource *)source.get())
1449 ->getQueuedDuration(&eos) < 5000000ll && !eos) {
1450 usleep(100000ll);
1451 }
1452#endif
1453
1454 const char *mime;
1455 CHECK(source->getFormat()->findCString(kKeyMIMEType, &mime));
1456
1457 if (!strncasecmp("video/", mime, 6)) {
1458 setVideoSource(source);
1459 } else {
1460 CHECK(!strncasecmp("audio/", mime, 6));
1461 setAudioSource(source);
1462 }
1463
1464 mExtractorFlags = MediaExtractor::CAN_PAUSE;
1465
1466 return OK;
Andreas Huber7a747b82010-06-07 15:19:40 -07001467 } else if (!strncasecmp("rtsp://", mUri.string(), 7)) {
1468 if (mLooper == NULL) {
1469 mLooper = new ALooper;
Andreas Huberc4e0b702010-08-27 15:21:07 -07001470 mLooper->setName("rtsp");
Andreas Huber7a747b82010-06-07 15:19:40 -07001471 mLooper->start();
1472 }
1473 mRTSPController = new ARTSPController(mLooper);
1474 status_t err = mRTSPController->connect(mUri.string());
Andreas Huber202348e2010-06-07 14:35:29 -07001475
Andreas Huber7a747b82010-06-07 15:19:40 -07001476 LOGI("ARTSPController::connect returned %d", err);
1477
1478 if (err != OK) {
1479 mRTSPController.clear();
1480 return err;
1481 }
1482
1483 sp<MediaExtractor> extractor = mRTSPController.get();
Andreas Huber202348e2010-06-07 14:35:29 -07001484 return setDataSource_l(extractor);
Andreas Huberedbb4d82010-03-12 08:59:22 -08001485 } else {
1486 dataSource = DataSource::CreateFromURI(mUri.string(), &mUriHeaders);
1487 }
Andreas Huberffdf4782010-02-09 14:05:43 -08001488
1489 if (dataSource == NULL) {
1490 return UNKNOWN_ERROR;
1491 }
1492
1493 sp<MediaExtractor> extractor = MediaExtractor::Create(dataSource);
1494
1495 if (extractor == NULL) {
1496 return UNKNOWN_ERROR;
1497 }
1498
Andreas Huberffdf4782010-02-09 14:05:43 -08001499 return setDataSource_l(extractor);
1500}
1501
Andreas Huber3ac94ef2010-03-05 10:42:10 -08001502void AwesomePlayer::abortPrepare(status_t err) {
1503 CHECK(err != OK);
1504
1505 if (mIsAsyncPrepare) {
1506 notifyListener_l(MEDIA_ERROR, MEDIA_ERROR_UNKNOWN, err);
1507 }
1508
1509 mPrepareResult = err;
Andreas Huberedbb4d82010-03-12 08:59:22 -08001510 mFlags &= ~(PREPARING|PREPARE_CANCELLED);
Andreas Huber3ac94ef2010-03-05 10:42:10 -08001511 mAsyncPrepareEvent = NULL;
1512 mPreparedCondition.broadcast();
1513}
1514
Andreas Huberf71daba2010-03-24 09:24:40 -07001515// static
1516bool AwesomePlayer::ContinuePreparation(void *cookie) {
1517 AwesomePlayer *me = static_cast<AwesomePlayer *>(cookie);
1518
1519 return (me->mFlags & PREPARE_CANCELLED) == 0;
1520}
1521
Andreas Huber6be780e2010-02-08 14:40:30 -08001522void AwesomePlayer::onPrepareAsyncEvent() {
Andreas Huber87ab9cd2010-09-03 13:20:33 -07001523 Mutex::Autolock autoLock(mLock);
Andreas Huberffdf4782010-02-09 14:05:43 -08001524
Andreas Huber87ab9cd2010-09-03 13:20:33 -07001525 if (mFlags & PREPARE_CANCELLED) {
1526 LOGI("prepare was cancelled before doing anything");
1527 abortPrepare(UNKNOWN_ERROR);
1528 return;
1529 }
1530
1531 if (mUri.size() > 0) {
1532 status_t err = finishSetDataSource_l();
1533
1534 if (err != OK) {
1535 abortPrepare(err);
Andreas Huberedbb4d82010-03-12 08:59:22 -08001536 return;
1537 }
Andreas Huber6be780e2010-02-08 14:40:30 -08001538 }
1539
Andreas Huber87ab9cd2010-09-03 13:20:33 -07001540 if (mVideoTrack != NULL && mVideoSource == NULL) {
1541 status_t err = initVideoDecoder();
Andreas Huber6be780e2010-02-08 14:40:30 -08001542
Andreas Huber87ab9cd2010-09-03 13:20:33 -07001543 if (err != OK) {
1544 abortPrepare(err);
1545 return;
1546 }
1547 }
1548
1549 if (mAudioTrack != NULL && mAudioSource == NULL) {
1550 status_t err = initAudioDecoder();
1551
1552 if (err != OK) {
1553 abortPrepare(err);
1554 return;
1555 }
1556 }
1557
1558 if (mCachedSource != NULL || mRTSPController != NULL) {
1559 postBufferingEvent_l();
1560 } else {
1561 finishAsyncPrepare_l();
1562 }
1563}
1564
1565void AwesomePlayer::finishAsyncPrepare_l() {
Andreas Huberffdf4782010-02-09 14:05:43 -08001566 if (mIsAsyncPrepare) {
1567 if (mVideoWidth < 0 || mVideoHeight < 0) {
1568 notifyListener_l(MEDIA_SET_VIDEO_SIZE, 0, 0);
1569 } else {
1570 notifyListener_l(MEDIA_SET_VIDEO_SIZE, mVideoWidth, mVideoHeight);
1571 }
1572
1573 notifyListener_l(MEDIA_PREPARED);
Andreas Huber6be780e2010-02-08 14:40:30 -08001574 }
1575
Andreas Huberffdf4782010-02-09 14:05:43 -08001576 mPrepareResult = OK;
Andreas Huberedbb4d82010-03-12 08:59:22 -08001577 mFlags &= ~(PREPARING|PREPARE_CANCELLED);
Andreas Huberffdf4782010-02-09 14:05:43 -08001578 mFlags |= PREPARED;
Andreas Huber6be780e2010-02-08 14:40:30 -08001579 mAsyncPrepareEvent = NULL;
Andreas Huberffdf4782010-02-09 14:05:43 -08001580 mPreparedCondition.broadcast();
Andreas Huber6be780e2010-02-08 14:40:30 -08001581}
1582
Andreas Huberba7ec912010-02-12 10:42:02 -08001583status_t AwesomePlayer::suspend() {
Andreas Huberedbb4d82010-03-12 08:59:22 -08001584 LOGV("suspend");
Andreas Huberba7ec912010-02-12 10:42:02 -08001585 Mutex::Autolock autoLock(mLock);
1586
1587 if (mSuspensionState != NULL) {
Gloria Wangb19da8e2010-04-12 17:13:06 -07001588 if (mLastVideoBuffer == NULL) {
1589 //go into here if video is suspended again
1590 //after resuming without being played between
1591 //them
1592 SuspensionState *state = mSuspensionState;
1593 mSuspensionState = NULL;
1594 reset_l();
1595 mSuspensionState = state;
1596 return OK;
1597 }
1598
1599 delete mSuspensionState;
1600 mSuspensionState = NULL;
Andreas Huberba7ec912010-02-12 10:42:02 -08001601 }
1602
Andreas Huberedbb4d82010-03-12 08:59:22 -08001603 if (mFlags & PREPARING) {
1604 mFlags |= PREPARE_CANCELLED;
1605 if (mConnectingDataSource != NULL) {
1606 LOGI("interrupting the connection process");
1607 mConnectingDataSource->disconnect();
1608 }
1609 }
1610
Andreas Huberba7ec912010-02-12 10:42:02 -08001611 while (mFlags & PREPARING) {
1612 mPreparedCondition.wait(mLock);
1613 }
1614
1615 SuspensionState *state = new SuspensionState;
1616 state->mUri = mUri;
1617 state->mUriHeaders = mUriHeaders;
1618 state->mFileSource = mFileSource;
1619
Andreas Huber9fee0b22010-09-03 14:09:21 -07001620 state->mFlags = mFlags & (PLAYING | AUTO_LOOPING | LOOPING | AT_EOS);
Andreas Huber252573c2010-03-26 10:17:17 -07001621 getPosition(&state->mPositionUs);
Andreas Huberba7ec912010-02-12 10:42:02 -08001622
Andreas Huber7b73cfc2010-02-12 14:40:08 -08001623 if (mLastVideoBuffer) {
1624 size_t size = mLastVideoBuffer->range_length();
Andreas Huber1e194162010-10-06 16:43:57 -07001625
Andreas Huber7b73cfc2010-02-12 14:40:08 -08001626 if (size) {
Andreas Huber1e194162010-10-06 16:43:57 -07001627 int32_t unreadable;
1628 if (!mLastVideoBuffer->meta_data()->findInt32(
1629 kKeyIsUnreadable, &unreadable)
1630 || unreadable == 0) {
1631 state->mLastVideoFrameSize = size;
1632 state->mLastVideoFrame = malloc(size);
1633 memcpy(state->mLastVideoFrame,
1634 (const uint8_t *)mLastVideoBuffer->data()
1635 + mLastVideoBuffer->range_offset(),
1636 size);
Andreas Huber7b73cfc2010-02-12 14:40:08 -08001637
Andreas Huber1e194162010-10-06 16:43:57 -07001638 state->mVideoWidth = mVideoWidth;
1639 state->mVideoHeight = mVideoHeight;
Andreas Huber7b73cfc2010-02-12 14:40:08 -08001640
Andreas Huber1e194162010-10-06 16:43:57 -07001641 sp<MetaData> meta = mVideoSource->getFormat();
1642 CHECK(meta->findInt32(kKeyColorFormat, &state->mColorFormat));
1643 CHECK(meta->findInt32(kKeyWidth, &state->mDecodedWidth));
1644 CHECK(meta->findInt32(kKeyHeight, &state->mDecodedHeight));
1645 } else {
1646 LOGV("Unable to save last video frame, we have no access to "
1647 "the decoded video data.");
1648 }
Andreas Huber7b73cfc2010-02-12 14:40:08 -08001649 }
1650 }
1651
Andreas Huberba7ec912010-02-12 10:42:02 -08001652 reset_l();
1653
1654 mSuspensionState = state;
1655
1656 return OK;
1657}
1658
1659status_t AwesomePlayer::resume() {
Andreas Huberedbb4d82010-03-12 08:59:22 -08001660 LOGV("resume");
Andreas Huberba7ec912010-02-12 10:42:02 -08001661 Mutex::Autolock autoLock(mLock);
1662
1663 if (mSuspensionState == NULL) {
1664 return INVALID_OPERATION;
1665 }
1666
1667 SuspensionState *state = mSuspensionState;
1668 mSuspensionState = NULL;
1669
1670 status_t err;
1671 if (state->mFileSource != NULL) {
1672 err = setDataSource_l(state->mFileSource);
1673
1674 if (err == OK) {
1675 mFileSource = state->mFileSource;
1676 }
1677 } else {
1678 err = setDataSource_l(state->mUri, &state->mUriHeaders);
1679 }
1680
1681 if (err != OK) {
1682 delete state;
1683 state = NULL;
1684
1685 return err;
1686 }
1687
1688 seekTo_l(state->mPositionUs);
1689
Andreas Huber9fee0b22010-09-03 14:09:21 -07001690 mFlags = state->mFlags & (AUTO_LOOPING | LOOPING | AT_EOS);
Andreas Huberba7ec912010-02-12 10:42:02 -08001691
Andreas Huber7b73cfc2010-02-12 14:40:08 -08001692 if (state->mLastVideoFrame && mISurface != NULL) {
1693 mVideoRenderer =
1694 new AwesomeLocalRenderer(
1695 true, // previewOnly
1696 "",
1697 (OMX_COLOR_FORMATTYPE)state->mColorFormat,
1698 mISurface,
1699 state->mVideoWidth,
1700 state->mVideoHeight,
1701 state->mDecodedWidth,
1702 state->mDecodedHeight);
1703
1704 mVideoRendererIsPreview = true;
1705
1706 ((AwesomeLocalRenderer *)mVideoRenderer.get())->render(
1707 state->mLastVideoFrame, state->mLastVideoFrameSize);
1708 }
1709
Andreas Huberba7ec912010-02-12 10:42:02 -08001710 if (state->mFlags & PLAYING) {
1711 play_l();
1712 }
1713
Gloria Wangb19da8e2010-04-12 17:13:06 -07001714 mSuspensionState = state;
Andreas Huberba7ec912010-02-12 10:42:02 -08001715 state = NULL;
1716
1717 return OK;
1718}
1719
Andreas Huber62f7ffe2010-05-06 10:18:05 -07001720uint32_t AwesomePlayer::flags() const {
1721 return mExtractorFlags;
1722}
1723
Andreas Huber2b359ed2010-09-28 11:56:39 -07001724void AwesomePlayer::postAudioEOS() {
1725 postCheckAudioStatusEvent_l();
1726}
1727
1728void AwesomePlayer::postAudioSeekComplete() {
1729 postCheckAudioStatusEvent_l();
1730}
1731
Andreas Huber27366fc2009-11-20 09:32:46 -08001732} // namespace android
1733