AwesomePlayer.cpp revision 3cf613507f1e2f7bd932d921a6e222e426fd3be4
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 <dlfcn.h>
22
23#include "include/AwesomePlayer.h"
24#include "include/Prefetcher.h"
25#include "include/SoftwareRenderer.h"
26
27#include <binder/IPCThreadState.h>
28#include <media/stagefright/AudioPlayer.h>
29#include <media/stagefright/DataSource.h>
30#include <media/stagefright/FileSource.h>
31#include <media/stagefright/MediaBuffer.h>
32#include <media/stagefright/MediaDefs.h>
33#include <media/stagefright/MediaExtractor.h>
34#include <media/stagefright/MediaDebug.h>
35#include <media/stagefright/MediaSource.h>
36#include <media/stagefright/MetaData.h>
37#include <media/stagefright/OMXCodec.h>
38
39#include <surfaceflinger/ISurface.h>
40
41namespace android {
42
43struct AwesomeEvent : public TimedEventQueue::Event {
44    AwesomeEvent(
45            AwesomePlayer *player,
46            void (AwesomePlayer::*method)())
47        : mPlayer(player),
48          mMethod(method) {
49    }
50
51protected:
52    virtual ~AwesomeEvent() {}
53
54    virtual void fire(TimedEventQueue *queue, int64_t /* now_us */) {
55        (mPlayer->*mMethod)();
56    }
57
58private:
59    AwesomePlayer *mPlayer;
60    void (AwesomePlayer::*mMethod)();
61
62    AwesomeEvent(const AwesomeEvent &);
63    AwesomeEvent &operator=(const AwesomeEvent &);
64};
65
66struct AwesomeRemoteRenderer : public AwesomeRenderer {
67    AwesomeRemoteRenderer(const sp<IOMXRenderer> &target)
68        : mTarget(target) {
69    }
70
71    virtual void render(MediaBuffer *buffer) {
72        void *id;
73        if (buffer->meta_data()->findPointer(kKeyBufferID, &id)) {
74            mTarget->render((IOMX::buffer_id)id);
75        }
76    }
77
78private:
79    sp<IOMXRenderer> mTarget;
80
81    AwesomeRemoteRenderer(const AwesomeRemoteRenderer &);
82    AwesomeRemoteRenderer &operator=(const AwesomeRemoteRenderer &);
83};
84
85struct AwesomeLocalRenderer : public AwesomeRenderer {
86    AwesomeLocalRenderer(
87            const char *componentName,
88            OMX_COLOR_FORMATTYPE colorFormat,
89            const sp<ISurface> &surface,
90            size_t displayWidth, size_t displayHeight,
91            size_t decodedWidth, size_t decodedHeight)
92        : mTarget(NULL),
93          mLibHandle(NULL) {
94            init(componentName,
95                 colorFormat, surface, displayWidth,
96                 displayHeight, decodedWidth, decodedHeight);
97    }
98
99    virtual void render(MediaBuffer *buffer) {
100        mTarget->render(
101                (const uint8_t *)buffer->data() + buffer->range_offset(),
102                buffer->range_length(), NULL);
103    }
104
105protected:
106    virtual ~AwesomeLocalRenderer() {
107        delete mTarget;
108        mTarget = NULL;
109
110        if (mLibHandle) {
111            dlclose(mLibHandle);
112            mLibHandle = NULL;
113        }
114    }
115
116private:
117    VideoRenderer *mTarget;
118    void *mLibHandle;
119
120    void init(
121            const char *componentName,
122            OMX_COLOR_FORMATTYPE colorFormat,
123            const sp<ISurface> &surface,
124            size_t displayWidth, size_t displayHeight,
125            size_t decodedWidth, size_t decodedHeight);
126
127    AwesomeLocalRenderer(const AwesomeLocalRenderer &);
128    AwesomeLocalRenderer &operator=(const AwesomeLocalRenderer &);;
129};
130
131void AwesomeLocalRenderer::init(
132        const char *componentName,
133        OMX_COLOR_FORMATTYPE colorFormat,
134        const sp<ISurface> &surface,
135        size_t displayWidth, size_t displayHeight,
136        size_t decodedWidth, size_t decodedHeight) {
137    mLibHandle = dlopen("libstagefrighthw.so", RTLD_NOW);
138
139    if (mLibHandle) {
140        typedef VideoRenderer *(*CreateRendererFunc)(
141                const sp<ISurface> &surface,
142                const char *componentName,
143                OMX_COLOR_FORMATTYPE colorFormat,
144                size_t displayWidth, size_t displayHeight,
145                size_t decodedWidth, size_t decodedHeight);
146
147        CreateRendererFunc func =
148            (CreateRendererFunc)dlsym(
149                    mLibHandle,
150                    "_Z14createRendererRKN7android2spINS_8ISurfaceEEEPKc20"
151                    "OMX_COLOR_FORMATTYPEjjjj");
152
153        if (func) {
154            mTarget =
155                (*func)(surface, componentName, colorFormat,
156                    displayWidth, displayHeight, decodedWidth, decodedHeight);
157        }
158    }
159
160    if (mTarget == NULL) {
161        mTarget = new SoftwareRenderer(
162                colorFormat, surface, displayWidth, displayHeight,
163                decodedWidth, decodedHeight);
164    }
165}
166
167AwesomePlayer::AwesomePlayer()
168    : mTimeSource(NULL),
169      mAudioPlayer(NULL),
170      mFlags(0),
171      mLastVideoBuffer(NULL),
172      mVideoBuffer(NULL) {
173    CHECK_EQ(mClient.connect(), OK);
174
175    DataSource::RegisterDefaultSniffers();
176
177    mVideoEvent = new AwesomeEvent(this, &AwesomePlayer::onVideoEvent);
178    mVideoEventPending = false;
179    mStreamDoneEvent = new AwesomeEvent(this, &AwesomePlayer::onStreamDone);
180    mStreamDoneEventPending = false;
181    mBufferingEvent = new AwesomeEvent(this, &AwesomePlayer::onBufferingUpdate);
182    mBufferingEventPending = false;
183
184    mCheckAudioStatusEvent = new AwesomeEvent(
185            this, &AwesomePlayer::onCheckAudioStatus);
186
187    mAudioStatusEventPending = false;
188
189    mQueue.start();
190
191    reset();
192}
193
194AwesomePlayer::~AwesomePlayer() {
195    mQueue.stop();
196
197    reset();
198
199    mClient.disconnect();
200}
201
202void AwesomePlayer::cancelPlayerEvents(bool keepBufferingGoing) {
203    mQueue.cancelEvent(mVideoEvent->eventID());
204    mVideoEventPending = false;
205    mQueue.cancelEvent(mStreamDoneEvent->eventID());
206    mStreamDoneEventPending = false;
207    mQueue.cancelEvent(mCheckAudioStatusEvent->eventID());
208    mAudioStatusEventPending = false;
209
210    if (!keepBufferingGoing) {
211        mQueue.cancelEvent(mBufferingEvent->eventID());
212        mBufferingEventPending = false;
213    }
214}
215
216void AwesomePlayer::setListener(const wp<MediaPlayerBase> &listener) {
217    Mutex::Autolock autoLock(mLock);
218    mListener = listener;
219}
220
221status_t AwesomePlayer::setDataSource(
222        const char *uri, const KeyedVector<String8, String8> *headers) {
223    Mutex::Autolock autoLock(mLock);
224
225    reset_l();
226
227    mUri = uri;
228
229    if (headers) {
230        mUriHeaders = *headers;
231    }
232
233    // The actual work will be done during preparation in the call to
234    // ::finishSetDataSource_l to avoid blocking the calling thread in
235    // setDataSource for any significant time.
236
237    return OK;
238}
239
240status_t AwesomePlayer::setDataSource(
241        int fd, int64_t offset, int64_t length) {
242    Mutex::Autolock autoLock(mLock);
243
244    reset_l();
245
246    sp<DataSource> source = new FileSource(fd, offset, length);
247
248    status_t err = source->initCheck();
249
250    if (err != OK) {
251        return err;
252    }
253
254    sp<MediaExtractor> extractor = MediaExtractor::Create(source);
255
256    if (extractor == NULL) {
257        return UNKNOWN_ERROR;
258    }
259
260    return setDataSource_l(extractor);
261}
262
263status_t AwesomePlayer::setDataSource_l(const sp<MediaExtractor> &extractor) {
264    bool haveAudio = false;
265    bool haveVideo = false;
266    for (size_t i = 0; i < extractor->countTracks(); ++i) {
267        sp<MetaData> meta = extractor->getTrackMetaData(i);
268
269        const char *mime;
270        CHECK(meta->findCString(kKeyMIMEType, &mime));
271
272        if (!haveVideo && !strncasecmp(mime, "video/", 6)) {
273            if (setVideoSource(extractor->getTrack(i)) == OK) {
274                haveVideo = true;
275            }
276        } else if (!haveAudio && !strncasecmp(mime, "audio/", 6)) {
277            if (setAudioSource(extractor->getTrack(i)) == OK) {
278                haveAudio = true;
279            }
280        }
281
282        if (haveAudio && haveVideo) {
283            break;
284        }
285    }
286
287    return !haveAudio && !haveVideo ? UNKNOWN_ERROR : OK;
288}
289
290void AwesomePlayer::reset() {
291    Mutex::Autolock autoLock(mLock);
292    reset_l();
293}
294
295void AwesomePlayer::reset_l() {
296    while (mFlags & PREPARING) {
297        mPreparedCondition.wait(mLock);
298    }
299
300    cancelPlayerEvents();
301
302    mVideoRenderer.clear();
303
304    if (mLastVideoBuffer) {
305        mLastVideoBuffer->release();
306        mLastVideoBuffer = NULL;
307    }
308
309    if (mVideoBuffer) {
310        mVideoBuffer->release();
311        mVideoBuffer = NULL;
312    }
313
314    if (mVideoSource != NULL) {
315        mVideoSource->stop();
316
317        // The following hack is necessary to ensure that the OMX
318        // component is completely released by the time we may try
319        // to instantiate it again.
320        wp<MediaSource> tmp = mVideoSource;
321        mVideoSource.clear();
322        while (tmp.promote() != NULL) {
323            usleep(1000);
324        }
325        IPCThreadState::self()->flushCommands();
326    }
327
328    mAudioSource.clear();
329
330    if (mTimeSource != mAudioPlayer) {
331        delete mTimeSource;
332    }
333    mTimeSource = NULL;
334
335    delete mAudioPlayer;
336    mAudioPlayer = NULL;
337
338    mDurationUs = -1;
339    mFlags = 0;
340    mVideoWidth = mVideoHeight = -1;
341    mTimeSourceDeltaUs = 0;
342    mVideoTimeUs = 0;
343
344    mSeeking = false;
345    mSeekTimeUs = 0;
346
347    mPrefetcher.clear();
348
349    mUri.setTo("");
350    mUriHeaders.clear();
351}
352
353void AwesomePlayer::notifyListener_l(int msg, int ext1, int ext2) {
354    if (mListener != NULL) {
355        sp<MediaPlayerBase> listener = mListener.promote();
356
357        if (listener != NULL) {
358            listener->sendEvent(msg, ext1, ext2);
359        }
360    }
361}
362
363void AwesomePlayer::onBufferingUpdate() {
364    Mutex::Autolock autoLock(mLock);
365    mBufferingEventPending = false;
366
367    if (mDurationUs >= 0) {
368        int64_t cachedDurationUs = mPrefetcher->getCachedDurationUs();
369        int64_t positionUs = 0;
370        if (mVideoSource != NULL) {
371            positionUs = mVideoTimeUs;
372        } else if (mAudioPlayer != NULL) {
373            positionUs = mAudioPlayer->getMediaTimeUs();
374        }
375
376        cachedDurationUs += positionUs;
377
378        double percentage = (double)cachedDurationUs / mDurationUs;
379        notifyListener_l(MEDIA_BUFFERING_UPDATE, percentage * 100.0);
380
381        postBufferingEvent_l();
382    }
383}
384
385void AwesomePlayer::onStreamDone() {
386    // Posted whenever any stream finishes playing.
387
388    Mutex::Autolock autoLock(mLock);
389    mStreamDoneEventPending = false;
390
391    if (mFlags & LOOPING) {
392        seekTo_l(0);
393
394        if (mVideoSource != NULL) {
395            postVideoEvent_l();
396        }
397    } else {
398        notifyListener_l(MEDIA_PLAYBACK_COMPLETE);
399
400        pause_l();
401    }
402}
403
404status_t AwesomePlayer::play() {
405    Mutex::Autolock autoLock(mLock);
406
407    if (mFlags & PLAYING) {
408        return OK;
409    }
410
411    if (!(mFlags & PREPARED)) {
412        status_t err = prepare_l();
413
414        if (err != OK) {
415            return err;
416        }
417    }
418
419    mFlags |= PLAYING;
420    mFlags |= FIRST_FRAME;
421
422    bool deferredAudioSeek = false;
423
424    if (mAudioSource != NULL) {
425        if (mAudioPlayer == NULL) {
426            if (mAudioSink != NULL) {
427                mAudioPlayer = new AudioPlayer(mAudioSink);
428                mAudioPlayer->setSource(mAudioSource);
429                status_t err = mAudioPlayer->start();
430
431                if (err != OK) {
432                    delete mAudioPlayer;
433                    mAudioPlayer = NULL;
434
435                    mFlags &= ~(PLAYING | FIRST_FRAME);
436
437                    return err;
438                }
439
440                delete mTimeSource;
441                mTimeSource = mAudioPlayer;
442
443                deferredAudioSeek = true;
444
445                mWatchForAudioSeekComplete = false;
446                mWatchForAudioEOS = true;
447            }
448        } else {
449            mAudioPlayer->resume();
450        }
451
452        postCheckAudioStatusEvent_l();
453    }
454
455    if (mTimeSource == NULL && mAudioPlayer == NULL) {
456        mTimeSource = new SystemTimeSource;
457    }
458
459    if (mVideoSource != NULL) {
460        // Kick off video playback
461        postVideoEvent_l();
462    }
463
464    if (deferredAudioSeek) {
465        // If there was a seek request while we were paused
466        // and we're just starting up again, honor the request now.
467        seekAudioIfNecessary_l();
468    }
469
470    postBufferingEvent_l();
471
472    return OK;
473}
474
475void AwesomePlayer::initRenderer_l() {
476    if (mISurface != NULL) {
477        sp<MetaData> meta = mVideoSource->getFormat();
478
479        int32_t format;
480        const char *component;
481        int32_t decodedWidth, decodedHeight;
482        CHECK(meta->findInt32(kKeyColorFormat, &format));
483        CHECK(meta->findCString(kKeyDecoderComponent, &component));
484        CHECK(meta->findInt32(kKeyWidth, &decodedWidth));
485        CHECK(meta->findInt32(kKeyHeight, &decodedHeight));
486
487        mVideoRenderer.clear();
488
489        // Must ensure that mVideoRenderer's destructor is actually executed
490        // before creating a new one.
491        IPCThreadState::self()->flushCommands();
492
493        if (!strncmp("OMX.", component, 4)) {
494            // Our OMX codecs allocate buffers on the media_server side
495            // therefore they require a remote IOMXRenderer that knows how
496            // to display them.
497            mVideoRenderer = new AwesomeRemoteRenderer(
498                mClient.interface()->createRenderer(
499                        mISurface, component,
500                        (OMX_COLOR_FORMATTYPE)format,
501                        decodedWidth, decodedHeight,
502                        mVideoWidth, mVideoHeight));
503        } else {
504            // Other decoders are instantiated locally and as a consequence
505            // allocate their buffers in local address space.
506            mVideoRenderer = new AwesomeLocalRenderer(
507                component,
508                (OMX_COLOR_FORMATTYPE)format,
509                mISurface,
510                mVideoWidth, mVideoHeight,
511                decodedWidth, decodedHeight);
512        }
513    }
514}
515
516status_t AwesomePlayer::pause() {
517    Mutex::Autolock autoLock(mLock);
518    return pause_l();
519}
520
521status_t AwesomePlayer::pause_l() {
522    if (!(mFlags & PLAYING)) {
523        return OK;
524    }
525
526    cancelPlayerEvents(true /* keepBufferingGoing */);
527
528    if (mAudioPlayer != NULL) {
529        mAudioPlayer->pause();
530    }
531
532    mFlags &= ~PLAYING;
533
534    return OK;
535}
536
537bool AwesomePlayer::isPlaying() const {
538    Mutex::Autolock autoLock(mLock);
539
540    return mFlags & PLAYING;
541}
542
543void AwesomePlayer::setISurface(const sp<ISurface> &isurface) {
544    Mutex::Autolock autoLock(mLock);
545
546    mISurface = isurface;
547}
548
549void AwesomePlayer::setAudioSink(
550        const sp<MediaPlayerBase::AudioSink> &audioSink) {
551    Mutex::Autolock autoLock(mLock);
552
553    mAudioSink = audioSink;
554}
555
556status_t AwesomePlayer::setLooping(bool shouldLoop) {
557    Mutex::Autolock autoLock(mLock);
558
559    mFlags = mFlags & ~LOOPING;
560
561    if (shouldLoop) {
562        mFlags |= LOOPING;
563    }
564
565    return OK;
566}
567
568status_t AwesomePlayer::getDuration(int64_t *durationUs) {
569    Mutex::Autolock autoLock(mLock);
570
571    if (mDurationUs < 0) {
572        return UNKNOWN_ERROR;
573    }
574
575    *durationUs = mDurationUs;
576
577    return OK;
578}
579
580status_t AwesomePlayer::getPosition(int64_t *positionUs) {
581    Mutex::Autolock autoLock(mLock);
582
583    if (mVideoSource != NULL) {
584        *positionUs = mVideoTimeUs;
585    } else if (mAudioPlayer != NULL) {
586        *positionUs = mAudioPlayer->getMediaTimeUs();
587    } else {
588        *positionUs = 0;
589    }
590
591    return OK;
592}
593
594status_t AwesomePlayer::seekTo(int64_t timeUs) {
595    Mutex::Autolock autoLock(mLock);
596    return seekTo_l(timeUs);
597}
598
599status_t AwesomePlayer::seekTo_l(int64_t timeUs) {
600    mSeeking = true;
601    mSeekTimeUs = timeUs;
602
603    seekAudioIfNecessary_l();
604
605    return OK;
606}
607
608void AwesomePlayer::seekAudioIfNecessary_l() {
609    if (mSeeking && mVideoSource == NULL && mAudioPlayer != NULL) {
610        mAudioPlayer->seekTo(mSeekTimeUs);
611
612        mWatchForAudioSeekComplete = true;
613        mWatchForAudioEOS = true;
614        mSeeking = false;
615    }
616}
617
618status_t AwesomePlayer::getVideoDimensions(
619        int32_t *width, int32_t *height) const {
620    Mutex::Autolock autoLock(mLock);
621
622    if (mVideoWidth < 0 || mVideoHeight < 0) {
623        return UNKNOWN_ERROR;
624    }
625
626    *width = mVideoWidth;
627    *height = mVideoHeight;
628
629    return OK;
630}
631
632status_t AwesomePlayer::setAudioSource(sp<MediaSource> source) {
633    if (source == NULL) {
634        return UNKNOWN_ERROR;
635    }
636
637    if (mPrefetcher != NULL) {
638        source = mPrefetcher->addSource(source);
639    }
640
641    sp<MetaData> meta = source->getFormat();
642
643    const char *mime;
644    CHECK(meta->findCString(kKeyMIMEType, &mime));
645
646    if (!strcasecmp(mime, MEDIA_MIMETYPE_AUDIO_RAW)) {
647        mAudioSource = source;
648    } else {
649        mAudioSource = OMXCodec::Create(
650                mClient.interface(), source->getFormat(),
651                false, // createEncoder
652                source);
653    }
654
655    if (mAudioSource != NULL) {
656        int64_t durationUs;
657        if (source->getFormat()->findInt64(kKeyDuration, &durationUs)) {
658            if (mDurationUs < 0 || durationUs > mDurationUs) {
659                mDurationUs = durationUs;
660            }
661        }
662    }
663
664    return mAudioSource != NULL ? OK : UNKNOWN_ERROR;
665}
666
667status_t AwesomePlayer::setVideoSource(sp<MediaSource> source) {
668    if (source == NULL) {
669        return UNKNOWN_ERROR;
670    }
671
672    if (mPrefetcher != NULL) {
673        source = mPrefetcher->addSource(source);
674    }
675
676    mVideoSource = OMXCodec::Create(
677            mClient.interface(), source->getFormat(),
678            false, // createEncoder
679            source);
680
681    if (mVideoSource != NULL) {
682        int64_t durationUs;
683        if (source->getFormat()->findInt64(kKeyDuration, &durationUs)) {
684            if (mDurationUs < 0 || durationUs > mDurationUs) {
685                mDurationUs = durationUs;
686            }
687        }
688
689        CHECK(source->getFormat()->findInt32(kKeyWidth, &mVideoWidth));
690        CHECK(source->getFormat()->findInt32(kKeyHeight, &mVideoHeight));
691
692        mVideoSource->start();
693    }
694
695    return mVideoSource != NULL ? OK : UNKNOWN_ERROR;
696}
697
698void AwesomePlayer::onVideoEvent() {
699    Mutex::Autolock autoLock(mLock);
700
701    mVideoEventPending = false;
702
703    if (mSeeking) {
704        if (mLastVideoBuffer) {
705            mLastVideoBuffer->release();
706            mLastVideoBuffer = NULL;
707        }
708
709        if (mVideoBuffer) {
710            mVideoBuffer->release();
711            mVideoBuffer = NULL;
712        }
713    }
714
715    if (!mVideoBuffer) {
716        MediaSource::ReadOptions options;
717        if (mSeeking) {
718            LOGV("seeking to %lld us (%.2f secs)", mSeekTimeUs, mSeekTimeUs / 1E6);
719
720            options.setSeekTo(mSeekTimeUs);
721        }
722        for (;;) {
723            status_t err = mVideoSource->read(&mVideoBuffer, &options);
724            options.clearSeekTo();
725
726            if (err != OK) {
727                CHECK_EQ(mVideoBuffer, NULL);
728
729                if (err == INFO_FORMAT_CHANGED) {
730                    LOGV("VideoSource signalled format change.");
731
732                    if (mVideoRenderer != NULL) {
733                        initRenderer_l();
734                    }
735                    continue;
736                }
737
738                postStreamDoneEvent_l();
739                return;
740            }
741
742            if (mVideoBuffer->range_length() == 0) {
743                // Some decoders, notably the PV AVC software decoder
744                // return spurious empty buffers that we just want to ignore.
745
746                mVideoBuffer->release();
747                mVideoBuffer = NULL;
748                continue;
749            }
750
751            break;
752        }
753    }
754
755    int64_t timeUs;
756    CHECK(mVideoBuffer->meta_data()->findInt64(kKeyTime, &timeUs));
757
758    mVideoTimeUs = timeUs;
759
760    if (mSeeking) {
761        if (mAudioPlayer != NULL) {
762            LOGV("seeking audio to %lld us (%.2f secs).", timeUs, timeUs / 1E6);
763
764            mAudioPlayer->seekTo(timeUs);
765            mWatchForAudioSeekComplete = true;
766            mWatchForAudioEOS = true;
767        } else {
768            // If we're playing video only, report seek complete now,
769            // otherwise audio player will notify us later.
770            notifyListener_l(MEDIA_SEEK_COMPLETE);
771        }
772
773        mFlags |= FIRST_FRAME;
774        mSeeking = false;
775    }
776
777    if (mFlags & FIRST_FRAME) {
778        mFlags &= ~FIRST_FRAME;
779
780        mTimeSourceDeltaUs = mTimeSource->getRealTimeUs() - timeUs;
781    }
782
783    int64_t realTimeUs, mediaTimeUs;
784    if (mAudioPlayer != NULL
785        && mAudioPlayer->getMediaTimeMapping(&realTimeUs, &mediaTimeUs)) {
786        mTimeSourceDeltaUs = realTimeUs - mediaTimeUs;
787    }
788
789    int64_t nowUs = mTimeSource->getRealTimeUs() - mTimeSourceDeltaUs;
790
791    int64_t latenessUs = nowUs - timeUs;
792
793    if (latenessUs > 40000) {
794        // We're more than 40ms late.
795        LOGV("we're late by %lld us (%.2f secs)", latenessUs, latenessUs / 1E6);
796
797        mVideoBuffer->release();
798        mVideoBuffer = NULL;
799
800        postVideoEvent_l();
801        return;
802    }
803
804    if (latenessUs < -10000) {
805        // We're more than 10ms early.
806
807        postVideoEvent_l(10000);
808        return;
809    }
810
811    if (mVideoRenderer == NULL) {
812        initRenderer_l();
813    }
814
815    if (mVideoRenderer != NULL) {
816        mVideoRenderer->render(mVideoBuffer);
817    }
818
819    if (mLastVideoBuffer) {
820        mLastVideoBuffer->release();
821        mLastVideoBuffer = NULL;
822    }
823    mLastVideoBuffer = mVideoBuffer;
824    mVideoBuffer = NULL;
825
826    postVideoEvent_l();
827}
828
829void AwesomePlayer::postVideoEvent_l(int64_t delayUs) {
830    if (mVideoEventPending) {
831        return;
832    }
833
834    mVideoEventPending = true;
835    mQueue.postEventWithDelay(mVideoEvent, delayUs < 0 ? 10000 : delayUs);
836}
837
838void AwesomePlayer::postStreamDoneEvent_l() {
839    if (mStreamDoneEventPending) {
840        return;
841    }
842    mStreamDoneEventPending = true;
843    mQueue.postEvent(mStreamDoneEvent);
844}
845
846void AwesomePlayer::postBufferingEvent_l() {
847    if (mPrefetcher == NULL) {
848        return;
849    }
850
851    if (mBufferingEventPending) {
852        return;
853    }
854    mBufferingEventPending = true;
855    mQueue.postEventWithDelay(mBufferingEvent, 1000000ll);
856}
857
858void AwesomePlayer::postCheckAudioStatusEvent_l() {
859    if (mAudioStatusEventPending) {
860        return;
861    }
862    mAudioStatusEventPending = true;
863    mQueue.postEventWithDelay(mCheckAudioStatusEvent, 100000ll);
864}
865
866void AwesomePlayer::onCheckAudioStatus() {
867    Mutex::Autolock autoLock(mLock);
868    mAudioStatusEventPending = false;
869
870    if (mWatchForAudioSeekComplete && !mAudioPlayer->isSeeking()) {
871        mWatchForAudioSeekComplete = false;
872        notifyListener_l(MEDIA_SEEK_COMPLETE);
873    }
874
875    if (mWatchForAudioEOS && mAudioPlayer->reachedEOS()) {
876        mWatchForAudioEOS = false;
877        postStreamDoneEvent_l();
878    }
879
880    postCheckAudioStatusEvent_l();
881}
882
883status_t AwesomePlayer::prepare() {
884    Mutex::Autolock autoLock(mLock);
885    return prepare_l();
886}
887
888status_t AwesomePlayer::prepare_l() {
889    if (mFlags & PREPARED) {
890        return OK;
891    }
892
893    if (mFlags & PREPARING) {
894        return UNKNOWN_ERROR;
895    }
896
897    mIsAsyncPrepare = false;
898    status_t err = prepareAsync_l();
899
900    if (err != OK) {
901        return err;
902    }
903
904    while (mFlags & PREPARING) {
905        mPreparedCondition.wait(mLock);
906    }
907
908    return mPrepareResult;
909}
910
911status_t AwesomePlayer::prepareAsync() {
912    Mutex::Autolock autoLock(mLock);
913
914    if (mFlags & PREPARING) {
915        return UNKNOWN_ERROR;  // async prepare already pending
916    }
917
918    mIsAsyncPrepare = true;
919    return prepareAsync_l();
920}
921
922status_t AwesomePlayer::prepareAsync_l() {
923    if (mFlags & PREPARING) {
924        return UNKNOWN_ERROR;  // async prepare already pending
925    }
926
927    mFlags |= PREPARING;
928    mAsyncPrepareEvent = new AwesomeEvent(
929            this, &AwesomePlayer::onPrepareAsyncEvent);
930
931    mQueue.postEvent(mAsyncPrepareEvent);
932
933    return OK;
934}
935
936status_t AwesomePlayer::finishSetDataSource_l() {
937    sp<DataSource> dataSource =
938        DataSource::CreateFromURI(mUri.string(), &mUriHeaders);
939
940    if (dataSource == NULL) {
941        return UNKNOWN_ERROR;
942    }
943
944    sp<MediaExtractor> extractor = MediaExtractor::Create(dataSource);
945
946    if (extractor == NULL) {
947        return UNKNOWN_ERROR;
948    }
949
950    if (dataSource->flags() & DataSource::kWantsPrefetching) {
951        mPrefetcher = new Prefetcher;
952    }
953
954    return setDataSource_l(extractor);
955}
956
957void AwesomePlayer::onPrepareAsyncEvent() {
958    {
959        Mutex::Autolock autoLock(mLock);
960
961        if (mUri.size() > 0) {
962            status_t err = finishSetDataSource_l();
963
964            if (err != OK) {
965                if (mIsAsyncPrepare) {
966                    notifyListener_l(MEDIA_ERROR, MEDIA_ERROR_UNKNOWN, err);
967                }
968
969                mPrepareResult = err;
970                mFlags &= ~PREPARING;
971                mAsyncPrepareEvent = NULL;
972                mPreparedCondition.broadcast();
973
974                return;
975            }
976        }
977    }
978
979    sp<Prefetcher> prefetcher;
980
981    {
982        Mutex::Autolock autoLock(mLock);
983        prefetcher = mPrefetcher;
984    }
985
986    if (prefetcher != NULL) {
987        prefetcher->prepare();
988    }
989
990    Mutex::Autolock autoLock(mLock);
991
992    if (mIsAsyncPrepare) {
993        if (mVideoWidth < 0 || mVideoHeight < 0) {
994            notifyListener_l(MEDIA_SET_VIDEO_SIZE, 0, 0);
995        } else {
996            notifyListener_l(MEDIA_SET_VIDEO_SIZE, mVideoWidth, mVideoHeight);
997        }
998
999        notifyListener_l(MEDIA_PREPARED);
1000    }
1001
1002    mPrepareResult = OK;
1003    mFlags &= ~PREPARING;
1004    mFlags |= PREPARED;
1005    mAsyncPrepareEvent = NULL;
1006    mPreparedCondition.broadcast();
1007}
1008
1009}  // namespace android
1010
1011