AwesomePlayer.cpp revision 4844ac54e8b5997c3b03872dbafe8ebed4787517
1/*
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 <binder/IPCThreadState.h>
24#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
264    if (mAudioSource != NULL) {
265        if (mAudioPlayer == NULL) {
266            if (mAudioSink != NULL) {
267                mAudioPlayer = new AudioPlayer(mAudioSink);
268
269                mAudioPlayer->setListenerCallback(
270                        &AwesomePlayer::AudioNotify, this);
271
272                mAudioPlayer->setSource(mAudioSource);
273                mAudioPlayer->start();
274
275                delete mTimeSource;
276                mTimeSource = mAudioPlayer;
277
278                // If there was a seek request while we were paused
279                // and we're just starting up again, honor the request now.
280                seekAudioIfNecessary_l();
281            }
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
302    return OK;
303}
304
305void AwesomePlayer::initRenderer_l() {
306    if (mISurface != NULL) {
307        sp<MetaData> meta = mVideoSource->getFormat();
308
309        int32_t format;
310        const char *component;
311        int32_t decodedWidth, decodedHeight;
312        CHECK(meta->findInt32(kKeyColorFormat, &format));
313        CHECK(meta->findCString(kKeyDecoderComponent, &component));
314        CHECK(meta->findInt32(kKeyWidth, &decodedWidth));
315        CHECK(meta->findInt32(kKeyHeight, &decodedHeight));
316
317        mVideoRenderer.clear();
318
319        // Must ensure that mVideoRenderer's destructor is actually executed
320        // before creating a new one.
321        IPCThreadState::self()->flushCommands();
322
323        mVideoRenderer =
324            mClient.interface()->createRenderer(
325                    mISurface, component,
326                    (OMX_COLOR_FORMATTYPE)format,
327                    decodedWidth, decodedHeight,
328                    mVideoWidth, mVideoHeight);
329    }
330}
331
332status_t AwesomePlayer::pause() {
333    Mutex::Autolock autoLock(mLock);
334    return pause_l();
335}
336
337status_t AwesomePlayer::pause_l() {
338    if (!(mFlags & PLAYING)) {
339        return OK;
340    }
341
342    cancelPlayerEvents();
343
344    if (mAudioPlayer != NULL) {
345        mAudioPlayer->pause();
346    }
347
348    mFlags &= ~PLAYING;
349
350    return OK;
351}
352
353bool AwesomePlayer::isPlaying() const {
354    Mutex::Autolock autoLock(mLock);
355
356    return mFlags & PLAYING;
357}
358
359void AwesomePlayer::setISurface(const sp<ISurface> &isurface) {
360    Mutex::Autolock autoLock(mLock);
361
362    mISurface = isurface;
363}
364
365void AwesomePlayer::setAudioSink(
366        const sp<MediaPlayerBase::AudioSink> &audioSink) {
367    Mutex::Autolock autoLock(mLock);
368
369    mAudioSink = audioSink;
370}
371
372status_t AwesomePlayer::setLooping(bool shouldLoop) {
373    Mutex::Autolock autoLock(mLock);
374
375    mFlags = mFlags & ~LOOPING;
376
377    if (shouldLoop) {
378        mFlags |= LOOPING;
379    }
380
381    return OK;
382}
383
384status_t AwesomePlayer::getDuration(int64_t *durationUs) {
385    Mutex::Autolock autoLock(mLock);
386
387    if (mDurationUs < 0) {
388        return UNKNOWN_ERROR;
389    }
390
391    *durationUs = mDurationUs;
392
393    return OK;
394}
395
396status_t AwesomePlayer::getPosition(int64_t *positionUs) {
397    Mutex::Autolock autoLock(mLock);
398
399    if (mVideoRenderer != NULL) {
400        *positionUs = mVideoTimeUs;
401    } else if (mAudioPlayer != NULL) {
402        *positionUs = mAudioPlayer->getMediaTimeUs();
403    } else {
404        *positionUs = 0;
405    }
406
407    return OK;
408}
409
410status_t AwesomePlayer::seekTo(int64_t timeUs) {
411    Mutex::Autolock autoLock(mLock);
412    return seekTo_l(timeUs);
413}
414
415status_t AwesomePlayer::seekTo_l(int64_t timeUs) {
416    mSeeking = true;
417    mSeekTimeUs = timeUs;
418
419    seekAudioIfNecessary_l();
420
421    return OK;
422}
423
424void AwesomePlayer::seekAudioIfNecessary_l() {
425    if (mSeeking && mVideoRenderer == NULL && mAudioPlayer != NULL) {
426        mAudioPlayer->seekTo(mSeekTimeUs);
427
428        mSeeking = false;
429    }
430}
431
432status_t AwesomePlayer::getVideoDimensions(
433        int32_t *width, int32_t *height) const {
434    Mutex::Autolock autoLock(mLock);
435
436    if (mVideoWidth < 0 || mVideoHeight < 0) {
437        return UNKNOWN_ERROR;
438    }
439
440    *width = mVideoWidth;
441    *height = mVideoHeight;
442
443    return OK;
444}
445
446status_t AwesomePlayer::setAudioSource(const sp<MediaSource> &source) {
447    if (source == NULL) {
448        return UNKNOWN_ERROR;
449    }
450
451    mAudioSource = OMXCodec::Create(
452            mClient.interface(), source->getFormat(),
453            false, // createEncoder
454            source);
455
456    if (mAudioSource != NULL) {
457        int64_t durationUs;
458        if (source->getFormat()->findInt64(kKeyDuration, &durationUs)) {
459            if (mDurationUs < 0 || durationUs > mDurationUs) {
460                mDurationUs = durationUs;
461            }
462        }
463    }
464
465    return mAudioSource != NULL ? OK : UNKNOWN_ERROR;
466}
467
468status_t AwesomePlayer::setVideoSource(const sp<MediaSource> &source) {
469    if (source == NULL) {
470        return UNKNOWN_ERROR;
471    }
472
473    mVideoSource = OMXCodec::Create(
474            mClient.interface(), source->getFormat(),
475            false, // createEncoder
476            source);
477
478    if (mVideoSource != NULL) {
479        int64_t durationUs;
480        if (source->getFormat()->findInt64(kKeyDuration, &durationUs)) {
481            if (mDurationUs < 0 || durationUs > mDurationUs) {
482                mDurationUs = durationUs;
483            }
484        }
485
486        CHECK(source->getFormat()->findInt32(kKeyWidth, &mVideoWidth));
487        CHECK(source->getFormat()->findInt32(kKeyHeight, &mVideoHeight));
488
489        mVideoSource->start();
490    }
491
492    return mVideoSource != NULL ? OK : UNKNOWN_ERROR;
493}
494
495void AwesomePlayer::onEvent(int32_t code) {
496    if (code == 1) {
497        onStreamDone();
498        return;
499    }
500
501    Mutex::Autolock autoLock(mLock);
502    mVideoEventPending = false;
503
504    if (mSeeking) {
505        if (mLastVideoBuffer) {
506            mLastVideoBuffer->release();
507            mLastVideoBuffer = NULL;
508        }
509
510        if (mVideoBuffer) {
511            mVideoBuffer->release();
512            mVideoBuffer = NULL;
513        }
514    }
515
516    if (!mVideoBuffer) {
517        MediaSource::ReadOptions options;
518        if (mSeeking) {
519            LOGV("seeking to %lld us (%.2f secs)", mSeekTimeUs, mSeekTimeUs / 1E6);
520
521            options.setSeekTo(mSeekTimeUs);
522        }
523        for (;;) {
524            status_t err = mVideoSource->read(&mVideoBuffer, &options);
525
526            if (err != OK) {
527                CHECK_EQ(mVideoBuffer, NULL);
528
529                if (err == INFO_FORMAT_CHANGED) {
530                    LOGV("VideoSource signalled format change.");
531
532                    initRenderer_l();
533                    continue;
534                }
535
536                postStreamDoneEvent_l();
537                return;
538            }
539
540            if (mVideoBuffer->range_length() == 0) {
541                mVideoBuffer->release();
542                mVideoBuffer = NULL;
543                continue;
544            }
545
546            break;
547        }
548    }
549
550    int64_t timeUs;
551    CHECK(mVideoBuffer->meta_data()->findInt64(kKeyTime, &timeUs));
552
553    mVideoTimeUs = timeUs;
554
555    if (mSeeking) {
556        if (mAudioPlayer != NULL) {
557            LOGV("seeking audio to %lld us (%.2f secs).", timeUs, timeUs / 1E6);
558
559            mAudioPlayer->seekTo(timeUs);
560        } else {
561            // If we're playing video only, report seek complete now,
562            // otherwise audio player will notify us later.
563            if (mListener != NULL) {
564                mListener->sendEvent(MEDIA_SEEK_COMPLETE);
565            }
566        }
567
568        mFlags |= FIRST_FRAME;
569        mSeeking = false;
570    }
571
572    if (mFlags & FIRST_FRAME) {
573        mFlags &= ~FIRST_FRAME;
574
575        mTimeSourceDeltaUs = mTimeSource->getRealTimeUs() - timeUs;
576    }
577
578    int64_t realTimeUs, mediaTimeUs;
579    if (mAudioPlayer != NULL
580        && mAudioPlayer->getMediaTimeMapping(&realTimeUs, &mediaTimeUs)) {
581        mTimeSourceDeltaUs = realTimeUs - mediaTimeUs;
582    }
583
584    int64_t nowUs = mTimeSource->getRealTimeUs() - mTimeSourceDeltaUs;
585
586    int64_t latenessUs = nowUs - timeUs;
587
588    if (latenessUs > 40000) {
589        // We're more than 40ms late.
590        LOGI("we're late by %lld us (%.2f secs)", latenessUs, latenessUs / 1E6);
591
592        mVideoBuffer->release();
593        mVideoBuffer = NULL;
594
595        postVideoEvent_l();
596        return;
597    }
598
599    if (latenessUs < -10000) {
600        // We're more than 10ms early.
601
602        postVideoEvent_l(10000);
603        return;
604    }
605
606    void *id;
607    if (mVideoBuffer->meta_data()->findPointer(kKeyBufferID, &id)) {
608        mVideoRenderer->render((IOMX::buffer_id)id);
609    }
610
611    if (mLastVideoBuffer) {
612        mLastVideoBuffer->release();
613        mLastVideoBuffer = NULL;
614    }
615    mLastVideoBuffer = mVideoBuffer;
616    mVideoBuffer = NULL;
617
618    postVideoEvent_l();
619}
620
621void AwesomePlayer::postVideoEvent_l(int64_t delayUs) {
622    if (mVideoEventPending) {
623        return;
624    }
625
626    mVideoEventPending = true;
627    mQueue.postEventWithDelay(mVideoEvent, delayUs < 0 ? 10000 : delayUs);
628}
629
630void AwesomePlayer::postStreamDoneEvent_l() {
631    if (mStreamDoneEventPending) {
632        return;
633    }
634    mStreamDoneEventPending = true;
635    mQueue.postEvent(mStreamDoneEvent);
636}
637
638}  // namespace android
639
640