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