blob: 236a62b4bf6decee82a112b88bc16ecf44d407c3 [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
Andreas Huberba7ec912010-02-12 10:42:02 -0800374 mTimeSource = NULL;
375
376 delete mAudioPlayer;
377 mAudioPlayer = NULL;
378
Andreas Huber3522b5a52010-01-22 14:36:53 -0800379 mVideoRenderer.clear();
380
Andreas Huber27366fc2009-11-20 09:32:46 -0800381 if (mLastVideoBuffer) {
382 mLastVideoBuffer->release();
383 mLastVideoBuffer = NULL;
384 }
385
386 if (mVideoBuffer) {
387 mVideoBuffer->release();
388 mVideoBuffer = NULL;
389 }
390
Andreas Huber7a747b82010-06-07 15:19:40 -0700391 mRTSPController.clear();
392
Andreas Huber27366fc2009-11-20 09:32:46 -0800393 if (mVideoSource != NULL) {
394 mVideoSource->stop();
Andreas Huber98b48de2010-01-29 10:10:22 -0800395
396 // The following hack is necessary to ensure that the OMX
397 // component is completely released by the time we may try
398 // to instantiate it again.
399 wp<MediaSource> tmp = mVideoSource;
Andreas Huber27366fc2009-11-20 09:32:46 -0800400 mVideoSource.clear();
Andreas Huber98b48de2010-01-29 10:10:22 -0800401 while (tmp.promote() != NULL) {
402 usleep(1000);
403 }
404 IPCThreadState::self()->flushCommands();
Andreas Huber27366fc2009-11-20 09:32:46 -0800405 }
406
Andreas Huber27366fc2009-11-20 09:32:46 -0800407 mDurationUs = -1;
408 mFlags = 0;
Andreas Huber62f7ffe2010-05-06 10:18:05 -0700409 mExtractorFlags = 0;
Andreas Huber27366fc2009-11-20 09:32:46 -0800410 mVideoWidth = mVideoHeight = -1;
411 mTimeSourceDeltaUs = 0;
412 mVideoTimeUs = 0;
413
414 mSeeking = false;
Andreas Huber8e2b9412010-03-31 09:40:15 -0700415 mSeekNotificationSent = false;
Andreas Huber27366fc2009-11-20 09:32:46 -0800416 mSeekTimeUs = 0;
Andreas Huberb9e63832010-01-26 16:20:10 -0800417
Andreas Huberffdf4782010-02-09 14:05:43 -0800418 mUri.setTo("");
419 mUriHeaders.clear();
Andreas Huberba7ec912010-02-12 10:42:02 -0800420
421 mFileSource.clear();
422
423 delete mSuspensionState;
424 mSuspensionState = NULL;
Andreas Huber27366fc2009-11-20 09:32:46 -0800425}
426
Andreas Huber6be780e2010-02-08 14:40:30 -0800427void AwesomePlayer::notifyListener_l(int msg, int ext1, int ext2) {
Andreas Hubera3f43842010-01-21 10:28:45 -0800428 if (mListener != NULL) {
429 sp<MediaPlayerBase> listener = mListener.promote();
430
431 if (listener != NULL) {
Andreas Huber6be780e2010-02-08 14:40:30 -0800432 listener->sendEvent(msg, ext1, ext2);
Andreas Hubera3f43842010-01-21 10:28:45 -0800433 }
434 }
435}
436
Andreas Huberb9e63832010-01-26 16:20:10 -0800437void AwesomePlayer::onBufferingUpdate() {
438 Mutex::Autolock autoLock(mLock);
Andreas Huberc0178f12010-02-17 15:58:57 -0800439 if (!mBufferingEventPending) {
440 return;
441 }
Andreas Huberb9e63832010-01-26 16:20:10 -0800442 mBufferingEventPending = false;
443
Andreas Huber4d61f602010-06-10 11:17:50 -0700444 if (mCachedSource == NULL) {
445 return;
Andreas Huber252573c2010-03-26 10:17:17 -0700446 }
447
Andreas Huber4d61f602010-06-10 11:17:50 -0700448 size_t lowWatermark = 400000;
449 size_t highWatermark = 1000000;
Andreas Huber202348e2010-06-07 14:35:29 -0700450
Andreas Huber4d61f602010-06-10 11:17:50 -0700451 off_t size;
452 if (mDurationUs >= 0 && mCachedSource->getSize(&size) == OK) {
453 int64_t bitrate = size * 8000000ll / mDurationUs; // in bits/sec
Andreas Huber202348e2010-06-07 14:35:29 -0700454
Andreas Huber4d61f602010-06-10 11:17:50 -0700455 size_t cachedSize = mCachedSource->cachedSize();
456 int64_t cachedDurationUs = cachedSize * 8000000ll / bitrate;
Andreas Huberb9e63832010-01-26 16:20:10 -0800457
Andreas Huber4d61f602010-06-10 11:17:50 -0700458 double percentage = (double)cachedDurationUs / mDurationUs;
Andreas Huberb9e63832010-01-26 16:20:10 -0800459
Andreas Huberb9e63832010-01-26 16:20:10 -0800460 notifyListener_l(MEDIA_BUFFERING_UPDATE, percentage * 100.0);
461
Andreas Huber4d61f602010-06-10 11:17:50 -0700462 lowWatermark = 2 * bitrate / 8; // 2 secs
463 highWatermark = 10 * bitrate / 8; // 10 secs
Andreas Huberb9e63832010-01-26 16:20:10 -0800464 }
Andreas Huber4d61f602010-06-10 11:17:50 -0700465
466 bool eos;
467 size_t cachedDataRemaining = mCachedSource->approxDataRemaining(&eos);
468
469 if ((mFlags & PLAYING) && !eos && (cachedDataRemaining < lowWatermark)) {
470 LOGI("cache is running low (< %d) , pausing.", lowWatermark);
471 mFlags |= CACHE_UNDERRUN;
472 pause_l();
473 notifyListener_l(MEDIA_INFO, MEDIA_INFO_BUFFERING_START);
474 } else if ((mFlags & CACHE_UNDERRUN)
475 && (eos || cachedDataRemaining > highWatermark)) {
476 LOGI("cache has filled up (> %d), resuming.", highWatermark);
477 mFlags &= ~CACHE_UNDERRUN;
478 play_l();
479 notifyListener_l(MEDIA_INFO, MEDIA_INFO_BUFFERING_END);
480 }
481
482 postBufferingEvent_l();
Andreas Huberb9e63832010-01-26 16:20:10 -0800483}
484
Andreas Huber27366fc2009-11-20 09:32:46 -0800485void AwesomePlayer::onStreamDone() {
486 // Posted whenever any stream finishes playing.
487
488 Mutex::Autolock autoLock(mLock);
Andreas Huberc0178f12010-02-17 15:58:57 -0800489 if (!mStreamDoneEventPending) {
490 return;
491 }
Andreas Huber27366fc2009-11-20 09:32:46 -0800492 mStreamDoneEventPending = false;
493
Andreas Huber971305d2010-07-07 13:35:27 -0700494 if (mStreamDoneStatus != ERROR_END_OF_STREAM) {
495 LOGV("MEDIA_ERROR %d", mStreamDoneStatus);
496
497 notifyListener_l(
498 MEDIA_ERROR, MEDIA_ERROR_UNKNOWN, mStreamDoneStatus);
499
500 pause_l();
501
502 mFlags |= AT_EOS;
503 return;
504 }
505
506 const bool allDone =
507 (mVideoSource == NULL || (mFlags & VIDEO_AT_EOS))
508 && (mAudioSource == NULL || (mFlags & AUDIO_AT_EOS));
509
510 if (!allDone) {
511 return;
512 }
513
514 if (mFlags & LOOPING) {
Andreas Huber27366fc2009-11-20 09:32:46 -0800515 seekTo_l(0);
516
Andreas Huber7085b6842010-02-03 16:02:02 -0800517 if (mVideoSource != NULL) {
Andreas Huber27366fc2009-11-20 09:32:46 -0800518 postVideoEvent_l();
519 }
520 } else {
Andreas Huber971305d2010-07-07 13:35:27 -0700521 LOGV("MEDIA_PLAYBACK_COMPLETE");
522 notifyListener_l(MEDIA_PLAYBACK_COMPLETE);
Andreas Huber27366fc2009-11-20 09:32:46 -0800523
524 pause_l();
Andreas Huber406a18b2010-02-18 16:45:13 -0800525
526 mFlags |= AT_EOS;
Andreas Huber27366fc2009-11-20 09:32:46 -0800527 }
528}
529
530status_t AwesomePlayer::play() {
531 Mutex::Autolock autoLock(mLock);
Andreas Huber4d61f602010-06-10 11:17:50 -0700532
533 mFlags &= ~CACHE_UNDERRUN;
534
Andreas Huberba7ec912010-02-12 10:42:02 -0800535 return play_l();
536}
Andreas Huber27366fc2009-11-20 09:32:46 -0800537
Andreas Huberba7ec912010-02-12 10:42:02 -0800538status_t AwesomePlayer::play_l() {
Andreas Huber27366fc2009-11-20 09:32:46 -0800539 if (mFlags & PLAYING) {
540 return OK;
541 }
542
Andreas Huberffdf4782010-02-09 14:05:43 -0800543 if (!(mFlags & PREPARED)) {
544 status_t err = prepare_l();
545
546 if (err != OK) {
547 return err;
548 }
549 }
550
Andreas Huber27366fc2009-11-20 09:32:46 -0800551 mFlags |= PLAYING;
552 mFlags |= FIRST_FRAME;
553
Andreas Huberc1d5c922009-12-10 15:49:04 -0800554 bool deferredAudioSeek = false;
555
Andreas Huber27366fc2009-11-20 09:32:46 -0800556 if (mAudioSource != NULL) {
557 if (mAudioPlayer == NULL) {
558 if (mAudioSink != NULL) {
559 mAudioPlayer = new AudioPlayer(mAudioSink);
Andreas Huber27366fc2009-11-20 09:32:46 -0800560 mAudioPlayer->setSource(mAudioSource);
Andreas Huberdc9927d2010-03-08 15:46:13 -0800561
562 // We've already started the MediaSource in order to enable
563 // the prefetcher to read its data.
564 status_t err = mAudioPlayer->start(
565 true /* sourceAlreadyStarted */);
Andreas Huber62eac002010-01-29 13:24:58 -0800566
567 if (err != OK) {
568 delete mAudioPlayer;
569 mAudioPlayer = NULL;
570
571 mFlags &= ~(PLAYING | FIRST_FRAME);
572
573 return err;
574 }
Andreas Huber27366fc2009-11-20 09:32:46 -0800575
Andreas Huber27366fc2009-11-20 09:32:46 -0800576 mTimeSource = mAudioPlayer;
577
Andreas Huberc1d5c922009-12-10 15:49:04 -0800578 deferredAudioSeek = true;
Andreas Huber70d10c02010-02-03 11:37:29 -0800579
580 mWatchForAudioSeekComplete = false;
581 mWatchForAudioEOS = true;
Andreas Huber27366fc2009-11-20 09:32:46 -0800582 }
583 } else {
584 mAudioPlayer->resume();
585 }
Andreas Huber70d10c02010-02-03 11:37:29 -0800586
587 postCheckAudioStatusEvent_l();
Andreas Huber27366fc2009-11-20 09:32:46 -0800588 }
589
590 if (mTimeSource == NULL && mAudioPlayer == NULL) {
Andreas Huber971305d2010-07-07 13:35:27 -0700591 mTimeSource = &mSystemTimeSource;
Andreas Huber27366fc2009-11-20 09:32:46 -0800592 }
593
594 if (mVideoSource != NULL) {
Andreas Huber7085b6842010-02-03 16:02:02 -0800595 // Kick off video playback
596 postVideoEvent_l();
Andreas Huber27366fc2009-11-20 09:32:46 -0800597 }
598
Andreas Huberc1d5c922009-12-10 15:49:04 -0800599 if (deferredAudioSeek) {
600 // If there was a seek request while we were paused
601 // and we're just starting up again, honor the request now.
602 seekAudioIfNecessary_l();
603 }
604
Andreas Huber406a18b2010-02-18 16:45:13 -0800605 if (mFlags & AT_EOS) {
606 // Legacy behaviour, if a stream finishes playing and then
607 // is started again, we play from the start...
608 seekTo_l(0);
609 }
610
Andreas Huber27366fc2009-11-20 09:32:46 -0800611 return OK;
612}
613
614void AwesomePlayer::initRenderer_l() {
615 if (mISurface != NULL) {
616 sp<MetaData> meta = mVideoSource->getFormat();
617
618 int32_t format;
619 const char *component;
620 int32_t decodedWidth, decodedHeight;
621 CHECK(meta->findInt32(kKeyColorFormat, &format));
622 CHECK(meta->findCString(kKeyDecoderComponent, &component));
623 CHECK(meta->findInt32(kKeyWidth, &decodedWidth));
624 CHECK(meta->findInt32(kKeyHeight, &decodedHeight));
625
Andreas Hubera67d5382009-12-10 15:32:12 -0800626 mVideoRenderer.clear();
627
628 // Must ensure that mVideoRenderer's destructor is actually executed
629 // before creating a new one.
630 IPCThreadState::self()->flushCommands();
631
Andreas Huber1314e732009-12-14 14:18:22 -0800632 if (!strncmp("OMX.", component, 4)) {
633 // Our OMX codecs allocate buffers on the media_server side
634 // therefore they require a remote IOMXRenderer that knows how
635 // to display them.
636 mVideoRenderer = new AwesomeRemoteRenderer(
637 mClient.interface()->createRenderer(
638 mISurface, component,
639 (OMX_COLOR_FORMATTYPE)format,
640 decodedWidth, decodedHeight,
641 mVideoWidth, mVideoHeight));
642 } else {
643 // Other decoders are instantiated locally and as a consequence
644 // allocate their buffers in local address space.
645 mVideoRenderer = new AwesomeLocalRenderer(
Andreas Huber7b73cfc2010-02-12 14:40:08 -0800646 false, // previewOnly
Andreas Huber4ab5a6f2010-02-11 11:00:26 -0800647 component,
Andreas Huber1314e732009-12-14 14:18:22 -0800648 (OMX_COLOR_FORMATTYPE)format,
649 mISurface,
650 mVideoWidth, mVideoHeight,
651 decodedWidth, decodedHeight);
652 }
Andreas Huber27366fc2009-11-20 09:32:46 -0800653 }
654}
655
656status_t AwesomePlayer::pause() {
657 Mutex::Autolock autoLock(mLock);
Andreas Huber4d61f602010-06-10 11:17:50 -0700658
659 mFlags &= ~CACHE_UNDERRUN;
660
Andreas Huber27366fc2009-11-20 09:32:46 -0800661 return pause_l();
662}
663
664status_t AwesomePlayer::pause_l() {
665 if (!(mFlags & PLAYING)) {
666 return OK;
667 }
668
Andreas Huberb9e63832010-01-26 16:20:10 -0800669 cancelPlayerEvents(true /* keepBufferingGoing */);
Andreas Huber27366fc2009-11-20 09:32:46 -0800670
671 if (mAudioPlayer != NULL) {
672 mAudioPlayer->pause();
673 }
674
675 mFlags &= ~PLAYING;
676
677 return OK;
678}
679
680bool AwesomePlayer::isPlaying() const {
Andreas Huber4d61f602010-06-10 11:17:50 -0700681 return (mFlags & PLAYING) || (mFlags & CACHE_UNDERRUN);
Andreas Huber27366fc2009-11-20 09:32:46 -0800682}
683
684void AwesomePlayer::setISurface(const sp<ISurface> &isurface) {
685 Mutex::Autolock autoLock(mLock);
686
687 mISurface = isurface;
688}
689
690void AwesomePlayer::setAudioSink(
691 const sp<MediaPlayerBase::AudioSink> &audioSink) {
692 Mutex::Autolock autoLock(mLock);
693
694 mAudioSink = audioSink;
695}
696
697status_t AwesomePlayer::setLooping(bool shouldLoop) {
698 Mutex::Autolock autoLock(mLock);
699
700 mFlags = mFlags & ~LOOPING;
701
702 if (shouldLoop) {
703 mFlags |= LOOPING;
704 }
705
706 return OK;
707}
708
709status_t AwesomePlayer::getDuration(int64_t *durationUs) {
Andreas Huber252573c2010-03-26 10:17:17 -0700710 Mutex::Autolock autoLock(mMiscStateLock);
Andreas Huber27366fc2009-11-20 09:32:46 -0800711
712 if (mDurationUs < 0) {
713 return UNKNOWN_ERROR;
714 }
715
716 *durationUs = mDurationUs;
717
718 return OK;
719}
720
721status_t AwesomePlayer::getPosition(int64_t *positionUs) {
Andreas Huberddb709c2010-04-07 10:24:35 -0700722 if (mSeeking) {
723 *positionUs = mSeekTimeUs;
724 } else if (mVideoSource != NULL) {
Andreas Huber252573c2010-03-26 10:17:17 -0700725 Mutex::Autolock autoLock(mMiscStateLock);
Andreas Huber27366fc2009-11-20 09:32:46 -0800726 *positionUs = mVideoTimeUs;
727 } else if (mAudioPlayer != NULL) {
728 *positionUs = mAudioPlayer->getMediaTimeUs();
729 } else {
730 *positionUs = 0;
731 }
732
733 return OK;
734}
735
736status_t AwesomePlayer::seekTo(int64_t timeUs) {
Andreas Huber62f7ffe2010-05-06 10:18:05 -0700737 if (mExtractorFlags
738 & (MediaExtractor::CAN_SEEK_FORWARD
739 | MediaExtractor::CAN_SEEK_BACKWARD)) {
740 Mutex::Autolock autoLock(mLock);
741 return seekTo_l(timeUs);
742 }
743
744 return OK;
Andreas Huber27366fc2009-11-20 09:32:46 -0800745}
746
747status_t AwesomePlayer::seekTo_l(int64_t timeUs) {
Andreas Huber4d61f602010-06-10 11:17:50 -0700748 if (mFlags & CACHE_UNDERRUN) {
749 mFlags &= ~CACHE_UNDERRUN;
750 play_l();
751 }
752
Andreas Huber27366fc2009-11-20 09:32:46 -0800753 mSeeking = true;
Andreas Huber8e2b9412010-03-31 09:40:15 -0700754 mSeekNotificationSent = false;
Andreas Huber27366fc2009-11-20 09:32:46 -0800755 mSeekTimeUs = timeUs;
Andreas Huber971305d2010-07-07 13:35:27 -0700756 mFlags &= ~(AT_EOS | AUDIO_AT_EOS | VIDEO_AT_EOS);
Andreas Huber27366fc2009-11-20 09:32:46 -0800757
758 seekAudioIfNecessary_l();
759
Andreas Huber8e2b9412010-03-31 09:40:15 -0700760 if (!(mFlags & PLAYING)) {
761 LOGV("seeking while paused, sending SEEK_COMPLETE notification"
762 " immediately.");
763
764 notifyListener_l(MEDIA_SEEK_COMPLETE);
765 mSeekNotificationSent = true;
766 }
767
Andreas Huber27366fc2009-11-20 09:32:46 -0800768 return OK;
769}
770
771void AwesomePlayer::seekAudioIfNecessary_l() {
Andreas Huber7085b6842010-02-03 16:02:02 -0800772 if (mSeeking && mVideoSource == NULL && mAudioPlayer != NULL) {
Andreas Huber27366fc2009-11-20 09:32:46 -0800773 mAudioPlayer->seekTo(mSeekTimeUs);
774
Andreas Huber70d10c02010-02-03 11:37:29 -0800775 mWatchForAudioSeekComplete = true;
776 mWatchForAudioEOS = true;
Andreas Huber8e2b9412010-03-31 09:40:15 -0700777 mSeekNotificationSent = false;
Andreas Huber27366fc2009-11-20 09:32:46 -0800778 }
779}
780
781status_t AwesomePlayer::getVideoDimensions(
782 int32_t *width, int32_t *height) const {
783 Mutex::Autolock autoLock(mLock);
784
785 if (mVideoWidth < 0 || mVideoHeight < 0) {
786 return UNKNOWN_ERROR;
787 }
788
789 *width = mVideoWidth;
790 *height = mVideoHeight;
791
792 return OK;
793}
794
Andreas Huber3ac94ef2010-03-05 10:42:10 -0800795void AwesomePlayer::setAudioSource(sp<MediaSource> source) {
796 CHECK(source != NULL);
Andreas Huber27366fc2009-11-20 09:32:46 -0800797
Andreas Huber3ac94ef2010-03-05 10:42:10 -0800798 mAudioTrack = source;
799}
800
801status_t AwesomePlayer::initAudioDecoder() {
802 sp<MetaData> meta = mAudioTrack->getFormat();
Andreas Huberc79827a2010-01-05 10:54:55 -0800803
804 const char *mime;
805 CHECK(meta->findCString(kKeyMIMEType, &mime));
806
807 if (!strcasecmp(mime, MEDIA_MIMETYPE_AUDIO_RAW)) {
Andreas Huber3ac94ef2010-03-05 10:42:10 -0800808 mAudioSource = mAudioTrack;
Andreas Huberc79827a2010-01-05 10:54:55 -0800809 } else {
810 mAudioSource = OMXCodec::Create(
Andreas Huber3ac94ef2010-03-05 10:42:10 -0800811 mClient.interface(), mAudioTrack->getFormat(),
Andreas Huberc79827a2010-01-05 10:54:55 -0800812 false, // createEncoder
Andreas Huber3ac94ef2010-03-05 10:42:10 -0800813 mAudioTrack);
Andreas Huberc79827a2010-01-05 10:54:55 -0800814 }
Andreas Huber27366fc2009-11-20 09:32:46 -0800815
816 if (mAudioSource != NULL) {
817 int64_t durationUs;
Andreas Huber3ac94ef2010-03-05 10:42:10 -0800818 if (mAudioTrack->getFormat()->findInt64(kKeyDuration, &durationUs)) {
Andreas Huber252573c2010-03-26 10:17:17 -0700819 Mutex::Autolock autoLock(mMiscStateLock);
Andreas Huber27366fc2009-11-20 09:32:46 -0800820 if (mDurationUs < 0 || durationUs > mDurationUs) {
821 mDurationUs = durationUs;
822 }
823 }
Andreas Huber27366fc2009-11-20 09:32:46 -0800824
Andreas Huber3c78a1b2010-05-13 09:15:21 -0700825 status_t err = mAudioSource->start();
826
827 if (err != OK) {
828 mAudioSource.clear();
829 return err;
830 }
Andreas Huberd0332ad2010-04-12 16:05:57 -0700831 } else if (!strcasecmp(mime, MEDIA_MIMETYPE_AUDIO_QCELP)) {
832 // For legacy reasons we're simply going to ignore the absence
833 // of an audio decoder for QCELP instead of aborting playback
834 // altogether.
835 return OK;
836 }
Andreas Huberdc9927d2010-03-08 15:46:13 -0800837
Andreas Huber27366fc2009-11-20 09:32:46 -0800838 return mAudioSource != NULL ? OK : UNKNOWN_ERROR;
839}
840
Andreas Huber3ac94ef2010-03-05 10:42:10 -0800841void AwesomePlayer::setVideoSource(sp<MediaSource> source) {
842 CHECK(source != NULL);
Andreas Huber27366fc2009-11-20 09:32:46 -0800843
Andreas Huber3ac94ef2010-03-05 10:42:10 -0800844 mVideoTrack = source;
845}
846
847status_t AwesomePlayer::initVideoDecoder() {
Andreas Huber27366fc2009-11-20 09:32:46 -0800848 mVideoSource = OMXCodec::Create(
Andreas Huber3ac94ef2010-03-05 10:42:10 -0800849 mClient.interface(), mVideoTrack->getFormat(),
Andreas Huber27366fc2009-11-20 09:32:46 -0800850 false, // createEncoder
Andreas Huber3ac94ef2010-03-05 10:42:10 -0800851 mVideoTrack);
Andreas Huber27366fc2009-11-20 09:32:46 -0800852
853 if (mVideoSource != NULL) {
854 int64_t durationUs;
Andreas Huber3ac94ef2010-03-05 10:42:10 -0800855 if (mVideoTrack->getFormat()->findInt64(kKeyDuration, &durationUs)) {
Andreas Huber252573c2010-03-26 10:17:17 -0700856 Mutex::Autolock autoLock(mMiscStateLock);
Andreas Huber27366fc2009-11-20 09:32:46 -0800857 if (mDurationUs < 0 || durationUs > mDurationUs) {
858 mDurationUs = durationUs;
859 }
860 }
861
Andreas Huber3ac94ef2010-03-05 10:42:10 -0800862 CHECK(mVideoTrack->getFormat()->findInt32(kKeyWidth, &mVideoWidth));
863 CHECK(mVideoTrack->getFormat()->findInt32(kKeyHeight, &mVideoHeight));
Andreas Huber27366fc2009-11-20 09:32:46 -0800864
Andreas Huber1919e5a2010-05-20 10:37:06 -0700865 status_t err = mVideoSource->start();
866
867 if (err != OK) {
868 mVideoSource.clear();
869 return err;
870 }
Andreas Huber27366fc2009-11-20 09:32:46 -0800871 }
872
873 return mVideoSource != NULL ? OK : UNKNOWN_ERROR;
874}
875
Andreas Huber6be780e2010-02-08 14:40:30 -0800876void AwesomePlayer::onVideoEvent() {
Andreas Huber27366fc2009-11-20 09:32:46 -0800877 Mutex::Autolock autoLock(mLock);
Andreas Huberba7ec912010-02-12 10:42:02 -0800878 if (!mVideoEventPending) {
879 // The event has been cancelled in reset_l() but had already
880 // been scheduled for execution at that time.
881 return;
882 }
Andreas Huber27366fc2009-11-20 09:32:46 -0800883 mVideoEventPending = false;
884
885 if (mSeeking) {
886 if (mLastVideoBuffer) {
887 mLastVideoBuffer->release();
888 mLastVideoBuffer = NULL;
889 }
890
891 if (mVideoBuffer) {
892 mVideoBuffer->release();
893 mVideoBuffer = NULL;
894 }
Andreas Huber4d61f602010-06-10 11:17:50 -0700895
896 if (mCachedSource != NULL && mAudioSource != NULL) {
897 // We're going to seek the video source first, followed by
898 // the audio source.
899 // In order to avoid jumps in the DataSource offset caused by
900 // the audio codec prefetching data from the old locations
901 // while the video codec is already reading data from the new
902 // locations, we'll "pause" the audio source, causing it to
903 // stop reading input data until a subsequent seek.
904
905 if (mAudioPlayer != NULL) {
906 mAudioPlayer->pause();
907 }
908 mAudioSource->pause();
909 }
Andreas Huber27366fc2009-11-20 09:32:46 -0800910 }
911
912 if (!mVideoBuffer) {
913 MediaSource::ReadOptions options;
914 if (mSeeking) {
915 LOGV("seeking to %lld us (%.2f secs)", mSeekTimeUs, mSeekTimeUs / 1E6);
916
Andreas Huber6624c9f2010-07-20 15:04:28 -0700917 options.setSeekTo(
918 mSeekTimeUs, MediaSource::ReadOptions::SEEK_CLOSEST_SYNC);
Andreas Huber27366fc2009-11-20 09:32:46 -0800919 }
920 for (;;) {
921 status_t err = mVideoSource->read(&mVideoBuffer, &options);
Andreas Huberb1f5ee42009-12-14 15:34:11 -0800922 options.clearSeekTo();
Andreas Huber27366fc2009-11-20 09:32:46 -0800923
924 if (err != OK) {
925 CHECK_EQ(mVideoBuffer, NULL);
926
927 if (err == INFO_FORMAT_CHANGED) {
928 LOGV("VideoSource signalled format change.");
929
Andreas Huber7085b6842010-02-03 16:02:02 -0800930 if (mVideoRenderer != NULL) {
Andreas Huber7b73cfc2010-02-12 14:40:08 -0800931 mVideoRendererIsPreview = false;
Andreas Huber7085b6842010-02-03 16:02:02 -0800932 initRenderer_l();
933 }
Andreas Huber27366fc2009-11-20 09:32:46 -0800934 continue;
935 }
936
Andreas Huber971305d2010-07-07 13:35:27 -0700937 mFlags |= VIDEO_AT_EOS;
Andreas Huberd7d22eb2010-02-23 13:45:33 -0800938 postStreamDoneEvent_l(err);
Andreas Huber27366fc2009-11-20 09:32:46 -0800939 return;
940 }
941
Andreas Hubera67d5382009-12-10 15:32:12 -0800942 if (mVideoBuffer->range_length() == 0) {
Andreas Huber6ddcf012009-12-10 15:32:12 -0800943 // Some decoders, notably the PV AVC software decoder
944 // return spurious empty buffers that we just want to ignore.
945
Andreas Hubera67d5382009-12-10 15:32:12 -0800946 mVideoBuffer->release();
947 mVideoBuffer = NULL;
948 continue;
949 }
950
Andreas Huber27366fc2009-11-20 09:32:46 -0800951 break;
952 }
953 }
954
955 int64_t timeUs;
956 CHECK(mVideoBuffer->meta_data()->findInt64(kKeyTime, &timeUs));
957
Andreas Huber252573c2010-03-26 10:17:17 -0700958 {
959 Mutex::Autolock autoLock(mMiscStateLock);
960 mVideoTimeUs = timeUs;
961 }
Andreas Huber27366fc2009-11-20 09:32:46 -0800962
963 if (mSeeking) {
964 if (mAudioPlayer != NULL) {
965 LOGV("seeking audio to %lld us (%.2f secs).", timeUs, timeUs / 1E6);
966
967 mAudioPlayer->seekTo(timeUs);
Andreas Huber4d61f602010-06-10 11:17:50 -0700968 mAudioPlayer->resume();
Andreas Huber70d10c02010-02-03 11:37:29 -0800969 mWatchForAudioSeekComplete = true;
970 mWatchForAudioEOS = true;
Andreas Huber8e2b9412010-03-31 09:40:15 -0700971 } else if (!mSeekNotificationSent) {
Andreas Huber27366fc2009-11-20 09:32:46 -0800972 // If we're playing video only, report seek complete now,
973 // otherwise audio player will notify us later.
Andreas Hubera3f43842010-01-21 10:28:45 -0800974 notifyListener_l(MEDIA_SEEK_COMPLETE);
Andreas Huber27366fc2009-11-20 09:32:46 -0800975 }
976
977 mFlags |= FIRST_FRAME;
978 mSeeking = false;
Andreas Huber8e2b9412010-03-31 09:40:15 -0700979 mSeekNotificationSent = false;
Andreas Huber27366fc2009-11-20 09:32:46 -0800980 }
981
Andreas Huber971305d2010-07-07 13:35:27 -0700982 TimeSource *ts = (mFlags & AUDIO_AT_EOS) ? &mSystemTimeSource : mTimeSource;
983
Andreas Huber27366fc2009-11-20 09:32:46 -0800984 if (mFlags & FIRST_FRAME) {
985 mFlags &= ~FIRST_FRAME;
986
Andreas Huber971305d2010-07-07 13:35:27 -0700987 mTimeSourceDeltaUs = ts->getRealTimeUs() - timeUs;
Andreas Huber27366fc2009-11-20 09:32:46 -0800988 }
989
990 int64_t realTimeUs, mediaTimeUs;
Andreas Huber971305d2010-07-07 13:35:27 -0700991 if (!(mFlags & AUDIO_AT_EOS) && mAudioPlayer != NULL
Andreas Huber27366fc2009-11-20 09:32:46 -0800992 && mAudioPlayer->getMediaTimeMapping(&realTimeUs, &mediaTimeUs)) {
993 mTimeSourceDeltaUs = realTimeUs - mediaTimeUs;
994 }
995
Andreas Huber971305d2010-07-07 13:35:27 -0700996 int64_t nowUs = ts->getRealTimeUs() - mTimeSourceDeltaUs;
Andreas Huber27366fc2009-11-20 09:32:46 -0800997
998 int64_t latenessUs = nowUs - timeUs;
999
Andreas Huber24b0a952009-11-23 14:02:00 -08001000 if (latenessUs > 40000) {
1001 // We're more than 40ms late.
Andreas Huber4a9375e2010-02-09 11:54:33 -08001002 LOGV("we're late by %lld us (%.2f secs)", latenessUs, latenessUs / 1E6);
Andreas Huber27366fc2009-11-20 09:32:46 -08001003
1004 mVideoBuffer->release();
1005 mVideoBuffer = NULL;
1006
1007 postVideoEvent_l();
1008 return;
1009 }
1010
1011 if (latenessUs < -10000) {
1012 // We're more than 10ms early.
1013
1014 postVideoEvent_l(10000);
1015 return;
1016 }
1017
Andreas Huber7b73cfc2010-02-12 14:40:08 -08001018 if (mVideoRendererIsPreview || mVideoRenderer == NULL) {
1019 mVideoRendererIsPreview = false;
1020
Andreas Huber7085b6842010-02-03 16:02:02 -08001021 initRenderer_l();
1022 }
1023
1024 if (mVideoRenderer != NULL) {
1025 mVideoRenderer->render(mVideoBuffer);
1026 }
Andreas Huber27366fc2009-11-20 09:32:46 -08001027
1028 if (mLastVideoBuffer) {
1029 mLastVideoBuffer->release();
1030 mLastVideoBuffer = NULL;
1031 }
1032 mLastVideoBuffer = mVideoBuffer;
1033 mVideoBuffer = NULL;
1034
1035 postVideoEvent_l();
1036}
1037
1038void AwesomePlayer::postVideoEvent_l(int64_t delayUs) {
1039 if (mVideoEventPending) {
1040 return;
1041 }
1042
1043 mVideoEventPending = true;
1044 mQueue.postEventWithDelay(mVideoEvent, delayUs < 0 ? 10000 : delayUs);
1045}
1046
Andreas Huberd7d22eb2010-02-23 13:45:33 -08001047void AwesomePlayer::postStreamDoneEvent_l(status_t status) {
Andreas Huber27366fc2009-11-20 09:32:46 -08001048 if (mStreamDoneEventPending) {
1049 return;
1050 }
1051 mStreamDoneEventPending = true;
Andreas Huberd7d22eb2010-02-23 13:45:33 -08001052
1053 mStreamDoneStatus = status;
Andreas Huber27366fc2009-11-20 09:32:46 -08001054 mQueue.postEvent(mStreamDoneEvent);
1055}
1056
Andreas Huberb9e63832010-01-26 16:20:10 -08001057void AwesomePlayer::postBufferingEvent_l() {
Andreas Huberb9e63832010-01-26 16:20:10 -08001058 if (mBufferingEventPending) {
1059 return;
1060 }
1061 mBufferingEventPending = true;
1062 mQueue.postEventWithDelay(mBufferingEvent, 1000000ll);
1063}
1064
Andreas Huber70d10c02010-02-03 11:37:29 -08001065void AwesomePlayer::postCheckAudioStatusEvent_l() {
1066 if (mAudioStatusEventPending) {
1067 return;
1068 }
1069 mAudioStatusEventPending = true;
1070 mQueue.postEventWithDelay(mCheckAudioStatusEvent, 100000ll);
1071}
1072
1073void AwesomePlayer::onCheckAudioStatus() {
1074 Mutex::Autolock autoLock(mLock);
Andreas Huberc0178f12010-02-17 15:58:57 -08001075 if (!mAudioStatusEventPending) {
1076 // Event was dispatched and while we were blocking on the mutex,
1077 // has already been cancelled.
1078 return;
1079 }
1080
Andreas Huber70d10c02010-02-03 11:37:29 -08001081 mAudioStatusEventPending = false;
1082
1083 if (mWatchForAudioSeekComplete && !mAudioPlayer->isSeeking()) {
1084 mWatchForAudioSeekComplete = false;
Andreas Huber8e2b9412010-03-31 09:40:15 -07001085
1086 if (!mSeekNotificationSent) {
1087 notifyListener_l(MEDIA_SEEK_COMPLETE);
1088 mSeekNotificationSent = true;
1089 }
Andreas Huberddb709c2010-04-07 10:24:35 -07001090
1091 mSeeking = false;
Andreas Huber70d10c02010-02-03 11:37:29 -08001092 }
1093
Andreas Huberd7d22eb2010-02-23 13:45:33 -08001094 status_t finalStatus;
1095 if (mWatchForAudioEOS && mAudioPlayer->reachedEOS(&finalStatus)) {
Andreas Huber70d10c02010-02-03 11:37:29 -08001096 mWatchForAudioEOS = false;
Andreas Huber971305d2010-07-07 13:35:27 -07001097 mFlags |= AUDIO_AT_EOS;
1098 mFlags |= FIRST_FRAME;
Andreas Huberd7d22eb2010-02-23 13:45:33 -08001099 postStreamDoneEvent_l(finalStatus);
Andreas Huber70d10c02010-02-03 11:37:29 -08001100 }
1101
1102 postCheckAudioStatusEvent_l();
1103}
1104
Andreas Huber6be780e2010-02-08 14:40:30 -08001105status_t AwesomePlayer::prepare() {
1106 Mutex::Autolock autoLock(mLock);
Andreas Huberffdf4782010-02-09 14:05:43 -08001107 return prepare_l();
1108}
Andreas Huber6be780e2010-02-08 14:40:30 -08001109
Andreas Huberffdf4782010-02-09 14:05:43 -08001110status_t AwesomePlayer::prepare_l() {
1111 if (mFlags & PREPARED) {
1112 return OK;
1113 }
1114
1115 if (mFlags & PREPARING) {
1116 return UNKNOWN_ERROR;
1117 }
1118
1119 mIsAsyncPrepare = false;
Andreas Huber6be780e2010-02-08 14:40:30 -08001120 status_t err = prepareAsync_l();
1121
1122 if (err != OK) {
1123 return err;
1124 }
1125
Andreas Huberffdf4782010-02-09 14:05:43 -08001126 while (mFlags & PREPARING) {
Andreas Huber6be780e2010-02-08 14:40:30 -08001127 mPreparedCondition.wait(mLock);
1128 }
1129
Andreas Huberffdf4782010-02-09 14:05:43 -08001130 return mPrepareResult;
Andreas Huber6be780e2010-02-08 14:40:30 -08001131}
1132
1133status_t AwesomePlayer::prepareAsync() {
1134 Mutex::Autolock autoLock(mLock);
Andreas Huberffdf4782010-02-09 14:05:43 -08001135
1136 if (mFlags & PREPARING) {
1137 return UNKNOWN_ERROR; // async prepare already pending
1138 }
1139
1140 mIsAsyncPrepare = true;
Andreas Huber6be780e2010-02-08 14:40:30 -08001141 return prepareAsync_l();
1142}
1143
1144status_t AwesomePlayer::prepareAsync_l() {
Andreas Huberffdf4782010-02-09 14:05:43 -08001145 if (mFlags & PREPARING) {
1146 return UNKNOWN_ERROR; // async prepare already pending
Andreas Huber6be780e2010-02-08 14:40:30 -08001147 }
1148
Andreas Huber406a18b2010-02-18 16:45:13 -08001149 if (!mQueueStarted) {
1150 mQueue.start();
1151 mQueueStarted = true;
1152 }
1153
Andreas Huberffdf4782010-02-09 14:05:43 -08001154 mFlags |= PREPARING;
Andreas Huber6be780e2010-02-08 14:40:30 -08001155 mAsyncPrepareEvent = new AwesomeEvent(
1156 this, &AwesomePlayer::onPrepareAsyncEvent);
1157
1158 mQueue.postEvent(mAsyncPrepareEvent);
1159
1160 return OK;
1161}
1162
Andreas Huberffdf4782010-02-09 14:05:43 -08001163status_t AwesomePlayer::finishSetDataSource_l() {
Andreas Huberedbb4d82010-03-12 08:59:22 -08001164 sp<DataSource> dataSource;
1165
1166 if (!strncasecmp("http://", mUri.string(), 7)) {
Andreas Huber4d61f602010-06-10 11:17:50 -07001167 mConnectingDataSource = new NuHTTPDataSource;
Andreas Huberedbb4d82010-03-12 08:59:22 -08001168
1169 mLock.unlock();
Andreas Huber3a53dc52010-06-11 09:57:46 -07001170 status_t err = mConnectingDataSource->connect(mUri, &mUriHeaders);
Andreas Huberedbb4d82010-03-12 08:59:22 -08001171 mLock.lock();
1172
1173 if (err != OK) {
1174 mConnectingDataSource.clear();
1175
1176 LOGI("mConnectingDataSource->connect() returned %d", err);
1177 return err;
1178 }
1179
Andreas Huber4d61f602010-06-10 11:17:50 -07001180#if 0
1181 mCachedSource = new NuCachedSource2(
1182 new ThrottledSource(
1183 mConnectingDataSource, 50 * 1024 /* bytes/sec */));
1184#else
1185 mCachedSource = new NuCachedSource2(mConnectingDataSource);
1186#endif
Andreas Huberedbb4d82010-03-12 08:59:22 -08001187 mConnectingDataSource.clear();
Andreas Huber4d61f602010-06-10 11:17:50 -07001188
1189 dataSource = mCachedSource;
Andreas Huber202348e2010-06-07 14:35:29 -07001190 } else if (!strncasecmp(mUri.string(), "httplive://", 11)) {
1191 String8 uri("http://");
1192 uri.append(mUri.string() + 11);
1193
1194 dataSource = new LiveSource(uri.string());
1195
Andreas Huber4d61f602010-06-10 11:17:50 -07001196 mCachedSource = new NuCachedSource2(dataSource);
1197 dataSource = mCachedSource;
Andreas Huber202348e2010-06-07 14:35:29 -07001198
1199 sp<MediaExtractor> extractor =
1200 MediaExtractor::Create(dataSource, MEDIA_MIMETYPE_CONTAINER_MPEG2TS);
Andreas Huber4d61f602010-06-10 11:17:50 -07001201
1202 return setDataSource_l(extractor);
Andreas Huber7a747b82010-06-07 15:19:40 -07001203 } else if (!strncasecmp("rtsp://", mUri.string(), 7)) {
1204 if (mLooper == NULL) {
1205 mLooper = new ALooper;
1206 mLooper->start();
1207 }
1208 mRTSPController = new ARTSPController(mLooper);
1209 status_t err = mRTSPController->connect(mUri.string());
Andreas Huber202348e2010-06-07 14:35:29 -07001210
Andreas Huber7a747b82010-06-07 15:19:40 -07001211 LOGI("ARTSPController::connect returned %d", err);
1212
1213 if (err != OK) {
1214 mRTSPController.clear();
1215 return err;
1216 }
1217
1218 sp<MediaExtractor> extractor = mRTSPController.get();
Andreas Huber202348e2010-06-07 14:35:29 -07001219 return setDataSource_l(extractor);
Andreas Huberedbb4d82010-03-12 08:59:22 -08001220 } else {
1221 dataSource = DataSource::CreateFromURI(mUri.string(), &mUriHeaders);
1222 }
Andreas Huberffdf4782010-02-09 14:05:43 -08001223
1224 if (dataSource == NULL) {
1225 return UNKNOWN_ERROR;
1226 }
1227
1228 sp<MediaExtractor> extractor = MediaExtractor::Create(dataSource);
1229
1230 if (extractor == NULL) {
1231 return UNKNOWN_ERROR;
1232 }
1233
Andreas Huberffdf4782010-02-09 14:05:43 -08001234 return setDataSource_l(extractor);
1235}
1236
Andreas Huber3ac94ef2010-03-05 10:42:10 -08001237void AwesomePlayer::abortPrepare(status_t err) {
1238 CHECK(err != OK);
1239
1240 if (mIsAsyncPrepare) {
1241 notifyListener_l(MEDIA_ERROR, MEDIA_ERROR_UNKNOWN, err);
1242 }
1243
1244 mPrepareResult = err;
Andreas Huberedbb4d82010-03-12 08:59:22 -08001245 mFlags &= ~(PREPARING|PREPARE_CANCELLED);
Andreas Huber3ac94ef2010-03-05 10:42:10 -08001246 mAsyncPrepareEvent = NULL;
1247 mPreparedCondition.broadcast();
1248}
1249
Andreas Huberf71daba2010-03-24 09:24:40 -07001250// static
1251bool AwesomePlayer::ContinuePreparation(void *cookie) {
1252 AwesomePlayer *me = static_cast<AwesomePlayer *>(cookie);
1253
1254 return (me->mFlags & PREPARE_CANCELLED) == 0;
1255}
1256
Andreas Huber6be780e2010-02-08 14:40:30 -08001257void AwesomePlayer::onPrepareAsyncEvent() {
Andreas Huberffdf4782010-02-09 14:05:43 -08001258 {
1259 Mutex::Autolock autoLock(mLock);
1260
Andreas Huberedbb4d82010-03-12 08:59:22 -08001261 if (mFlags & PREPARE_CANCELLED) {
1262 LOGI("prepare was cancelled before doing anything");
1263 abortPrepare(UNKNOWN_ERROR);
1264 return;
1265 }
1266
Andreas Huberffdf4782010-02-09 14:05:43 -08001267 if (mUri.size() > 0) {
1268 status_t err = finishSetDataSource_l();
1269
1270 if (err != OK) {
Andreas Huber3ac94ef2010-03-05 10:42:10 -08001271 abortPrepare(err);
Andreas Huberffdf4782010-02-09 14:05:43 -08001272 return;
1273 }
1274 }
Andreas Huberffdf4782010-02-09 14:05:43 -08001275
Andreas Huber55864df72010-03-08 12:28:22 -08001276 if (mVideoTrack != NULL && mVideoSource == NULL) {
1277 status_t err = initVideoDecoder();
Andreas Huber6be780e2010-02-08 14:40:30 -08001278
Andreas Huber55864df72010-03-08 12:28:22 -08001279 if (err != OK) {
1280 abortPrepare(err);
1281 return;
1282 }
1283 }
1284
1285 if (mAudioTrack != NULL && mAudioSource == NULL) {
1286 status_t err = initAudioDecoder();
1287
1288 if (err != OK) {
1289 abortPrepare(err);
1290 return;
1291 }
1292 }
Andreas Huber6be780e2010-02-08 14:40:30 -08001293 }
1294
1295 Mutex::Autolock autoLock(mLock);
1296
Andreas Huberffdf4782010-02-09 14:05:43 -08001297 if (mIsAsyncPrepare) {
1298 if (mVideoWidth < 0 || mVideoHeight < 0) {
1299 notifyListener_l(MEDIA_SET_VIDEO_SIZE, 0, 0);
1300 } else {
1301 notifyListener_l(MEDIA_SET_VIDEO_SIZE, mVideoWidth, mVideoHeight);
1302 }
1303
1304 notifyListener_l(MEDIA_PREPARED);
Andreas Huber6be780e2010-02-08 14:40:30 -08001305 }
1306
Andreas Huberffdf4782010-02-09 14:05:43 -08001307 mPrepareResult = OK;
Andreas Huberedbb4d82010-03-12 08:59:22 -08001308 mFlags &= ~(PREPARING|PREPARE_CANCELLED);
Andreas Huberffdf4782010-02-09 14:05:43 -08001309 mFlags |= PREPARED;
Andreas Huber6be780e2010-02-08 14:40:30 -08001310 mAsyncPrepareEvent = NULL;
Andreas Huberffdf4782010-02-09 14:05:43 -08001311 mPreparedCondition.broadcast();
Andreas Huber040301c2010-04-12 09:41:12 -07001312
1313 postBufferingEvent_l();
Andreas Huber6be780e2010-02-08 14:40:30 -08001314}
1315
Andreas Huberba7ec912010-02-12 10:42:02 -08001316status_t AwesomePlayer::suspend() {
Andreas Huberedbb4d82010-03-12 08:59:22 -08001317 LOGV("suspend");
Andreas Huberba7ec912010-02-12 10:42:02 -08001318 Mutex::Autolock autoLock(mLock);
1319
1320 if (mSuspensionState != NULL) {
Gloria Wangb19da8e2010-04-12 17:13:06 -07001321 if (mLastVideoBuffer == NULL) {
1322 //go into here if video is suspended again
1323 //after resuming without being played between
1324 //them
1325 SuspensionState *state = mSuspensionState;
1326 mSuspensionState = NULL;
1327 reset_l();
1328 mSuspensionState = state;
1329 return OK;
1330 }
1331
1332 delete mSuspensionState;
1333 mSuspensionState = NULL;
Andreas Huberba7ec912010-02-12 10:42:02 -08001334 }
1335
Andreas Huberedbb4d82010-03-12 08:59:22 -08001336 if (mFlags & PREPARING) {
1337 mFlags |= PREPARE_CANCELLED;
1338 if (mConnectingDataSource != NULL) {
1339 LOGI("interrupting the connection process");
1340 mConnectingDataSource->disconnect();
1341 }
1342 }
1343
Andreas Huberba7ec912010-02-12 10:42:02 -08001344 while (mFlags & PREPARING) {
1345 mPreparedCondition.wait(mLock);
1346 }
1347
1348 SuspensionState *state = new SuspensionState;
1349 state->mUri = mUri;
1350 state->mUriHeaders = mUriHeaders;
1351 state->mFileSource = mFileSource;
1352
Andreas Huber406a18b2010-02-18 16:45:13 -08001353 state->mFlags = mFlags & (PLAYING | LOOPING | AT_EOS);
Andreas Huber252573c2010-03-26 10:17:17 -07001354 getPosition(&state->mPositionUs);
Andreas Huberba7ec912010-02-12 10:42:02 -08001355
Andreas Huber7b73cfc2010-02-12 14:40:08 -08001356 if (mLastVideoBuffer) {
1357 size_t size = mLastVideoBuffer->range_length();
1358 if (size) {
1359 state->mLastVideoFrameSize = size;
1360 state->mLastVideoFrame = malloc(size);
1361 memcpy(state->mLastVideoFrame,
1362 (const uint8_t *)mLastVideoBuffer->data()
1363 + mLastVideoBuffer->range_offset(),
1364 size);
1365
1366 state->mVideoWidth = mVideoWidth;
1367 state->mVideoHeight = mVideoHeight;
1368
1369 sp<MetaData> meta = mVideoSource->getFormat();
1370 CHECK(meta->findInt32(kKeyColorFormat, &state->mColorFormat));
1371 CHECK(meta->findInt32(kKeyWidth, &state->mDecodedWidth));
1372 CHECK(meta->findInt32(kKeyHeight, &state->mDecodedHeight));
1373 }
1374 }
1375
Andreas Huberba7ec912010-02-12 10:42:02 -08001376 reset_l();
1377
1378 mSuspensionState = state;
1379
1380 return OK;
1381}
1382
1383status_t AwesomePlayer::resume() {
Andreas Huberedbb4d82010-03-12 08:59:22 -08001384 LOGV("resume");
Andreas Huberba7ec912010-02-12 10:42:02 -08001385 Mutex::Autolock autoLock(mLock);
1386
1387 if (mSuspensionState == NULL) {
1388 return INVALID_OPERATION;
1389 }
1390
1391 SuspensionState *state = mSuspensionState;
1392 mSuspensionState = NULL;
1393
1394 status_t err;
1395 if (state->mFileSource != NULL) {
1396 err = setDataSource_l(state->mFileSource);
1397
1398 if (err == OK) {
1399 mFileSource = state->mFileSource;
1400 }
1401 } else {
1402 err = setDataSource_l(state->mUri, &state->mUriHeaders);
1403 }
1404
1405 if (err != OK) {
1406 delete state;
1407 state = NULL;
1408
1409 return err;
1410 }
1411
1412 seekTo_l(state->mPositionUs);
1413
Andreas Huber406a18b2010-02-18 16:45:13 -08001414 mFlags = state->mFlags & (LOOPING | AT_EOS);
Andreas Huberba7ec912010-02-12 10:42:02 -08001415
Andreas Huber7b73cfc2010-02-12 14:40:08 -08001416 if (state->mLastVideoFrame && mISurface != NULL) {
1417 mVideoRenderer =
1418 new AwesomeLocalRenderer(
1419 true, // previewOnly
1420 "",
1421 (OMX_COLOR_FORMATTYPE)state->mColorFormat,
1422 mISurface,
1423 state->mVideoWidth,
1424 state->mVideoHeight,
1425 state->mDecodedWidth,
1426 state->mDecodedHeight);
1427
1428 mVideoRendererIsPreview = true;
1429
1430 ((AwesomeLocalRenderer *)mVideoRenderer.get())->render(
1431 state->mLastVideoFrame, state->mLastVideoFrameSize);
1432 }
1433
Andreas Huberba7ec912010-02-12 10:42:02 -08001434 if (state->mFlags & PLAYING) {
1435 play_l();
1436 }
1437
Gloria Wangb19da8e2010-04-12 17:13:06 -07001438 mSuspensionState = state;
Andreas Huberba7ec912010-02-12 10:42:02 -08001439 state = NULL;
1440
1441 return OK;
1442}
1443
Andreas Huber62f7ffe2010-05-06 10:18:05 -07001444uint32_t AwesomePlayer::flags() const {
1445 return mExtractorFlags;
1446}
1447
Andreas Huber27366fc2009-11-20 09:32:46 -08001448} // namespace android
1449