AwesomePlayer.cpp revision 650773d00356129ffd661cdaef3fb3095c343707
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 <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
575    if (latenessUs > 40000) {
576        // We're more than 40ms late.
577        LOGI("we're late by %lld us (%.2f secs)", latenessUs, latenessUs / 1E6);
578
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
627