AwesomePlayer.cpp revision 2415ecb5bb4e1459024f6d6c8ae2d6e3dc4fbdc7
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/CachingDataSource.h>
30#include <media/stagefright/DataSource.h>
31#include <media/stagefright/FileSource.h>
32#include <media/stagefright/MediaBuffer.h>
33#include <media/stagefright/MediaDefs.h>
34#include <media/stagefright/MediaExtractor.h>
35#include <media/stagefright/MediaDebug.h>
36#include <media/stagefright/MediaSource.h>
37#include <media/stagefright/MetaData.h>
38#include <media/stagefright/OMXCodec.h>
39
40#include <surfaceflinger/ISurface.h>
41
42namespace android {
43
44struct AwesomeEvent : public TimedEventQueue::Event {
45    AwesomeEvent(
46            AwesomePlayer *player,
47            void (AwesomePlayer::*method)())
48        : mPlayer(player),
49          mMethod(method) {
50    }
51
52protected:
53    virtual ~AwesomeEvent() {}
54
55    virtual void fire(TimedEventQueue *queue, int64_t /* now_us */) {
56        (mPlayer->*mMethod)();
57    }
58
59private:
60    AwesomePlayer *mPlayer;
61    void (AwesomePlayer::*mMethod)();
62
63    AwesomeEvent(const AwesomeEvent &);
64    AwesomeEvent &operator=(const AwesomeEvent &);
65};
66
67struct AwesomeRemoteRenderer : public AwesomeRenderer {
68    AwesomeRemoteRenderer(const sp<IOMXRenderer> &target)
69        : mTarget(target) {
70    }
71
72    virtual void render(MediaBuffer *buffer) {
73        void *id;
74        if (buffer->meta_data()->findPointer(kKeyBufferID, &id)) {
75            mTarget->render((IOMX::buffer_id)id);
76        }
77    }
78
79private:
80    sp<IOMXRenderer> mTarget;
81
82    AwesomeRemoteRenderer(const AwesomeRemoteRenderer &);
83    AwesomeRemoteRenderer &operator=(const AwesomeRemoteRenderer &);
84};
85
86struct AwesomeLocalRenderer : public AwesomeRenderer {
87    AwesomeLocalRenderer(
88            bool previewOnly,
89            const char *componentName,
90            OMX_COLOR_FORMATTYPE colorFormat,
91            const sp<ISurface> &surface,
92            size_t displayWidth, size_t displayHeight,
93            size_t decodedWidth, size_t decodedHeight)
94        : mTarget(NULL),
95          mLibHandle(NULL) {
96            init(previewOnly, componentName,
97                 colorFormat, surface, displayWidth,
98                 displayHeight, decodedWidth, decodedHeight);
99    }
100
101    virtual void render(MediaBuffer *buffer) {
102        render((const uint8_t *)buffer->data() + buffer->range_offset(),
103               buffer->range_length());
104    }
105
106    void render(const void *data, size_t size) {
107        mTarget->render(data, size, NULL);
108    }
109
110protected:
111    virtual ~AwesomeLocalRenderer() {
112        delete mTarget;
113        mTarget = NULL;
114
115        if (mLibHandle) {
116            dlclose(mLibHandle);
117            mLibHandle = NULL;
118        }
119    }
120
121private:
122    VideoRenderer *mTarget;
123    void *mLibHandle;
124
125    void init(
126            bool previewOnly,
127            const char *componentName,
128            OMX_COLOR_FORMATTYPE colorFormat,
129            const sp<ISurface> &surface,
130            size_t displayWidth, size_t displayHeight,
131            size_t decodedWidth, size_t decodedHeight);
132
133    AwesomeLocalRenderer(const AwesomeLocalRenderer &);
134    AwesomeLocalRenderer &operator=(const AwesomeLocalRenderer &);;
135};
136
137void AwesomeLocalRenderer::init(
138        bool previewOnly,
139        const char *componentName,
140        OMX_COLOR_FORMATTYPE colorFormat,
141        const sp<ISurface> &surface,
142        size_t displayWidth, size_t displayHeight,
143        size_t decodedWidth, size_t decodedHeight) {
144    if (!previewOnly) {
145        // We will stick to the vanilla software-color-converting renderer
146        // for "previewOnly" mode, to avoid unneccessarily switching overlays
147        // more often than necessary.
148
149        mLibHandle = dlopen("libstagefrighthw.so", RTLD_NOW);
150
151        if (mLibHandle) {
152            typedef VideoRenderer *(*CreateRendererFunc)(
153                    const sp<ISurface> &surface,
154                    const char *componentName,
155                    OMX_COLOR_FORMATTYPE colorFormat,
156                    size_t displayWidth, size_t displayHeight,
157                    size_t decodedWidth, size_t decodedHeight);
158
159            CreateRendererFunc func =
160                (CreateRendererFunc)dlsym(
161                        mLibHandle,
162                        "_Z14createRendererRKN7android2spINS_8ISurfaceEEEPKc20"
163                        "OMX_COLOR_FORMATTYPEjjjj");
164
165            if (func) {
166                mTarget =
167                    (*func)(surface, componentName, colorFormat,
168                        displayWidth, displayHeight,
169                        decodedWidth, decodedHeight);
170            }
171        }
172    }
173
174    if (mTarget == NULL) {
175        mTarget = new SoftwareRenderer(
176                colorFormat, surface, displayWidth, displayHeight,
177                decodedWidth, decodedHeight);
178    }
179}
180
181AwesomePlayer::AwesomePlayer()
182    : mQueueStarted(false),
183      mTimeSource(NULL),
184      mVideoRendererIsPreview(false),
185      mAudioPlayer(NULL),
186      mFlags(0),
187      mLastVideoBuffer(NULL),
188      mVideoBuffer(NULL),
189      mSuspensionState(NULL) {
190    CHECK_EQ(mClient.connect(), OK);
191
192    DataSource::RegisterDefaultSniffers();
193
194    mVideoEvent = new AwesomeEvent(this, &AwesomePlayer::onVideoEvent);
195    mVideoEventPending = false;
196    mStreamDoneEvent = new AwesomeEvent(this, &AwesomePlayer::onStreamDone);
197    mStreamDoneEventPending = false;
198    mBufferingEvent = new AwesomeEvent(this, &AwesomePlayer::onBufferingUpdate);
199    mBufferingEventPending = false;
200
201    mCheckAudioStatusEvent = new AwesomeEvent(
202            this, &AwesomePlayer::onCheckAudioStatus);
203
204    mAudioStatusEventPending = false;
205
206    reset();
207}
208
209AwesomePlayer::~AwesomePlayer() {
210    if (mQueueStarted) {
211        mQueue.stop();
212    }
213
214    reset();
215
216    mClient.disconnect();
217}
218
219void AwesomePlayer::cancelPlayerEvents(bool keepBufferingGoing) {
220    mQueue.cancelEvent(mVideoEvent->eventID());
221    mVideoEventPending = false;
222    mQueue.cancelEvent(mStreamDoneEvent->eventID());
223    mStreamDoneEventPending = false;
224    mQueue.cancelEvent(mCheckAudioStatusEvent->eventID());
225    mAudioStatusEventPending = false;
226
227    if (!keepBufferingGoing) {
228        mQueue.cancelEvent(mBufferingEvent->eventID());
229        mBufferingEventPending = false;
230    }
231}
232
233void AwesomePlayer::setListener(const wp<MediaPlayerBase> &listener) {
234    Mutex::Autolock autoLock(mLock);
235    mListener = listener;
236}
237
238status_t AwesomePlayer::setDataSource(
239        const char *uri, const KeyedVector<String8, String8> *headers) {
240    Mutex::Autolock autoLock(mLock);
241    return setDataSource_l(uri, headers);
242}
243
244status_t AwesomePlayer::setDataSource_l(
245        const char *uri, const KeyedVector<String8, String8> *headers) {
246    reset_l();
247
248    mUri = uri;
249
250    if (headers) {
251        mUriHeaders = *headers;
252    }
253
254    // The actual work will be done during preparation in the call to
255    // ::finishSetDataSource_l to avoid blocking the calling thread in
256    // setDataSource for any significant time.
257
258    return OK;
259}
260
261status_t AwesomePlayer::setDataSource(
262        int fd, int64_t offset, int64_t length) {
263    Mutex::Autolock autoLock(mLock);
264
265    reset_l();
266
267    sp<DataSource> dataSource = new FileSource(fd, offset, length);
268
269    status_t err = dataSource->initCheck();
270
271    if (err != OK) {
272        return err;
273    }
274
275    mFileSource = dataSource;
276
277    return setDataSource_l(dataSource);
278}
279
280status_t AwesomePlayer::setDataSource_l(
281        const sp<DataSource> &dataSource) {
282    sp<MediaExtractor> extractor = MediaExtractor::Create(dataSource);
283
284    if (extractor == NULL) {
285        return UNKNOWN_ERROR;
286    }
287
288    return setDataSource_l(extractor);
289}
290
291status_t AwesomePlayer::setDataSource_l(const sp<MediaExtractor> &extractor) {
292    bool haveAudio = false;
293    bool haveVideo = false;
294    for (size_t i = 0; i < extractor->countTracks(); ++i) {
295        sp<MetaData> meta = extractor->getTrackMetaData(i);
296
297        const char *mime;
298        CHECK(meta->findCString(kKeyMIMEType, &mime));
299
300        if (!haveVideo && !strncasecmp(mime, "video/", 6)) {
301            setVideoSource(extractor->getTrack(i));
302            haveVideo = true;
303        } else if (!haveAudio && !strncasecmp(mime, "audio/", 6)) {
304            setAudioSource(extractor->getTrack(i));
305            haveAudio = true;
306        }
307
308        if (haveAudio && haveVideo) {
309            break;
310        }
311    }
312
313    return !haveAudio && !haveVideo ? UNKNOWN_ERROR : OK;
314}
315
316void AwesomePlayer::reset() {
317    Mutex::Autolock autoLock(mLock);
318    reset_l();
319}
320
321void AwesomePlayer::reset_l() {
322    if (mFlags & PREPARING) {
323        mFlags |= PREPARE_CANCELLED;
324        if (mConnectingDataSource != NULL) {
325            LOGI("interrupting the connection process");
326            mConnectingDataSource->disconnect();
327        }
328    }
329
330    while (mFlags & PREPARING) {
331        mPreparedCondition.wait(mLock);
332    }
333
334    cancelPlayerEvents();
335
336    if (mPrefetcher != NULL) {
337        CHECK_EQ(mPrefetcher->getStrongCount(), 1);
338    }
339    mPrefetcher.clear();
340
341    mAudioTrack.clear();
342    mVideoTrack.clear();
343
344    // Shutdown audio first, so that the respone to the reset request
345    // appears to happen instantaneously as far as the user is concerned
346    // If we did this later, audio would continue playing while we
347    // shutdown the video-related resources and the player appear to
348    // not be as responsive to a reset request.
349    if (mAudioPlayer == NULL && mAudioSource != NULL) {
350        // If we had an audio player, it would have effectively
351        // taken possession of the audio source and stopped it when
352        // _it_ is stopped. Otherwise this is still our responsibility.
353        mAudioSource->stop();
354    }
355    mAudioSource.clear();
356
357    if (mTimeSource != mAudioPlayer) {
358        delete mTimeSource;
359    }
360    mTimeSource = NULL;
361
362    delete mAudioPlayer;
363    mAudioPlayer = NULL;
364
365    mVideoRenderer.clear();
366
367    if (mLastVideoBuffer) {
368        mLastVideoBuffer->release();
369        mLastVideoBuffer = NULL;
370    }
371
372    if (mVideoBuffer) {
373        mVideoBuffer->release();
374        mVideoBuffer = NULL;
375    }
376
377    if (mVideoSource != NULL) {
378        mVideoSource->stop();
379
380        // The following hack is necessary to ensure that the OMX
381        // component is completely released by the time we may try
382        // to instantiate it again.
383        wp<MediaSource> tmp = mVideoSource;
384        mVideoSource.clear();
385        while (tmp.promote() != NULL) {
386            usleep(1000);
387        }
388        IPCThreadState::self()->flushCommands();
389    }
390
391    mDurationUs = -1;
392    mFlags = 0;
393    mVideoWidth = mVideoHeight = -1;
394    mTimeSourceDeltaUs = 0;
395    mVideoTimeUs = 0;
396
397    mSeeking = false;
398    mSeekTimeUs = 0;
399
400    mUri.setTo("");
401    mUriHeaders.clear();
402
403    mFileSource.clear();
404
405    delete mSuspensionState;
406    mSuspensionState = NULL;
407}
408
409void AwesomePlayer::notifyListener_l(int msg, int ext1, int ext2) {
410    if (mListener != NULL) {
411        sp<MediaPlayerBase> listener = mListener.promote();
412
413        if (listener != NULL) {
414            listener->sendEvent(msg, ext1, ext2);
415        }
416    }
417}
418
419void AwesomePlayer::onBufferingUpdate() {
420    Mutex::Autolock autoLock(mLock);
421    if (!mBufferingEventPending) {
422        return;
423    }
424    mBufferingEventPending = false;
425
426    int64_t durationUs;
427    {
428        Mutex::Autolock autoLock(mMiscStateLock);
429        durationUs = mDurationUs;
430    }
431
432    if (durationUs >= 0) {
433        int64_t cachedDurationUs = mPrefetcher->getCachedDurationUs();
434
435        LOGV("cache holds %.2f secs worth of data.", cachedDurationUs / 1E6);
436
437        int64_t positionUs;
438        getPosition(&positionUs);
439
440        cachedDurationUs += positionUs;
441
442        double percentage = (double)cachedDurationUs / durationUs;
443        notifyListener_l(MEDIA_BUFFERING_UPDATE, percentage * 100.0);
444
445        postBufferingEvent_l();
446    }
447}
448
449void AwesomePlayer::onStreamDone() {
450    // Posted whenever any stream finishes playing.
451
452    Mutex::Autolock autoLock(mLock);
453    if (!mStreamDoneEventPending) {
454        return;
455    }
456    mStreamDoneEventPending = false;
457
458    if (mStreamDoneStatus == ERROR_END_OF_STREAM && (mFlags & LOOPING)) {
459        seekTo_l(0);
460
461        if (mVideoSource != NULL) {
462            postVideoEvent_l();
463        }
464    } else {
465        if (mStreamDoneStatus == ERROR_END_OF_STREAM) {
466            LOGV("MEDIA_PLAYBACK_COMPLETE");
467            notifyListener_l(MEDIA_PLAYBACK_COMPLETE);
468        } else {
469            LOGV("MEDIA_ERROR %d", mStreamDoneStatus);
470
471            notifyListener_l(
472                    MEDIA_ERROR, MEDIA_ERROR_UNKNOWN, mStreamDoneStatus);
473        }
474
475        pause_l();
476
477        mFlags |= AT_EOS;
478    }
479}
480
481status_t AwesomePlayer::play() {
482    Mutex::Autolock autoLock(mLock);
483    return play_l();
484}
485
486status_t AwesomePlayer::play_l() {
487    if (mFlags & PLAYING) {
488        return OK;
489    }
490
491    if (!(mFlags & PREPARED)) {
492        status_t err = prepare_l();
493
494        if (err != OK) {
495            return err;
496        }
497    }
498
499    mFlags |= PLAYING;
500    mFlags |= FIRST_FRAME;
501
502    bool deferredAudioSeek = false;
503
504    if (mAudioSource != NULL) {
505        if (mAudioPlayer == NULL) {
506            if (mAudioSink != NULL) {
507                mAudioPlayer = new AudioPlayer(mAudioSink);
508                mAudioPlayer->setSource(mAudioSource);
509
510                // We've already started the MediaSource in order to enable
511                // the prefetcher to read its data.
512                status_t err = mAudioPlayer->start(
513                        true /* sourceAlreadyStarted */);
514
515                if (err != OK) {
516                    delete mAudioPlayer;
517                    mAudioPlayer = NULL;
518
519                    mFlags &= ~(PLAYING | FIRST_FRAME);
520
521                    return err;
522                }
523
524                delete mTimeSource;
525                mTimeSource = mAudioPlayer;
526
527                deferredAudioSeek = true;
528
529                mWatchForAudioSeekComplete = false;
530                mWatchForAudioEOS = true;
531            }
532        } else {
533            mAudioPlayer->resume();
534        }
535
536        postCheckAudioStatusEvent_l();
537    }
538
539    if (mTimeSource == NULL && mAudioPlayer == NULL) {
540        mTimeSource = new SystemTimeSource;
541    }
542
543    if (mVideoSource != NULL) {
544        // Kick off video playback
545        postVideoEvent_l();
546    }
547
548    if (deferredAudioSeek) {
549        // If there was a seek request while we were paused
550        // and we're just starting up again, honor the request now.
551        seekAudioIfNecessary_l();
552    }
553
554    postBufferingEvent_l();
555
556    if (mFlags & AT_EOS) {
557        // Legacy behaviour, if a stream finishes playing and then
558        // is started again, we play from the start...
559        seekTo_l(0);
560    }
561
562    return OK;
563}
564
565void AwesomePlayer::initRenderer_l() {
566    if (mISurface != NULL) {
567        sp<MetaData> meta = mVideoSource->getFormat();
568
569        int32_t format;
570        const char *component;
571        int32_t decodedWidth, decodedHeight;
572        CHECK(meta->findInt32(kKeyColorFormat, &format));
573        CHECK(meta->findCString(kKeyDecoderComponent, &component));
574        CHECK(meta->findInt32(kKeyWidth, &decodedWidth));
575        CHECK(meta->findInt32(kKeyHeight, &decodedHeight));
576
577        mVideoRenderer.clear();
578
579        // Must ensure that mVideoRenderer's destructor is actually executed
580        // before creating a new one.
581        IPCThreadState::self()->flushCommands();
582
583        if (!strncmp("OMX.", component, 4)) {
584            // Our OMX codecs allocate buffers on the media_server side
585            // therefore they require a remote IOMXRenderer that knows how
586            // to display them.
587            mVideoRenderer = new AwesomeRemoteRenderer(
588                mClient.interface()->createRenderer(
589                        mISurface, component,
590                        (OMX_COLOR_FORMATTYPE)format,
591                        decodedWidth, decodedHeight,
592                        mVideoWidth, mVideoHeight));
593        } else {
594            // Other decoders are instantiated locally and as a consequence
595            // allocate their buffers in local address space.
596            mVideoRenderer = new AwesomeLocalRenderer(
597                false,  // previewOnly
598                component,
599                (OMX_COLOR_FORMATTYPE)format,
600                mISurface,
601                mVideoWidth, mVideoHeight,
602                decodedWidth, decodedHeight);
603        }
604    }
605}
606
607status_t AwesomePlayer::pause() {
608    Mutex::Autolock autoLock(mLock);
609    return pause_l();
610}
611
612status_t AwesomePlayer::pause_l() {
613    if (!(mFlags & PLAYING)) {
614        return OK;
615    }
616
617    cancelPlayerEvents(true /* keepBufferingGoing */);
618
619    if (mAudioPlayer != NULL) {
620        mAudioPlayer->pause();
621    }
622
623    mFlags &= ~PLAYING;
624
625    return OK;
626}
627
628bool AwesomePlayer::isPlaying() const {
629    return mFlags & PLAYING;
630}
631
632void AwesomePlayer::setISurface(const sp<ISurface> &isurface) {
633    Mutex::Autolock autoLock(mLock);
634
635    mISurface = isurface;
636}
637
638void AwesomePlayer::setAudioSink(
639        const sp<MediaPlayerBase::AudioSink> &audioSink) {
640    Mutex::Autolock autoLock(mLock);
641
642    mAudioSink = audioSink;
643}
644
645status_t AwesomePlayer::setLooping(bool shouldLoop) {
646    Mutex::Autolock autoLock(mLock);
647
648    mFlags = mFlags & ~LOOPING;
649
650    if (shouldLoop) {
651        mFlags |= LOOPING;
652    }
653
654    return OK;
655}
656
657status_t AwesomePlayer::getDuration(int64_t *durationUs) {
658    Mutex::Autolock autoLock(mMiscStateLock);
659
660    if (mDurationUs < 0) {
661        return UNKNOWN_ERROR;
662    }
663
664    *durationUs = mDurationUs;
665
666    return OK;
667}
668
669status_t AwesomePlayer::getPosition(int64_t *positionUs) {
670    if (mVideoSource != NULL) {
671        Mutex::Autolock autoLock(mMiscStateLock);
672        *positionUs = mVideoTimeUs;
673    } else if (mAudioPlayer != NULL) {
674        *positionUs = mAudioPlayer->getMediaTimeUs();
675    } else {
676        *positionUs = 0;
677    }
678
679    return OK;
680}
681
682status_t AwesomePlayer::seekTo(int64_t timeUs) {
683    Mutex::Autolock autoLock(mLock);
684    return seekTo_l(timeUs);
685}
686
687status_t AwesomePlayer::seekTo_l(int64_t timeUs) {
688    mSeeking = true;
689    mSeekTimeUs = timeUs;
690    mFlags &= ~AT_EOS;
691
692    seekAudioIfNecessary_l();
693
694    return OK;
695}
696
697void AwesomePlayer::seekAudioIfNecessary_l() {
698    if (mSeeking && mVideoSource == NULL && mAudioPlayer != NULL) {
699        mAudioPlayer->seekTo(mSeekTimeUs);
700
701        mWatchForAudioSeekComplete = true;
702        mWatchForAudioEOS = true;
703        mSeeking = false;
704    }
705}
706
707status_t AwesomePlayer::getVideoDimensions(
708        int32_t *width, int32_t *height) const {
709    Mutex::Autolock autoLock(mLock);
710
711    if (mVideoWidth < 0 || mVideoHeight < 0) {
712        return UNKNOWN_ERROR;
713    }
714
715    *width = mVideoWidth;
716    *height = mVideoHeight;
717
718    return OK;
719}
720
721void AwesomePlayer::setAudioSource(sp<MediaSource> source) {
722    CHECK(source != NULL);
723
724    if (mPrefetcher != NULL) {
725        source = mPrefetcher->addSource(source);
726    }
727
728    mAudioTrack = source;
729}
730
731status_t AwesomePlayer::initAudioDecoder() {
732    sp<MetaData> meta = mAudioTrack->getFormat();
733
734    const char *mime;
735    CHECK(meta->findCString(kKeyMIMEType, &mime));
736
737    if (!strcasecmp(mime, MEDIA_MIMETYPE_AUDIO_RAW)) {
738        mAudioSource = mAudioTrack;
739    } else {
740        mAudioSource = OMXCodec::Create(
741                mClient.interface(), mAudioTrack->getFormat(),
742                false, // createEncoder
743                mAudioTrack);
744    }
745
746    if (mAudioSource != NULL) {
747        int64_t durationUs;
748        if (mAudioTrack->getFormat()->findInt64(kKeyDuration, &durationUs)) {
749            Mutex::Autolock autoLock(mMiscStateLock);
750            if (mDurationUs < 0 || durationUs > mDurationUs) {
751                mDurationUs = durationUs;
752            }
753        }
754    }
755
756    mAudioSource->start();
757
758    return mAudioSource != NULL ? OK : UNKNOWN_ERROR;
759}
760
761void AwesomePlayer::setVideoSource(sp<MediaSource> source) {
762    CHECK(source != NULL);
763
764    if (mPrefetcher != NULL) {
765        source = mPrefetcher->addSource(source);
766    }
767
768    mVideoTrack = source;
769}
770
771status_t AwesomePlayer::initVideoDecoder() {
772    mVideoSource = OMXCodec::Create(
773            mClient.interface(), mVideoTrack->getFormat(),
774            false, // createEncoder
775            mVideoTrack);
776
777    if (mVideoSource != NULL) {
778        int64_t durationUs;
779        if (mVideoTrack->getFormat()->findInt64(kKeyDuration, &durationUs)) {
780            Mutex::Autolock autoLock(mMiscStateLock);
781            if (mDurationUs < 0 || durationUs > mDurationUs) {
782                mDurationUs = durationUs;
783            }
784        }
785
786        CHECK(mVideoTrack->getFormat()->findInt32(kKeyWidth, &mVideoWidth));
787        CHECK(mVideoTrack->getFormat()->findInt32(kKeyHeight, &mVideoHeight));
788
789        mVideoSource->start();
790    }
791
792    return mVideoSource != NULL ? OK : UNKNOWN_ERROR;
793}
794
795void AwesomePlayer::onVideoEvent() {
796    Mutex::Autolock autoLock(mLock);
797    if (!mVideoEventPending) {
798        // The event has been cancelled in reset_l() but had already
799        // been scheduled for execution at that time.
800        return;
801    }
802    mVideoEventPending = false;
803
804    if (mSeeking) {
805        if (mLastVideoBuffer) {
806            mLastVideoBuffer->release();
807            mLastVideoBuffer = NULL;
808        }
809
810        if (mVideoBuffer) {
811            mVideoBuffer->release();
812            mVideoBuffer = NULL;
813        }
814    }
815
816    if (!mVideoBuffer) {
817        MediaSource::ReadOptions options;
818        if (mSeeking) {
819            LOGV("seeking to %lld us (%.2f secs)", mSeekTimeUs, mSeekTimeUs / 1E6);
820
821            options.setSeekTo(mSeekTimeUs);
822        }
823        for (;;) {
824            status_t err = mVideoSource->read(&mVideoBuffer, &options);
825            options.clearSeekTo();
826
827            if (err != OK) {
828                CHECK_EQ(mVideoBuffer, NULL);
829
830                if (err == INFO_FORMAT_CHANGED) {
831                    LOGV("VideoSource signalled format change.");
832
833                    if (mVideoRenderer != NULL) {
834                        mVideoRendererIsPreview = false;
835                        initRenderer_l();
836                    }
837                    continue;
838                }
839
840                postStreamDoneEvent_l(err);
841                return;
842            }
843
844            if (mVideoBuffer->range_length() == 0) {
845                // Some decoders, notably the PV AVC software decoder
846                // return spurious empty buffers that we just want to ignore.
847
848                mVideoBuffer->release();
849                mVideoBuffer = NULL;
850                continue;
851            }
852
853            break;
854        }
855    }
856
857    int64_t timeUs;
858    CHECK(mVideoBuffer->meta_data()->findInt64(kKeyTime, &timeUs));
859
860    {
861        Mutex::Autolock autoLock(mMiscStateLock);
862        mVideoTimeUs = timeUs;
863    }
864
865    if (mSeeking) {
866        if (mAudioPlayer != NULL) {
867            LOGV("seeking audio to %lld us (%.2f secs).", timeUs, timeUs / 1E6);
868
869            mAudioPlayer->seekTo(timeUs);
870            mWatchForAudioSeekComplete = true;
871            mWatchForAudioEOS = true;
872        } else {
873            // If we're playing video only, report seek complete now,
874            // otherwise audio player will notify us later.
875            notifyListener_l(MEDIA_SEEK_COMPLETE);
876        }
877
878        mFlags |= FIRST_FRAME;
879        mSeeking = false;
880    }
881
882    if (mFlags & FIRST_FRAME) {
883        mFlags &= ~FIRST_FRAME;
884
885        mTimeSourceDeltaUs = mTimeSource->getRealTimeUs() - timeUs;
886    }
887
888    int64_t realTimeUs, mediaTimeUs;
889    if (mAudioPlayer != NULL
890        && mAudioPlayer->getMediaTimeMapping(&realTimeUs, &mediaTimeUs)) {
891        mTimeSourceDeltaUs = realTimeUs - mediaTimeUs;
892    }
893
894    int64_t nowUs = mTimeSource->getRealTimeUs() - mTimeSourceDeltaUs;
895
896    int64_t latenessUs = nowUs - timeUs;
897
898    if (latenessUs > 40000) {
899        // We're more than 40ms late.
900        LOGV("we're late by %lld us (%.2f secs)", latenessUs, latenessUs / 1E6);
901
902        mVideoBuffer->release();
903        mVideoBuffer = NULL;
904
905        postVideoEvent_l();
906        return;
907    }
908
909    if (latenessUs < -10000) {
910        // We're more than 10ms early.
911
912        postVideoEvent_l(10000);
913        return;
914    }
915
916    if (mVideoRendererIsPreview || mVideoRenderer == NULL) {
917        mVideoRendererIsPreview = false;
918
919        initRenderer_l();
920    }
921
922    if (mVideoRenderer != NULL) {
923        mVideoRenderer->render(mVideoBuffer);
924    }
925
926    if (mLastVideoBuffer) {
927        mLastVideoBuffer->release();
928        mLastVideoBuffer = NULL;
929    }
930    mLastVideoBuffer = mVideoBuffer;
931    mVideoBuffer = NULL;
932
933    postVideoEvent_l();
934}
935
936void AwesomePlayer::postVideoEvent_l(int64_t delayUs) {
937    if (mVideoEventPending) {
938        return;
939    }
940
941    mVideoEventPending = true;
942    mQueue.postEventWithDelay(mVideoEvent, delayUs < 0 ? 10000 : delayUs);
943}
944
945void AwesomePlayer::postStreamDoneEvent_l(status_t status) {
946    if (mStreamDoneEventPending) {
947        return;
948    }
949    mStreamDoneEventPending = true;
950
951    mStreamDoneStatus = status;
952    mQueue.postEvent(mStreamDoneEvent);
953}
954
955void AwesomePlayer::postBufferingEvent_l() {
956    if (mPrefetcher == NULL) {
957        return;
958    }
959
960    if (mBufferingEventPending) {
961        return;
962    }
963    mBufferingEventPending = true;
964    mQueue.postEventWithDelay(mBufferingEvent, 1000000ll);
965}
966
967void AwesomePlayer::postCheckAudioStatusEvent_l() {
968    if (mAudioStatusEventPending) {
969        return;
970    }
971    mAudioStatusEventPending = true;
972    mQueue.postEventWithDelay(mCheckAudioStatusEvent, 100000ll);
973}
974
975void AwesomePlayer::onCheckAudioStatus() {
976    Mutex::Autolock autoLock(mLock);
977    if (!mAudioStatusEventPending) {
978        // Event was dispatched and while we were blocking on the mutex,
979        // has already been cancelled.
980        return;
981    }
982
983    mAudioStatusEventPending = false;
984
985    if (mWatchForAudioSeekComplete && !mAudioPlayer->isSeeking()) {
986        mWatchForAudioSeekComplete = false;
987        notifyListener_l(MEDIA_SEEK_COMPLETE);
988    }
989
990    status_t finalStatus;
991    if (mWatchForAudioEOS && mAudioPlayer->reachedEOS(&finalStatus)) {
992        mWatchForAudioEOS = false;
993        postStreamDoneEvent_l(finalStatus);
994    }
995
996    postCheckAudioStatusEvent_l();
997}
998
999status_t AwesomePlayer::prepare() {
1000    Mutex::Autolock autoLock(mLock);
1001    return prepare_l();
1002}
1003
1004status_t AwesomePlayer::prepare_l() {
1005    if (mFlags & PREPARED) {
1006        return OK;
1007    }
1008
1009    if (mFlags & PREPARING) {
1010        return UNKNOWN_ERROR;
1011    }
1012
1013    mIsAsyncPrepare = false;
1014    status_t err = prepareAsync_l();
1015
1016    if (err != OK) {
1017        return err;
1018    }
1019
1020    while (mFlags & PREPARING) {
1021        mPreparedCondition.wait(mLock);
1022    }
1023
1024    return mPrepareResult;
1025}
1026
1027status_t AwesomePlayer::prepareAsync() {
1028    Mutex::Autolock autoLock(mLock);
1029
1030    if (mFlags & PREPARING) {
1031        return UNKNOWN_ERROR;  // async prepare already pending
1032    }
1033
1034    mIsAsyncPrepare = true;
1035    return prepareAsync_l();
1036}
1037
1038status_t AwesomePlayer::prepareAsync_l() {
1039    if (mFlags & PREPARING) {
1040        return UNKNOWN_ERROR;  // async prepare already pending
1041    }
1042
1043    if (!mQueueStarted) {
1044        mQueue.start();
1045        mQueueStarted = true;
1046    }
1047
1048    mFlags |= PREPARING;
1049    mAsyncPrepareEvent = new AwesomeEvent(
1050            this, &AwesomePlayer::onPrepareAsyncEvent);
1051
1052    mQueue.postEvent(mAsyncPrepareEvent);
1053
1054    return OK;
1055}
1056
1057status_t AwesomePlayer::finishSetDataSource_l() {
1058    sp<DataSource> dataSource;
1059
1060    if (!strncasecmp("http://", mUri.string(), 7)) {
1061        mConnectingDataSource = new HTTPDataSource(mUri, &mUriHeaders);
1062
1063        mLock.unlock();
1064        status_t err = mConnectingDataSource->connect();
1065        mLock.lock();
1066
1067        if (err != OK) {
1068            mConnectingDataSource.clear();
1069
1070            LOGI("mConnectingDataSource->connect() returned %d", err);
1071            return err;
1072        }
1073
1074        dataSource = new CachingDataSource(
1075                mConnectingDataSource, 32 * 1024, 20);
1076
1077        mConnectingDataSource.clear();
1078    } else {
1079        dataSource = DataSource::CreateFromURI(mUri.string(), &mUriHeaders);
1080    }
1081
1082    if (dataSource == NULL) {
1083        return UNKNOWN_ERROR;
1084    }
1085
1086    sp<MediaExtractor> extractor = MediaExtractor::Create(dataSource);
1087
1088    if (extractor == NULL) {
1089        return UNKNOWN_ERROR;
1090    }
1091
1092    if (dataSource->flags() & DataSource::kWantsPrefetching) {
1093        mPrefetcher = new Prefetcher;
1094    }
1095
1096    return setDataSource_l(extractor);
1097}
1098
1099void AwesomePlayer::abortPrepare(status_t err) {
1100    CHECK(err != OK);
1101
1102    if (mIsAsyncPrepare) {
1103        notifyListener_l(MEDIA_ERROR, MEDIA_ERROR_UNKNOWN, err);
1104    }
1105
1106    mPrepareResult = err;
1107    mFlags &= ~(PREPARING|PREPARE_CANCELLED);
1108    mAsyncPrepareEvent = NULL;
1109    mPreparedCondition.broadcast();
1110}
1111
1112// static
1113bool AwesomePlayer::ContinuePreparation(void *cookie) {
1114    AwesomePlayer *me = static_cast<AwesomePlayer *>(cookie);
1115
1116    return (me->mFlags & PREPARE_CANCELLED) == 0;
1117}
1118
1119void AwesomePlayer::onPrepareAsyncEvent() {
1120    sp<Prefetcher> prefetcher;
1121
1122    {
1123        Mutex::Autolock autoLock(mLock);
1124
1125        if (mFlags & PREPARE_CANCELLED) {
1126            LOGI("prepare was cancelled before doing anything");
1127            abortPrepare(UNKNOWN_ERROR);
1128            return;
1129        }
1130
1131        if (mUri.size() > 0) {
1132            status_t err = finishSetDataSource_l();
1133
1134            if (err != OK) {
1135                abortPrepare(err);
1136                return;
1137            }
1138        }
1139
1140        if (mVideoTrack != NULL && mVideoSource == NULL) {
1141            status_t err = initVideoDecoder();
1142
1143            if (err != OK) {
1144                abortPrepare(err);
1145                return;
1146            }
1147        }
1148
1149        if (mAudioTrack != NULL && mAudioSource == NULL) {
1150            status_t err = initAudioDecoder();
1151
1152            if (err != OK) {
1153                abortPrepare(err);
1154                return;
1155            }
1156        }
1157
1158        prefetcher = mPrefetcher;
1159    }
1160
1161    if (prefetcher != NULL) {
1162        {
1163            Mutex::Autolock autoLock(mLock);
1164            if (mFlags & PREPARE_CANCELLED) {
1165                LOGI("prepare was cancelled before preparing the prefetcher");
1166
1167                prefetcher.clear();
1168                abortPrepare(UNKNOWN_ERROR);
1169                return;
1170            }
1171        }
1172
1173        LOGI("calling prefetcher->prepare()");
1174        status_t result =
1175            prefetcher->prepare(&AwesomePlayer::ContinuePreparation, this);
1176
1177        prefetcher.clear();
1178
1179        if (result == OK) {
1180            LOGI("prefetcher is done preparing");
1181        } else {
1182            Mutex::Autolock autoLock(mLock);
1183
1184            CHECK_EQ(result, -EINTR);
1185
1186            LOGI("prefetcher->prepare() was cancelled early.");
1187            abortPrepare(UNKNOWN_ERROR);
1188            return;
1189        }
1190    }
1191
1192    Mutex::Autolock autoLock(mLock);
1193
1194    if (mIsAsyncPrepare) {
1195        if (mVideoWidth < 0 || mVideoHeight < 0) {
1196            notifyListener_l(MEDIA_SET_VIDEO_SIZE, 0, 0);
1197        } else {
1198            notifyListener_l(MEDIA_SET_VIDEO_SIZE, mVideoWidth, mVideoHeight);
1199        }
1200
1201        notifyListener_l(MEDIA_PREPARED);
1202    }
1203
1204    mPrepareResult = OK;
1205    mFlags &= ~(PREPARING|PREPARE_CANCELLED);
1206    mFlags |= PREPARED;
1207    mAsyncPrepareEvent = NULL;
1208    mPreparedCondition.broadcast();
1209}
1210
1211status_t AwesomePlayer::suspend() {
1212    LOGV("suspend");
1213    Mutex::Autolock autoLock(mLock);
1214
1215    if (mSuspensionState != NULL) {
1216        return INVALID_OPERATION;
1217    }
1218
1219    if (mFlags & PREPARING) {
1220        mFlags |= PREPARE_CANCELLED;
1221        if (mConnectingDataSource != NULL) {
1222            LOGI("interrupting the connection process");
1223            mConnectingDataSource->disconnect();
1224        }
1225    }
1226
1227    while (mFlags & PREPARING) {
1228        mPreparedCondition.wait(mLock);
1229    }
1230
1231    SuspensionState *state = new SuspensionState;
1232    state->mUri = mUri;
1233    state->mUriHeaders = mUriHeaders;
1234    state->mFileSource = mFileSource;
1235
1236    state->mFlags = mFlags & (PLAYING | LOOPING | AT_EOS);
1237    getPosition(&state->mPositionUs);
1238
1239    if (mLastVideoBuffer) {
1240        size_t size = mLastVideoBuffer->range_length();
1241        if (size) {
1242            state->mLastVideoFrameSize = size;
1243            state->mLastVideoFrame = malloc(size);
1244            memcpy(state->mLastVideoFrame,
1245                   (const uint8_t *)mLastVideoBuffer->data()
1246                        + mLastVideoBuffer->range_offset(),
1247                   size);
1248
1249            state->mVideoWidth = mVideoWidth;
1250            state->mVideoHeight = mVideoHeight;
1251
1252            sp<MetaData> meta = mVideoSource->getFormat();
1253            CHECK(meta->findInt32(kKeyColorFormat, &state->mColorFormat));
1254            CHECK(meta->findInt32(kKeyWidth, &state->mDecodedWidth));
1255            CHECK(meta->findInt32(kKeyHeight, &state->mDecodedHeight));
1256        }
1257    }
1258
1259    reset_l();
1260
1261    mSuspensionState = state;
1262
1263    return OK;
1264}
1265
1266status_t AwesomePlayer::resume() {
1267    LOGV("resume");
1268    Mutex::Autolock autoLock(mLock);
1269
1270    if (mSuspensionState == NULL) {
1271        return INVALID_OPERATION;
1272    }
1273
1274    SuspensionState *state = mSuspensionState;
1275    mSuspensionState = NULL;
1276
1277    status_t err;
1278    if (state->mFileSource != NULL) {
1279        err = setDataSource_l(state->mFileSource);
1280
1281        if (err == OK) {
1282            mFileSource = state->mFileSource;
1283        }
1284    } else {
1285        err = setDataSource_l(state->mUri, &state->mUriHeaders);
1286    }
1287
1288    if (err != OK) {
1289        delete state;
1290        state = NULL;
1291
1292        return err;
1293    }
1294
1295    seekTo_l(state->mPositionUs);
1296
1297    mFlags = state->mFlags & (LOOPING | AT_EOS);
1298
1299    if (state->mLastVideoFrame && mISurface != NULL) {
1300        mVideoRenderer =
1301            new AwesomeLocalRenderer(
1302                    true,  // previewOnly
1303                    "",
1304                    (OMX_COLOR_FORMATTYPE)state->mColorFormat,
1305                    mISurface,
1306                    state->mVideoWidth,
1307                    state->mVideoHeight,
1308                    state->mDecodedWidth,
1309                    state->mDecodedHeight);
1310
1311        mVideoRendererIsPreview = true;
1312
1313        ((AwesomeLocalRenderer *)mVideoRenderer.get())->render(
1314                state->mLastVideoFrame, state->mLastVideoFrameSize);
1315    }
1316
1317    if (state->mFlags & PLAYING) {
1318        play_l();
1319    }
1320
1321    delete state;
1322    state = NULL;
1323
1324    return OK;
1325}
1326
1327}  // namespace android
1328
1329