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