blob: 5d2127b13cf6a33c59bae8570ce6ef5af8700c20 [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 Huber27366fc2009-11-20 09:32:46 -080023#include "include/AwesomePlayer.h"
Andreas Huberb9e63832010-01-26 16:20:10 -080024#include "include/Prefetcher.h"
Andreas Huber1314e732009-12-14 14:18:22 -080025#include "include/SoftwareRenderer.h"
Andreas Huber27366fc2009-11-20 09:32:46 -080026
Andreas Hubera67d5382009-12-10 15:32:12 -080027#include <binder/IPCThreadState.h>
Andreas Huber27366fc2009-11-20 09:32:46 -080028#include <media/stagefright/AudioPlayer.h>
29#include <media/stagefright/DataSource.h>
30#include <media/stagefright/FileSource.h>
31#include <media/stagefright/MediaBuffer.h>
Andreas Huberc79827a2010-01-05 10:54:55 -080032#include <media/stagefright/MediaDefs.h>
Andreas Huber27366fc2009-11-20 09:32:46 -080033#include <media/stagefright/MediaExtractor.h>
34#include <media/stagefright/MediaDebug.h>
35#include <media/stagefright/MediaSource.h>
36#include <media/stagefright/MetaData.h>
37#include <media/stagefright/OMXCodec.h>
Andreas Huberc79827a2010-01-05 10:54:55 -080038
Mathias Agopian000479f2010-02-09 17:46:37 -080039#include <surfaceflinger/ISurface.h>
40
Andreas Huber27366fc2009-11-20 09:32:46 -080041namespace android {
42
43struct AwesomeEvent : public TimedEventQueue::Event {
Andreas Huber6be780e2010-02-08 14:40:30 -080044 AwesomeEvent(
45 AwesomePlayer *player,
46 void (AwesomePlayer::*method)())
Andreas Huber27366fc2009-11-20 09:32:46 -080047 : mPlayer(player),
Andreas Huber6be780e2010-02-08 14:40:30 -080048 mMethod(method) {
Andreas Huber27366fc2009-11-20 09:32:46 -080049 }
50
51protected:
52 virtual ~AwesomeEvent() {}
53
54 virtual void fire(TimedEventQueue *queue, int64_t /* now_us */) {
Andreas Huber6be780e2010-02-08 14:40:30 -080055 (mPlayer->*mMethod)();
Andreas Huber27366fc2009-11-20 09:32:46 -080056 }
57
58private:
59 AwesomePlayer *mPlayer;
Andreas Huber6be780e2010-02-08 14:40:30 -080060 void (AwesomePlayer::*mMethod)();
Andreas Huber27366fc2009-11-20 09:32:46 -080061
62 AwesomeEvent(const AwesomeEvent &);
63 AwesomeEvent &operator=(const AwesomeEvent &);
64};
65
Andreas Huber1314e732009-12-14 14:18:22 -080066struct AwesomeRemoteRenderer : public AwesomeRenderer {
67 AwesomeRemoteRenderer(const sp<IOMXRenderer> &target)
68 : mTarget(target) {
69 }
70
71 virtual void render(MediaBuffer *buffer) {
72 void *id;
73 if (buffer->meta_data()->findPointer(kKeyBufferID, &id)) {
74 mTarget->render((IOMX::buffer_id)id);
75 }
76 }
77
78private:
79 sp<IOMXRenderer> mTarget;
80
81 AwesomeRemoteRenderer(const AwesomeRemoteRenderer &);
82 AwesomeRemoteRenderer &operator=(const AwesomeRemoteRenderer &);
83};
84
85struct AwesomeLocalRenderer : public AwesomeRenderer {
86 AwesomeLocalRenderer(
Andreas Huber4ab5a6f2010-02-11 11:00:26 -080087 const char *componentName,
Andreas Huber1314e732009-12-14 14:18:22 -080088 OMX_COLOR_FORMATTYPE colorFormat,
89 const sp<ISurface> &surface,
90 size_t displayWidth, size_t displayHeight,
91 size_t decodedWidth, size_t decodedHeight)
Andreas Huber4ab5a6f2010-02-11 11:00:26 -080092 : mTarget(NULL),
93 mLibHandle(NULL) {
94 init(componentName,
95 colorFormat, surface, displayWidth,
96 displayHeight, decodedWidth, decodedHeight);
Andreas Huber1314e732009-12-14 14:18:22 -080097 }
98
99 virtual void render(MediaBuffer *buffer) {
100 mTarget->render(
101 (const uint8_t *)buffer->data() + buffer->range_offset(),
102 buffer->range_length(), NULL);
103 }
104
105protected:
106 virtual ~AwesomeLocalRenderer() {
107 delete mTarget;
108 mTarget = NULL;
Andreas Huber4ab5a6f2010-02-11 11:00:26 -0800109
110 if (mLibHandle) {
111 dlclose(mLibHandle);
112 mLibHandle = NULL;
113 }
Andreas Huber1314e732009-12-14 14:18:22 -0800114 }
115
116private:
Andreas Huber4ab5a6f2010-02-11 11:00:26 -0800117 VideoRenderer *mTarget;
118 void *mLibHandle;
119
120 void init(
121 const char *componentName,
122 OMX_COLOR_FORMATTYPE colorFormat,
123 const sp<ISurface> &surface,
124 size_t displayWidth, size_t displayHeight,
125 size_t decodedWidth, size_t decodedHeight);
Andreas Huber1314e732009-12-14 14:18:22 -0800126
127 AwesomeLocalRenderer(const AwesomeLocalRenderer &);
128 AwesomeLocalRenderer &operator=(const AwesomeLocalRenderer &);;
129};
130
Andreas Huber4ab5a6f2010-02-11 11:00:26 -0800131void AwesomeLocalRenderer::init(
132 const char *componentName,
133 OMX_COLOR_FORMATTYPE colorFormat,
134 const sp<ISurface> &surface,
135 size_t displayWidth, size_t displayHeight,
136 size_t decodedWidth, size_t decodedHeight) {
137 mLibHandle = dlopen("libstagefrighthw.so", RTLD_NOW);
138
139 if (mLibHandle) {
140 typedef VideoRenderer *(*CreateRendererFunc)(
141 const sp<ISurface> &surface,
142 const char *componentName,
143 OMX_COLOR_FORMATTYPE colorFormat,
144 size_t displayWidth, size_t displayHeight,
145 size_t decodedWidth, size_t decodedHeight);
146
147 CreateRendererFunc func =
148 (CreateRendererFunc)dlsym(
149 mLibHandle,
150 "_Z14createRendererRKN7android2spINS_8ISurfaceEEEPKc20"
151 "OMX_COLOR_FORMATTYPEjjjj");
152
153 if (func) {
154 mTarget =
155 (*func)(surface, componentName, colorFormat,
156 displayWidth, displayHeight, decodedWidth, decodedHeight);
157 }
158 }
159
160 if (mTarget == NULL) {
161 mTarget = new SoftwareRenderer(
162 colorFormat, surface, displayWidth, displayHeight,
163 decodedWidth, decodedHeight);
164 }
165}
166
Andreas Huber27366fc2009-11-20 09:32:46 -0800167AwesomePlayer::AwesomePlayer()
168 : mTimeSource(NULL),
169 mAudioPlayer(NULL),
Andreas Huberffdf4782010-02-09 14:05:43 -0800170 mFlags(0),
Andreas Huber27366fc2009-11-20 09:32:46 -0800171 mLastVideoBuffer(NULL),
172 mVideoBuffer(NULL) {
173 CHECK_EQ(mClient.connect(), OK);
174
175 DataSource::RegisterDefaultSniffers();
176
Andreas Huber6be780e2010-02-08 14:40:30 -0800177 mVideoEvent = new AwesomeEvent(this, &AwesomePlayer::onVideoEvent);
Andreas Huber27366fc2009-11-20 09:32:46 -0800178 mVideoEventPending = false;
Andreas Huber6be780e2010-02-08 14:40:30 -0800179 mStreamDoneEvent = new AwesomeEvent(this, &AwesomePlayer::onStreamDone);
Andreas Huber27366fc2009-11-20 09:32:46 -0800180 mStreamDoneEventPending = false;
Andreas Huber6be780e2010-02-08 14:40:30 -0800181 mBufferingEvent = new AwesomeEvent(this, &AwesomePlayer::onBufferingUpdate);
Andreas Huberb9e63832010-01-26 16:20:10 -0800182 mBufferingEventPending = false;
Andreas Huber6be780e2010-02-08 14:40:30 -0800183
184 mCheckAudioStatusEvent = new AwesomeEvent(
185 this, &AwesomePlayer::onCheckAudioStatus);
186
Andreas Huber70d10c02010-02-03 11:37:29 -0800187 mAudioStatusEventPending = false;
Andreas Huber27366fc2009-11-20 09:32:46 -0800188
189 mQueue.start();
190
191 reset();
192}
193
194AwesomePlayer::~AwesomePlayer() {
195 mQueue.stop();
196
197 reset();
198
199 mClient.disconnect();
200}
201
Andreas Huberb9e63832010-01-26 16:20:10 -0800202void AwesomePlayer::cancelPlayerEvents(bool keepBufferingGoing) {
Andreas Huber27366fc2009-11-20 09:32:46 -0800203 mQueue.cancelEvent(mVideoEvent->eventID());
204 mVideoEventPending = false;
205 mQueue.cancelEvent(mStreamDoneEvent->eventID());
206 mStreamDoneEventPending = false;
Andreas Huber70d10c02010-02-03 11:37:29 -0800207 mQueue.cancelEvent(mCheckAudioStatusEvent->eventID());
208 mAudioStatusEventPending = false;
Andreas Huberb9e63832010-01-26 16:20:10 -0800209
210 if (!keepBufferingGoing) {
211 mQueue.cancelEvent(mBufferingEvent->eventID());
212 mBufferingEventPending = false;
213 }
Andreas Huber27366fc2009-11-20 09:32:46 -0800214}
215
Andreas Hubera3f43842010-01-21 10:28:45 -0800216void AwesomePlayer::setListener(const wp<MediaPlayerBase> &listener) {
Andreas Huber27366fc2009-11-20 09:32:46 -0800217 Mutex::Autolock autoLock(mLock);
218 mListener = listener;
219}
220
Andreas Huber433c9ac2010-01-27 16:49:05 -0800221status_t AwesomePlayer::setDataSource(
222 const char *uri, const KeyedVector<String8, String8> *headers) {
Andreas Huber27366fc2009-11-20 09:32:46 -0800223 Mutex::Autolock autoLock(mLock);
224
225 reset_l();
226
Andreas Huberffdf4782010-02-09 14:05:43 -0800227 mUri = uri;
Andreas Huberb9e63832010-01-26 16:20:10 -0800228
Andreas Huberffdf4782010-02-09 14:05:43 -0800229 if (headers) {
230 mUriHeaders = *headers;
Andreas Huberb9e63832010-01-26 16:20:10 -0800231 }
232
Andreas Huberffdf4782010-02-09 14:05:43 -0800233 // The actual work will be done during preparation in the call to
234 // ::finishSetDataSource_l to avoid blocking the calling thread in
235 // setDataSource for any significant time.
Andreas Huber27366fc2009-11-20 09:32:46 -0800236
Andreas Huberffdf4782010-02-09 14:05:43 -0800237 return OK;
Andreas Huber27366fc2009-11-20 09:32:46 -0800238}
239
240status_t AwesomePlayer::setDataSource(
241 int fd, int64_t offset, int64_t length) {
242 Mutex::Autolock autoLock(mLock);
243
244 reset_l();
245
246 sp<DataSource> source = new FileSource(fd, offset, length);
247
248 status_t err = source->initCheck();
249
250 if (err != OK) {
251 return err;
252 }
253
254 sp<MediaExtractor> extractor = MediaExtractor::Create(source);
255
256 if (extractor == NULL) {
257 return UNKNOWN_ERROR;
258 }
259
260 return setDataSource_l(extractor);
261}
262
263status_t AwesomePlayer::setDataSource_l(const sp<MediaExtractor> &extractor) {
Andreas Huber27366fc2009-11-20 09:32:46 -0800264 bool haveAudio = false;
265 bool haveVideo = false;
266 for (size_t i = 0; i < extractor->countTracks(); ++i) {
267 sp<MetaData> meta = extractor->getTrackMetaData(i);
268
269 const char *mime;
270 CHECK(meta->findCString(kKeyMIMEType, &mime));
271
272 if (!haveVideo && !strncasecmp(mime, "video/", 6)) {
273 if (setVideoSource(extractor->getTrack(i)) == OK) {
274 haveVideo = true;
275 }
276 } else if (!haveAudio && !strncasecmp(mime, "audio/", 6)) {
277 if (setAudioSource(extractor->getTrack(i)) == OK) {
278 haveAudio = true;
279 }
280 }
281
282 if (haveAudio && haveVideo) {
283 break;
284 }
285 }
286
287 return !haveAudio && !haveVideo ? UNKNOWN_ERROR : OK;
288}
289
290void AwesomePlayer::reset() {
291 Mutex::Autolock autoLock(mLock);
292 reset_l();
293}
294
295void AwesomePlayer::reset_l() {
Andreas Huberffdf4782010-02-09 14:05:43 -0800296 while (mFlags & PREPARING) {
297 mPreparedCondition.wait(mLock);
298 }
299
Andreas Huber27366fc2009-11-20 09:32:46 -0800300 cancelPlayerEvents();
301
Andreas Huber3522b5a52010-01-22 14:36:53 -0800302 mVideoRenderer.clear();
303
Andreas Huber27366fc2009-11-20 09:32:46 -0800304 if (mLastVideoBuffer) {
305 mLastVideoBuffer->release();
306 mLastVideoBuffer = NULL;
307 }
308
309 if (mVideoBuffer) {
310 mVideoBuffer->release();
311 mVideoBuffer = NULL;
312 }
313
314 if (mVideoSource != NULL) {
315 mVideoSource->stop();
Andreas Huber98b48de2010-01-29 10:10:22 -0800316
317 // The following hack is necessary to ensure that the OMX
318 // component is completely released by the time we may try
319 // to instantiate it again.
320 wp<MediaSource> tmp = mVideoSource;
Andreas Huber27366fc2009-11-20 09:32:46 -0800321 mVideoSource.clear();
Andreas Huber98b48de2010-01-29 10:10:22 -0800322 while (tmp.promote() != NULL) {
323 usleep(1000);
324 }
325 IPCThreadState::self()->flushCommands();
Andreas Huber27366fc2009-11-20 09:32:46 -0800326 }
327
328 mAudioSource.clear();
329
330 if (mTimeSource != mAudioPlayer) {
331 delete mTimeSource;
332 }
333 mTimeSource = NULL;
334
335 delete mAudioPlayer;
336 mAudioPlayer = NULL;
337
Andreas Huber27366fc2009-11-20 09:32:46 -0800338 mDurationUs = -1;
339 mFlags = 0;
340 mVideoWidth = mVideoHeight = -1;
341 mTimeSourceDeltaUs = 0;
342 mVideoTimeUs = 0;
343
344 mSeeking = false;
345 mSeekTimeUs = 0;
Andreas Huberb9e63832010-01-26 16:20:10 -0800346
347 mPrefetcher.clear();
Andreas Huberffdf4782010-02-09 14:05:43 -0800348
349 mUri.setTo("");
350 mUriHeaders.clear();
Andreas Huber27366fc2009-11-20 09:32:46 -0800351}
352
Andreas Huber6be780e2010-02-08 14:40:30 -0800353void AwesomePlayer::notifyListener_l(int msg, int ext1, int ext2) {
Andreas Hubera3f43842010-01-21 10:28:45 -0800354 if (mListener != NULL) {
355 sp<MediaPlayerBase> listener = mListener.promote();
356
357 if (listener != NULL) {
Andreas Huber6be780e2010-02-08 14:40:30 -0800358 listener->sendEvent(msg, ext1, ext2);
Andreas Hubera3f43842010-01-21 10:28:45 -0800359 }
360 }
361}
362
Andreas Huberb9e63832010-01-26 16:20:10 -0800363void AwesomePlayer::onBufferingUpdate() {
364 Mutex::Autolock autoLock(mLock);
365 mBufferingEventPending = false;
366
367 if (mDurationUs >= 0) {
368 int64_t cachedDurationUs = mPrefetcher->getCachedDurationUs();
369 int64_t positionUs = 0;
Andreas Huber7085b6842010-02-03 16:02:02 -0800370 if (mVideoSource != NULL) {
Andreas Huberb9e63832010-01-26 16:20:10 -0800371 positionUs = mVideoTimeUs;
372 } else if (mAudioPlayer != NULL) {
373 positionUs = mAudioPlayer->getMediaTimeUs();
374 }
375
376 cachedDurationUs += positionUs;
377
378 double percentage = (double)cachedDurationUs / mDurationUs;
379 notifyListener_l(MEDIA_BUFFERING_UPDATE, percentage * 100.0);
380
381 postBufferingEvent_l();
382 }
383}
384
Andreas Huber27366fc2009-11-20 09:32:46 -0800385void AwesomePlayer::onStreamDone() {
386 // Posted whenever any stream finishes playing.
387
388 Mutex::Autolock autoLock(mLock);
389 mStreamDoneEventPending = false;
390
391 if (mFlags & LOOPING) {
392 seekTo_l(0);
393
Andreas Huber7085b6842010-02-03 16:02:02 -0800394 if (mVideoSource != NULL) {
Andreas Huber27366fc2009-11-20 09:32:46 -0800395 postVideoEvent_l();
396 }
397 } else {
Andreas Hubera3f43842010-01-21 10:28:45 -0800398 notifyListener_l(MEDIA_PLAYBACK_COMPLETE);
Andreas Huber27366fc2009-11-20 09:32:46 -0800399
400 pause_l();
401 }
402}
403
404status_t AwesomePlayer::play() {
405 Mutex::Autolock autoLock(mLock);
406
407 if (mFlags & PLAYING) {
408 return OK;
409 }
410
Andreas Huberffdf4782010-02-09 14:05:43 -0800411 if (!(mFlags & PREPARED)) {
412 status_t err = prepare_l();
413
414 if (err != OK) {
415 return err;
416 }
417 }
418
Andreas Huber27366fc2009-11-20 09:32:46 -0800419 mFlags |= PLAYING;
420 mFlags |= FIRST_FRAME;
421
Andreas Huberc1d5c922009-12-10 15:49:04 -0800422 bool deferredAudioSeek = false;
423
Andreas Huber27366fc2009-11-20 09:32:46 -0800424 if (mAudioSource != NULL) {
425 if (mAudioPlayer == NULL) {
426 if (mAudioSink != NULL) {
427 mAudioPlayer = new AudioPlayer(mAudioSink);
Andreas Huber27366fc2009-11-20 09:32:46 -0800428 mAudioPlayer->setSource(mAudioSource);
Andreas Huber62eac002010-01-29 13:24:58 -0800429 status_t err = mAudioPlayer->start();
430
431 if (err != OK) {
432 delete mAudioPlayer;
433 mAudioPlayer = NULL;
434
435 mFlags &= ~(PLAYING | FIRST_FRAME);
436
437 return err;
438 }
Andreas Huber27366fc2009-11-20 09:32:46 -0800439
440 delete mTimeSource;
441 mTimeSource = mAudioPlayer;
442
Andreas Huberc1d5c922009-12-10 15:49:04 -0800443 deferredAudioSeek = true;
Andreas Huber70d10c02010-02-03 11:37:29 -0800444
445 mWatchForAudioSeekComplete = false;
446 mWatchForAudioEOS = true;
Andreas Huber27366fc2009-11-20 09:32:46 -0800447 }
448 } else {
449 mAudioPlayer->resume();
450 }
Andreas Huber70d10c02010-02-03 11:37:29 -0800451
452 postCheckAudioStatusEvent_l();
Andreas Huber27366fc2009-11-20 09:32:46 -0800453 }
454
455 if (mTimeSource == NULL && mAudioPlayer == NULL) {
456 mTimeSource = new SystemTimeSource;
457 }
458
459 if (mVideoSource != NULL) {
Andreas Huber7085b6842010-02-03 16:02:02 -0800460 // Kick off video playback
461 postVideoEvent_l();
Andreas Huber27366fc2009-11-20 09:32:46 -0800462 }
463
Andreas Huberc1d5c922009-12-10 15:49:04 -0800464 if (deferredAudioSeek) {
465 // If there was a seek request while we were paused
466 // and we're just starting up again, honor the request now.
467 seekAudioIfNecessary_l();
468 }
469
Andreas Huberb9e63832010-01-26 16:20:10 -0800470 postBufferingEvent_l();
471
Andreas Huber27366fc2009-11-20 09:32:46 -0800472 return OK;
473}
474
475void AwesomePlayer::initRenderer_l() {
476 if (mISurface != NULL) {
477 sp<MetaData> meta = mVideoSource->getFormat();
478
479 int32_t format;
480 const char *component;
481 int32_t decodedWidth, decodedHeight;
482 CHECK(meta->findInt32(kKeyColorFormat, &format));
483 CHECK(meta->findCString(kKeyDecoderComponent, &component));
484 CHECK(meta->findInt32(kKeyWidth, &decodedWidth));
485 CHECK(meta->findInt32(kKeyHeight, &decodedHeight));
486
Andreas Hubera67d5382009-12-10 15:32:12 -0800487 mVideoRenderer.clear();
488
489 // Must ensure that mVideoRenderer's destructor is actually executed
490 // before creating a new one.
491 IPCThreadState::self()->flushCommands();
492
Andreas Huber1314e732009-12-14 14:18:22 -0800493 if (!strncmp("OMX.", component, 4)) {
494 // Our OMX codecs allocate buffers on the media_server side
495 // therefore they require a remote IOMXRenderer that knows how
496 // to display them.
497 mVideoRenderer = new AwesomeRemoteRenderer(
498 mClient.interface()->createRenderer(
499 mISurface, component,
500 (OMX_COLOR_FORMATTYPE)format,
501 decodedWidth, decodedHeight,
502 mVideoWidth, mVideoHeight));
503 } else {
504 // Other decoders are instantiated locally and as a consequence
505 // allocate their buffers in local address space.
506 mVideoRenderer = new AwesomeLocalRenderer(
Andreas Huber4ab5a6f2010-02-11 11:00:26 -0800507 component,
Andreas Huber1314e732009-12-14 14:18:22 -0800508 (OMX_COLOR_FORMATTYPE)format,
509 mISurface,
510 mVideoWidth, mVideoHeight,
511 decodedWidth, decodedHeight);
512 }
Andreas Huber27366fc2009-11-20 09:32:46 -0800513 }
514}
515
516status_t AwesomePlayer::pause() {
517 Mutex::Autolock autoLock(mLock);
518 return pause_l();
519}
520
521status_t AwesomePlayer::pause_l() {
522 if (!(mFlags & PLAYING)) {
523 return OK;
524 }
525
Andreas Huberb9e63832010-01-26 16:20:10 -0800526 cancelPlayerEvents(true /* keepBufferingGoing */);
Andreas Huber27366fc2009-11-20 09:32:46 -0800527
528 if (mAudioPlayer != NULL) {
529 mAudioPlayer->pause();
530 }
531
532 mFlags &= ~PLAYING;
533
534 return OK;
535}
536
537bool AwesomePlayer::isPlaying() const {
538 Mutex::Autolock autoLock(mLock);
539
540 return mFlags & PLAYING;
541}
542
543void AwesomePlayer::setISurface(const sp<ISurface> &isurface) {
544 Mutex::Autolock autoLock(mLock);
545
546 mISurface = isurface;
547}
548
549void AwesomePlayer::setAudioSink(
550 const sp<MediaPlayerBase::AudioSink> &audioSink) {
551 Mutex::Autolock autoLock(mLock);
552
553 mAudioSink = audioSink;
554}
555
556status_t AwesomePlayer::setLooping(bool shouldLoop) {
557 Mutex::Autolock autoLock(mLock);
558
559 mFlags = mFlags & ~LOOPING;
560
561 if (shouldLoop) {
562 mFlags |= LOOPING;
563 }
564
565 return OK;
566}
567
568status_t AwesomePlayer::getDuration(int64_t *durationUs) {
569 Mutex::Autolock autoLock(mLock);
570
571 if (mDurationUs < 0) {
572 return UNKNOWN_ERROR;
573 }
574
575 *durationUs = mDurationUs;
576
577 return OK;
578}
579
580status_t AwesomePlayer::getPosition(int64_t *positionUs) {
581 Mutex::Autolock autoLock(mLock);
582
Andreas Huber7085b6842010-02-03 16:02:02 -0800583 if (mVideoSource != NULL) {
Andreas Huber27366fc2009-11-20 09:32:46 -0800584 *positionUs = mVideoTimeUs;
585 } else if (mAudioPlayer != NULL) {
586 *positionUs = mAudioPlayer->getMediaTimeUs();
587 } else {
588 *positionUs = 0;
589 }
590
591 return OK;
592}
593
594status_t AwesomePlayer::seekTo(int64_t timeUs) {
595 Mutex::Autolock autoLock(mLock);
596 return seekTo_l(timeUs);
597}
598
599status_t AwesomePlayer::seekTo_l(int64_t timeUs) {
600 mSeeking = true;
601 mSeekTimeUs = timeUs;
602
603 seekAudioIfNecessary_l();
604
605 return OK;
606}
607
608void AwesomePlayer::seekAudioIfNecessary_l() {
Andreas Huber7085b6842010-02-03 16:02:02 -0800609 if (mSeeking && mVideoSource == NULL && mAudioPlayer != NULL) {
Andreas Huber27366fc2009-11-20 09:32:46 -0800610 mAudioPlayer->seekTo(mSeekTimeUs);
611
Andreas Huber70d10c02010-02-03 11:37:29 -0800612 mWatchForAudioSeekComplete = true;
613 mWatchForAudioEOS = true;
Andreas Huber27366fc2009-11-20 09:32:46 -0800614 mSeeking = false;
615 }
616}
617
618status_t AwesomePlayer::getVideoDimensions(
619 int32_t *width, int32_t *height) const {
620 Mutex::Autolock autoLock(mLock);
621
622 if (mVideoWidth < 0 || mVideoHeight < 0) {
623 return UNKNOWN_ERROR;
624 }
625
626 *width = mVideoWidth;
627 *height = mVideoHeight;
628
629 return OK;
630}
631
Andreas Huberb9e63832010-01-26 16:20:10 -0800632status_t AwesomePlayer::setAudioSource(sp<MediaSource> source) {
Andreas Huber27366fc2009-11-20 09:32:46 -0800633 if (source == NULL) {
634 return UNKNOWN_ERROR;
635 }
636
Andreas Huberb9e63832010-01-26 16:20:10 -0800637 if (mPrefetcher != NULL) {
638 source = mPrefetcher->addSource(source);
639 }
640
Andreas Huberc79827a2010-01-05 10:54:55 -0800641 sp<MetaData> meta = source->getFormat();
642
643 const char *mime;
644 CHECK(meta->findCString(kKeyMIMEType, &mime));
645
646 if (!strcasecmp(mime, MEDIA_MIMETYPE_AUDIO_RAW)) {
647 mAudioSource = source;
648 } else {
649 mAudioSource = OMXCodec::Create(
650 mClient.interface(), source->getFormat(),
651 false, // createEncoder
652 source);
653 }
Andreas Huber27366fc2009-11-20 09:32:46 -0800654
655 if (mAudioSource != NULL) {
656 int64_t durationUs;
657 if (source->getFormat()->findInt64(kKeyDuration, &durationUs)) {
658 if (mDurationUs < 0 || durationUs > mDurationUs) {
659 mDurationUs = durationUs;
660 }
661 }
662 }
663
664 return mAudioSource != NULL ? OK : UNKNOWN_ERROR;
665}
666
Andreas Huberb9e63832010-01-26 16:20:10 -0800667status_t AwesomePlayer::setVideoSource(sp<MediaSource> source) {
Andreas Huber27366fc2009-11-20 09:32:46 -0800668 if (source == NULL) {
669 return UNKNOWN_ERROR;
670 }
671
Andreas Huberb9e63832010-01-26 16:20:10 -0800672 if (mPrefetcher != NULL) {
673 source = mPrefetcher->addSource(source);
674 }
675
Andreas Huber27366fc2009-11-20 09:32:46 -0800676 mVideoSource = OMXCodec::Create(
677 mClient.interface(), source->getFormat(),
678 false, // createEncoder
679 source);
680
681 if (mVideoSource != NULL) {
682 int64_t durationUs;
683 if (source->getFormat()->findInt64(kKeyDuration, &durationUs)) {
684 if (mDurationUs < 0 || durationUs > mDurationUs) {
685 mDurationUs = durationUs;
686 }
687 }
688
689 CHECK(source->getFormat()->findInt32(kKeyWidth, &mVideoWidth));
690 CHECK(source->getFormat()->findInt32(kKeyHeight, &mVideoHeight));
691
692 mVideoSource->start();
693 }
694
695 return mVideoSource != NULL ? OK : UNKNOWN_ERROR;
696}
697
Andreas Huber6be780e2010-02-08 14:40:30 -0800698void AwesomePlayer::onVideoEvent() {
Andreas Huber27366fc2009-11-20 09:32:46 -0800699 Mutex::Autolock autoLock(mLock);
Andreas Huberb9e63832010-01-26 16:20:10 -0800700
Andreas Huber27366fc2009-11-20 09:32:46 -0800701 mVideoEventPending = false;
702
703 if (mSeeking) {
704 if (mLastVideoBuffer) {
705 mLastVideoBuffer->release();
706 mLastVideoBuffer = NULL;
707 }
708
709 if (mVideoBuffer) {
710 mVideoBuffer->release();
711 mVideoBuffer = NULL;
712 }
713 }
714
715 if (!mVideoBuffer) {
716 MediaSource::ReadOptions options;
717 if (mSeeking) {
718 LOGV("seeking to %lld us (%.2f secs)", mSeekTimeUs, mSeekTimeUs / 1E6);
719
720 options.setSeekTo(mSeekTimeUs);
721 }
722 for (;;) {
723 status_t err = mVideoSource->read(&mVideoBuffer, &options);
Andreas Huberb1f5ee42009-12-14 15:34:11 -0800724 options.clearSeekTo();
Andreas Huber27366fc2009-11-20 09:32:46 -0800725
726 if (err != OK) {
727 CHECK_EQ(mVideoBuffer, NULL);
728
729 if (err == INFO_FORMAT_CHANGED) {
730 LOGV("VideoSource signalled format change.");
731
Andreas Huber7085b6842010-02-03 16:02:02 -0800732 if (mVideoRenderer != NULL) {
733 initRenderer_l();
734 }
Andreas Huber27366fc2009-11-20 09:32:46 -0800735 continue;
736 }
737
738 postStreamDoneEvent_l();
739 return;
740 }
741
Andreas Hubera67d5382009-12-10 15:32:12 -0800742 if (mVideoBuffer->range_length() == 0) {
Andreas Huber6ddcf012009-12-10 15:32:12 -0800743 // Some decoders, notably the PV AVC software decoder
744 // return spurious empty buffers that we just want to ignore.
745
Andreas Hubera67d5382009-12-10 15:32:12 -0800746 mVideoBuffer->release();
747 mVideoBuffer = NULL;
748 continue;
749 }
750
Andreas Huber27366fc2009-11-20 09:32:46 -0800751 break;
752 }
753 }
754
755 int64_t timeUs;
756 CHECK(mVideoBuffer->meta_data()->findInt64(kKeyTime, &timeUs));
757
758 mVideoTimeUs = timeUs;
759
760 if (mSeeking) {
761 if (mAudioPlayer != NULL) {
762 LOGV("seeking audio to %lld us (%.2f secs).", timeUs, timeUs / 1E6);
763
764 mAudioPlayer->seekTo(timeUs);
Andreas Huber70d10c02010-02-03 11:37:29 -0800765 mWatchForAudioSeekComplete = true;
766 mWatchForAudioEOS = true;
Andreas Huber27366fc2009-11-20 09:32:46 -0800767 } else {
768 // If we're playing video only, report seek complete now,
769 // otherwise audio player will notify us later.
Andreas Hubera3f43842010-01-21 10:28:45 -0800770 notifyListener_l(MEDIA_SEEK_COMPLETE);
Andreas Huber27366fc2009-11-20 09:32:46 -0800771 }
772
773 mFlags |= FIRST_FRAME;
774 mSeeking = false;
775 }
776
777 if (mFlags & FIRST_FRAME) {
778 mFlags &= ~FIRST_FRAME;
779
780 mTimeSourceDeltaUs = mTimeSource->getRealTimeUs() - timeUs;
781 }
782
783 int64_t realTimeUs, mediaTimeUs;
784 if (mAudioPlayer != NULL
785 && mAudioPlayer->getMediaTimeMapping(&realTimeUs, &mediaTimeUs)) {
786 mTimeSourceDeltaUs = realTimeUs - mediaTimeUs;
787 }
788
789 int64_t nowUs = mTimeSource->getRealTimeUs() - mTimeSourceDeltaUs;
790
791 int64_t latenessUs = nowUs - timeUs;
792
Andreas Huber24b0a952009-11-23 14:02:00 -0800793 if (latenessUs > 40000) {
794 // We're more than 40ms late.
Andreas Huber4a9375e2010-02-09 11:54:33 -0800795 LOGV("we're late by %lld us (%.2f secs)", latenessUs, latenessUs / 1E6);
Andreas Huber27366fc2009-11-20 09:32:46 -0800796
797 mVideoBuffer->release();
798 mVideoBuffer = NULL;
799
800 postVideoEvent_l();
801 return;
802 }
803
804 if (latenessUs < -10000) {
805 // We're more than 10ms early.
806
807 postVideoEvent_l(10000);
808 return;
809 }
810
Andreas Huber7085b6842010-02-03 16:02:02 -0800811 if (mVideoRenderer == NULL) {
812 initRenderer_l();
813 }
814
815 if (mVideoRenderer != NULL) {
816 mVideoRenderer->render(mVideoBuffer);
817 }
Andreas Huber27366fc2009-11-20 09:32:46 -0800818
819 if (mLastVideoBuffer) {
820 mLastVideoBuffer->release();
821 mLastVideoBuffer = NULL;
822 }
823 mLastVideoBuffer = mVideoBuffer;
824 mVideoBuffer = NULL;
825
826 postVideoEvent_l();
827}
828
829void AwesomePlayer::postVideoEvent_l(int64_t delayUs) {
830 if (mVideoEventPending) {
831 return;
832 }
833
834 mVideoEventPending = true;
835 mQueue.postEventWithDelay(mVideoEvent, delayUs < 0 ? 10000 : delayUs);
836}
837
838void AwesomePlayer::postStreamDoneEvent_l() {
839 if (mStreamDoneEventPending) {
840 return;
841 }
842 mStreamDoneEventPending = true;
843 mQueue.postEvent(mStreamDoneEvent);
844}
845
Andreas Huberb9e63832010-01-26 16:20:10 -0800846void AwesomePlayer::postBufferingEvent_l() {
847 if (mPrefetcher == NULL) {
848 return;
849 }
850
851 if (mBufferingEventPending) {
852 return;
853 }
854 mBufferingEventPending = true;
855 mQueue.postEventWithDelay(mBufferingEvent, 1000000ll);
856}
857
Andreas Huber70d10c02010-02-03 11:37:29 -0800858void AwesomePlayer::postCheckAudioStatusEvent_l() {
859 if (mAudioStatusEventPending) {
860 return;
861 }
862 mAudioStatusEventPending = true;
863 mQueue.postEventWithDelay(mCheckAudioStatusEvent, 100000ll);
864}
865
866void AwesomePlayer::onCheckAudioStatus() {
867 Mutex::Autolock autoLock(mLock);
868 mAudioStatusEventPending = false;
869
870 if (mWatchForAudioSeekComplete && !mAudioPlayer->isSeeking()) {
871 mWatchForAudioSeekComplete = false;
872 notifyListener_l(MEDIA_SEEK_COMPLETE);
873 }
874
875 if (mWatchForAudioEOS && mAudioPlayer->reachedEOS()) {
876 mWatchForAudioEOS = false;
877 postStreamDoneEvent_l();
878 }
879
880 postCheckAudioStatusEvent_l();
881}
882
Andreas Huber6be780e2010-02-08 14:40:30 -0800883status_t AwesomePlayer::prepare() {
884 Mutex::Autolock autoLock(mLock);
Andreas Huberffdf4782010-02-09 14:05:43 -0800885 return prepare_l();
886}
Andreas Huber6be780e2010-02-08 14:40:30 -0800887
Andreas Huberffdf4782010-02-09 14:05:43 -0800888status_t AwesomePlayer::prepare_l() {
889 if (mFlags & PREPARED) {
890 return OK;
891 }
892
893 if (mFlags & PREPARING) {
894 return UNKNOWN_ERROR;
895 }
896
897 mIsAsyncPrepare = false;
Andreas Huber6be780e2010-02-08 14:40:30 -0800898 status_t err = prepareAsync_l();
899
900 if (err != OK) {
901 return err;
902 }
903
Andreas Huberffdf4782010-02-09 14:05:43 -0800904 while (mFlags & PREPARING) {
Andreas Huber6be780e2010-02-08 14:40:30 -0800905 mPreparedCondition.wait(mLock);
906 }
907
Andreas Huberffdf4782010-02-09 14:05:43 -0800908 return mPrepareResult;
Andreas Huber6be780e2010-02-08 14:40:30 -0800909}
910
911status_t AwesomePlayer::prepareAsync() {
912 Mutex::Autolock autoLock(mLock);
Andreas Huberffdf4782010-02-09 14:05:43 -0800913
914 if (mFlags & PREPARING) {
915 return UNKNOWN_ERROR; // async prepare already pending
916 }
917
918 mIsAsyncPrepare = true;
Andreas Huber6be780e2010-02-08 14:40:30 -0800919 return prepareAsync_l();
920}
921
922status_t AwesomePlayer::prepareAsync_l() {
Andreas Huberffdf4782010-02-09 14:05:43 -0800923 if (mFlags & PREPARING) {
924 return UNKNOWN_ERROR; // async prepare already pending
Andreas Huber6be780e2010-02-08 14:40:30 -0800925 }
926
Andreas Huberffdf4782010-02-09 14:05:43 -0800927 mFlags |= PREPARING;
Andreas Huber6be780e2010-02-08 14:40:30 -0800928 mAsyncPrepareEvent = new AwesomeEvent(
929 this, &AwesomePlayer::onPrepareAsyncEvent);
930
931 mQueue.postEvent(mAsyncPrepareEvent);
932
933 return OK;
934}
935
Andreas Huberffdf4782010-02-09 14:05:43 -0800936status_t AwesomePlayer::finishSetDataSource_l() {
937 sp<DataSource> dataSource =
938 DataSource::CreateFromURI(mUri.string(), &mUriHeaders);
939
940 if (dataSource == NULL) {
941 return UNKNOWN_ERROR;
942 }
943
944 sp<MediaExtractor> extractor = MediaExtractor::Create(dataSource);
945
946 if (extractor == NULL) {
947 return UNKNOWN_ERROR;
948 }
949
950 if (dataSource->flags() & DataSource::kWantsPrefetching) {
951 mPrefetcher = new Prefetcher;
952 }
953
954 return setDataSource_l(extractor);
955}
956
Andreas Huber6be780e2010-02-08 14:40:30 -0800957void AwesomePlayer::onPrepareAsyncEvent() {
Andreas Huberffdf4782010-02-09 14:05:43 -0800958 {
959 Mutex::Autolock autoLock(mLock);
960
961 if (mUri.size() > 0) {
962 status_t err = finishSetDataSource_l();
963
964 if (err != OK) {
965 if (mIsAsyncPrepare) {
966 notifyListener_l(MEDIA_ERROR, MEDIA_ERROR_UNKNOWN, err);
967 }
968
969 mPrepareResult = err;
970 mFlags &= ~PREPARING;
971 mAsyncPrepareEvent = NULL;
972 mPreparedCondition.broadcast();
973
974 return;
975 }
976 }
977 }
978
Andreas Huber6be780e2010-02-08 14:40:30 -0800979 sp<Prefetcher> prefetcher;
980
981 {
982 Mutex::Autolock autoLock(mLock);
983 prefetcher = mPrefetcher;
984 }
985
986 if (prefetcher != NULL) {
987 prefetcher->prepare();
988 }
989
990 Mutex::Autolock autoLock(mLock);
991
Andreas Huberffdf4782010-02-09 14:05:43 -0800992 if (mIsAsyncPrepare) {
993 if (mVideoWidth < 0 || mVideoHeight < 0) {
994 notifyListener_l(MEDIA_SET_VIDEO_SIZE, 0, 0);
995 } else {
996 notifyListener_l(MEDIA_SET_VIDEO_SIZE, mVideoWidth, mVideoHeight);
997 }
998
999 notifyListener_l(MEDIA_PREPARED);
Andreas Huber6be780e2010-02-08 14:40:30 -08001000 }
1001
Andreas Huberffdf4782010-02-09 14:05:43 -08001002 mPrepareResult = OK;
1003 mFlags &= ~PREPARING;
1004 mFlags |= PREPARED;
Andreas Huber6be780e2010-02-08 14:40:30 -08001005 mAsyncPrepareEvent = NULL;
Andreas Huberffdf4782010-02-09 14:05:43 -08001006 mPreparedCondition.broadcast();
Andreas Huber6be780e2010-02-08 14:40:30 -08001007}
1008
Andreas Huber27366fc2009-11-20 09:32:46 -08001009} // namespace android
1010