blob: 2eec8de75600739ddf6cbf4a710bf3f7839967ee [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 Huber1314e732009-12-14 14:18:22 -080022#include "include/SoftwareRenderer.h"
Andreas Huber27366fc2009-11-20 09:32:46 -080023
Andreas Hubera67d5382009-12-10 15:32:12 -080024#include <binder/IPCThreadState.h>
Andreas Huber27366fc2009-11-20 09:32:46 -080025#include <media/stagefright/AudioPlayer.h>
26#include <media/stagefright/DataSource.h>
27#include <media/stagefright/FileSource.h>
28#include <media/stagefright/MediaBuffer.h>
29#include <media/stagefright/MediaExtractor.h>
30#include <media/stagefright/MediaDebug.h>
31#include <media/stagefright/MediaSource.h>
32#include <media/stagefright/MetaData.h>
33#include <media/stagefright/OMXCodec.h>
Andreas Huber27366fc2009-11-20 09:32:46 -080034namespace android {
35
36struct AwesomeEvent : public TimedEventQueue::Event {
37 AwesomeEvent(AwesomePlayer *player, int32_t code)
38 : mPlayer(player),
39 mCode(code) {
40 }
41
42protected:
43 virtual ~AwesomeEvent() {}
44
45 virtual void fire(TimedEventQueue *queue, int64_t /* now_us */) {
46 mPlayer->onEvent(mCode);
47 }
48
49private:
50 AwesomePlayer *mPlayer;
51 int32_t mCode;
52
53 AwesomeEvent(const AwesomeEvent &);
54 AwesomeEvent &operator=(const AwesomeEvent &);
55};
56
Andreas Huber1314e732009-12-14 14:18:22 -080057struct AwesomeRemoteRenderer : public AwesomeRenderer {
58 AwesomeRemoteRenderer(const sp<IOMXRenderer> &target)
59 : mTarget(target) {
60 }
61
62 virtual void render(MediaBuffer *buffer) {
63 void *id;
64 if (buffer->meta_data()->findPointer(kKeyBufferID, &id)) {
65 mTarget->render((IOMX::buffer_id)id);
66 }
67 }
68
69private:
70 sp<IOMXRenderer> mTarget;
71
72 AwesomeRemoteRenderer(const AwesomeRemoteRenderer &);
73 AwesomeRemoteRenderer &operator=(const AwesomeRemoteRenderer &);
74};
75
76struct AwesomeLocalRenderer : public AwesomeRenderer {
77 AwesomeLocalRenderer(
78 OMX_COLOR_FORMATTYPE colorFormat,
79 const sp<ISurface> &surface,
80 size_t displayWidth, size_t displayHeight,
81 size_t decodedWidth, size_t decodedHeight)
82 : mTarget(new SoftwareRenderer(
83 colorFormat, surface, displayWidth, displayHeight,
84 decodedWidth, decodedHeight)) {
85 }
86
87 virtual void render(MediaBuffer *buffer) {
88 mTarget->render(
89 (const uint8_t *)buffer->data() + buffer->range_offset(),
90 buffer->range_length(), NULL);
91 }
92
93protected:
94 virtual ~AwesomeLocalRenderer() {
95 delete mTarget;
96 mTarget = NULL;
97 }
98
99private:
100 SoftwareRenderer *mTarget;
101
102 AwesomeLocalRenderer(const AwesomeLocalRenderer &);
103 AwesomeLocalRenderer &operator=(const AwesomeLocalRenderer &);;
104};
105
Andreas Huber27366fc2009-11-20 09:32:46 -0800106AwesomePlayer::AwesomePlayer()
107 : mTimeSource(NULL),
108 mAudioPlayer(NULL),
109 mLastVideoBuffer(NULL),
110 mVideoBuffer(NULL) {
111 CHECK_EQ(mClient.connect(), OK);
112
113 DataSource::RegisterDefaultSniffers();
114
115 mVideoEvent = new AwesomeEvent(this, 0);
116 mVideoEventPending = false;
117 mStreamDoneEvent = new AwesomeEvent(this, 1);
118 mStreamDoneEventPending = false;
119
120 mQueue.start();
121
122 reset();
123}
124
125AwesomePlayer::~AwesomePlayer() {
126 mQueue.stop();
127
128 reset();
129
130 mClient.disconnect();
131}
132
133void AwesomePlayer::cancelPlayerEvents() {
134 mQueue.cancelEvent(mVideoEvent->eventID());
135 mVideoEventPending = false;
136 mQueue.cancelEvent(mStreamDoneEvent->eventID());
137 mStreamDoneEventPending = false;
138}
139
140void AwesomePlayer::setListener(const sp<MediaPlayerBase> &listener) {
141 Mutex::Autolock autoLock(mLock);
142 mListener = listener;
143}
144
145status_t AwesomePlayer::setDataSource(const char *uri) {
146 Mutex::Autolock autoLock(mLock);
147
148 reset_l();
149
150 sp<MediaExtractor> extractor = MediaExtractor::CreateFromURI(uri);
151
152 if (extractor == NULL) {
153 return UNKNOWN_ERROR;
154 }
155
156 return setDataSource_l(extractor);
157}
158
159status_t AwesomePlayer::setDataSource(
160 int fd, int64_t offset, int64_t length) {
161 Mutex::Autolock autoLock(mLock);
162
163 reset_l();
164
165 sp<DataSource> source = new FileSource(fd, offset, length);
166
167 status_t err = source->initCheck();
168
169 if (err != OK) {
170 return err;
171 }
172
173 sp<MediaExtractor> extractor = MediaExtractor::Create(source);
174
175 if (extractor == NULL) {
176 return UNKNOWN_ERROR;
177 }
178
179 return setDataSource_l(extractor);
180}
181
182status_t AwesomePlayer::setDataSource_l(const sp<MediaExtractor> &extractor) {
183 reset_l();
184
185 bool haveAudio = false;
186 bool haveVideo = false;
187 for (size_t i = 0; i < extractor->countTracks(); ++i) {
188 sp<MetaData> meta = extractor->getTrackMetaData(i);
189
190 const char *mime;
191 CHECK(meta->findCString(kKeyMIMEType, &mime));
192
193 if (!haveVideo && !strncasecmp(mime, "video/", 6)) {
194 if (setVideoSource(extractor->getTrack(i)) == OK) {
195 haveVideo = true;
196 }
197 } else if (!haveAudio && !strncasecmp(mime, "audio/", 6)) {
198 if (setAudioSource(extractor->getTrack(i)) == OK) {
199 haveAudio = true;
200 }
201 }
202
203 if (haveAudio && haveVideo) {
204 break;
205 }
206 }
207
208 return !haveAudio && !haveVideo ? UNKNOWN_ERROR : OK;
209}
210
211void AwesomePlayer::reset() {
212 Mutex::Autolock autoLock(mLock);
213 reset_l();
214}
215
216void AwesomePlayer::reset_l() {
217 cancelPlayerEvents();
218
219 if (mLastVideoBuffer) {
220 mLastVideoBuffer->release();
221 mLastVideoBuffer = NULL;
222 }
223
224 if (mVideoBuffer) {
225 mVideoBuffer->release();
226 mVideoBuffer = NULL;
227 }
228
229 if (mVideoSource != NULL) {
230 mVideoSource->stop();
231 mVideoSource.clear();
232 }
233
234 mAudioSource.clear();
235
236 if (mTimeSource != mAudioPlayer) {
237 delete mTimeSource;
238 }
239 mTimeSource = NULL;
240
241 delete mAudioPlayer;
242 mAudioPlayer = NULL;
243
244 mVideoRenderer.clear();
245
246 mDurationUs = -1;
247 mFlags = 0;
248 mVideoWidth = mVideoHeight = -1;
249 mTimeSourceDeltaUs = 0;
250 mVideoTimeUs = 0;
251
252 mSeeking = false;
253 mSeekTimeUs = 0;
254}
255
256// static
257void AwesomePlayer::AudioNotify(void *_me, int what) {
258 AwesomePlayer *me = (AwesomePlayer *)_me;
259
260 Mutex::Autolock autoLock(me->mLock);
261
262 switch (what) {
263 case AudioPlayer::REACHED_EOS:
264 me->postStreamDoneEvent_l();
265 break;
266
267 case AudioPlayer::SEEK_COMPLETE:
268 {
269 if (me->mListener != NULL) {
270 me->mListener->sendEvent(MEDIA_SEEK_COMPLETE);
271 }
272
273 break;
274 }
275
276 default:
277 CHECK(!"should not be here.");
278 break;
279 }
280}
281
282void AwesomePlayer::onStreamDone() {
283 // Posted whenever any stream finishes playing.
284
285 Mutex::Autolock autoLock(mLock);
286 mStreamDoneEventPending = false;
287
288 if (mFlags & LOOPING) {
289 seekTo_l(0);
290
291 if (mVideoRenderer != NULL) {
292 postVideoEvent_l();
293 }
294 } else {
295 if (mListener != NULL) {
296 mListener->sendEvent(MEDIA_PLAYBACK_COMPLETE);
297 }
298
299 pause_l();
300 }
301}
302
303status_t AwesomePlayer::play() {
304 Mutex::Autolock autoLock(mLock);
305
306 if (mFlags & PLAYING) {
307 return OK;
308 }
309
310 mFlags |= PLAYING;
311 mFlags |= FIRST_FRAME;
312
Andreas Huberc1d5c922009-12-10 15:49:04 -0800313 bool deferredAudioSeek = false;
314
Andreas Huber27366fc2009-11-20 09:32:46 -0800315 if (mAudioSource != NULL) {
316 if (mAudioPlayer == NULL) {
317 if (mAudioSink != NULL) {
318 mAudioPlayer = new AudioPlayer(mAudioSink);
319
320 mAudioPlayer->setListenerCallback(
321 &AwesomePlayer::AudioNotify, this);
322
323 mAudioPlayer->setSource(mAudioSource);
324 mAudioPlayer->start();
325
326 delete mTimeSource;
327 mTimeSource = mAudioPlayer;
328
Andreas Huberc1d5c922009-12-10 15:49:04 -0800329 deferredAudioSeek = true;
Andreas Huber27366fc2009-11-20 09:32:46 -0800330 }
331 } else {
332 mAudioPlayer->resume();
333 }
334 }
335
336 if (mTimeSource == NULL && mAudioPlayer == NULL) {
337 mTimeSource = new SystemTimeSource;
338 }
339
340 if (mVideoSource != NULL) {
341 if (mVideoRenderer == NULL) {
342 initRenderer_l();
343 }
344
345 if (mVideoRenderer != NULL) {
346 // Kick off video playback
347 postVideoEvent_l();
348 }
349 }
350
Andreas Huberc1d5c922009-12-10 15:49:04 -0800351 if (deferredAudioSeek) {
352 // If there was a seek request while we were paused
353 // and we're just starting up again, honor the request now.
354 seekAudioIfNecessary_l();
355 }
356
Andreas Huber27366fc2009-11-20 09:32:46 -0800357 return OK;
358}
359
360void AwesomePlayer::initRenderer_l() {
361 if (mISurface != NULL) {
362 sp<MetaData> meta = mVideoSource->getFormat();
363
364 int32_t format;
365 const char *component;
366 int32_t decodedWidth, decodedHeight;
367 CHECK(meta->findInt32(kKeyColorFormat, &format));
368 CHECK(meta->findCString(kKeyDecoderComponent, &component));
369 CHECK(meta->findInt32(kKeyWidth, &decodedWidth));
370 CHECK(meta->findInt32(kKeyHeight, &decodedHeight));
371
Andreas Hubera67d5382009-12-10 15:32:12 -0800372 mVideoRenderer.clear();
373
374 // Must ensure that mVideoRenderer's destructor is actually executed
375 // before creating a new one.
376 IPCThreadState::self()->flushCommands();
377
Andreas Huber1314e732009-12-14 14:18:22 -0800378 if (!strncmp("OMX.", component, 4)) {
379 // Our OMX codecs allocate buffers on the media_server side
380 // therefore they require a remote IOMXRenderer that knows how
381 // to display them.
382 mVideoRenderer = new AwesomeRemoteRenderer(
383 mClient.interface()->createRenderer(
384 mISurface, component,
385 (OMX_COLOR_FORMATTYPE)format,
386 decodedWidth, decodedHeight,
387 mVideoWidth, mVideoHeight));
388 } else {
389 // Other decoders are instantiated locally and as a consequence
390 // allocate their buffers in local address space.
391 mVideoRenderer = new AwesomeLocalRenderer(
392 (OMX_COLOR_FORMATTYPE)format,
393 mISurface,
394 mVideoWidth, mVideoHeight,
395 decodedWidth, decodedHeight);
396 }
Andreas Huber27366fc2009-11-20 09:32:46 -0800397 }
398}
399
400status_t AwesomePlayer::pause() {
401 Mutex::Autolock autoLock(mLock);
402 return pause_l();
403}
404
405status_t AwesomePlayer::pause_l() {
406 if (!(mFlags & PLAYING)) {
407 return OK;
408 }
409
410 cancelPlayerEvents();
411
412 if (mAudioPlayer != NULL) {
413 mAudioPlayer->pause();
414 }
415
416 mFlags &= ~PLAYING;
417
418 return OK;
419}
420
421bool AwesomePlayer::isPlaying() const {
422 Mutex::Autolock autoLock(mLock);
423
424 return mFlags & PLAYING;
425}
426
427void AwesomePlayer::setISurface(const sp<ISurface> &isurface) {
428 Mutex::Autolock autoLock(mLock);
429
430 mISurface = isurface;
431}
432
433void AwesomePlayer::setAudioSink(
434 const sp<MediaPlayerBase::AudioSink> &audioSink) {
435 Mutex::Autolock autoLock(mLock);
436
437 mAudioSink = audioSink;
438}
439
440status_t AwesomePlayer::setLooping(bool shouldLoop) {
441 Mutex::Autolock autoLock(mLock);
442
443 mFlags = mFlags & ~LOOPING;
444
445 if (shouldLoop) {
446 mFlags |= LOOPING;
447 }
448
449 return OK;
450}
451
452status_t AwesomePlayer::getDuration(int64_t *durationUs) {
453 Mutex::Autolock autoLock(mLock);
454
455 if (mDurationUs < 0) {
456 return UNKNOWN_ERROR;
457 }
458
459 *durationUs = mDurationUs;
460
461 return OK;
462}
463
464status_t AwesomePlayer::getPosition(int64_t *positionUs) {
465 Mutex::Autolock autoLock(mLock);
466
467 if (mVideoRenderer != NULL) {
468 *positionUs = mVideoTimeUs;
469 } else if (mAudioPlayer != NULL) {
470 *positionUs = mAudioPlayer->getMediaTimeUs();
471 } else {
472 *positionUs = 0;
473 }
474
475 return OK;
476}
477
478status_t AwesomePlayer::seekTo(int64_t timeUs) {
479 Mutex::Autolock autoLock(mLock);
480 return seekTo_l(timeUs);
481}
482
483status_t AwesomePlayer::seekTo_l(int64_t timeUs) {
484 mSeeking = true;
485 mSeekTimeUs = timeUs;
486
487 seekAudioIfNecessary_l();
488
489 return OK;
490}
491
492void AwesomePlayer::seekAudioIfNecessary_l() {
493 if (mSeeking && mVideoRenderer == NULL && mAudioPlayer != NULL) {
494 mAudioPlayer->seekTo(mSeekTimeUs);
495
496 mSeeking = false;
497 }
498}
499
500status_t AwesomePlayer::getVideoDimensions(
501 int32_t *width, int32_t *height) const {
502 Mutex::Autolock autoLock(mLock);
503
504 if (mVideoWidth < 0 || mVideoHeight < 0) {
505 return UNKNOWN_ERROR;
506 }
507
508 *width = mVideoWidth;
509 *height = mVideoHeight;
510
511 return OK;
512}
513
514status_t AwesomePlayer::setAudioSource(const sp<MediaSource> &source) {
515 if (source == NULL) {
516 return UNKNOWN_ERROR;
517 }
518
519 mAudioSource = OMXCodec::Create(
520 mClient.interface(), source->getFormat(),
521 false, // createEncoder
522 source);
523
524 if (mAudioSource != NULL) {
525 int64_t durationUs;
526 if (source->getFormat()->findInt64(kKeyDuration, &durationUs)) {
527 if (mDurationUs < 0 || durationUs > mDurationUs) {
528 mDurationUs = durationUs;
529 }
530 }
531 }
532
533 return mAudioSource != NULL ? OK : UNKNOWN_ERROR;
534}
535
536status_t AwesomePlayer::setVideoSource(const sp<MediaSource> &source) {
537 if (source == NULL) {
538 return UNKNOWN_ERROR;
539 }
540
541 mVideoSource = OMXCodec::Create(
542 mClient.interface(), source->getFormat(),
543 false, // createEncoder
544 source);
545
546 if (mVideoSource != NULL) {
547 int64_t durationUs;
548 if (source->getFormat()->findInt64(kKeyDuration, &durationUs)) {
549 if (mDurationUs < 0 || durationUs > mDurationUs) {
550 mDurationUs = durationUs;
551 }
552 }
553
554 CHECK(source->getFormat()->findInt32(kKeyWidth, &mVideoWidth));
555 CHECK(source->getFormat()->findInt32(kKeyHeight, &mVideoHeight));
556
557 mVideoSource->start();
558 }
559
560 return mVideoSource != NULL ? OK : UNKNOWN_ERROR;
561}
562
563void AwesomePlayer::onEvent(int32_t code) {
564 if (code == 1) {
565 onStreamDone();
566 return;
567 }
568
569 Mutex::Autolock autoLock(mLock);
570 mVideoEventPending = false;
571
572 if (mSeeking) {
573 if (mLastVideoBuffer) {
574 mLastVideoBuffer->release();
575 mLastVideoBuffer = NULL;
576 }
577
578 if (mVideoBuffer) {
579 mVideoBuffer->release();
580 mVideoBuffer = NULL;
581 }
582 }
583
584 if (!mVideoBuffer) {
585 MediaSource::ReadOptions options;
586 if (mSeeking) {
587 LOGV("seeking to %lld us (%.2f secs)", mSeekTimeUs, mSeekTimeUs / 1E6);
588
589 options.setSeekTo(mSeekTimeUs);
590 }
591 for (;;) {
592 status_t err = mVideoSource->read(&mVideoBuffer, &options);
593
594 if (err != OK) {
595 CHECK_EQ(mVideoBuffer, NULL);
596
597 if (err == INFO_FORMAT_CHANGED) {
598 LOGV("VideoSource signalled format change.");
599
600 initRenderer_l();
601 continue;
602 }
603
604 postStreamDoneEvent_l();
605 return;
606 }
607
Andreas Hubera67d5382009-12-10 15:32:12 -0800608 if (mVideoBuffer->range_length() == 0) {
Andreas Huber6ddcf012009-12-10 15:32:12 -0800609 // Some decoders, notably the PV AVC software decoder
610 // return spurious empty buffers that we just want to ignore.
611
Andreas Hubera67d5382009-12-10 15:32:12 -0800612 mVideoBuffer->release();
613 mVideoBuffer = NULL;
614 continue;
615 }
616
Andreas Huber27366fc2009-11-20 09:32:46 -0800617 break;
618 }
619 }
620
621 int64_t timeUs;
622 CHECK(mVideoBuffer->meta_data()->findInt64(kKeyTime, &timeUs));
623
624 mVideoTimeUs = timeUs;
625
626 if (mSeeking) {
627 if (mAudioPlayer != NULL) {
628 LOGV("seeking audio to %lld us (%.2f secs).", timeUs, timeUs / 1E6);
629
630 mAudioPlayer->seekTo(timeUs);
631 } else {
632 // If we're playing video only, report seek complete now,
633 // otherwise audio player will notify us later.
634 if (mListener != NULL) {
635 mListener->sendEvent(MEDIA_SEEK_COMPLETE);
636 }
637 }
638
639 mFlags |= FIRST_FRAME;
640 mSeeking = false;
641 }
642
643 if (mFlags & FIRST_FRAME) {
644 mFlags &= ~FIRST_FRAME;
645
646 mTimeSourceDeltaUs = mTimeSource->getRealTimeUs() - timeUs;
647 }
648
649 int64_t realTimeUs, mediaTimeUs;
650 if (mAudioPlayer != NULL
651 && mAudioPlayer->getMediaTimeMapping(&realTimeUs, &mediaTimeUs)) {
652 mTimeSourceDeltaUs = realTimeUs - mediaTimeUs;
653 }
654
655 int64_t nowUs = mTimeSource->getRealTimeUs() - mTimeSourceDeltaUs;
656
657 int64_t latenessUs = nowUs - timeUs;
658
Andreas Huber24b0a952009-11-23 14:02:00 -0800659 if (latenessUs > 40000) {
660 // We're more than 40ms late.
661 LOGI("we're late by %lld us (%.2f secs)", latenessUs, latenessUs / 1E6);
Andreas Huber27366fc2009-11-20 09:32:46 -0800662
663 mVideoBuffer->release();
664 mVideoBuffer = NULL;
665
666 postVideoEvent_l();
667 return;
668 }
669
670 if (latenessUs < -10000) {
671 // We're more than 10ms early.
672
673 postVideoEvent_l(10000);
674 return;
675 }
676
Andreas Huber1314e732009-12-14 14:18:22 -0800677 mVideoRenderer->render(mVideoBuffer);
Andreas Huber27366fc2009-11-20 09:32:46 -0800678
679 if (mLastVideoBuffer) {
680 mLastVideoBuffer->release();
681 mLastVideoBuffer = NULL;
682 }
683 mLastVideoBuffer = mVideoBuffer;
684 mVideoBuffer = NULL;
685
686 postVideoEvent_l();
687}
688
689void AwesomePlayer::postVideoEvent_l(int64_t delayUs) {
690 if (mVideoEventPending) {
691 return;
692 }
693
694 mVideoEventPending = true;
695 mQueue.postEventWithDelay(mVideoEvent, delayUs < 0 ? 10000 : delayUs);
696}
697
698void AwesomePlayer::postStreamDoneEvent_l() {
699 if (mStreamDoneEventPending) {
700 return;
701 }
702 mStreamDoneEventPending = true;
703 mQueue.postEvent(mStreamDoneEvent);
704}
705
706} // namespace android
707