blob: d25f7f6e1f83296f97a945964e3604102ced6774 [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
21#include "include/AwesomePlayer.h"
Andreas Huberb9e63832010-01-26 16:20:10 -080022#include "include/Prefetcher.h"
Andreas Huber1314e732009-12-14 14:18:22 -080023#include "include/SoftwareRenderer.h"
Andreas Huber27366fc2009-11-20 09:32:46 -080024
Andreas Hubera67d5382009-12-10 15:32:12 -080025#include <binder/IPCThreadState.h>
Andreas Huber27366fc2009-11-20 09:32:46 -080026#include <media/stagefright/AudioPlayer.h>
27#include <media/stagefright/DataSource.h>
28#include <media/stagefright/FileSource.h>
29#include <media/stagefright/MediaBuffer.h>
Andreas Huberc79827a2010-01-05 10:54:55 -080030#include <media/stagefright/MediaDefs.h>
Andreas Huber27366fc2009-11-20 09:32:46 -080031#include <media/stagefright/MediaExtractor.h>
32#include <media/stagefright/MediaDebug.h>
33#include <media/stagefright/MediaSource.h>
34#include <media/stagefright/MetaData.h>
35#include <media/stagefright/OMXCodec.h>
Andreas Huberc79827a2010-01-05 10:54:55 -080036
Andreas Huber27366fc2009-11-20 09:32:46 -080037namespace android {
38
39struct AwesomeEvent : public TimedEventQueue::Event {
Andreas Huber6be780e2010-02-08 14:40:30 -080040 AwesomeEvent(
41 AwesomePlayer *player,
42 void (AwesomePlayer::*method)())
Andreas Huber27366fc2009-11-20 09:32:46 -080043 : mPlayer(player),
Andreas Huber6be780e2010-02-08 14:40:30 -080044 mMethod(method) {
Andreas Huber27366fc2009-11-20 09:32:46 -080045 }
46
47protected:
48 virtual ~AwesomeEvent() {}
49
50 virtual void fire(TimedEventQueue *queue, int64_t /* now_us */) {
Andreas Huber6be780e2010-02-08 14:40:30 -080051 (mPlayer->*mMethod)();
Andreas Huber27366fc2009-11-20 09:32:46 -080052 }
53
54private:
55 AwesomePlayer *mPlayer;
Andreas Huber6be780e2010-02-08 14:40:30 -080056 void (AwesomePlayer::*mMethod)();
Andreas Huber27366fc2009-11-20 09:32:46 -080057
58 AwesomeEvent(const AwesomeEvent &);
59 AwesomeEvent &operator=(const AwesomeEvent &);
60};
61
Andreas Huber1314e732009-12-14 14:18:22 -080062struct AwesomeRemoteRenderer : public AwesomeRenderer {
63 AwesomeRemoteRenderer(const sp<IOMXRenderer> &target)
64 : mTarget(target) {
65 }
66
67 virtual void render(MediaBuffer *buffer) {
68 void *id;
69 if (buffer->meta_data()->findPointer(kKeyBufferID, &id)) {
70 mTarget->render((IOMX::buffer_id)id);
71 }
72 }
73
74private:
75 sp<IOMXRenderer> mTarget;
76
77 AwesomeRemoteRenderer(const AwesomeRemoteRenderer &);
78 AwesomeRemoteRenderer &operator=(const AwesomeRemoteRenderer &);
79};
80
81struct AwesomeLocalRenderer : public AwesomeRenderer {
82 AwesomeLocalRenderer(
83 OMX_COLOR_FORMATTYPE colorFormat,
84 const sp<ISurface> &surface,
85 size_t displayWidth, size_t displayHeight,
86 size_t decodedWidth, size_t decodedHeight)
87 : mTarget(new SoftwareRenderer(
88 colorFormat, surface, displayWidth, displayHeight,
89 decodedWidth, decodedHeight)) {
90 }
91
92 virtual void render(MediaBuffer *buffer) {
93 mTarget->render(
94 (const uint8_t *)buffer->data() + buffer->range_offset(),
95 buffer->range_length(), NULL);
96 }
97
98protected:
99 virtual ~AwesomeLocalRenderer() {
100 delete mTarget;
101 mTarget = NULL;
102 }
103
104private:
105 SoftwareRenderer *mTarget;
106
107 AwesomeLocalRenderer(const AwesomeLocalRenderer &);
108 AwesomeLocalRenderer &operator=(const AwesomeLocalRenderer &);;
109};
110
Andreas Huber27366fc2009-11-20 09:32:46 -0800111AwesomePlayer::AwesomePlayer()
112 : mTimeSource(NULL),
113 mAudioPlayer(NULL),
114 mLastVideoBuffer(NULL),
115 mVideoBuffer(NULL) {
116 CHECK_EQ(mClient.connect(), OK);
117
118 DataSource::RegisterDefaultSniffers();
119
Andreas Huber6be780e2010-02-08 14:40:30 -0800120 mVideoEvent = new AwesomeEvent(this, &AwesomePlayer::onVideoEvent);
Andreas Huber27366fc2009-11-20 09:32:46 -0800121 mVideoEventPending = false;
Andreas Huber6be780e2010-02-08 14:40:30 -0800122 mStreamDoneEvent = new AwesomeEvent(this, &AwesomePlayer::onStreamDone);
Andreas Huber27366fc2009-11-20 09:32:46 -0800123 mStreamDoneEventPending = false;
Andreas Huber6be780e2010-02-08 14:40:30 -0800124 mBufferingEvent = new AwesomeEvent(this, &AwesomePlayer::onBufferingUpdate);
Andreas Huberb9e63832010-01-26 16:20:10 -0800125 mBufferingEventPending = false;
Andreas Huber6be780e2010-02-08 14:40:30 -0800126
127 mCheckAudioStatusEvent = new AwesomeEvent(
128 this, &AwesomePlayer::onCheckAudioStatus);
129
Andreas Huber70d10c02010-02-03 11:37:29 -0800130 mAudioStatusEventPending = false;
Andreas Huber27366fc2009-11-20 09:32:46 -0800131
132 mQueue.start();
133
134 reset();
135}
136
137AwesomePlayer::~AwesomePlayer() {
138 mQueue.stop();
139
140 reset();
141
142 mClient.disconnect();
143}
144
Andreas Huberb9e63832010-01-26 16:20:10 -0800145void AwesomePlayer::cancelPlayerEvents(bool keepBufferingGoing) {
Andreas Huber27366fc2009-11-20 09:32:46 -0800146 mQueue.cancelEvent(mVideoEvent->eventID());
147 mVideoEventPending = false;
148 mQueue.cancelEvent(mStreamDoneEvent->eventID());
149 mStreamDoneEventPending = false;
Andreas Huber70d10c02010-02-03 11:37:29 -0800150 mQueue.cancelEvent(mCheckAudioStatusEvent->eventID());
151 mAudioStatusEventPending = false;
Andreas Huberb9e63832010-01-26 16:20:10 -0800152
153 if (!keepBufferingGoing) {
154 mQueue.cancelEvent(mBufferingEvent->eventID());
155 mBufferingEventPending = false;
156 }
Andreas Huber27366fc2009-11-20 09:32:46 -0800157}
158
Andreas Hubera3f43842010-01-21 10:28:45 -0800159void AwesomePlayer::setListener(const wp<MediaPlayerBase> &listener) {
Andreas Huber27366fc2009-11-20 09:32:46 -0800160 Mutex::Autolock autoLock(mLock);
161 mListener = listener;
162}
163
Andreas Huber433c9ac2010-01-27 16:49:05 -0800164status_t AwesomePlayer::setDataSource(
165 const char *uri, const KeyedVector<String8, String8> *headers) {
Andreas Huber27366fc2009-11-20 09:32:46 -0800166 Mutex::Autolock autoLock(mLock);
167
168 reset_l();
169
Andreas Huber433c9ac2010-01-27 16:49:05 -0800170 sp<DataSource> dataSource = DataSource::CreateFromURI(uri, headers);
Andreas Huberb9e63832010-01-26 16:20:10 -0800171
172 if (dataSource == NULL) {
173 return UNKNOWN_ERROR;
174 }
175
176 sp<MediaExtractor> extractor = MediaExtractor::Create(dataSource);
Andreas Huber27366fc2009-11-20 09:32:46 -0800177
178 if (extractor == NULL) {
179 return UNKNOWN_ERROR;
180 }
181
Andreas Huberb9e63832010-01-26 16:20:10 -0800182 if (dataSource->flags() & DataSource::kWantsPrefetching) {
183 mPrefetcher = new Prefetcher;
184 }
185
Andreas Huber27366fc2009-11-20 09:32:46 -0800186 return setDataSource_l(extractor);
187}
188
189status_t AwesomePlayer::setDataSource(
190 int fd, int64_t offset, int64_t length) {
191 Mutex::Autolock autoLock(mLock);
192
193 reset_l();
194
195 sp<DataSource> source = new FileSource(fd, offset, length);
196
197 status_t err = source->initCheck();
198
199 if (err != OK) {
200 return err;
201 }
202
203 sp<MediaExtractor> extractor = MediaExtractor::Create(source);
204
205 if (extractor == NULL) {
206 return UNKNOWN_ERROR;
207 }
208
209 return setDataSource_l(extractor);
210}
211
212status_t AwesomePlayer::setDataSource_l(const sp<MediaExtractor> &extractor) {
Andreas Huber27366fc2009-11-20 09:32:46 -0800213 bool haveAudio = false;
214 bool haveVideo = false;
215 for (size_t i = 0; i < extractor->countTracks(); ++i) {
216 sp<MetaData> meta = extractor->getTrackMetaData(i);
217
218 const char *mime;
219 CHECK(meta->findCString(kKeyMIMEType, &mime));
220
221 if (!haveVideo && !strncasecmp(mime, "video/", 6)) {
222 if (setVideoSource(extractor->getTrack(i)) == OK) {
223 haveVideo = true;
224 }
225 } else if (!haveAudio && !strncasecmp(mime, "audio/", 6)) {
226 if (setAudioSource(extractor->getTrack(i)) == OK) {
227 haveAudio = true;
228 }
229 }
230
231 if (haveAudio && haveVideo) {
232 break;
233 }
234 }
235
236 return !haveAudio && !haveVideo ? UNKNOWN_ERROR : OK;
237}
238
239void AwesomePlayer::reset() {
240 Mutex::Autolock autoLock(mLock);
241 reset_l();
242}
243
244void AwesomePlayer::reset_l() {
245 cancelPlayerEvents();
246
Andreas Huber3522b5a52010-01-22 14:36:53 -0800247 mVideoRenderer.clear();
248
Andreas Huber27366fc2009-11-20 09:32:46 -0800249 if (mLastVideoBuffer) {
250 mLastVideoBuffer->release();
251 mLastVideoBuffer = NULL;
252 }
253
254 if (mVideoBuffer) {
255 mVideoBuffer->release();
256 mVideoBuffer = NULL;
257 }
258
259 if (mVideoSource != NULL) {
260 mVideoSource->stop();
Andreas Huber98b48de2010-01-29 10:10:22 -0800261
262 // The following hack is necessary to ensure that the OMX
263 // component is completely released by the time we may try
264 // to instantiate it again.
265 wp<MediaSource> tmp = mVideoSource;
Andreas Huber27366fc2009-11-20 09:32:46 -0800266 mVideoSource.clear();
Andreas Huber98b48de2010-01-29 10:10:22 -0800267 while (tmp.promote() != NULL) {
268 usleep(1000);
269 }
270 IPCThreadState::self()->flushCommands();
Andreas Huber27366fc2009-11-20 09:32:46 -0800271 }
272
273 mAudioSource.clear();
274
275 if (mTimeSource != mAudioPlayer) {
276 delete mTimeSource;
277 }
278 mTimeSource = NULL;
279
280 delete mAudioPlayer;
281 mAudioPlayer = NULL;
282
Andreas Huber27366fc2009-11-20 09:32:46 -0800283 mDurationUs = -1;
284 mFlags = 0;
285 mVideoWidth = mVideoHeight = -1;
286 mTimeSourceDeltaUs = 0;
287 mVideoTimeUs = 0;
288
289 mSeeking = false;
290 mSeekTimeUs = 0;
Andreas Huberb9e63832010-01-26 16:20:10 -0800291
292 mPrefetcher.clear();
Andreas Huber27366fc2009-11-20 09:32:46 -0800293}
294
Andreas Huber6be780e2010-02-08 14:40:30 -0800295void AwesomePlayer::notifyListener_l(int msg, int ext1, int ext2) {
Andreas Hubera3f43842010-01-21 10:28:45 -0800296 if (mListener != NULL) {
297 sp<MediaPlayerBase> listener = mListener.promote();
298
299 if (listener != NULL) {
Andreas Huber6be780e2010-02-08 14:40:30 -0800300 listener->sendEvent(msg, ext1, ext2);
Andreas Hubera3f43842010-01-21 10:28:45 -0800301 }
302 }
303}
304
Andreas Huberb9e63832010-01-26 16:20:10 -0800305void AwesomePlayer::onBufferingUpdate() {
306 Mutex::Autolock autoLock(mLock);
307 mBufferingEventPending = false;
308
309 if (mDurationUs >= 0) {
310 int64_t cachedDurationUs = mPrefetcher->getCachedDurationUs();
311 int64_t positionUs = 0;
Andreas Huber7085b6842010-02-03 16:02:02 -0800312 if (mVideoSource != NULL) {
Andreas Huberb9e63832010-01-26 16:20:10 -0800313 positionUs = mVideoTimeUs;
314 } else if (mAudioPlayer != NULL) {
315 positionUs = mAudioPlayer->getMediaTimeUs();
316 }
317
318 cachedDurationUs += positionUs;
319
320 double percentage = (double)cachedDurationUs / mDurationUs;
321 notifyListener_l(MEDIA_BUFFERING_UPDATE, percentage * 100.0);
322
323 postBufferingEvent_l();
324 }
325}
326
Andreas Huber27366fc2009-11-20 09:32:46 -0800327void AwesomePlayer::onStreamDone() {
328 // Posted whenever any stream finishes playing.
329
330 Mutex::Autolock autoLock(mLock);
331 mStreamDoneEventPending = false;
332
333 if (mFlags & LOOPING) {
334 seekTo_l(0);
335
Andreas Huber7085b6842010-02-03 16:02:02 -0800336 if (mVideoSource != NULL) {
Andreas Huber27366fc2009-11-20 09:32:46 -0800337 postVideoEvent_l();
338 }
339 } else {
Andreas Hubera3f43842010-01-21 10:28:45 -0800340 notifyListener_l(MEDIA_PLAYBACK_COMPLETE);
Andreas Huber27366fc2009-11-20 09:32:46 -0800341
342 pause_l();
343 }
344}
345
346status_t AwesomePlayer::play() {
347 Mutex::Autolock autoLock(mLock);
348
349 if (mFlags & PLAYING) {
350 return OK;
351 }
352
353 mFlags |= PLAYING;
354 mFlags |= FIRST_FRAME;
355
Andreas Huberc1d5c922009-12-10 15:49:04 -0800356 bool deferredAudioSeek = false;
357
Andreas Huber27366fc2009-11-20 09:32:46 -0800358 if (mAudioSource != NULL) {
359 if (mAudioPlayer == NULL) {
360 if (mAudioSink != NULL) {
361 mAudioPlayer = new AudioPlayer(mAudioSink);
Andreas Huber27366fc2009-11-20 09:32:46 -0800362 mAudioPlayer->setSource(mAudioSource);
Andreas Huber62eac002010-01-29 13:24:58 -0800363 status_t err = mAudioPlayer->start();
364
365 if (err != OK) {
366 delete mAudioPlayer;
367 mAudioPlayer = NULL;
368
369 mFlags &= ~(PLAYING | FIRST_FRAME);
370
371 return err;
372 }
Andreas Huber27366fc2009-11-20 09:32:46 -0800373
374 delete mTimeSource;
375 mTimeSource = mAudioPlayer;
376
Andreas Huberc1d5c922009-12-10 15:49:04 -0800377 deferredAudioSeek = true;
Andreas Huber70d10c02010-02-03 11:37:29 -0800378
379 mWatchForAudioSeekComplete = false;
380 mWatchForAudioEOS = true;
Andreas Huber27366fc2009-11-20 09:32:46 -0800381 }
382 } else {
383 mAudioPlayer->resume();
384 }
Andreas Huber70d10c02010-02-03 11:37:29 -0800385
386 postCheckAudioStatusEvent_l();
Andreas Huber27366fc2009-11-20 09:32:46 -0800387 }
388
389 if (mTimeSource == NULL && mAudioPlayer == NULL) {
390 mTimeSource = new SystemTimeSource;
391 }
392
393 if (mVideoSource != NULL) {
Andreas Huber7085b6842010-02-03 16:02:02 -0800394 // Kick off video playback
395 postVideoEvent_l();
Andreas Huber27366fc2009-11-20 09:32:46 -0800396 }
397
Andreas Huberc1d5c922009-12-10 15:49:04 -0800398 if (deferredAudioSeek) {
399 // If there was a seek request while we were paused
400 // and we're just starting up again, honor the request now.
401 seekAudioIfNecessary_l();
402 }
403
Andreas Huberb9e63832010-01-26 16:20:10 -0800404 postBufferingEvent_l();
405
Andreas Huber27366fc2009-11-20 09:32:46 -0800406 return OK;
407}
408
409void AwesomePlayer::initRenderer_l() {
410 if (mISurface != NULL) {
411 sp<MetaData> meta = mVideoSource->getFormat();
412
413 int32_t format;
414 const char *component;
415 int32_t decodedWidth, decodedHeight;
416 CHECK(meta->findInt32(kKeyColorFormat, &format));
417 CHECK(meta->findCString(kKeyDecoderComponent, &component));
418 CHECK(meta->findInt32(kKeyWidth, &decodedWidth));
419 CHECK(meta->findInt32(kKeyHeight, &decodedHeight));
420
Andreas Hubera67d5382009-12-10 15:32:12 -0800421 mVideoRenderer.clear();
422
423 // Must ensure that mVideoRenderer's destructor is actually executed
424 // before creating a new one.
425 IPCThreadState::self()->flushCommands();
426
Andreas Huber1314e732009-12-14 14:18:22 -0800427 if (!strncmp("OMX.", component, 4)) {
428 // Our OMX codecs allocate buffers on the media_server side
429 // therefore they require a remote IOMXRenderer that knows how
430 // to display them.
431 mVideoRenderer = new AwesomeRemoteRenderer(
432 mClient.interface()->createRenderer(
433 mISurface, component,
434 (OMX_COLOR_FORMATTYPE)format,
435 decodedWidth, decodedHeight,
436 mVideoWidth, mVideoHeight));
437 } else {
438 // Other decoders are instantiated locally and as a consequence
439 // allocate their buffers in local address space.
440 mVideoRenderer = new AwesomeLocalRenderer(
441 (OMX_COLOR_FORMATTYPE)format,
442 mISurface,
443 mVideoWidth, mVideoHeight,
444 decodedWidth, decodedHeight);
445 }
Andreas Huber27366fc2009-11-20 09:32:46 -0800446 }
447}
448
449status_t AwesomePlayer::pause() {
450 Mutex::Autolock autoLock(mLock);
451 return pause_l();
452}
453
454status_t AwesomePlayer::pause_l() {
455 if (!(mFlags & PLAYING)) {
456 return OK;
457 }
458
Andreas Huberb9e63832010-01-26 16:20:10 -0800459 cancelPlayerEvents(true /* keepBufferingGoing */);
Andreas Huber27366fc2009-11-20 09:32:46 -0800460
461 if (mAudioPlayer != NULL) {
462 mAudioPlayer->pause();
463 }
464
465 mFlags &= ~PLAYING;
466
467 return OK;
468}
469
470bool AwesomePlayer::isPlaying() const {
471 Mutex::Autolock autoLock(mLock);
472
473 return mFlags & PLAYING;
474}
475
476void AwesomePlayer::setISurface(const sp<ISurface> &isurface) {
477 Mutex::Autolock autoLock(mLock);
478
479 mISurface = isurface;
480}
481
482void AwesomePlayer::setAudioSink(
483 const sp<MediaPlayerBase::AudioSink> &audioSink) {
484 Mutex::Autolock autoLock(mLock);
485
486 mAudioSink = audioSink;
487}
488
489status_t AwesomePlayer::setLooping(bool shouldLoop) {
490 Mutex::Autolock autoLock(mLock);
491
492 mFlags = mFlags & ~LOOPING;
493
494 if (shouldLoop) {
495 mFlags |= LOOPING;
496 }
497
498 return OK;
499}
500
501status_t AwesomePlayer::getDuration(int64_t *durationUs) {
502 Mutex::Autolock autoLock(mLock);
503
504 if (mDurationUs < 0) {
505 return UNKNOWN_ERROR;
506 }
507
508 *durationUs = mDurationUs;
509
510 return OK;
511}
512
513status_t AwesomePlayer::getPosition(int64_t *positionUs) {
514 Mutex::Autolock autoLock(mLock);
515
Andreas Huber7085b6842010-02-03 16:02:02 -0800516 if (mVideoSource != NULL) {
Andreas Huber27366fc2009-11-20 09:32:46 -0800517 *positionUs = mVideoTimeUs;
518 } else if (mAudioPlayer != NULL) {
519 *positionUs = mAudioPlayer->getMediaTimeUs();
520 } else {
521 *positionUs = 0;
522 }
523
524 return OK;
525}
526
527status_t AwesomePlayer::seekTo(int64_t timeUs) {
528 Mutex::Autolock autoLock(mLock);
529 return seekTo_l(timeUs);
530}
531
532status_t AwesomePlayer::seekTo_l(int64_t timeUs) {
533 mSeeking = true;
534 mSeekTimeUs = timeUs;
535
536 seekAudioIfNecessary_l();
537
538 return OK;
539}
540
541void AwesomePlayer::seekAudioIfNecessary_l() {
Andreas Huber7085b6842010-02-03 16:02:02 -0800542 if (mSeeking && mVideoSource == NULL && mAudioPlayer != NULL) {
Andreas Huber27366fc2009-11-20 09:32:46 -0800543 mAudioPlayer->seekTo(mSeekTimeUs);
544
Andreas Huber70d10c02010-02-03 11:37:29 -0800545 mWatchForAudioSeekComplete = true;
546 mWatchForAudioEOS = true;
Andreas Huber27366fc2009-11-20 09:32:46 -0800547 mSeeking = false;
548 }
549}
550
551status_t AwesomePlayer::getVideoDimensions(
552 int32_t *width, int32_t *height) const {
553 Mutex::Autolock autoLock(mLock);
554
555 if (mVideoWidth < 0 || mVideoHeight < 0) {
556 return UNKNOWN_ERROR;
557 }
558
559 *width = mVideoWidth;
560 *height = mVideoHeight;
561
562 return OK;
563}
564
Andreas Huberb9e63832010-01-26 16:20:10 -0800565status_t AwesomePlayer::setAudioSource(sp<MediaSource> source) {
Andreas Huber27366fc2009-11-20 09:32:46 -0800566 if (source == NULL) {
567 return UNKNOWN_ERROR;
568 }
569
Andreas Huberb9e63832010-01-26 16:20:10 -0800570 if (mPrefetcher != NULL) {
571 source = mPrefetcher->addSource(source);
572 }
573
Andreas Huberc79827a2010-01-05 10:54:55 -0800574 sp<MetaData> meta = source->getFormat();
575
576 const char *mime;
577 CHECK(meta->findCString(kKeyMIMEType, &mime));
578
579 if (!strcasecmp(mime, MEDIA_MIMETYPE_AUDIO_RAW)) {
580 mAudioSource = source;
581 } else {
582 mAudioSource = OMXCodec::Create(
583 mClient.interface(), source->getFormat(),
584 false, // createEncoder
585 source);
586 }
Andreas Huber27366fc2009-11-20 09:32:46 -0800587
588 if (mAudioSource != NULL) {
589 int64_t durationUs;
590 if (source->getFormat()->findInt64(kKeyDuration, &durationUs)) {
591 if (mDurationUs < 0 || durationUs > mDurationUs) {
592 mDurationUs = durationUs;
593 }
594 }
595 }
596
597 return mAudioSource != NULL ? OK : UNKNOWN_ERROR;
598}
599
Andreas Huberb9e63832010-01-26 16:20:10 -0800600status_t AwesomePlayer::setVideoSource(sp<MediaSource> source) {
Andreas Huber27366fc2009-11-20 09:32:46 -0800601 if (source == NULL) {
602 return UNKNOWN_ERROR;
603 }
604
Andreas Huberb9e63832010-01-26 16:20:10 -0800605 if (mPrefetcher != NULL) {
606 source = mPrefetcher->addSource(source);
607 }
608
Andreas Huber27366fc2009-11-20 09:32:46 -0800609 mVideoSource = OMXCodec::Create(
610 mClient.interface(), source->getFormat(),
611 false, // createEncoder
612 source);
613
614 if (mVideoSource != NULL) {
615 int64_t durationUs;
616 if (source->getFormat()->findInt64(kKeyDuration, &durationUs)) {
617 if (mDurationUs < 0 || durationUs > mDurationUs) {
618 mDurationUs = durationUs;
619 }
620 }
621
622 CHECK(source->getFormat()->findInt32(kKeyWidth, &mVideoWidth));
623 CHECK(source->getFormat()->findInt32(kKeyHeight, &mVideoHeight));
624
625 mVideoSource->start();
626 }
627
628 return mVideoSource != NULL ? OK : UNKNOWN_ERROR;
629}
630
Andreas Huber6be780e2010-02-08 14:40:30 -0800631void AwesomePlayer::onVideoEvent() {
Andreas Huber27366fc2009-11-20 09:32:46 -0800632 Mutex::Autolock autoLock(mLock);
Andreas Huberb9e63832010-01-26 16:20:10 -0800633
Andreas Huber27366fc2009-11-20 09:32:46 -0800634 mVideoEventPending = false;
635
636 if (mSeeking) {
637 if (mLastVideoBuffer) {
638 mLastVideoBuffer->release();
639 mLastVideoBuffer = NULL;
640 }
641
642 if (mVideoBuffer) {
643 mVideoBuffer->release();
644 mVideoBuffer = NULL;
645 }
646 }
647
648 if (!mVideoBuffer) {
649 MediaSource::ReadOptions options;
650 if (mSeeking) {
651 LOGV("seeking to %lld us (%.2f secs)", mSeekTimeUs, mSeekTimeUs / 1E6);
652
653 options.setSeekTo(mSeekTimeUs);
654 }
655 for (;;) {
656 status_t err = mVideoSource->read(&mVideoBuffer, &options);
Andreas Huberb1f5ee42009-12-14 15:34:11 -0800657 options.clearSeekTo();
Andreas Huber27366fc2009-11-20 09:32:46 -0800658
659 if (err != OK) {
660 CHECK_EQ(mVideoBuffer, NULL);
661
662 if (err == INFO_FORMAT_CHANGED) {
663 LOGV("VideoSource signalled format change.");
664
Andreas Huber7085b6842010-02-03 16:02:02 -0800665 if (mVideoRenderer != NULL) {
666 initRenderer_l();
667 }
Andreas Huber27366fc2009-11-20 09:32:46 -0800668 continue;
669 }
670
671 postStreamDoneEvent_l();
672 return;
673 }
674
Andreas Hubera67d5382009-12-10 15:32:12 -0800675 if (mVideoBuffer->range_length() == 0) {
Andreas Huber6ddcf012009-12-10 15:32:12 -0800676 // Some decoders, notably the PV AVC software decoder
677 // return spurious empty buffers that we just want to ignore.
678
Andreas Hubera67d5382009-12-10 15:32:12 -0800679 mVideoBuffer->release();
680 mVideoBuffer = NULL;
681 continue;
682 }
683
Andreas Huber27366fc2009-11-20 09:32:46 -0800684 break;
685 }
686 }
687
688 int64_t timeUs;
689 CHECK(mVideoBuffer->meta_data()->findInt64(kKeyTime, &timeUs));
690
691 mVideoTimeUs = timeUs;
692
693 if (mSeeking) {
694 if (mAudioPlayer != NULL) {
695 LOGV("seeking audio to %lld us (%.2f secs).", timeUs, timeUs / 1E6);
696
697 mAudioPlayer->seekTo(timeUs);
Andreas Huber70d10c02010-02-03 11:37:29 -0800698 mWatchForAudioSeekComplete = true;
699 mWatchForAudioEOS = true;
Andreas Huber27366fc2009-11-20 09:32:46 -0800700 } else {
701 // If we're playing video only, report seek complete now,
702 // otherwise audio player will notify us later.
Andreas Hubera3f43842010-01-21 10:28:45 -0800703 notifyListener_l(MEDIA_SEEK_COMPLETE);
Andreas Huber27366fc2009-11-20 09:32:46 -0800704 }
705
706 mFlags |= FIRST_FRAME;
707 mSeeking = false;
708 }
709
710 if (mFlags & FIRST_FRAME) {
711 mFlags &= ~FIRST_FRAME;
712
713 mTimeSourceDeltaUs = mTimeSource->getRealTimeUs() - timeUs;
714 }
715
716 int64_t realTimeUs, mediaTimeUs;
717 if (mAudioPlayer != NULL
718 && mAudioPlayer->getMediaTimeMapping(&realTimeUs, &mediaTimeUs)) {
719 mTimeSourceDeltaUs = realTimeUs - mediaTimeUs;
720 }
721
722 int64_t nowUs = mTimeSource->getRealTimeUs() - mTimeSourceDeltaUs;
723
724 int64_t latenessUs = nowUs - timeUs;
725
Andreas Huber24b0a952009-11-23 14:02:00 -0800726 if (latenessUs > 40000) {
727 // We're more than 40ms late.
728 LOGI("we're late by %lld us (%.2f secs)", latenessUs, latenessUs / 1E6);
Andreas Huber27366fc2009-11-20 09:32:46 -0800729
730 mVideoBuffer->release();
731 mVideoBuffer = NULL;
732
733 postVideoEvent_l();
734 return;
735 }
736
737 if (latenessUs < -10000) {
738 // We're more than 10ms early.
739
740 postVideoEvent_l(10000);
741 return;
742 }
743
Andreas Huber7085b6842010-02-03 16:02:02 -0800744 if (mVideoRenderer == NULL) {
745 initRenderer_l();
746 }
747
748 if (mVideoRenderer != NULL) {
749 mVideoRenderer->render(mVideoBuffer);
750 }
Andreas Huber27366fc2009-11-20 09:32:46 -0800751
752 if (mLastVideoBuffer) {
753 mLastVideoBuffer->release();
754 mLastVideoBuffer = NULL;
755 }
756 mLastVideoBuffer = mVideoBuffer;
757 mVideoBuffer = NULL;
758
759 postVideoEvent_l();
760}
761
762void AwesomePlayer::postVideoEvent_l(int64_t delayUs) {
763 if (mVideoEventPending) {
764 return;
765 }
766
767 mVideoEventPending = true;
768 mQueue.postEventWithDelay(mVideoEvent, delayUs < 0 ? 10000 : delayUs);
769}
770
771void AwesomePlayer::postStreamDoneEvent_l() {
772 if (mStreamDoneEventPending) {
773 return;
774 }
775 mStreamDoneEventPending = true;
776 mQueue.postEvent(mStreamDoneEvent);
777}
778
Andreas Huberb9e63832010-01-26 16:20:10 -0800779void AwesomePlayer::postBufferingEvent_l() {
780 if (mPrefetcher == NULL) {
781 return;
782 }
783
784 if (mBufferingEventPending) {
785 return;
786 }
787 mBufferingEventPending = true;
788 mQueue.postEventWithDelay(mBufferingEvent, 1000000ll);
789}
790
Andreas Huber70d10c02010-02-03 11:37:29 -0800791void AwesomePlayer::postCheckAudioStatusEvent_l() {
792 if (mAudioStatusEventPending) {
793 return;
794 }
795 mAudioStatusEventPending = true;
796 mQueue.postEventWithDelay(mCheckAudioStatusEvent, 100000ll);
797}
798
799void AwesomePlayer::onCheckAudioStatus() {
800 Mutex::Autolock autoLock(mLock);
801 mAudioStatusEventPending = false;
802
803 if (mWatchForAudioSeekComplete && !mAudioPlayer->isSeeking()) {
804 mWatchForAudioSeekComplete = false;
805 notifyListener_l(MEDIA_SEEK_COMPLETE);
806 }
807
808 if (mWatchForAudioEOS && mAudioPlayer->reachedEOS()) {
809 mWatchForAudioEOS = false;
810 postStreamDoneEvent_l();
811 }
812
813 postCheckAudioStatusEvent_l();
814}
815
Andreas Huber6be780e2010-02-08 14:40:30 -0800816status_t AwesomePlayer::prepare() {
817 Mutex::Autolock autoLock(mLock);
818
819 status_t err = prepareAsync_l();
820
821 if (err != OK) {
822 return err;
823 }
824
825 while (mAsyncPrepareEvent != NULL) {
826 mPreparedCondition.wait(mLock);
827 }
828
829 return OK;
830}
831
832status_t AwesomePlayer::prepareAsync() {
833 Mutex::Autolock autoLock(mLock);
834 return prepareAsync_l();
835}
836
837status_t AwesomePlayer::prepareAsync_l() {
838 if (mAsyncPrepareEvent != NULL) {
839 return UNKNOWN_ERROR; // async prepare already pending.
840 }
841
842 mAsyncPrepareEvent = new AwesomeEvent(
843 this, &AwesomePlayer::onPrepareAsyncEvent);
844
845 mQueue.postEvent(mAsyncPrepareEvent);
846
847 return OK;
848}
849
850void AwesomePlayer::onPrepareAsyncEvent() {
851 sp<Prefetcher> prefetcher;
852
853 {
854 Mutex::Autolock autoLock(mLock);
855 prefetcher = mPrefetcher;
856 }
857
858 if (prefetcher != NULL) {
859 prefetcher->prepare();
860 }
861
862 Mutex::Autolock autoLock(mLock);
863
864 if (mVideoWidth < 0 || mVideoHeight < 0) {
865 notifyListener_l(MEDIA_SET_VIDEO_SIZE, 0, 0);
866 } else {
867 notifyListener_l(MEDIA_SET_VIDEO_SIZE, mVideoWidth, mVideoHeight);
868 }
869
870 notifyListener_l(MEDIA_PREPARED);
871
872 mAsyncPrepareEvent = NULL;
873 mPreparedCondition.signal();
874}
875
Andreas Huber27366fc2009-11-20 09:32:46 -0800876} // namespace android
877