blob: 85019aae02cbd2bb84b331391d5359e9ce3568fa [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 {
40 AwesomeEvent(AwesomePlayer *player, int32_t code)
41 : mPlayer(player),
42 mCode(code) {
43 }
44
45protected:
46 virtual ~AwesomeEvent() {}
47
48 virtual void fire(TimedEventQueue *queue, int64_t /* now_us */) {
49 mPlayer->onEvent(mCode);
50 }
51
52private:
53 AwesomePlayer *mPlayer;
54 int32_t mCode;
55
56 AwesomeEvent(const AwesomeEvent &);
57 AwesomeEvent &operator=(const AwesomeEvent &);
58};
59
Andreas Huber1314e732009-12-14 14:18:22 -080060struct AwesomeRemoteRenderer : public AwesomeRenderer {
61 AwesomeRemoteRenderer(const sp<IOMXRenderer> &target)
62 : mTarget(target) {
63 }
64
65 virtual void render(MediaBuffer *buffer) {
66 void *id;
67 if (buffer->meta_data()->findPointer(kKeyBufferID, &id)) {
68 mTarget->render((IOMX::buffer_id)id);
69 }
70 }
71
72private:
73 sp<IOMXRenderer> mTarget;
74
75 AwesomeRemoteRenderer(const AwesomeRemoteRenderer &);
76 AwesomeRemoteRenderer &operator=(const AwesomeRemoteRenderer &);
77};
78
79struct AwesomeLocalRenderer : public AwesomeRenderer {
80 AwesomeLocalRenderer(
81 OMX_COLOR_FORMATTYPE colorFormat,
82 const sp<ISurface> &surface,
83 size_t displayWidth, size_t displayHeight,
84 size_t decodedWidth, size_t decodedHeight)
85 : mTarget(new SoftwareRenderer(
86 colorFormat, surface, displayWidth, displayHeight,
87 decodedWidth, decodedHeight)) {
88 }
89
90 virtual void render(MediaBuffer *buffer) {
91 mTarget->render(
92 (const uint8_t *)buffer->data() + buffer->range_offset(),
93 buffer->range_length(), NULL);
94 }
95
96protected:
97 virtual ~AwesomeLocalRenderer() {
98 delete mTarget;
99 mTarget = NULL;
100 }
101
102private:
103 SoftwareRenderer *mTarget;
104
105 AwesomeLocalRenderer(const AwesomeLocalRenderer &);
106 AwesomeLocalRenderer &operator=(const AwesomeLocalRenderer &);;
107};
108
Andreas Huber27366fc2009-11-20 09:32:46 -0800109AwesomePlayer::AwesomePlayer()
110 : mTimeSource(NULL),
111 mAudioPlayer(NULL),
112 mLastVideoBuffer(NULL),
113 mVideoBuffer(NULL) {
114 CHECK_EQ(mClient.connect(), OK);
115
116 DataSource::RegisterDefaultSniffers();
117
118 mVideoEvent = new AwesomeEvent(this, 0);
119 mVideoEventPending = false;
120 mStreamDoneEvent = new AwesomeEvent(this, 1);
121 mStreamDoneEventPending = false;
Andreas Huberb9e63832010-01-26 16:20:10 -0800122 mBufferingEvent = new AwesomeEvent(this, 2);
123 mBufferingEventPending = false;
Andreas Huber27366fc2009-11-20 09:32:46 -0800124
125 mQueue.start();
126
127 reset();
128}
129
130AwesomePlayer::~AwesomePlayer() {
131 mQueue.stop();
132
133 reset();
134
135 mClient.disconnect();
136}
137
Andreas Huberb9e63832010-01-26 16:20:10 -0800138void AwesomePlayer::cancelPlayerEvents(bool keepBufferingGoing) {
Andreas Huber27366fc2009-11-20 09:32:46 -0800139 mQueue.cancelEvent(mVideoEvent->eventID());
140 mVideoEventPending = false;
141 mQueue.cancelEvent(mStreamDoneEvent->eventID());
142 mStreamDoneEventPending = false;
Andreas Huberb9e63832010-01-26 16:20:10 -0800143
144 if (!keepBufferingGoing) {
145 mQueue.cancelEvent(mBufferingEvent->eventID());
146 mBufferingEventPending = false;
147 }
Andreas Huber27366fc2009-11-20 09:32:46 -0800148}
149
Andreas Hubera3f43842010-01-21 10:28:45 -0800150void AwesomePlayer::setListener(const wp<MediaPlayerBase> &listener) {
Andreas Huber27366fc2009-11-20 09:32:46 -0800151 Mutex::Autolock autoLock(mLock);
152 mListener = listener;
153}
154
Andreas Huber433c9ac2010-01-27 16:49:05 -0800155status_t AwesomePlayer::setDataSource(
156 const char *uri, const KeyedVector<String8, String8> *headers) {
Andreas Huber27366fc2009-11-20 09:32:46 -0800157 Mutex::Autolock autoLock(mLock);
158
159 reset_l();
160
Andreas Huber433c9ac2010-01-27 16:49:05 -0800161 sp<DataSource> dataSource = DataSource::CreateFromURI(uri, headers);
Andreas Huberb9e63832010-01-26 16:20:10 -0800162
163 if (dataSource == NULL) {
164 return UNKNOWN_ERROR;
165 }
166
167 sp<MediaExtractor> extractor = MediaExtractor::Create(dataSource);
Andreas Huber27366fc2009-11-20 09:32:46 -0800168
169 if (extractor == NULL) {
170 return UNKNOWN_ERROR;
171 }
172
Andreas Huberb9e63832010-01-26 16:20:10 -0800173 if (dataSource->flags() & DataSource::kWantsPrefetching) {
174 mPrefetcher = new Prefetcher;
175 }
176
Andreas Huber27366fc2009-11-20 09:32:46 -0800177 return setDataSource_l(extractor);
178}
179
180status_t AwesomePlayer::setDataSource(
181 int fd, int64_t offset, int64_t length) {
182 Mutex::Autolock autoLock(mLock);
183
184 reset_l();
185
186 sp<DataSource> source = new FileSource(fd, offset, length);
187
188 status_t err = source->initCheck();
189
190 if (err != OK) {
191 return err;
192 }
193
194 sp<MediaExtractor> extractor = MediaExtractor::Create(source);
195
196 if (extractor == NULL) {
197 return UNKNOWN_ERROR;
198 }
199
200 return setDataSource_l(extractor);
201}
202
203status_t AwesomePlayer::setDataSource_l(const sp<MediaExtractor> &extractor) {
Andreas Huber27366fc2009-11-20 09:32:46 -0800204 bool haveAudio = false;
205 bool haveVideo = false;
206 for (size_t i = 0; i < extractor->countTracks(); ++i) {
207 sp<MetaData> meta = extractor->getTrackMetaData(i);
208
209 const char *mime;
210 CHECK(meta->findCString(kKeyMIMEType, &mime));
211
212 if (!haveVideo && !strncasecmp(mime, "video/", 6)) {
213 if (setVideoSource(extractor->getTrack(i)) == OK) {
214 haveVideo = true;
215 }
216 } else if (!haveAudio && !strncasecmp(mime, "audio/", 6)) {
217 if (setAudioSource(extractor->getTrack(i)) == OK) {
218 haveAudio = true;
219 }
220 }
221
222 if (haveAudio && haveVideo) {
223 break;
224 }
225 }
226
227 return !haveAudio && !haveVideo ? UNKNOWN_ERROR : OK;
228}
229
230void AwesomePlayer::reset() {
231 Mutex::Autolock autoLock(mLock);
232 reset_l();
233}
234
235void AwesomePlayer::reset_l() {
236 cancelPlayerEvents();
237
Andreas Huber3522b5a52010-01-22 14:36:53 -0800238 mVideoRenderer.clear();
239
Andreas Huber27366fc2009-11-20 09:32:46 -0800240 if (mLastVideoBuffer) {
241 mLastVideoBuffer->release();
242 mLastVideoBuffer = NULL;
243 }
244
245 if (mVideoBuffer) {
246 mVideoBuffer->release();
247 mVideoBuffer = NULL;
248 }
249
250 if (mVideoSource != NULL) {
251 mVideoSource->stop();
Andreas Huber98b48de2010-01-29 10:10:22 -0800252
253 // The following hack is necessary to ensure that the OMX
254 // component is completely released by the time we may try
255 // to instantiate it again.
256 wp<MediaSource> tmp = mVideoSource;
Andreas Huber27366fc2009-11-20 09:32:46 -0800257 mVideoSource.clear();
Andreas Huber98b48de2010-01-29 10:10:22 -0800258 while (tmp.promote() != NULL) {
259 usleep(1000);
260 }
261 IPCThreadState::self()->flushCommands();
Andreas Huber27366fc2009-11-20 09:32:46 -0800262 }
263
264 mAudioSource.clear();
265
266 if (mTimeSource != mAudioPlayer) {
267 delete mTimeSource;
268 }
269 mTimeSource = NULL;
270
271 delete mAudioPlayer;
272 mAudioPlayer = NULL;
273
Andreas Huber27366fc2009-11-20 09:32:46 -0800274 mDurationUs = -1;
275 mFlags = 0;
276 mVideoWidth = mVideoHeight = -1;
277 mTimeSourceDeltaUs = 0;
278 mVideoTimeUs = 0;
279
280 mSeeking = false;
281 mSeekTimeUs = 0;
Andreas Huberb9e63832010-01-26 16:20:10 -0800282
283 mPrefetcher.clear();
Andreas Huber27366fc2009-11-20 09:32:46 -0800284}
285
286// static
287void AwesomePlayer::AudioNotify(void *_me, int what) {
288 AwesomePlayer *me = (AwesomePlayer *)_me;
289
290 Mutex::Autolock autoLock(me->mLock);
291
292 switch (what) {
293 case AudioPlayer::REACHED_EOS:
294 me->postStreamDoneEvent_l();
295 break;
296
297 case AudioPlayer::SEEK_COMPLETE:
298 {
Andreas Hubera3f43842010-01-21 10:28:45 -0800299 me->notifyListener_l(MEDIA_SEEK_COMPLETE);
Andreas Huber27366fc2009-11-20 09:32:46 -0800300 break;
301 }
302
303 default:
304 CHECK(!"should not be here.");
305 break;
306 }
307}
308
Andreas Huberb9e63832010-01-26 16:20:10 -0800309void AwesomePlayer::notifyListener_l(int msg, int ext1) {
Andreas Hubera3f43842010-01-21 10:28:45 -0800310 if (mListener != NULL) {
311 sp<MediaPlayerBase> listener = mListener.promote();
312
313 if (listener != NULL) {
Andreas Huberb9e63832010-01-26 16:20:10 -0800314 listener->sendEvent(msg, ext1);
Andreas Hubera3f43842010-01-21 10:28:45 -0800315 }
316 }
317}
318
Andreas Huberb9e63832010-01-26 16:20:10 -0800319void AwesomePlayer::onBufferingUpdate() {
320 Mutex::Autolock autoLock(mLock);
321 mBufferingEventPending = false;
322
323 if (mDurationUs >= 0) {
324 int64_t cachedDurationUs = mPrefetcher->getCachedDurationUs();
325 int64_t positionUs = 0;
326 if (mVideoRenderer != NULL) {
327 positionUs = mVideoTimeUs;
328 } else if (mAudioPlayer != NULL) {
329 positionUs = mAudioPlayer->getMediaTimeUs();
330 }
331
332 cachedDurationUs += positionUs;
333
334 double percentage = (double)cachedDurationUs / mDurationUs;
335 notifyListener_l(MEDIA_BUFFERING_UPDATE, percentage * 100.0);
336
337 postBufferingEvent_l();
338 }
339}
340
Andreas Huber27366fc2009-11-20 09:32:46 -0800341void AwesomePlayer::onStreamDone() {
342 // Posted whenever any stream finishes playing.
343
344 Mutex::Autolock autoLock(mLock);
345 mStreamDoneEventPending = false;
346
347 if (mFlags & LOOPING) {
348 seekTo_l(0);
349
350 if (mVideoRenderer != NULL) {
351 postVideoEvent_l();
352 }
353 } else {
Andreas Hubera3f43842010-01-21 10:28:45 -0800354 notifyListener_l(MEDIA_PLAYBACK_COMPLETE);
Andreas Huber27366fc2009-11-20 09:32:46 -0800355
356 pause_l();
357 }
358}
359
360status_t AwesomePlayer::play() {
361 Mutex::Autolock autoLock(mLock);
362
363 if (mFlags & PLAYING) {
364 return OK;
365 }
366
367 mFlags |= PLAYING;
368 mFlags |= FIRST_FRAME;
369
Andreas Huberc1d5c922009-12-10 15:49:04 -0800370 bool deferredAudioSeek = false;
371
Andreas Huber27366fc2009-11-20 09:32:46 -0800372 if (mAudioSource != NULL) {
373 if (mAudioPlayer == NULL) {
374 if (mAudioSink != NULL) {
375 mAudioPlayer = new AudioPlayer(mAudioSink);
376
377 mAudioPlayer->setListenerCallback(
378 &AwesomePlayer::AudioNotify, this);
379
380 mAudioPlayer->setSource(mAudioSource);
381 mAudioPlayer->start();
382
383 delete mTimeSource;
384 mTimeSource = mAudioPlayer;
385
Andreas Huberc1d5c922009-12-10 15:49:04 -0800386 deferredAudioSeek = true;
Andreas Huber27366fc2009-11-20 09:32:46 -0800387 }
388 } else {
389 mAudioPlayer->resume();
390 }
391 }
392
393 if (mTimeSource == NULL && mAudioPlayer == NULL) {
394 mTimeSource = new SystemTimeSource;
395 }
396
397 if (mVideoSource != NULL) {
398 if (mVideoRenderer == NULL) {
399 initRenderer_l();
400 }
401
402 if (mVideoRenderer != NULL) {
403 // Kick off video playback
404 postVideoEvent_l();
405 }
406 }
407
Andreas Huberc1d5c922009-12-10 15:49:04 -0800408 if (deferredAudioSeek) {
409 // If there was a seek request while we were paused
410 // and we're just starting up again, honor the request now.
411 seekAudioIfNecessary_l();
412 }
413
Andreas Huberb9e63832010-01-26 16:20:10 -0800414 postBufferingEvent_l();
415
Andreas Huber27366fc2009-11-20 09:32:46 -0800416 return OK;
417}
418
419void AwesomePlayer::initRenderer_l() {
420 if (mISurface != NULL) {
421 sp<MetaData> meta = mVideoSource->getFormat();
422
423 int32_t format;
424 const char *component;
425 int32_t decodedWidth, decodedHeight;
426 CHECK(meta->findInt32(kKeyColorFormat, &format));
427 CHECK(meta->findCString(kKeyDecoderComponent, &component));
428 CHECK(meta->findInt32(kKeyWidth, &decodedWidth));
429 CHECK(meta->findInt32(kKeyHeight, &decodedHeight));
430
Andreas Hubera67d5382009-12-10 15:32:12 -0800431 mVideoRenderer.clear();
432
433 // Must ensure that mVideoRenderer's destructor is actually executed
434 // before creating a new one.
435 IPCThreadState::self()->flushCommands();
436
Andreas Huber1314e732009-12-14 14:18:22 -0800437 if (!strncmp("OMX.", component, 4)) {
438 // Our OMX codecs allocate buffers on the media_server side
439 // therefore they require a remote IOMXRenderer that knows how
440 // to display them.
441 mVideoRenderer = new AwesomeRemoteRenderer(
442 mClient.interface()->createRenderer(
443 mISurface, component,
444 (OMX_COLOR_FORMATTYPE)format,
445 decodedWidth, decodedHeight,
446 mVideoWidth, mVideoHeight));
447 } else {
448 // Other decoders are instantiated locally and as a consequence
449 // allocate their buffers in local address space.
450 mVideoRenderer = new AwesomeLocalRenderer(
451 (OMX_COLOR_FORMATTYPE)format,
452 mISurface,
453 mVideoWidth, mVideoHeight,
454 decodedWidth, decodedHeight);
455 }
Andreas Huber27366fc2009-11-20 09:32:46 -0800456 }
457}
458
459status_t AwesomePlayer::pause() {
460 Mutex::Autolock autoLock(mLock);
461 return pause_l();
462}
463
464status_t AwesomePlayer::pause_l() {
465 if (!(mFlags & PLAYING)) {
466 return OK;
467 }
468
Andreas Huberb9e63832010-01-26 16:20:10 -0800469 cancelPlayerEvents(true /* keepBufferingGoing */);
Andreas Huber27366fc2009-11-20 09:32:46 -0800470
471 if (mAudioPlayer != NULL) {
472 mAudioPlayer->pause();
473 }
474
475 mFlags &= ~PLAYING;
476
477 return OK;
478}
479
480bool AwesomePlayer::isPlaying() const {
481 Mutex::Autolock autoLock(mLock);
482
483 return mFlags & PLAYING;
484}
485
486void AwesomePlayer::setISurface(const sp<ISurface> &isurface) {
487 Mutex::Autolock autoLock(mLock);
488
489 mISurface = isurface;
490}
491
492void AwesomePlayer::setAudioSink(
493 const sp<MediaPlayerBase::AudioSink> &audioSink) {
494 Mutex::Autolock autoLock(mLock);
495
496 mAudioSink = audioSink;
497}
498
499status_t AwesomePlayer::setLooping(bool shouldLoop) {
500 Mutex::Autolock autoLock(mLock);
501
502 mFlags = mFlags & ~LOOPING;
503
504 if (shouldLoop) {
505 mFlags |= LOOPING;
506 }
507
508 return OK;
509}
510
511status_t AwesomePlayer::getDuration(int64_t *durationUs) {
512 Mutex::Autolock autoLock(mLock);
513
514 if (mDurationUs < 0) {
515 return UNKNOWN_ERROR;
516 }
517
518 *durationUs = mDurationUs;
519
520 return OK;
521}
522
523status_t AwesomePlayer::getPosition(int64_t *positionUs) {
524 Mutex::Autolock autoLock(mLock);
525
526 if (mVideoRenderer != NULL) {
527 *positionUs = mVideoTimeUs;
528 } else if (mAudioPlayer != NULL) {
529 *positionUs = mAudioPlayer->getMediaTimeUs();
530 } else {
531 *positionUs = 0;
532 }
533
534 return OK;
535}
536
537status_t AwesomePlayer::seekTo(int64_t timeUs) {
538 Mutex::Autolock autoLock(mLock);
539 return seekTo_l(timeUs);
540}
541
542status_t AwesomePlayer::seekTo_l(int64_t timeUs) {
543 mSeeking = true;
544 mSeekTimeUs = timeUs;
545
546 seekAudioIfNecessary_l();
547
548 return OK;
549}
550
551void AwesomePlayer::seekAudioIfNecessary_l() {
552 if (mSeeking && mVideoRenderer == NULL && mAudioPlayer != NULL) {
553 mAudioPlayer->seekTo(mSeekTimeUs);
554
555 mSeeking = false;
556 }
557}
558
559status_t AwesomePlayer::getVideoDimensions(
560 int32_t *width, int32_t *height) const {
561 Mutex::Autolock autoLock(mLock);
562
563 if (mVideoWidth < 0 || mVideoHeight < 0) {
564 return UNKNOWN_ERROR;
565 }
566
567 *width = mVideoWidth;
568 *height = mVideoHeight;
569
570 return OK;
571}
572
Andreas Huberb9e63832010-01-26 16:20:10 -0800573status_t AwesomePlayer::setAudioSource(sp<MediaSource> source) {
Andreas Huber27366fc2009-11-20 09:32:46 -0800574 if (source == NULL) {
575 return UNKNOWN_ERROR;
576 }
577
Andreas Huberb9e63832010-01-26 16:20:10 -0800578 if (mPrefetcher != NULL) {
579 source = mPrefetcher->addSource(source);
580 }
581
Andreas Huberc79827a2010-01-05 10:54:55 -0800582 sp<MetaData> meta = source->getFormat();
583
584 const char *mime;
585 CHECK(meta->findCString(kKeyMIMEType, &mime));
586
587 if (!strcasecmp(mime, MEDIA_MIMETYPE_AUDIO_RAW)) {
588 mAudioSource = source;
589 } else {
590 mAudioSource = OMXCodec::Create(
591 mClient.interface(), source->getFormat(),
592 false, // createEncoder
593 source);
594 }
Andreas Huber27366fc2009-11-20 09:32:46 -0800595
596 if (mAudioSource != NULL) {
597 int64_t durationUs;
598 if (source->getFormat()->findInt64(kKeyDuration, &durationUs)) {
599 if (mDurationUs < 0 || durationUs > mDurationUs) {
600 mDurationUs = durationUs;
601 }
602 }
603 }
604
605 return mAudioSource != NULL ? OK : UNKNOWN_ERROR;
606}
607
Andreas Huberb9e63832010-01-26 16:20:10 -0800608status_t AwesomePlayer::setVideoSource(sp<MediaSource> source) {
Andreas Huber27366fc2009-11-20 09:32:46 -0800609 if (source == NULL) {
610 return UNKNOWN_ERROR;
611 }
612
Andreas Huberb9e63832010-01-26 16:20:10 -0800613 if (mPrefetcher != NULL) {
614 source = mPrefetcher->addSource(source);
615 }
616
Andreas Huber27366fc2009-11-20 09:32:46 -0800617 mVideoSource = OMXCodec::Create(
618 mClient.interface(), source->getFormat(),
619 false, // createEncoder
620 source);
621
622 if (mVideoSource != NULL) {
623 int64_t durationUs;
624 if (source->getFormat()->findInt64(kKeyDuration, &durationUs)) {
625 if (mDurationUs < 0 || durationUs > mDurationUs) {
626 mDurationUs = durationUs;
627 }
628 }
629
630 CHECK(source->getFormat()->findInt32(kKeyWidth, &mVideoWidth));
631 CHECK(source->getFormat()->findInt32(kKeyHeight, &mVideoHeight));
632
633 mVideoSource->start();
634 }
635
636 return mVideoSource != NULL ? OK : UNKNOWN_ERROR;
637}
638
639void AwesomePlayer::onEvent(int32_t code) {
640 if (code == 1) {
641 onStreamDone();
642 return;
Andreas Huberb9e63832010-01-26 16:20:10 -0800643 } else if (code == 2) {
644 onBufferingUpdate();
645 return;
Andreas Huber27366fc2009-11-20 09:32:46 -0800646 }
647
648 Mutex::Autolock autoLock(mLock);
Andreas Huberb9e63832010-01-26 16:20:10 -0800649
Andreas Huber27366fc2009-11-20 09:32:46 -0800650 mVideoEventPending = false;
651
652 if (mSeeking) {
653 if (mLastVideoBuffer) {
654 mLastVideoBuffer->release();
655 mLastVideoBuffer = NULL;
656 }
657
658 if (mVideoBuffer) {
659 mVideoBuffer->release();
660 mVideoBuffer = NULL;
661 }
662 }
663
664 if (!mVideoBuffer) {
665 MediaSource::ReadOptions options;
666 if (mSeeking) {
667 LOGV("seeking to %lld us (%.2f secs)", mSeekTimeUs, mSeekTimeUs / 1E6);
668
669 options.setSeekTo(mSeekTimeUs);
670 }
671 for (;;) {
672 status_t err = mVideoSource->read(&mVideoBuffer, &options);
Andreas Huberb1f5ee42009-12-14 15:34:11 -0800673 options.clearSeekTo();
Andreas Huber27366fc2009-11-20 09:32:46 -0800674
675 if (err != OK) {
676 CHECK_EQ(mVideoBuffer, NULL);
677
678 if (err == INFO_FORMAT_CHANGED) {
679 LOGV("VideoSource signalled format change.");
680
681 initRenderer_l();
682 continue;
683 }
684
685 postStreamDoneEvent_l();
686 return;
687 }
688
Andreas Hubera67d5382009-12-10 15:32:12 -0800689 if (mVideoBuffer->range_length() == 0) {
Andreas Huber6ddcf012009-12-10 15:32:12 -0800690 // Some decoders, notably the PV AVC software decoder
691 // return spurious empty buffers that we just want to ignore.
692
Andreas Hubera67d5382009-12-10 15:32:12 -0800693 mVideoBuffer->release();
694 mVideoBuffer = NULL;
695 continue;
696 }
697
Andreas Huber27366fc2009-11-20 09:32:46 -0800698 break;
699 }
700 }
701
702 int64_t timeUs;
703 CHECK(mVideoBuffer->meta_data()->findInt64(kKeyTime, &timeUs));
704
705 mVideoTimeUs = timeUs;
706
707 if (mSeeking) {
708 if (mAudioPlayer != NULL) {
709 LOGV("seeking audio to %lld us (%.2f secs).", timeUs, timeUs / 1E6);
710
711 mAudioPlayer->seekTo(timeUs);
712 } else {
713 // If we're playing video only, report seek complete now,
714 // otherwise audio player will notify us later.
Andreas Hubera3f43842010-01-21 10:28:45 -0800715 notifyListener_l(MEDIA_SEEK_COMPLETE);
Andreas Huber27366fc2009-11-20 09:32:46 -0800716 }
717
718 mFlags |= FIRST_FRAME;
719 mSeeking = false;
720 }
721
722 if (mFlags & FIRST_FRAME) {
723 mFlags &= ~FIRST_FRAME;
724
725 mTimeSourceDeltaUs = mTimeSource->getRealTimeUs() - timeUs;
726 }
727
728 int64_t realTimeUs, mediaTimeUs;
729 if (mAudioPlayer != NULL
730 && mAudioPlayer->getMediaTimeMapping(&realTimeUs, &mediaTimeUs)) {
731 mTimeSourceDeltaUs = realTimeUs - mediaTimeUs;
732 }
733
734 int64_t nowUs = mTimeSource->getRealTimeUs() - mTimeSourceDeltaUs;
735
736 int64_t latenessUs = nowUs - timeUs;
737
Andreas Huber24b0a952009-11-23 14:02:00 -0800738 if (latenessUs > 40000) {
739 // We're more than 40ms late.
740 LOGI("we're late by %lld us (%.2f secs)", latenessUs, latenessUs / 1E6);
Andreas Huber27366fc2009-11-20 09:32:46 -0800741
742 mVideoBuffer->release();
743 mVideoBuffer = NULL;
744
745 postVideoEvent_l();
746 return;
747 }
748
749 if (latenessUs < -10000) {
750 // We're more than 10ms early.
751
752 postVideoEvent_l(10000);
753 return;
754 }
755
Andreas Huber1314e732009-12-14 14:18:22 -0800756 mVideoRenderer->render(mVideoBuffer);
Andreas Huber27366fc2009-11-20 09:32:46 -0800757
758 if (mLastVideoBuffer) {
759 mLastVideoBuffer->release();
760 mLastVideoBuffer = NULL;
761 }
762 mLastVideoBuffer = mVideoBuffer;
763 mVideoBuffer = NULL;
764
765 postVideoEvent_l();
766}
767
768void AwesomePlayer::postVideoEvent_l(int64_t delayUs) {
769 if (mVideoEventPending) {
770 return;
771 }
772
773 mVideoEventPending = true;
774 mQueue.postEventWithDelay(mVideoEvent, delayUs < 0 ? 10000 : delayUs);
775}
776
777void AwesomePlayer::postStreamDoneEvent_l() {
778 if (mStreamDoneEventPending) {
779 return;
780 }
781 mStreamDoneEventPending = true;
782 mQueue.postEvent(mStreamDoneEvent);
783}
784
Andreas Huberb9e63832010-01-26 16:20:10 -0800785void AwesomePlayer::postBufferingEvent_l() {
786 if (mPrefetcher == NULL) {
787 return;
788 }
789
790 if (mBufferingEventPending) {
791 return;
792 }
793 mBufferingEventPending = true;
794 mQueue.postEventWithDelay(mBufferingEvent, 1000000ll);
795}
796
Andreas Huber27366fc2009-11-20 09:32:46 -0800797} // namespace android
798