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