blob: 2a8c0353e8e76e96c8acde637696019af612cca7 [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 Hubera67d5382009-12-10 15:32:12 -080030#include <binder/IPCThreadState.h>
Andreas Huber27366fc2009-11-20 09:32:46 -080031#include <media/stagefright/AudioPlayer.h>
32#include <media/stagefright/DataSource.h>
33#include <media/stagefright/FileSource.h>
34#include <media/stagefright/MediaBuffer.h>
Andreas Huberc79827a2010-01-05 10:54:55 -080035#include <media/stagefright/MediaDefs.h>
Andreas Huber27366fc2009-11-20 09:32:46 -080036#include <media/stagefright/MediaExtractor.h>
37#include <media/stagefright/MediaDebug.h>
38#include <media/stagefright/MediaSource.h>
39#include <media/stagefright/MetaData.h>
40#include <media/stagefright/OMXCodec.h>
Andreas Huberc79827a2010-01-05 10:54:55 -080041
Mathias Agopian000479f2010-02-09 17:46:37 -080042#include <surfaceflinger/ISurface.h>
43
Andreas Huber7a747b82010-06-07 15:19:40 -070044#include <media/stagefright/foundation/ALooper.h>
Andreas Huber202348e2010-06-07 14:35:29 -070045
Andreas Huber27366fc2009-11-20 09:32:46 -080046namespace android {
47
48struct AwesomeEvent : public TimedEventQueue::Event {
Andreas Huber6be780e2010-02-08 14:40:30 -080049 AwesomeEvent(
50 AwesomePlayer *player,
51 void (AwesomePlayer::*method)())
Andreas Huber27366fc2009-11-20 09:32:46 -080052 : mPlayer(player),
Andreas Huber6be780e2010-02-08 14:40:30 -080053 mMethod(method) {
Andreas Huber27366fc2009-11-20 09:32:46 -080054 }
55
56protected:
57 virtual ~AwesomeEvent() {}
58
59 virtual void fire(TimedEventQueue *queue, int64_t /* now_us */) {
Andreas Huber6be780e2010-02-08 14:40:30 -080060 (mPlayer->*mMethod)();
Andreas Huber27366fc2009-11-20 09:32:46 -080061 }
62
63private:
64 AwesomePlayer *mPlayer;
Andreas Huber6be780e2010-02-08 14:40:30 -080065 void (AwesomePlayer::*mMethod)();
Andreas Huber27366fc2009-11-20 09:32:46 -080066
67 AwesomeEvent(const AwesomeEvent &);
68 AwesomeEvent &operator=(const AwesomeEvent &);
69};
70
Andreas Huber1314e732009-12-14 14:18:22 -080071struct AwesomeRemoteRenderer : public AwesomeRenderer {
72 AwesomeRemoteRenderer(const sp<IOMXRenderer> &target)
73 : mTarget(target) {
74 }
75
76 virtual void render(MediaBuffer *buffer) {
77 void *id;
78 if (buffer->meta_data()->findPointer(kKeyBufferID, &id)) {
79 mTarget->render((IOMX::buffer_id)id);
80 }
81 }
82
83private:
84 sp<IOMXRenderer> mTarget;
85
86 AwesomeRemoteRenderer(const AwesomeRemoteRenderer &);
87 AwesomeRemoteRenderer &operator=(const AwesomeRemoteRenderer &);
88};
89
90struct AwesomeLocalRenderer : public AwesomeRenderer {
91 AwesomeLocalRenderer(
Andreas Huber7b73cfc2010-02-12 14:40:08 -080092 bool previewOnly,
Andreas Huber4ab5a6f2010-02-11 11:00:26 -080093 const char *componentName,
Andreas Huber1314e732009-12-14 14:18:22 -080094 OMX_COLOR_FORMATTYPE colorFormat,
95 const sp<ISurface> &surface,
96 size_t displayWidth, size_t displayHeight,
97 size_t decodedWidth, size_t decodedHeight)
Andreas Huber4ab5a6f2010-02-11 11:00:26 -080098 : mTarget(NULL),
99 mLibHandle(NULL) {
Andreas Huber7b73cfc2010-02-12 14:40:08 -0800100 init(previewOnly, componentName,
Andreas Huber4ab5a6f2010-02-11 11:00:26 -0800101 colorFormat, surface, displayWidth,
102 displayHeight, decodedWidth, decodedHeight);
Andreas Huber1314e732009-12-14 14:18:22 -0800103 }
104
105 virtual void render(MediaBuffer *buffer) {
Andreas Huber7b73cfc2010-02-12 14:40:08 -0800106 render((const uint8_t *)buffer->data() + buffer->range_offset(),
107 buffer->range_length());
108 }
109
110 void render(const void *data, size_t size) {
111 mTarget->render(data, size, NULL);
Andreas Huber1314e732009-12-14 14:18:22 -0800112 }
113
114protected:
115 virtual ~AwesomeLocalRenderer() {
116 delete mTarget;
117 mTarget = NULL;
Andreas Huber4ab5a6f2010-02-11 11:00:26 -0800118
119 if (mLibHandle) {
120 dlclose(mLibHandle);
121 mLibHandle = NULL;
122 }
Andreas Huber1314e732009-12-14 14:18:22 -0800123 }
124
125private:
Andreas Huber4ab5a6f2010-02-11 11:00:26 -0800126 VideoRenderer *mTarget;
127 void *mLibHandle;
128
129 void init(
Andreas Huber7b73cfc2010-02-12 14:40:08 -0800130 bool previewOnly,
Andreas Huber4ab5a6f2010-02-11 11:00:26 -0800131 const char *componentName,
132 OMX_COLOR_FORMATTYPE colorFormat,
133 const sp<ISurface> &surface,
134 size_t displayWidth, size_t displayHeight,
135 size_t decodedWidth, size_t decodedHeight);
Andreas Huber1314e732009-12-14 14:18:22 -0800136
137 AwesomeLocalRenderer(const AwesomeLocalRenderer &);
138 AwesomeLocalRenderer &operator=(const AwesomeLocalRenderer &);;
139};
140
Andreas Huber4ab5a6f2010-02-11 11:00:26 -0800141void AwesomeLocalRenderer::init(
Andreas Huber7b73cfc2010-02-12 14:40:08 -0800142 bool previewOnly,
Andreas Huber4ab5a6f2010-02-11 11:00:26 -0800143 const char *componentName,
144 OMX_COLOR_FORMATTYPE colorFormat,
145 const sp<ISurface> &surface,
146 size_t displayWidth, size_t displayHeight,
147 size_t decodedWidth, size_t decodedHeight) {
Andreas Huber7b73cfc2010-02-12 14:40:08 -0800148 if (!previewOnly) {
149 // We will stick to the vanilla software-color-converting renderer
150 // for "previewOnly" mode, to avoid unneccessarily switching overlays
151 // more often than necessary.
Andreas Huber4ab5a6f2010-02-11 11:00:26 -0800152
Andreas Huber7b73cfc2010-02-12 14:40:08 -0800153 mLibHandle = dlopen("libstagefrighthw.so", RTLD_NOW);
Andreas Huber4ab5a6f2010-02-11 11:00:26 -0800154
Andreas Huber7b73cfc2010-02-12 14:40:08 -0800155 if (mLibHandle) {
156 typedef VideoRenderer *(*CreateRendererFunc)(
157 const sp<ISurface> &surface,
158 const char *componentName,
159 OMX_COLOR_FORMATTYPE colorFormat,
160 size_t displayWidth, size_t displayHeight,
161 size_t decodedWidth, size_t decodedHeight);
Andreas Huber4ab5a6f2010-02-11 11:00:26 -0800162
Andreas Huber7b73cfc2010-02-12 14:40:08 -0800163 CreateRendererFunc func =
164 (CreateRendererFunc)dlsym(
165 mLibHandle,
166 "_Z14createRendererRKN7android2spINS_8ISurfaceEEEPKc20"
167 "OMX_COLOR_FORMATTYPEjjjj");
168
169 if (func) {
170 mTarget =
171 (*func)(surface, componentName, colorFormat,
172 displayWidth, displayHeight,
173 decodedWidth, decodedHeight);
174 }
Andreas Huber4ab5a6f2010-02-11 11:00:26 -0800175 }
176 }
177
178 if (mTarget == NULL) {
179 mTarget = new SoftwareRenderer(
180 colorFormat, surface, displayWidth, displayHeight,
181 decodedWidth, decodedHeight);
182 }
183}
184
Andreas Huber27366fc2009-11-20 09:32:46 -0800185AwesomePlayer::AwesomePlayer()
Andreas Huber406a18b2010-02-18 16:45:13 -0800186 : mQueueStarted(false),
187 mTimeSource(NULL),
Andreas Huber7b73cfc2010-02-12 14:40:08 -0800188 mVideoRendererIsPreview(false),
Andreas Huber27366fc2009-11-20 09:32:46 -0800189 mAudioPlayer(NULL),
Andreas Huberffdf4782010-02-09 14:05:43 -0800190 mFlags(0),
Andreas Huber62f7ffe2010-05-06 10:18:05 -0700191 mExtractorFlags(0),
Andreas Huber27366fc2009-11-20 09:32:46 -0800192 mLastVideoBuffer(NULL),
Andreas Huberba7ec912010-02-12 10:42:02 -0800193 mVideoBuffer(NULL),
194 mSuspensionState(NULL) {
Andreas Huber27366fc2009-11-20 09:32:46 -0800195 CHECK_EQ(mClient.connect(), OK);
196
197 DataSource::RegisterDefaultSniffers();
198
Andreas Huber6be780e2010-02-08 14:40:30 -0800199 mVideoEvent = new AwesomeEvent(this, &AwesomePlayer::onVideoEvent);
Andreas Huber27366fc2009-11-20 09:32:46 -0800200 mVideoEventPending = false;
Andreas Huber6be780e2010-02-08 14:40:30 -0800201 mStreamDoneEvent = new AwesomeEvent(this, &AwesomePlayer::onStreamDone);
Andreas Huber27366fc2009-11-20 09:32:46 -0800202 mStreamDoneEventPending = false;
Andreas Huber6be780e2010-02-08 14:40:30 -0800203 mBufferingEvent = new AwesomeEvent(this, &AwesomePlayer::onBufferingUpdate);
Andreas Huberb9e63832010-01-26 16:20:10 -0800204 mBufferingEventPending = false;
Andreas Huber6be780e2010-02-08 14:40:30 -0800205
206 mCheckAudioStatusEvent = new AwesomeEvent(
207 this, &AwesomePlayer::onCheckAudioStatus);
208
Andreas Huber70d10c02010-02-03 11:37:29 -0800209 mAudioStatusEventPending = false;
Andreas Huber27366fc2009-11-20 09:32:46 -0800210
Andreas Huber27366fc2009-11-20 09:32:46 -0800211 reset();
212}
213
214AwesomePlayer::~AwesomePlayer() {
Andreas Huber406a18b2010-02-18 16:45:13 -0800215 if (mQueueStarted) {
216 mQueue.stop();
217 }
Andreas Huber27366fc2009-11-20 09:32:46 -0800218
219 reset();
220
221 mClient.disconnect();
222}
223
Andreas Huberb9e63832010-01-26 16:20:10 -0800224void AwesomePlayer::cancelPlayerEvents(bool keepBufferingGoing) {
Andreas Huber27366fc2009-11-20 09:32:46 -0800225 mQueue.cancelEvent(mVideoEvent->eventID());
226 mVideoEventPending = false;
227 mQueue.cancelEvent(mStreamDoneEvent->eventID());
228 mStreamDoneEventPending = false;
Andreas Huber70d10c02010-02-03 11:37:29 -0800229 mQueue.cancelEvent(mCheckAudioStatusEvent->eventID());
230 mAudioStatusEventPending = false;
Andreas Huberb9e63832010-01-26 16:20:10 -0800231
232 if (!keepBufferingGoing) {
233 mQueue.cancelEvent(mBufferingEvent->eventID());
234 mBufferingEventPending = false;
235 }
Andreas Huber27366fc2009-11-20 09:32:46 -0800236}
237
Andreas Hubera3f43842010-01-21 10:28:45 -0800238void AwesomePlayer::setListener(const wp<MediaPlayerBase> &listener) {
Andreas Huber27366fc2009-11-20 09:32:46 -0800239 Mutex::Autolock autoLock(mLock);
240 mListener = listener;
241}
242
Andreas Huber433c9ac2010-01-27 16:49:05 -0800243status_t AwesomePlayer::setDataSource(
244 const char *uri, const KeyedVector<String8, String8> *headers) {
Andreas Huber27366fc2009-11-20 09:32:46 -0800245 Mutex::Autolock autoLock(mLock);
Andreas Huberba7ec912010-02-12 10:42:02 -0800246 return setDataSource_l(uri, headers);
247}
Andreas Huber27366fc2009-11-20 09:32:46 -0800248
Andreas Huberba7ec912010-02-12 10:42:02 -0800249status_t AwesomePlayer::setDataSource_l(
250 const char *uri, const KeyedVector<String8, String8> *headers) {
Andreas Huber27366fc2009-11-20 09:32:46 -0800251 reset_l();
252
Andreas Huberffdf4782010-02-09 14:05:43 -0800253 mUri = uri;
Andreas Huberb9e63832010-01-26 16:20:10 -0800254
Andreas Huberffdf4782010-02-09 14:05:43 -0800255 if (headers) {
256 mUriHeaders = *headers;
Andreas Huberb9e63832010-01-26 16:20:10 -0800257 }
258
Andreas Huberffdf4782010-02-09 14:05:43 -0800259 // The actual work will be done during preparation in the call to
260 // ::finishSetDataSource_l to avoid blocking the calling thread in
261 // setDataSource for any significant time.
Andreas Huber27366fc2009-11-20 09:32:46 -0800262
Andreas Huberffdf4782010-02-09 14:05:43 -0800263 return OK;
Andreas Huber27366fc2009-11-20 09:32:46 -0800264}
265
266status_t AwesomePlayer::setDataSource(
267 int fd, int64_t offset, int64_t length) {
Andreas Huber202348e2010-06-07 14:35:29 -0700268#if 0
269 // return setDataSource("httplive://iphoned5.akamai.com.edgesuite.net/mhbarron/nasatv/nasatv_96.m3u8");
270 // return setDataSource("httplive://iphoned5.akamai.com.edgesuite.net/mhbarron/nasatv/nasatv_1500.m3u8");
271 return setDataSource("httplive://iphone.video.hsn.com/iPhone_high.m3u8");
272 // return setDataSource("httplive://iphoned5.akamai.com.edgesuite.net/mhbarron/iphonewebcast/webcast090209_all/webcast090209_all.m3u8");
273 // return setDataSource("httplive://qthttp.akamai.com.edgesuite.net/iphone_demo/Video_Content/usat/tt_062209_iphone/hi/prog_index.m3u8");
274 // return setDataSource("httplive://qthttp.akamai.com.edgesuite.net/iphone_demo/Video_Content/usat/tt_googmaps/hi/prog_index.m3u8");
275 // return setDataSource("httplive://qthttp.akamai.com.edgesuite.net/iphone_demo/Video_Content/mtv/ni_spo_25a_rt74137_clip_syn/hi/prog_index.m3u8");
276#endif
277
Andreas Huber27366fc2009-11-20 09:32:46 -0800278 Mutex::Autolock autoLock(mLock);
279
280 reset_l();
281
Andreas Huberba7ec912010-02-12 10:42:02 -0800282 sp<DataSource> dataSource = new FileSource(fd, offset, length);
Andreas Huber27366fc2009-11-20 09:32:46 -0800283
Andreas Huberba7ec912010-02-12 10:42:02 -0800284 status_t err = dataSource->initCheck();
Andreas Huber27366fc2009-11-20 09:32:46 -0800285
286 if (err != OK) {
287 return err;
288 }
289
Andreas Huberba7ec912010-02-12 10:42:02 -0800290 mFileSource = dataSource;
291
292 return setDataSource_l(dataSource);
293}
294
295status_t AwesomePlayer::setDataSource_l(
296 const sp<DataSource> &dataSource) {
297 sp<MediaExtractor> extractor = MediaExtractor::Create(dataSource);
Andreas Huber27366fc2009-11-20 09:32:46 -0800298
299 if (extractor == NULL) {
300 return UNKNOWN_ERROR;
301 }
302
303 return setDataSource_l(extractor);
304}
305
306status_t AwesomePlayer::setDataSource_l(const sp<MediaExtractor> &extractor) {
Andreas Huber27366fc2009-11-20 09:32:46 -0800307 bool haveAudio = false;
308 bool haveVideo = false;
309 for (size_t i = 0; i < extractor->countTracks(); ++i) {
310 sp<MetaData> meta = extractor->getTrackMetaData(i);
311
312 const char *mime;
313 CHECK(meta->findCString(kKeyMIMEType, &mime));
314
315 if (!haveVideo && !strncasecmp(mime, "video/", 6)) {
Andreas Huber3ac94ef2010-03-05 10:42:10 -0800316 setVideoSource(extractor->getTrack(i));
317 haveVideo = true;
Andreas Huber27366fc2009-11-20 09:32:46 -0800318 } else if (!haveAudio && !strncasecmp(mime, "audio/", 6)) {
Andreas Huber3ac94ef2010-03-05 10:42:10 -0800319 setAudioSource(extractor->getTrack(i));
320 haveAudio = true;
Andreas Huber27366fc2009-11-20 09:32:46 -0800321 }
322
323 if (haveAudio && haveVideo) {
324 break;
325 }
326 }
327
Andreas Huber62f7ffe2010-05-06 10:18:05 -0700328 if (!haveAudio && !haveVideo) {
329 return UNKNOWN_ERROR;
330 }
331
332 mExtractorFlags = extractor->flags();
333
334 return OK;
Andreas Huber27366fc2009-11-20 09:32:46 -0800335}
336
337void AwesomePlayer::reset() {
338 Mutex::Autolock autoLock(mLock);
339 reset_l();
340}
341
342void AwesomePlayer::reset_l() {
Andreas Huberedbb4d82010-03-12 08:59:22 -0800343 if (mFlags & PREPARING) {
344 mFlags |= PREPARE_CANCELLED;
345 if (mConnectingDataSource != NULL) {
346 LOGI("interrupting the connection process");
347 mConnectingDataSource->disconnect();
348 }
349 }
350
Andreas Huberffdf4782010-02-09 14:05:43 -0800351 while (mFlags & PREPARING) {
352 mPreparedCondition.wait(mLock);
353 }
354
Andreas Huber27366fc2009-11-20 09:32:46 -0800355 cancelPlayerEvents();
356
Andreas Huber4d61f602010-06-10 11:17:50 -0700357 mCachedSource.clear();
Andreas Huber3ac94ef2010-03-05 10:42:10 -0800358 mAudioTrack.clear();
359 mVideoTrack.clear();
360
Andreas Huberba7ec912010-02-12 10:42:02 -0800361 // Shutdown audio first, so that the respone to the reset request
362 // appears to happen instantaneously as far as the user is concerned
363 // If we did this later, audio would continue playing while we
364 // shutdown the video-related resources and the player appear to
365 // not be as responsive to a reset request.
Andreas Huberedbb4d82010-03-12 08:59:22 -0800366 if (mAudioPlayer == NULL && mAudioSource != NULL) {
367 // If we had an audio player, it would have effectively
368 // taken possession of the audio source and stopped it when
369 // _it_ is stopped. Otherwise this is still our responsibility.
370 mAudioSource->stop();
371 }
Andreas Huberba7ec912010-02-12 10:42:02 -0800372 mAudioSource.clear();
373
374 if (mTimeSource != mAudioPlayer) {
375 delete mTimeSource;
376 }
377 mTimeSource = NULL;
378
379 delete mAudioPlayer;
380 mAudioPlayer = NULL;
381
Andreas Huber3522b5a52010-01-22 14:36:53 -0800382 mVideoRenderer.clear();
383
Andreas Huber27366fc2009-11-20 09:32:46 -0800384 if (mLastVideoBuffer) {
385 mLastVideoBuffer->release();
386 mLastVideoBuffer = NULL;
387 }
388
389 if (mVideoBuffer) {
390 mVideoBuffer->release();
391 mVideoBuffer = NULL;
392 }
393
Andreas Huber7a747b82010-06-07 15:19:40 -0700394 mRTSPController.clear();
395
Andreas Huber27366fc2009-11-20 09:32:46 -0800396 if (mVideoSource != NULL) {
397 mVideoSource->stop();
Andreas Huber98b48de2010-01-29 10:10:22 -0800398
399 // The following hack is necessary to ensure that the OMX
400 // component is completely released by the time we may try
401 // to instantiate it again.
402 wp<MediaSource> tmp = mVideoSource;
Andreas Huber27366fc2009-11-20 09:32:46 -0800403 mVideoSource.clear();
Andreas Huber98b48de2010-01-29 10:10:22 -0800404 while (tmp.promote() != NULL) {
405 usleep(1000);
406 }
407 IPCThreadState::self()->flushCommands();
Andreas Huber27366fc2009-11-20 09:32:46 -0800408 }
409
Andreas Huber27366fc2009-11-20 09:32:46 -0800410 mDurationUs = -1;
411 mFlags = 0;
Andreas Huber62f7ffe2010-05-06 10:18:05 -0700412 mExtractorFlags = 0;
Andreas Huber27366fc2009-11-20 09:32:46 -0800413 mVideoWidth = mVideoHeight = -1;
414 mTimeSourceDeltaUs = 0;
415 mVideoTimeUs = 0;
416
417 mSeeking = false;
Andreas Huber8e2b9412010-03-31 09:40:15 -0700418 mSeekNotificationSent = false;
Andreas Huber27366fc2009-11-20 09:32:46 -0800419 mSeekTimeUs = 0;
Andreas Huberb9e63832010-01-26 16:20:10 -0800420
Andreas Huberffdf4782010-02-09 14:05:43 -0800421 mUri.setTo("");
422 mUriHeaders.clear();
Andreas Huberba7ec912010-02-12 10:42:02 -0800423
424 mFileSource.clear();
425
426 delete mSuspensionState;
427 mSuspensionState = NULL;
Andreas Huber27366fc2009-11-20 09:32:46 -0800428}
429
Andreas Huber6be780e2010-02-08 14:40:30 -0800430void AwesomePlayer::notifyListener_l(int msg, int ext1, int ext2) {
Andreas Hubera3f43842010-01-21 10:28:45 -0800431 if (mListener != NULL) {
432 sp<MediaPlayerBase> listener = mListener.promote();
433
434 if (listener != NULL) {
Andreas Huber6be780e2010-02-08 14:40:30 -0800435 listener->sendEvent(msg, ext1, ext2);
Andreas Hubera3f43842010-01-21 10:28:45 -0800436 }
437 }
438}
439
Andreas Huberb9e63832010-01-26 16:20:10 -0800440void AwesomePlayer::onBufferingUpdate() {
441 Mutex::Autolock autoLock(mLock);
Andreas Huberc0178f12010-02-17 15:58:57 -0800442 if (!mBufferingEventPending) {
443 return;
444 }
Andreas Huberb9e63832010-01-26 16:20:10 -0800445 mBufferingEventPending = false;
446
Andreas Huber4d61f602010-06-10 11:17:50 -0700447 if (mCachedSource == NULL) {
448 return;
Andreas Huber252573c2010-03-26 10:17:17 -0700449 }
450
Andreas Huber4d61f602010-06-10 11:17:50 -0700451 size_t lowWatermark = 400000;
452 size_t highWatermark = 1000000;
Andreas Huber202348e2010-06-07 14:35:29 -0700453
Andreas Huber4d61f602010-06-10 11:17:50 -0700454 off_t size;
455 if (mDurationUs >= 0 && mCachedSource->getSize(&size) == OK) {
456 int64_t bitrate = size * 8000000ll / mDurationUs; // in bits/sec
Andreas Huber202348e2010-06-07 14:35:29 -0700457
Andreas Huber4d61f602010-06-10 11:17:50 -0700458 size_t cachedSize = mCachedSource->cachedSize();
459 int64_t cachedDurationUs = cachedSize * 8000000ll / bitrate;
Andreas Huberb9e63832010-01-26 16:20:10 -0800460
Andreas Huber4d61f602010-06-10 11:17:50 -0700461 double percentage = (double)cachedDurationUs / mDurationUs;
Andreas Huberb9e63832010-01-26 16:20:10 -0800462
Andreas Huberb9e63832010-01-26 16:20:10 -0800463 notifyListener_l(MEDIA_BUFFERING_UPDATE, percentage * 100.0);
464
Andreas Huber4d61f602010-06-10 11:17:50 -0700465 lowWatermark = 2 * bitrate / 8; // 2 secs
466 highWatermark = 10 * bitrate / 8; // 10 secs
Andreas Huberb9e63832010-01-26 16:20:10 -0800467 }
Andreas Huber4d61f602010-06-10 11:17:50 -0700468
469 bool eos;
470 size_t cachedDataRemaining = mCachedSource->approxDataRemaining(&eos);
471
472 if ((mFlags & PLAYING) && !eos && (cachedDataRemaining < lowWatermark)) {
473 LOGI("cache is running low (< %d) , pausing.", lowWatermark);
474 mFlags |= CACHE_UNDERRUN;
475 pause_l();
476 notifyListener_l(MEDIA_INFO, MEDIA_INFO_BUFFERING_START);
477 } else if ((mFlags & CACHE_UNDERRUN)
478 && (eos || cachedDataRemaining > highWatermark)) {
479 LOGI("cache has filled up (> %d), resuming.", highWatermark);
480 mFlags &= ~CACHE_UNDERRUN;
481 play_l();
482 notifyListener_l(MEDIA_INFO, MEDIA_INFO_BUFFERING_END);
483 }
484
485 postBufferingEvent_l();
Andreas Huberb9e63832010-01-26 16:20:10 -0800486}
487
Andreas Huber27366fc2009-11-20 09:32:46 -0800488void AwesomePlayer::onStreamDone() {
489 // Posted whenever any stream finishes playing.
490
491 Mutex::Autolock autoLock(mLock);
Andreas Huberc0178f12010-02-17 15:58:57 -0800492 if (!mStreamDoneEventPending) {
493 return;
494 }
Andreas Huber27366fc2009-11-20 09:32:46 -0800495 mStreamDoneEventPending = false;
496
Andreas Huberd7d22eb2010-02-23 13:45:33 -0800497 if (mStreamDoneStatus == ERROR_END_OF_STREAM && (mFlags & LOOPING)) {
Andreas Huber27366fc2009-11-20 09:32:46 -0800498 seekTo_l(0);
499
Andreas Huber7085b6842010-02-03 16:02:02 -0800500 if (mVideoSource != NULL) {
Andreas Huber27366fc2009-11-20 09:32:46 -0800501 postVideoEvent_l();
502 }
503 } else {
Andreas Huberd7d22eb2010-02-23 13:45:33 -0800504 if (mStreamDoneStatus == ERROR_END_OF_STREAM) {
505 LOGV("MEDIA_PLAYBACK_COMPLETE");
506 notifyListener_l(MEDIA_PLAYBACK_COMPLETE);
507 } else {
508 LOGV("MEDIA_ERROR %d", mStreamDoneStatus);
509
510 notifyListener_l(
511 MEDIA_ERROR, MEDIA_ERROR_UNKNOWN, mStreamDoneStatus);
512 }
Andreas Huber27366fc2009-11-20 09:32:46 -0800513
514 pause_l();
Andreas Huber406a18b2010-02-18 16:45:13 -0800515
516 mFlags |= AT_EOS;
Andreas Huber27366fc2009-11-20 09:32:46 -0800517 }
518}
519
520status_t AwesomePlayer::play() {
521 Mutex::Autolock autoLock(mLock);
Andreas Huber4d61f602010-06-10 11:17:50 -0700522
523 mFlags &= ~CACHE_UNDERRUN;
524
Andreas Huberba7ec912010-02-12 10:42:02 -0800525 return play_l();
526}
Andreas Huber27366fc2009-11-20 09:32:46 -0800527
Andreas Huberba7ec912010-02-12 10:42:02 -0800528status_t AwesomePlayer::play_l() {
Andreas Huber27366fc2009-11-20 09:32:46 -0800529 if (mFlags & PLAYING) {
530 return OK;
531 }
532
Andreas Huberffdf4782010-02-09 14:05:43 -0800533 if (!(mFlags & PREPARED)) {
534 status_t err = prepare_l();
535
536 if (err != OK) {
537 return err;
538 }
539 }
540
Andreas Huber27366fc2009-11-20 09:32:46 -0800541 mFlags |= PLAYING;
542 mFlags |= FIRST_FRAME;
543
Andreas Huberc1d5c922009-12-10 15:49:04 -0800544 bool deferredAudioSeek = false;
545
Andreas Huber27366fc2009-11-20 09:32:46 -0800546 if (mAudioSource != NULL) {
547 if (mAudioPlayer == NULL) {
548 if (mAudioSink != NULL) {
549 mAudioPlayer = new AudioPlayer(mAudioSink);
Andreas Huber27366fc2009-11-20 09:32:46 -0800550 mAudioPlayer->setSource(mAudioSource);
Andreas Huberdc9927d2010-03-08 15:46:13 -0800551
552 // We've already started the MediaSource in order to enable
553 // the prefetcher to read its data.
554 status_t err = mAudioPlayer->start(
555 true /* sourceAlreadyStarted */);
Andreas Huber62eac002010-01-29 13:24:58 -0800556
557 if (err != OK) {
558 delete mAudioPlayer;
559 mAudioPlayer = NULL;
560
561 mFlags &= ~(PLAYING | FIRST_FRAME);
562
563 return err;
564 }
Andreas Huber27366fc2009-11-20 09:32:46 -0800565
566 delete mTimeSource;
567 mTimeSource = mAudioPlayer;
568
Andreas Huberc1d5c922009-12-10 15:49:04 -0800569 deferredAudioSeek = true;
Andreas Huber70d10c02010-02-03 11:37:29 -0800570
571 mWatchForAudioSeekComplete = false;
572 mWatchForAudioEOS = true;
Andreas Huber27366fc2009-11-20 09:32:46 -0800573 }
574 } else {
575 mAudioPlayer->resume();
576 }
Andreas Huber70d10c02010-02-03 11:37:29 -0800577
578 postCheckAudioStatusEvent_l();
Andreas Huber27366fc2009-11-20 09:32:46 -0800579 }
580
581 if (mTimeSource == NULL && mAudioPlayer == NULL) {
582 mTimeSource = new SystemTimeSource;
583 }
584
585 if (mVideoSource != NULL) {
Andreas Huber7085b6842010-02-03 16:02:02 -0800586 // Kick off video playback
587 postVideoEvent_l();
Andreas Huber27366fc2009-11-20 09:32:46 -0800588 }
589
Andreas Huberc1d5c922009-12-10 15:49:04 -0800590 if (deferredAudioSeek) {
591 // If there was a seek request while we were paused
592 // and we're just starting up again, honor the request now.
593 seekAudioIfNecessary_l();
594 }
595
Andreas Huber406a18b2010-02-18 16:45:13 -0800596 if (mFlags & AT_EOS) {
597 // Legacy behaviour, if a stream finishes playing and then
598 // is started again, we play from the start...
599 seekTo_l(0);
600 }
601
Andreas Huber27366fc2009-11-20 09:32:46 -0800602 return OK;
603}
604
605void AwesomePlayer::initRenderer_l() {
606 if (mISurface != NULL) {
607 sp<MetaData> meta = mVideoSource->getFormat();
608
609 int32_t format;
610 const char *component;
611 int32_t decodedWidth, decodedHeight;
612 CHECK(meta->findInt32(kKeyColorFormat, &format));
613 CHECK(meta->findCString(kKeyDecoderComponent, &component));
614 CHECK(meta->findInt32(kKeyWidth, &decodedWidth));
615 CHECK(meta->findInt32(kKeyHeight, &decodedHeight));
616
Andreas Hubera67d5382009-12-10 15:32:12 -0800617 mVideoRenderer.clear();
618
619 // Must ensure that mVideoRenderer's destructor is actually executed
620 // before creating a new one.
621 IPCThreadState::self()->flushCommands();
622
Andreas Huber1314e732009-12-14 14:18:22 -0800623 if (!strncmp("OMX.", component, 4)) {
624 // Our OMX codecs allocate buffers on the media_server side
625 // therefore they require a remote IOMXRenderer that knows how
626 // to display them.
627 mVideoRenderer = new AwesomeRemoteRenderer(
628 mClient.interface()->createRenderer(
629 mISurface, component,
630 (OMX_COLOR_FORMATTYPE)format,
631 decodedWidth, decodedHeight,
632 mVideoWidth, mVideoHeight));
633 } else {
634 // Other decoders are instantiated locally and as a consequence
635 // allocate their buffers in local address space.
636 mVideoRenderer = new AwesomeLocalRenderer(
Andreas Huber7b73cfc2010-02-12 14:40:08 -0800637 false, // previewOnly
Andreas Huber4ab5a6f2010-02-11 11:00:26 -0800638 component,
Andreas Huber1314e732009-12-14 14:18:22 -0800639 (OMX_COLOR_FORMATTYPE)format,
640 mISurface,
641 mVideoWidth, mVideoHeight,
642 decodedWidth, decodedHeight);
643 }
Andreas Huber27366fc2009-11-20 09:32:46 -0800644 }
645}
646
647status_t AwesomePlayer::pause() {
648 Mutex::Autolock autoLock(mLock);
Andreas Huber4d61f602010-06-10 11:17:50 -0700649
650 mFlags &= ~CACHE_UNDERRUN;
651
Andreas Huber27366fc2009-11-20 09:32:46 -0800652 return pause_l();
653}
654
655status_t AwesomePlayer::pause_l() {
656 if (!(mFlags & PLAYING)) {
657 return OK;
658 }
659
Andreas Huberb9e63832010-01-26 16:20:10 -0800660 cancelPlayerEvents(true /* keepBufferingGoing */);
Andreas Huber27366fc2009-11-20 09:32:46 -0800661
662 if (mAudioPlayer != NULL) {
663 mAudioPlayer->pause();
664 }
665
666 mFlags &= ~PLAYING;
667
668 return OK;
669}
670
671bool AwesomePlayer::isPlaying() const {
Andreas Huber4d61f602010-06-10 11:17:50 -0700672 return (mFlags & PLAYING) || (mFlags & CACHE_UNDERRUN);
Andreas Huber27366fc2009-11-20 09:32:46 -0800673}
674
675void AwesomePlayer::setISurface(const sp<ISurface> &isurface) {
676 Mutex::Autolock autoLock(mLock);
677
678 mISurface = isurface;
679}
680
681void AwesomePlayer::setAudioSink(
682 const sp<MediaPlayerBase::AudioSink> &audioSink) {
683 Mutex::Autolock autoLock(mLock);
684
685 mAudioSink = audioSink;
686}
687
688status_t AwesomePlayer::setLooping(bool shouldLoop) {
689 Mutex::Autolock autoLock(mLock);
690
691 mFlags = mFlags & ~LOOPING;
692
693 if (shouldLoop) {
694 mFlags |= LOOPING;
695 }
696
697 return OK;
698}
699
700status_t AwesomePlayer::getDuration(int64_t *durationUs) {
Andreas Huber252573c2010-03-26 10:17:17 -0700701 Mutex::Autolock autoLock(mMiscStateLock);
Andreas Huber27366fc2009-11-20 09:32:46 -0800702
703 if (mDurationUs < 0) {
704 return UNKNOWN_ERROR;
705 }
706
707 *durationUs = mDurationUs;
708
709 return OK;
710}
711
712status_t AwesomePlayer::getPosition(int64_t *positionUs) {
Andreas Huberddb709c2010-04-07 10:24:35 -0700713 if (mSeeking) {
714 *positionUs = mSeekTimeUs;
715 } else if (mVideoSource != NULL) {
Andreas Huber252573c2010-03-26 10:17:17 -0700716 Mutex::Autolock autoLock(mMiscStateLock);
Andreas Huber27366fc2009-11-20 09:32:46 -0800717 *positionUs = mVideoTimeUs;
718 } else if (mAudioPlayer != NULL) {
719 *positionUs = mAudioPlayer->getMediaTimeUs();
720 } else {
721 *positionUs = 0;
722 }
723
724 return OK;
725}
726
727status_t AwesomePlayer::seekTo(int64_t timeUs) {
Andreas Huber62f7ffe2010-05-06 10:18:05 -0700728 if (mExtractorFlags
729 & (MediaExtractor::CAN_SEEK_FORWARD
730 | MediaExtractor::CAN_SEEK_BACKWARD)) {
731 Mutex::Autolock autoLock(mLock);
732 return seekTo_l(timeUs);
733 }
734
735 return OK;
Andreas Huber27366fc2009-11-20 09:32:46 -0800736}
737
738status_t AwesomePlayer::seekTo_l(int64_t timeUs) {
Andreas Huber4d61f602010-06-10 11:17:50 -0700739 if (mFlags & CACHE_UNDERRUN) {
740 mFlags &= ~CACHE_UNDERRUN;
741 play_l();
742 }
743
Andreas Huber27366fc2009-11-20 09:32:46 -0800744 mSeeking = true;
Andreas Huber8e2b9412010-03-31 09:40:15 -0700745 mSeekNotificationSent = false;
Andreas Huber27366fc2009-11-20 09:32:46 -0800746 mSeekTimeUs = timeUs;
Andreas Huber406a18b2010-02-18 16:45:13 -0800747 mFlags &= ~AT_EOS;
Andreas Huber27366fc2009-11-20 09:32:46 -0800748
749 seekAudioIfNecessary_l();
750
Andreas Huber8e2b9412010-03-31 09:40:15 -0700751 if (!(mFlags & PLAYING)) {
752 LOGV("seeking while paused, sending SEEK_COMPLETE notification"
753 " immediately.");
754
755 notifyListener_l(MEDIA_SEEK_COMPLETE);
756 mSeekNotificationSent = true;
757 }
758
Andreas Huber27366fc2009-11-20 09:32:46 -0800759 return OK;
760}
761
762void AwesomePlayer::seekAudioIfNecessary_l() {
Andreas Huber7085b6842010-02-03 16:02:02 -0800763 if (mSeeking && mVideoSource == NULL && mAudioPlayer != NULL) {
Andreas Huber27366fc2009-11-20 09:32:46 -0800764 mAudioPlayer->seekTo(mSeekTimeUs);
765
Andreas Huber70d10c02010-02-03 11:37:29 -0800766 mWatchForAudioSeekComplete = true;
767 mWatchForAudioEOS = true;
Andreas Huber8e2b9412010-03-31 09:40:15 -0700768 mSeekNotificationSent = false;
Andreas Huber27366fc2009-11-20 09:32:46 -0800769 }
770}
771
772status_t AwesomePlayer::getVideoDimensions(
773 int32_t *width, int32_t *height) const {
774 Mutex::Autolock autoLock(mLock);
775
776 if (mVideoWidth < 0 || mVideoHeight < 0) {
777 return UNKNOWN_ERROR;
778 }
779
780 *width = mVideoWidth;
781 *height = mVideoHeight;
782
783 return OK;
784}
785
Andreas Huber3ac94ef2010-03-05 10:42:10 -0800786void AwesomePlayer::setAudioSource(sp<MediaSource> source) {
787 CHECK(source != NULL);
Andreas Huber27366fc2009-11-20 09:32:46 -0800788
Andreas Huber3ac94ef2010-03-05 10:42:10 -0800789 mAudioTrack = source;
790}
791
792status_t AwesomePlayer::initAudioDecoder() {
793 sp<MetaData> meta = mAudioTrack->getFormat();
Andreas Huberc79827a2010-01-05 10:54:55 -0800794
795 const char *mime;
796 CHECK(meta->findCString(kKeyMIMEType, &mime));
797
798 if (!strcasecmp(mime, MEDIA_MIMETYPE_AUDIO_RAW)) {
Andreas Huber3ac94ef2010-03-05 10:42:10 -0800799 mAudioSource = mAudioTrack;
Andreas Huberc79827a2010-01-05 10:54:55 -0800800 } else {
801 mAudioSource = OMXCodec::Create(
Andreas Huber3ac94ef2010-03-05 10:42:10 -0800802 mClient.interface(), mAudioTrack->getFormat(),
Andreas Huberc79827a2010-01-05 10:54:55 -0800803 false, // createEncoder
Andreas Huber3ac94ef2010-03-05 10:42:10 -0800804 mAudioTrack);
Andreas Huberc79827a2010-01-05 10:54:55 -0800805 }
Andreas Huber27366fc2009-11-20 09:32:46 -0800806
807 if (mAudioSource != NULL) {
808 int64_t durationUs;
Andreas Huber3ac94ef2010-03-05 10:42:10 -0800809 if (mAudioTrack->getFormat()->findInt64(kKeyDuration, &durationUs)) {
Andreas Huber252573c2010-03-26 10:17:17 -0700810 Mutex::Autolock autoLock(mMiscStateLock);
Andreas Huber27366fc2009-11-20 09:32:46 -0800811 if (mDurationUs < 0 || durationUs > mDurationUs) {
812 mDurationUs = durationUs;
813 }
814 }
Andreas Huber27366fc2009-11-20 09:32:46 -0800815
Andreas Huber3c78a1b2010-05-13 09:15:21 -0700816 status_t err = mAudioSource->start();
817
818 if (err != OK) {
819 mAudioSource.clear();
820 return err;
821 }
Andreas Huberd0332ad2010-04-12 16:05:57 -0700822 } else if (!strcasecmp(mime, MEDIA_MIMETYPE_AUDIO_QCELP)) {
823 // For legacy reasons we're simply going to ignore the absence
824 // of an audio decoder for QCELP instead of aborting playback
825 // altogether.
826 return OK;
827 }
Andreas Huberdc9927d2010-03-08 15:46:13 -0800828
Andreas Huber27366fc2009-11-20 09:32:46 -0800829 return mAudioSource != NULL ? OK : UNKNOWN_ERROR;
830}
831
Andreas Huber3ac94ef2010-03-05 10:42:10 -0800832void AwesomePlayer::setVideoSource(sp<MediaSource> source) {
833 CHECK(source != NULL);
Andreas Huber27366fc2009-11-20 09:32:46 -0800834
Andreas Huber3ac94ef2010-03-05 10:42:10 -0800835 mVideoTrack = source;
836}
837
838status_t AwesomePlayer::initVideoDecoder() {
Andreas Huber27366fc2009-11-20 09:32:46 -0800839 mVideoSource = OMXCodec::Create(
Andreas Huber3ac94ef2010-03-05 10:42:10 -0800840 mClient.interface(), mVideoTrack->getFormat(),
Andreas Huber27366fc2009-11-20 09:32:46 -0800841 false, // createEncoder
Andreas Huber3ac94ef2010-03-05 10:42:10 -0800842 mVideoTrack);
Andreas Huber27366fc2009-11-20 09:32:46 -0800843
844 if (mVideoSource != NULL) {
845 int64_t durationUs;
Andreas Huber3ac94ef2010-03-05 10:42:10 -0800846 if (mVideoTrack->getFormat()->findInt64(kKeyDuration, &durationUs)) {
Andreas Huber252573c2010-03-26 10:17:17 -0700847 Mutex::Autolock autoLock(mMiscStateLock);
Andreas Huber27366fc2009-11-20 09:32:46 -0800848 if (mDurationUs < 0 || durationUs > mDurationUs) {
849 mDurationUs = durationUs;
850 }
851 }
852
Andreas Huber3ac94ef2010-03-05 10:42:10 -0800853 CHECK(mVideoTrack->getFormat()->findInt32(kKeyWidth, &mVideoWidth));
854 CHECK(mVideoTrack->getFormat()->findInt32(kKeyHeight, &mVideoHeight));
Andreas Huber27366fc2009-11-20 09:32:46 -0800855
Andreas Huber1919e5a2010-05-20 10:37:06 -0700856 status_t err = mVideoSource->start();
857
858 if (err != OK) {
859 mVideoSource.clear();
860 return err;
861 }
Andreas Huber27366fc2009-11-20 09:32:46 -0800862 }
863
864 return mVideoSource != NULL ? OK : UNKNOWN_ERROR;
865}
866
Andreas Huber6be780e2010-02-08 14:40:30 -0800867void AwesomePlayer::onVideoEvent() {
Andreas Huber27366fc2009-11-20 09:32:46 -0800868 Mutex::Autolock autoLock(mLock);
Andreas Huberba7ec912010-02-12 10:42:02 -0800869 if (!mVideoEventPending) {
870 // The event has been cancelled in reset_l() but had already
871 // been scheduled for execution at that time.
872 return;
873 }
Andreas Huber27366fc2009-11-20 09:32:46 -0800874 mVideoEventPending = false;
875
876 if (mSeeking) {
877 if (mLastVideoBuffer) {
878 mLastVideoBuffer->release();
879 mLastVideoBuffer = NULL;
880 }
881
882 if (mVideoBuffer) {
883 mVideoBuffer->release();
884 mVideoBuffer = NULL;
885 }
Andreas Huber4d61f602010-06-10 11:17:50 -0700886
887 if (mCachedSource != NULL && mAudioSource != NULL) {
888 // We're going to seek the video source first, followed by
889 // the audio source.
890 // In order to avoid jumps in the DataSource offset caused by
891 // the audio codec prefetching data from the old locations
892 // while the video codec is already reading data from the new
893 // locations, we'll "pause" the audio source, causing it to
894 // stop reading input data until a subsequent seek.
895
896 if (mAudioPlayer != NULL) {
897 mAudioPlayer->pause();
898 }
899 mAudioSource->pause();
900 }
Andreas Huber27366fc2009-11-20 09:32:46 -0800901 }
902
903 if (!mVideoBuffer) {
904 MediaSource::ReadOptions options;
905 if (mSeeking) {
906 LOGV("seeking to %lld us (%.2f secs)", mSeekTimeUs, mSeekTimeUs / 1E6);
907
908 options.setSeekTo(mSeekTimeUs);
909 }
910 for (;;) {
911 status_t err = mVideoSource->read(&mVideoBuffer, &options);
Andreas Huberb1f5ee42009-12-14 15:34:11 -0800912 options.clearSeekTo();
Andreas Huber27366fc2009-11-20 09:32:46 -0800913
914 if (err != OK) {
915 CHECK_EQ(mVideoBuffer, NULL);
916
917 if (err == INFO_FORMAT_CHANGED) {
918 LOGV("VideoSource signalled format change.");
919
Andreas Huber7085b6842010-02-03 16:02:02 -0800920 if (mVideoRenderer != NULL) {
Andreas Huber7b73cfc2010-02-12 14:40:08 -0800921 mVideoRendererIsPreview = false;
Andreas Huber7085b6842010-02-03 16:02:02 -0800922 initRenderer_l();
923 }
Andreas Huber27366fc2009-11-20 09:32:46 -0800924 continue;
925 }
926
Andreas Huberd7d22eb2010-02-23 13:45:33 -0800927 postStreamDoneEvent_l(err);
Andreas Huber27366fc2009-11-20 09:32:46 -0800928 return;
929 }
930
Andreas Hubera67d5382009-12-10 15:32:12 -0800931 if (mVideoBuffer->range_length() == 0) {
Andreas Huber6ddcf012009-12-10 15:32:12 -0800932 // Some decoders, notably the PV AVC software decoder
933 // return spurious empty buffers that we just want to ignore.
934
Andreas Hubera67d5382009-12-10 15:32:12 -0800935 mVideoBuffer->release();
936 mVideoBuffer = NULL;
937 continue;
938 }
939
Andreas Huber27366fc2009-11-20 09:32:46 -0800940 break;
941 }
942 }
943
944 int64_t timeUs;
945 CHECK(mVideoBuffer->meta_data()->findInt64(kKeyTime, &timeUs));
946
Andreas Huber252573c2010-03-26 10:17:17 -0700947 {
948 Mutex::Autolock autoLock(mMiscStateLock);
949 mVideoTimeUs = timeUs;
950 }
Andreas Huber27366fc2009-11-20 09:32:46 -0800951
952 if (mSeeking) {
953 if (mAudioPlayer != NULL) {
954 LOGV("seeking audio to %lld us (%.2f secs).", timeUs, timeUs / 1E6);
955
956 mAudioPlayer->seekTo(timeUs);
Andreas Huber4d61f602010-06-10 11:17:50 -0700957 mAudioPlayer->resume();
Andreas Huber70d10c02010-02-03 11:37:29 -0800958 mWatchForAudioSeekComplete = true;
959 mWatchForAudioEOS = true;
Andreas Huber8e2b9412010-03-31 09:40:15 -0700960 } else if (!mSeekNotificationSent) {
Andreas Huber27366fc2009-11-20 09:32:46 -0800961 // If we're playing video only, report seek complete now,
962 // otherwise audio player will notify us later.
Andreas Hubera3f43842010-01-21 10:28:45 -0800963 notifyListener_l(MEDIA_SEEK_COMPLETE);
Andreas Huber27366fc2009-11-20 09:32:46 -0800964 }
965
966 mFlags |= FIRST_FRAME;
967 mSeeking = false;
Andreas Huber8e2b9412010-03-31 09:40:15 -0700968 mSeekNotificationSent = false;
Andreas Huber27366fc2009-11-20 09:32:46 -0800969 }
970
971 if (mFlags & FIRST_FRAME) {
972 mFlags &= ~FIRST_FRAME;
973
974 mTimeSourceDeltaUs = mTimeSource->getRealTimeUs() - timeUs;
975 }
976
977 int64_t realTimeUs, mediaTimeUs;
978 if (mAudioPlayer != NULL
979 && mAudioPlayer->getMediaTimeMapping(&realTimeUs, &mediaTimeUs)) {
980 mTimeSourceDeltaUs = realTimeUs - mediaTimeUs;
981 }
982
983 int64_t nowUs = mTimeSource->getRealTimeUs() - mTimeSourceDeltaUs;
984
985 int64_t latenessUs = nowUs - timeUs;
986
Andreas Huber24b0a952009-11-23 14:02:00 -0800987 if (latenessUs > 40000) {
988 // We're more than 40ms late.
Andreas Huber4a9375e2010-02-09 11:54:33 -0800989 LOGV("we're late by %lld us (%.2f secs)", latenessUs, latenessUs / 1E6);
Andreas Huber27366fc2009-11-20 09:32:46 -0800990
991 mVideoBuffer->release();
992 mVideoBuffer = NULL;
993
994 postVideoEvent_l();
995 return;
996 }
997
998 if (latenessUs < -10000) {
999 // We're more than 10ms early.
1000
1001 postVideoEvent_l(10000);
1002 return;
1003 }
1004
Andreas Huber7b73cfc2010-02-12 14:40:08 -08001005 if (mVideoRendererIsPreview || mVideoRenderer == NULL) {
1006 mVideoRendererIsPreview = false;
1007
Andreas Huber7085b6842010-02-03 16:02:02 -08001008 initRenderer_l();
1009 }
1010
1011 if (mVideoRenderer != NULL) {
1012 mVideoRenderer->render(mVideoBuffer);
1013 }
Andreas Huber27366fc2009-11-20 09:32:46 -08001014
1015 if (mLastVideoBuffer) {
1016 mLastVideoBuffer->release();
1017 mLastVideoBuffer = NULL;
1018 }
1019 mLastVideoBuffer = mVideoBuffer;
1020 mVideoBuffer = NULL;
1021
1022 postVideoEvent_l();
1023}
1024
1025void AwesomePlayer::postVideoEvent_l(int64_t delayUs) {
1026 if (mVideoEventPending) {
1027 return;
1028 }
1029
1030 mVideoEventPending = true;
1031 mQueue.postEventWithDelay(mVideoEvent, delayUs < 0 ? 10000 : delayUs);
1032}
1033
Andreas Huberd7d22eb2010-02-23 13:45:33 -08001034void AwesomePlayer::postStreamDoneEvent_l(status_t status) {
Andreas Huber27366fc2009-11-20 09:32:46 -08001035 if (mStreamDoneEventPending) {
1036 return;
1037 }
1038 mStreamDoneEventPending = true;
Andreas Huberd7d22eb2010-02-23 13:45:33 -08001039
1040 mStreamDoneStatus = status;
Andreas Huber27366fc2009-11-20 09:32:46 -08001041 mQueue.postEvent(mStreamDoneEvent);
1042}
1043
Andreas Huberb9e63832010-01-26 16:20:10 -08001044void AwesomePlayer::postBufferingEvent_l() {
Andreas Huberb9e63832010-01-26 16:20:10 -08001045 if (mBufferingEventPending) {
1046 return;
1047 }
1048 mBufferingEventPending = true;
1049 mQueue.postEventWithDelay(mBufferingEvent, 1000000ll);
1050}
1051
Andreas Huber70d10c02010-02-03 11:37:29 -08001052void AwesomePlayer::postCheckAudioStatusEvent_l() {
1053 if (mAudioStatusEventPending) {
1054 return;
1055 }
1056 mAudioStatusEventPending = true;
1057 mQueue.postEventWithDelay(mCheckAudioStatusEvent, 100000ll);
1058}
1059
1060void AwesomePlayer::onCheckAudioStatus() {
1061 Mutex::Autolock autoLock(mLock);
Andreas Huberc0178f12010-02-17 15:58:57 -08001062 if (!mAudioStatusEventPending) {
1063 // Event was dispatched and while we were blocking on the mutex,
1064 // has already been cancelled.
1065 return;
1066 }
1067
Andreas Huber70d10c02010-02-03 11:37:29 -08001068 mAudioStatusEventPending = false;
1069
1070 if (mWatchForAudioSeekComplete && !mAudioPlayer->isSeeking()) {
1071 mWatchForAudioSeekComplete = false;
Andreas Huber8e2b9412010-03-31 09:40:15 -07001072
1073 if (!mSeekNotificationSent) {
1074 notifyListener_l(MEDIA_SEEK_COMPLETE);
1075 mSeekNotificationSent = true;
1076 }
Andreas Huberddb709c2010-04-07 10:24:35 -07001077
1078 mSeeking = false;
Andreas Huber70d10c02010-02-03 11:37:29 -08001079 }
1080
Andreas Huberd7d22eb2010-02-23 13:45:33 -08001081 status_t finalStatus;
1082 if (mWatchForAudioEOS && mAudioPlayer->reachedEOS(&finalStatus)) {
Andreas Huber70d10c02010-02-03 11:37:29 -08001083 mWatchForAudioEOS = false;
Andreas Huberd7d22eb2010-02-23 13:45:33 -08001084 postStreamDoneEvent_l(finalStatus);
Andreas Huber70d10c02010-02-03 11:37:29 -08001085 }
1086
1087 postCheckAudioStatusEvent_l();
1088}
1089
Andreas Huber6be780e2010-02-08 14:40:30 -08001090status_t AwesomePlayer::prepare() {
1091 Mutex::Autolock autoLock(mLock);
Andreas Huberffdf4782010-02-09 14:05:43 -08001092 return prepare_l();
1093}
Andreas Huber6be780e2010-02-08 14:40:30 -08001094
Andreas Huberffdf4782010-02-09 14:05:43 -08001095status_t AwesomePlayer::prepare_l() {
1096 if (mFlags & PREPARED) {
1097 return OK;
1098 }
1099
1100 if (mFlags & PREPARING) {
1101 return UNKNOWN_ERROR;
1102 }
1103
1104 mIsAsyncPrepare = false;
Andreas Huber6be780e2010-02-08 14:40:30 -08001105 status_t err = prepareAsync_l();
1106
1107 if (err != OK) {
1108 return err;
1109 }
1110
Andreas Huberffdf4782010-02-09 14:05:43 -08001111 while (mFlags & PREPARING) {
Andreas Huber6be780e2010-02-08 14:40:30 -08001112 mPreparedCondition.wait(mLock);
1113 }
1114
Andreas Huberffdf4782010-02-09 14:05:43 -08001115 return mPrepareResult;
Andreas Huber6be780e2010-02-08 14:40:30 -08001116}
1117
1118status_t AwesomePlayer::prepareAsync() {
1119 Mutex::Autolock autoLock(mLock);
Andreas Huberffdf4782010-02-09 14:05:43 -08001120
1121 if (mFlags & PREPARING) {
1122 return UNKNOWN_ERROR; // async prepare already pending
1123 }
1124
1125 mIsAsyncPrepare = true;
Andreas Huber6be780e2010-02-08 14:40:30 -08001126 return prepareAsync_l();
1127}
1128
1129status_t AwesomePlayer::prepareAsync_l() {
Andreas Huberffdf4782010-02-09 14:05:43 -08001130 if (mFlags & PREPARING) {
1131 return UNKNOWN_ERROR; // async prepare already pending
Andreas Huber6be780e2010-02-08 14:40:30 -08001132 }
1133
Andreas Huber406a18b2010-02-18 16:45:13 -08001134 if (!mQueueStarted) {
1135 mQueue.start();
1136 mQueueStarted = true;
1137 }
1138
Andreas Huberffdf4782010-02-09 14:05:43 -08001139 mFlags |= PREPARING;
Andreas Huber6be780e2010-02-08 14:40:30 -08001140 mAsyncPrepareEvent = new AwesomeEvent(
1141 this, &AwesomePlayer::onPrepareAsyncEvent);
1142
1143 mQueue.postEvent(mAsyncPrepareEvent);
1144
1145 return OK;
1146}
1147
Andreas Huberffdf4782010-02-09 14:05:43 -08001148status_t AwesomePlayer::finishSetDataSource_l() {
Andreas Huberedbb4d82010-03-12 08:59:22 -08001149 sp<DataSource> dataSource;
1150
1151 if (!strncasecmp("http://", mUri.string(), 7)) {
Andreas Huber4d61f602010-06-10 11:17:50 -07001152 mConnectingDataSource = new NuHTTPDataSource;
Andreas Huberedbb4d82010-03-12 08:59:22 -08001153
1154 mLock.unlock();
Andreas Huber4d61f602010-06-10 11:17:50 -07001155 status_t err = mConnectingDataSource->connect(mUri/*, mUriHeaders */);
Andreas Huberedbb4d82010-03-12 08:59:22 -08001156 mLock.lock();
1157
1158 if (err != OK) {
1159 mConnectingDataSource.clear();
1160
1161 LOGI("mConnectingDataSource->connect() returned %d", err);
1162 return err;
1163 }
1164
Andreas Huber4d61f602010-06-10 11:17:50 -07001165#if 0
1166 mCachedSource = new NuCachedSource2(
1167 new ThrottledSource(
1168 mConnectingDataSource, 50 * 1024 /* bytes/sec */));
1169#else
1170 mCachedSource = new NuCachedSource2(mConnectingDataSource);
1171#endif
Andreas Huberedbb4d82010-03-12 08:59:22 -08001172 mConnectingDataSource.clear();
Andreas Huber4d61f602010-06-10 11:17:50 -07001173
1174 dataSource = mCachedSource;
Andreas Huber202348e2010-06-07 14:35:29 -07001175 } else if (!strncasecmp(mUri.string(), "httplive://", 11)) {
1176 String8 uri("http://");
1177 uri.append(mUri.string() + 11);
1178
1179 dataSource = new LiveSource(uri.string());
1180
Andreas Huber4d61f602010-06-10 11:17:50 -07001181 mCachedSource = new NuCachedSource2(dataSource);
1182 dataSource = mCachedSource;
Andreas Huber202348e2010-06-07 14:35:29 -07001183
1184 sp<MediaExtractor> extractor =
1185 MediaExtractor::Create(dataSource, MEDIA_MIMETYPE_CONTAINER_MPEG2TS);
Andreas Huber4d61f602010-06-10 11:17:50 -07001186
1187 return setDataSource_l(extractor);
Andreas Huber7a747b82010-06-07 15:19:40 -07001188 } else if (!strncasecmp("rtsp://", mUri.string(), 7)) {
1189 if (mLooper == NULL) {
1190 mLooper = new ALooper;
1191 mLooper->start();
1192 }
1193 mRTSPController = new ARTSPController(mLooper);
1194 status_t err = mRTSPController->connect(mUri.string());
Andreas Huber202348e2010-06-07 14:35:29 -07001195
Andreas Huber7a747b82010-06-07 15:19:40 -07001196 LOGI("ARTSPController::connect returned %d", err);
1197
1198 if (err != OK) {
1199 mRTSPController.clear();
1200 return err;
1201 }
1202
1203 sp<MediaExtractor> extractor = mRTSPController.get();
Andreas Huber202348e2010-06-07 14:35:29 -07001204 return setDataSource_l(extractor);
Andreas Huberedbb4d82010-03-12 08:59:22 -08001205 } else {
1206 dataSource = DataSource::CreateFromURI(mUri.string(), &mUriHeaders);
1207 }
Andreas Huberffdf4782010-02-09 14:05:43 -08001208
1209 if (dataSource == NULL) {
1210 return UNKNOWN_ERROR;
1211 }
1212
1213 sp<MediaExtractor> extractor = MediaExtractor::Create(dataSource);
1214
1215 if (extractor == NULL) {
1216 return UNKNOWN_ERROR;
1217 }
1218
Andreas Huberffdf4782010-02-09 14:05:43 -08001219 return setDataSource_l(extractor);
1220}
1221
Andreas Huber3ac94ef2010-03-05 10:42:10 -08001222void AwesomePlayer::abortPrepare(status_t err) {
1223 CHECK(err != OK);
1224
1225 if (mIsAsyncPrepare) {
1226 notifyListener_l(MEDIA_ERROR, MEDIA_ERROR_UNKNOWN, err);
1227 }
1228
1229 mPrepareResult = err;
Andreas Huberedbb4d82010-03-12 08:59:22 -08001230 mFlags &= ~(PREPARING|PREPARE_CANCELLED);
Andreas Huber3ac94ef2010-03-05 10:42:10 -08001231 mAsyncPrepareEvent = NULL;
1232 mPreparedCondition.broadcast();
1233}
1234
Andreas Huberf71daba2010-03-24 09:24:40 -07001235// static
1236bool AwesomePlayer::ContinuePreparation(void *cookie) {
1237 AwesomePlayer *me = static_cast<AwesomePlayer *>(cookie);
1238
1239 return (me->mFlags & PREPARE_CANCELLED) == 0;
1240}
1241
Andreas Huber6be780e2010-02-08 14:40:30 -08001242void AwesomePlayer::onPrepareAsyncEvent() {
Andreas Huberffdf4782010-02-09 14:05:43 -08001243 {
1244 Mutex::Autolock autoLock(mLock);
1245
Andreas Huberedbb4d82010-03-12 08:59:22 -08001246 if (mFlags & PREPARE_CANCELLED) {
1247 LOGI("prepare was cancelled before doing anything");
1248 abortPrepare(UNKNOWN_ERROR);
1249 return;
1250 }
1251
Andreas Huberffdf4782010-02-09 14:05:43 -08001252 if (mUri.size() > 0) {
1253 status_t err = finishSetDataSource_l();
1254
1255 if (err != OK) {
Andreas Huber3ac94ef2010-03-05 10:42:10 -08001256 abortPrepare(err);
Andreas Huberffdf4782010-02-09 14:05:43 -08001257 return;
1258 }
1259 }
Andreas Huberffdf4782010-02-09 14:05:43 -08001260
Andreas Huber55864df72010-03-08 12:28:22 -08001261 if (mVideoTrack != NULL && mVideoSource == NULL) {
1262 status_t err = initVideoDecoder();
Andreas Huber6be780e2010-02-08 14:40:30 -08001263
Andreas Huber55864df72010-03-08 12:28:22 -08001264 if (err != OK) {
1265 abortPrepare(err);
1266 return;
1267 }
1268 }
1269
1270 if (mAudioTrack != NULL && mAudioSource == NULL) {
1271 status_t err = initAudioDecoder();
1272
1273 if (err != OK) {
1274 abortPrepare(err);
1275 return;
1276 }
1277 }
Andreas Huber6be780e2010-02-08 14:40:30 -08001278 }
1279
1280 Mutex::Autolock autoLock(mLock);
1281
Andreas Huberffdf4782010-02-09 14:05:43 -08001282 if (mIsAsyncPrepare) {
1283 if (mVideoWidth < 0 || mVideoHeight < 0) {
1284 notifyListener_l(MEDIA_SET_VIDEO_SIZE, 0, 0);
1285 } else {
1286 notifyListener_l(MEDIA_SET_VIDEO_SIZE, mVideoWidth, mVideoHeight);
1287 }
1288
1289 notifyListener_l(MEDIA_PREPARED);
Andreas Huber6be780e2010-02-08 14:40:30 -08001290 }
1291
Andreas Huberffdf4782010-02-09 14:05:43 -08001292 mPrepareResult = OK;
Andreas Huberedbb4d82010-03-12 08:59:22 -08001293 mFlags &= ~(PREPARING|PREPARE_CANCELLED);
Andreas Huberffdf4782010-02-09 14:05:43 -08001294 mFlags |= PREPARED;
Andreas Huber6be780e2010-02-08 14:40:30 -08001295 mAsyncPrepareEvent = NULL;
Andreas Huberffdf4782010-02-09 14:05:43 -08001296 mPreparedCondition.broadcast();
Andreas Huber040301c2010-04-12 09:41:12 -07001297
1298 postBufferingEvent_l();
Andreas Huber6be780e2010-02-08 14:40:30 -08001299}
1300
Andreas Huberba7ec912010-02-12 10:42:02 -08001301status_t AwesomePlayer::suspend() {
Andreas Huberedbb4d82010-03-12 08:59:22 -08001302 LOGV("suspend");
Andreas Huberba7ec912010-02-12 10:42:02 -08001303 Mutex::Autolock autoLock(mLock);
1304
1305 if (mSuspensionState != NULL) {
Gloria Wangb19da8e2010-04-12 17:13:06 -07001306 if (mLastVideoBuffer == NULL) {
1307 //go into here if video is suspended again
1308 //after resuming without being played between
1309 //them
1310 SuspensionState *state = mSuspensionState;
1311 mSuspensionState = NULL;
1312 reset_l();
1313 mSuspensionState = state;
1314 return OK;
1315 }
1316
1317 delete mSuspensionState;
1318 mSuspensionState = NULL;
Andreas Huberba7ec912010-02-12 10:42:02 -08001319 }
1320
Andreas Huberedbb4d82010-03-12 08:59:22 -08001321 if (mFlags & PREPARING) {
1322 mFlags |= PREPARE_CANCELLED;
1323 if (mConnectingDataSource != NULL) {
1324 LOGI("interrupting the connection process");
1325 mConnectingDataSource->disconnect();
1326 }
1327 }
1328
Andreas Huberba7ec912010-02-12 10:42:02 -08001329 while (mFlags & PREPARING) {
1330 mPreparedCondition.wait(mLock);
1331 }
1332
1333 SuspensionState *state = new SuspensionState;
1334 state->mUri = mUri;
1335 state->mUriHeaders = mUriHeaders;
1336 state->mFileSource = mFileSource;
1337
Andreas Huber406a18b2010-02-18 16:45:13 -08001338 state->mFlags = mFlags & (PLAYING | LOOPING | AT_EOS);
Andreas Huber252573c2010-03-26 10:17:17 -07001339 getPosition(&state->mPositionUs);
Andreas Huberba7ec912010-02-12 10:42:02 -08001340
Andreas Huber7b73cfc2010-02-12 14:40:08 -08001341 if (mLastVideoBuffer) {
1342 size_t size = mLastVideoBuffer->range_length();
1343 if (size) {
1344 state->mLastVideoFrameSize = size;
1345 state->mLastVideoFrame = malloc(size);
1346 memcpy(state->mLastVideoFrame,
1347 (const uint8_t *)mLastVideoBuffer->data()
1348 + mLastVideoBuffer->range_offset(),
1349 size);
1350
1351 state->mVideoWidth = mVideoWidth;
1352 state->mVideoHeight = mVideoHeight;
1353
1354 sp<MetaData> meta = mVideoSource->getFormat();
1355 CHECK(meta->findInt32(kKeyColorFormat, &state->mColorFormat));
1356 CHECK(meta->findInt32(kKeyWidth, &state->mDecodedWidth));
1357 CHECK(meta->findInt32(kKeyHeight, &state->mDecodedHeight));
1358 }
1359 }
1360
Andreas Huberba7ec912010-02-12 10:42:02 -08001361 reset_l();
1362
1363 mSuspensionState = state;
1364
1365 return OK;
1366}
1367
1368status_t AwesomePlayer::resume() {
Andreas Huberedbb4d82010-03-12 08:59:22 -08001369 LOGV("resume");
Andreas Huberba7ec912010-02-12 10:42:02 -08001370 Mutex::Autolock autoLock(mLock);
1371
1372 if (mSuspensionState == NULL) {
1373 return INVALID_OPERATION;
1374 }
1375
1376 SuspensionState *state = mSuspensionState;
1377 mSuspensionState = NULL;
1378
1379 status_t err;
1380 if (state->mFileSource != NULL) {
1381 err = setDataSource_l(state->mFileSource);
1382
1383 if (err == OK) {
1384 mFileSource = state->mFileSource;
1385 }
1386 } else {
1387 err = setDataSource_l(state->mUri, &state->mUriHeaders);
1388 }
1389
1390 if (err != OK) {
1391 delete state;
1392 state = NULL;
1393
1394 return err;
1395 }
1396
1397 seekTo_l(state->mPositionUs);
1398
Andreas Huber406a18b2010-02-18 16:45:13 -08001399 mFlags = state->mFlags & (LOOPING | AT_EOS);
Andreas Huberba7ec912010-02-12 10:42:02 -08001400
Andreas Huber7b73cfc2010-02-12 14:40:08 -08001401 if (state->mLastVideoFrame && mISurface != NULL) {
1402 mVideoRenderer =
1403 new AwesomeLocalRenderer(
1404 true, // previewOnly
1405 "",
1406 (OMX_COLOR_FORMATTYPE)state->mColorFormat,
1407 mISurface,
1408 state->mVideoWidth,
1409 state->mVideoHeight,
1410 state->mDecodedWidth,
1411 state->mDecodedHeight);
1412
1413 mVideoRendererIsPreview = true;
1414
1415 ((AwesomeLocalRenderer *)mVideoRenderer.get())->render(
1416 state->mLastVideoFrame, state->mLastVideoFrameSize);
1417 }
1418
Andreas Huberba7ec912010-02-12 10:42:02 -08001419 if (state->mFlags & PLAYING) {
1420 play_l();
1421 }
1422
Gloria Wangb19da8e2010-04-12 17:13:06 -07001423 mSuspensionState = state;
Andreas Huberba7ec912010-02-12 10:42:02 -08001424 state = NULL;
1425
1426 return OK;
1427}
1428
Andreas Huber62f7ffe2010-05-06 10:18:05 -07001429uint32_t AwesomePlayer::flags() const {
1430 return mExtractorFlags;
1431}
1432
Andreas Huber27366fc2009-11-20 09:32:46 -08001433} // namespace android
1434