AwesomePlayer.cpp revision 8650e1960905097f6f1d6aa462ccb1c93c656834
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/ARTSPController.h"
24#include "include/AwesomePlayer.h"
25#include "include/LiveSource.h"
26#include "include/SoftwareRenderer.h"
27#include "include/NuCachedSource2.h"
28#include "include/ThrottledSource.h"
29
30#include "ARTPSession.h"
31#include "APacketSource.h"
32#include "ASessionDescription.h"
33#include "UDPPusher.h"
34
35#include <binder/IPCThreadState.h>
36#include <media/stagefright/AudioPlayer.h>
37#include <media/stagefright/DataSource.h>
38#include <media/stagefright/FileSource.h>
39#include <media/stagefright/MediaBuffer.h>
40#include <media/stagefright/MediaDefs.h>
41#include <media/stagefright/MediaExtractor.h>
42#include <media/stagefright/MediaDebug.h>
43#include <media/stagefright/MediaSource.h>
44#include <media/stagefright/MetaData.h>
45#include <media/stagefright/OMXCodec.h>
46
47#include <surfaceflinger/ISurface.h>
48
49#include <media/stagefright/foundation/ALooper.h>
50
51namespace android {
52
53static int64_t kLowWaterMarkUs = 2000000ll;  // 2secs
54static int64_t kHighWaterMarkUs = 10000000ll;  // 10secs
55
56struct AwesomeEvent : public TimedEventQueue::Event {
57    AwesomeEvent(
58            AwesomePlayer *player,
59            void (AwesomePlayer::*method)())
60        : mPlayer(player),
61          mMethod(method) {
62    }
63
64protected:
65    virtual ~AwesomeEvent() {}
66
67    virtual void fire(TimedEventQueue *queue, int64_t /* now_us */) {
68        (mPlayer->*mMethod)();
69    }
70
71private:
72    AwesomePlayer *mPlayer;
73    void (AwesomePlayer::*mMethod)();
74
75    AwesomeEvent(const AwesomeEvent &);
76    AwesomeEvent &operator=(const AwesomeEvent &);
77};
78
79struct AwesomeRemoteRenderer : public AwesomeRenderer {
80    AwesomeRemoteRenderer(const sp<IOMXRenderer> &target)
81        : mTarget(target) {
82    }
83
84    virtual void render(MediaBuffer *buffer) {
85        void *id;
86        if (buffer->meta_data()->findPointer(kKeyBufferID, &id)) {
87            mTarget->render((IOMX::buffer_id)id);
88        }
89    }
90
91private:
92    sp<IOMXRenderer> mTarget;
93
94    AwesomeRemoteRenderer(const AwesomeRemoteRenderer &);
95    AwesomeRemoteRenderer &operator=(const AwesomeRemoteRenderer &);
96};
97
98struct AwesomeLocalRenderer : public AwesomeRenderer {
99    AwesomeLocalRenderer(
100            bool previewOnly,
101            const char *componentName,
102            OMX_COLOR_FORMATTYPE colorFormat,
103            const sp<ISurface> &surface,
104            size_t displayWidth, size_t displayHeight,
105            size_t decodedWidth, size_t decodedHeight)
106        : mTarget(NULL),
107          mLibHandle(NULL) {
108            init(previewOnly, componentName,
109                 colorFormat, surface, displayWidth,
110                 displayHeight, decodedWidth, decodedHeight);
111    }
112
113    virtual void render(MediaBuffer *buffer) {
114        render((const uint8_t *)buffer->data() + buffer->range_offset(),
115               buffer->range_length());
116    }
117
118    void render(const void *data, size_t size) {
119        mTarget->render(data, size, NULL);
120    }
121
122protected:
123    virtual ~AwesomeLocalRenderer() {
124        delete mTarget;
125        mTarget = NULL;
126
127        if (mLibHandle) {
128            dlclose(mLibHandle);
129            mLibHandle = NULL;
130        }
131    }
132
133private:
134    VideoRenderer *mTarget;
135    void *mLibHandle;
136
137    void 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
145    AwesomeLocalRenderer(const AwesomeLocalRenderer &);
146    AwesomeLocalRenderer &operator=(const AwesomeLocalRenderer &);;
147};
148
149void AwesomeLocalRenderer::init(
150        bool previewOnly,
151        const char *componentName,
152        OMX_COLOR_FORMATTYPE colorFormat,
153        const sp<ISurface> &surface,
154        size_t displayWidth, size_t displayHeight,
155        size_t decodedWidth, size_t decodedHeight) {
156    if (!previewOnly) {
157        // We will stick to the vanilla software-color-converting renderer
158        // for "previewOnly" mode, to avoid unneccessarily switching overlays
159        // more often than necessary.
160
161        mLibHandle = dlopen("libstagefrighthw.so", RTLD_NOW);
162
163        if (mLibHandle) {
164            typedef VideoRenderer *(*CreateRendererFunc)(
165                    const sp<ISurface> &surface,
166                    const char *componentName,
167                    OMX_COLOR_FORMATTYPE colorFormat,
168                    size_t displayWidth, size_t displayHeight,
169                    size_t decodedWidth, size_t decodedHeight);
170
171            CreateRendererFunc func =
172                (CreateRendererFunc)dlsym(
173                        mLibHandle,
174                        "_Z14createRendererRKN7android2spINS_8ISurfaceEEEPKc20"
175                        "OMX_COLOR_FORMATTYPEjjjj");
176
177            if (func) {
178                mTarget =
179                    (*func)(surface, componentName, colorFormat,
180                        displayWidth, displayHeight,
181                        decodedWidth, decodedHeight);
182            }
183        }
184    }
185
186    if (mTarget == NULL) {
187        mTarget = new SoftwareRenderer(
188                colorFormat, surface, displayWidth, displayHeight,
189                decodedWidth, decodedHeight);
190    }
191}
192
193AwesomePlayer::AwesomePlayer()
194    : mQueueStarted(false),
195      mTimeSource(NULL),
196      mVideoRendererIsPreview(false),
197      mAudioPlayer(NULL),
198      mFlags(0),
199      mExtractorFlags(0),
200      mLastVideoBuffer(NULL),
201      mVideoBuffer(NULL),
202      mSuspensionState(NULL) {
203    CHECK_EQ(mClient.connect(), OK);
204
205    DataSource::RegisterDefaultSniffers();
206
207    mVideoEvent = new AwesomeEvent(this, &AwesomePlayer::onVideoEvent);
208    mVideoEventPending = false;
209    mStreamDoneEvent = new AwesomeEvent(this, &AwesomePlayer::onStreamDone);
210    mStreamDoneEventPending = false;
211    mBufferingEvent = new AwesomeEvent(this, &AwesomePlayer::onBufferingUpdate);
212    mBufferingEventPending = false;
213
214    mCheckAudioStatusEvent = new AwesomeEvent(
215            this, &AwesomePlayer::onCheckAudioStatus);
216
217    mAudioStatusEventPending = false;
218
219    reset();
220}
221
222AwesomePlayer::~AwesomePlayer() {
223    if (mQueueStarted) {
224        mQueue.stop();
225    }
226
227    reset();
228
229    mClient.disconnect();
230}
231
232void AwesomePlayer::cancelPlayerEvents(bool keepBufferingGoing) {
233    mQueue.cancelEvent(mVideoEvent->eventID());
234    mVideoEventPending = false;
235    mQueue.cancelEvent(mStreamDoneEvent->eventID());
236    mStreamDoneEventPending = false;
237    mQueue.cancelEvent(mCheckAudioStatusEvent->eventID());
238    mAudioStatusEventPending = false;
239
240    if (!keepBufferingGoing) {
241        mQueue.cancelEvent(mBufferingEvent->eventID());
242        mBufferingEventPending = false;
243    }
244}
245
246void AwesomePlayer::setListener(const wp<MediaPlayerBase> &listener) {
247    Mutex::Autolock autoLock(mLock);
248    mListener = listener;
249}
250
251status_t AwesomePlayer::setDataSource(
252        const char *uri, const KeyedVector<String8, String8> *headers) {
253    Mutex::Autolock autoLock(mLock);
254    return setDataSource_l(uri, headers);
255}
256
257status_t AwesomePlayer::setDataSource_l(
258        const char *uri, const KeyedVector<String8, String8> *headers) {
259    reset_l();
260
261    mUri = uri;
262
263    if (headers) {
264        mUriHeaders = *headers;
265    }
266
267    // The actual work will be done during preparation in the call to
268    // ::finishSetDataSource_l to avoid blocking the calling thread in
269    // setDataSource for any significant time.
270
271    return OK;
272}
273
274status_t AwesomePlayer::setDataSource(
275        int fd, int64_t offset, int64_t length) {
276#if 0
277    // return setDataSource("httplive://qthttp.apple.com.edgesuite.net/1009qpeijrfn/sl.m3u8");
278    return setDataSource("httplive://qthttp.apple.com.edgesuite.net/1009qpeijrfn/0440.m3u8");
279    // return setDataSource("httplive://qthttp.apple.com.edgesuite.net/1009qpeijrfn/0640.m3u8");
280    // return setDataSource("httplive://qthttp.apple.com.edgesuite.net/1009qpeijrfn/1240_vod.m3u8");
281    // return setDataSource("httplive://iphoned5.akamai.com.edgesuite.net/mhbarron/nasatv/nasatv_96.m3u8");
282    // return setDataSource("httplive://iphoned5.akamai.com.edgesuite.net/mhbarron/nasatv/nasatv_1500.m3u8");
283    // return setDataSource("httplive://iphone.video.hsn.com/iPhone_high.m3u8");
284    // return setDataSource("httplive://iphoned5.akamai.com.edgesuite.net/mhbarron/iphonewebcast/webcast090209_all/webcast090209_all.m3u8");
285    // return setDataSource("httplive://qthttp.akamai.com.edgesuite.net/iphone_demo/Video_Content/usat/tt_062209_iphone/hi/prog_index.m3u8");
286    // return setDataSource("httplive://qthttp.akamai.com.edgesuite.net/iphone_demo/Video_Content/usat/tt_googmaps/hi/prog_index.m3u8");
287    // return setDataSource("httplive://qthttp.akamai.com.edgesuite.net/iphone_demo/Video_Content/mtv/ni_spo_25a_rt74137_clip_syn/hi/prog_index.m3u8");
288#endif
289
290    Mutex::Autolock autoLock(mLock);
291
292    reset_l();
293
294    sp<DataSource> dataSource = new FileSource(fd, offset, length);
295
296    status_t err = dataSource->initCheck();
297
298    if (err != OK) {
299        return err;
300    }
301
302    mFileSource = dataSource;
303
304    return setDataSource_l(dataSource);
305}
306
307status_t AwesomePlayer::setDataSource_l(
308        const sp<DataSource> &dataSource) {
309    sp<MediaExtractor> extractor = MediaExtractor::Create(dataSource);
310
311    if (extractor == NULL) {
312        return UNKNOWN_ERROR;
313    }
314
315    return setDataSource_l(extractor);
316}
317
318status_t AwesomePlayer::setDataSource_l(const sp<MediaExtractor> &extractor) {
319    bool haveAudio = false;
320    bool haveVideo = false;
321    for (size_t i = 0; i < extractor->countTracks(); ++i) {
322        sp<MetaData> meta = extractor->getTrackMetaData(i);
323
324        const char *mime;
325        CHECK(meta->findCString(kKeyMIMEType, &mime));
326
327        if (!haveVideo && !strncasecmp(mime, "video/", 6)) {
328            setVideoSource(extractor->getTrack(i));
329            haveVideo = true;
330        } else if (!haveAudio && !strncasecmp(mime, "audio/", 6)) {
331            setAudioSource(extractor->getTrack(i));
332            haveAudio = true;
333        }
334
335        if (haveAudio && haveVideo) {
336            break;
337        }
338    }
339
340    if (!haveAudio && !haveVideo) {
341        return UNKNOWN_ERROR;
342    }
343
344    mExtractorFlags = extractor->flags();
345
346    return OK;
347}
348
349void AwesomePlayer::reset() {
350    Mutex::Autolock autoLock(mLock);
351    reset_l();
352}
353
354void AwesomePlayer::reset_l() {
355    if (mFlags & PREPARING) {
356        mFlags |= PREPARE_CANCELLED;
357        if (mConnectingDataSource != NULL) {
358            LOGI("interrupting the connection process");
359            mConnectingDataSource->disconnect();
360        }
361    }
362
363    while (mFlags & PREPARING) {
364        mPreparedCondition.wait(mLock);
365    }
366
367    cancelPlayerEvents();
368
369    mCachedSource.clear();
370    mAudioTrack.clear();
371    mVideoTrack.clear();
372
373    // Shutdown audio first, so that the respone to the reset request
374    // appears to happen instantaneously as far as the user is concerned
375    // If we did this later, audio would continue playing while we
376    // shutdown the video-related resources and the player appear to
377    // not be as responsive to a reset request.
378    if (mAudioPlayer == NULL && mAudioSource != NULL) {
379        // If we had an audio player, it would have effectively
380        // taken possession of the audio source and stopped it when
381        // _it_ is stopped. Otherwise this is still our responsibility.
382        mAudioSource->stop();
383    }
384    mAudioSource.clear();
385
386    mTimeSource = NULL;
387
388    delete mAudioPlayer;
389    mAudioPlayer = NULL;
390
391    mVideoRenderer.clear();
392
393    if (mLastVideoBuffer) {
394        mLastVideoBuffer->release();
395        mLastVideoBuffer = NULL;
396    }
397
398    if (mVideoBuffer) {
399        mVideoBuffer->release();
400        mVideoBuffer = NULL;
401    }
402
403    if (mRTSPController != NULL) {
404        mRTSPController->disconnect();
405        mRTSPController.clear();
406    }
407
408    mRTPPusher.clear();
409    mRTCPPusher.clear();
410    mRTPSession.clear();
411
412    if (mVideoSource != NULL) {
413        mVideoSource->stop();
414
415        // The following hack is necessary to ensure that the OMX
416        // component is completely released by the time we may try
417        // to instantiate it again.
418        wp<MediaSource> tmp = mVideoSource;
419        mVideoSource.clear();
420        while (tmp.promote() != NULL) {
421            usleep(1000);
422        }
423        IPCThreadState::self()->flushCommands();
424    }
425
426    mDurationUs = -1;
427    mFlags = 0;
428    mExtractorFlags = 0;
429    mVideoWidth = mVideoHeight = -1;
430    mTimeSourceDeltaUs = 0;
431    mVideoTimeUs = 0;
432
433    mSeeking = false;
434    mSeekNotificationSent = false;
435    mSeekTimeUs = 0;
436
437    mUri.setTo("");
438    mUriHeaders.clear();
439
440    mFileSource.clear();
441
442    delete mSuspensionState;
443    mSuspensionState = NULL;
444}
445
446void AwesomePlayer::notifyListener_l(int msg, int ext1, int ext2) {
447    if (mListener != NULL) {
448        sp<MediaPlayerBase> listener = mListener.promote();
449
450        if (listener != NULL) {
451            listener->sendEvent(msg, ext1, ext2);
452        }
453    }
454}
455
456// Returns true iff cached duration is available/applicable.
457bool AwesomePlayer::getCachedDuration_l(int64_t *durationUs, bool *eos) {
458    off_t totalSize;
459
460    if (mRTSPController != NULL) {
461        *durationUs = mRTSPController->getQueueDurationUs(eos);
462        return true;
463    } else if (mCachedSource != NULL && mDurationUs >= 0
464            && mCachedSource->getSize(&totalSize) == OK) {
465        int64_t bitrate = totalSize * 8000000ll / mDurationUs;  // in bits/sec
466
467        size_t cachedDataRemaining = mCachedSource->approxDataRemaining(eos);
468        *durationUs = cachedDataRemaining * 8000000ll / bitrate;
469        return true;
470    }
471
472    return false;
473}
474
475void AwesomePlayer::onBufferingUpdate() {
476    Mutex::Autolock autoLock(mLock);
477    if (!mBufferingEventPending) {
478        return;
479    }
480    mBufferingEventPending = false;
481
482    if (mCachedSource != NULL) {
483        bool eos;
484        size_t cachedDataRemaining = mCachedSource->approxDataRemaining(&eos);
485
486        if (eos) {
487            notifyListener_l(MEDIA_BUFFERING_UPDATE, 100);
488        } else {
489            off_t size;
490            if (mDurationUs >= 0 && mCachedSource->getSize(&size) == OK) {
491                int64_t bitrate = size * 8000000ll / mDurationUs;  // in bits/sec
492
493                size_t cachedSize = mCachedSource->cachedSize();
494                int64_t cachedDurationUs = cachedSize * 8000000ll / bitrate;
495
496                int percentage = 100.0 * (double)cachedDurationUs / mDurationUs;
497                if (percentage > 100) {
498                    percentage = 100;
499                }
500
501                notifyListener_l(MEDIA_BUFFERING_UPDATE, percentage);
502            } else {
503                // We don't know the bitrate of the stream, use absolute size
504                // limits to maintain the cache.
505
506                const size_t kLowWaterMarkBytes = 400000;
507                const size_t kHighWaterMarkBytes = 1000000;
508
509                if ((mFlags & PLAYING) && !eos
510                        && (cachedDataRemaining < kLowWaterMarkBytes)) {
511                    LOGI("cache is running low (< %d) , pausing.",
512                         kLowWaterMarkBytes);
513                    mFlags |= CACHE_UNDERRUN;
514                    pause_l();
515                    notifyListener_l(MEDIA_INFO, MEDIA_INFO_BUFFERING_START);
516                } else if (eos || cachedDataRemaining > kHighWaterMarkBytes) {
517                    if (mFlags & CACHE_UNDERRUN) {
518                        LOGI("cache has filled up (> %d), resuming.",
519                             kHighWaterMarkBytes);
520                        mFlags &= ~CACHE_UNDERRUN;
521                        play_l();
522                        notifyListener_l(MEDIA_INFO, MEDIA_INFO_BUFFERING_END);
523                    } else if (mFlags & PREPARING) {
524                        LOGV("cache has filled up (> %d), prepare is done",
525                             kHighWaterMarkBytes);
526                        finishAsyncPrepare_l();
527                    }
528                }
529            }
530        }
531    }
532
533    int64_t cachedDurationUs;
534    bool eos;
535    if (getCachedDuration_l(&cachedDurationUs, &eos)) {
536        if ((mFlags & PLAYING) && !eos
537                && (cachedDurationUs < kLowWaterMarkUs)) {
538            LOGI("cache is running low (%.2f secs) , pausing.",
539                 cachedDurationUs / 1E6);
540            mFlags |= CACHE_UNDERRUN;
541            pause_l();
542            notifyListener_l(MEDIA_INFO, MEDIA_INFO_BUFFERING_START);
543        } else if (eos || cachedDurationUs > kHighWaterMarkUs) {
544            if (mFlags & CACHE_UNDERRUN) {
545                LOGI("cache has filled up (%.2f secs), resuming.",
546                     cachedDurationUs / 1E6);
547                mFlags &= ~CACHE_UNDERRUN;
548                play_l();
549                notifyListener_l(MEDIA_INFO, MEDIA_INFO_BUFFERING_END);
550            } else if (mFlags & PREPARING) {
551                LOGV("cache has filled up (%.2f secs), prepare is done",
552                     cachedDurationUs / 1E6);
553                finishAsyncPrepare_l();
554            }
555        }
556    }
557
558    postBufferingEvent_l();
559}
560
561void AwesomePlayer::onStreamDone() {
562    // Posted whenever any stream finishes playing.
563
564    Mutex::Autolock autoLock(mLock);
565    if (!mStreamDoneEventPending) {
566        return;
567    }
568    mStreamDoneEventPending = false;
569
570    if (mStreamDoneStatus != ERROR_END_OF_STREAM) {
571        LOGV("MEDIA_ERROR %d", mStreamDoneStatus);
572
573        notifyListener_l(
574                MEDIA_ERROR, MEDIA_ERROR_UNKNOWN, mStreamDoneStatus);
575
576        pause_l();
577
578        mFlags |= AT_EOS;
579        return;
580    }
581
582    const bool allDone =
583        (mVideoSource == NULL || (mFlags & VIDEO_AT_EOS))
584            && (mAudioSource == NULL || (mFlags & AUDIO_AT_EOS));
585
586    if (!allDone) {
587        return;
588    }
589
590    if (mFlags & LOOPING) {
591        seekTo_l(0);
592
593        if (mVideoSource != NULL) {
594            postVideoEvent_l();
595        }
596    } else {
597        LOGV("MEDIA_PLAYBACK_COMPLETE");
598        notifyListener_l(MEDIA_PLAYBACK_COMPLETE);
599
600        pause_l();
601
602        mFlags |= AT_EOS;
603    }
604}
605
606status_t AwesomePlayer::play() {
607    Mutex::Autolock autoLock(mLock);
608
609    mFlags &= ~CACHE_UNDERRUN;
610
611    return play_l();
612}
613
614status_t AwesomePlayer::play_l() {
615    if (mFlags & PLAYING) {
616        return OK;
617    }
618
619    if (!(mFlags & PREPARED)) {
620        status_t err = prepare_l();
621
622        if (err != OK) {
623            return err;
624        }
625    }
626
627    mFlags |= PLAYING;
628    mFlags |= FIRST_FRAME;
629
630    bool deferredAudioSeek = false;
631
632    if (mAudioSource != NULL) {
633        if (mAudioPlayer == NULL) {
634            if (mAudioSink != NULL) {
635                mAudioPlayer = new AudioPlayer(mAudioSink);
636                mAudioPlayer->setSource(mAudioSource);
637
638                // We've already started the MediaSource in order to enable
639                // the prefetcher to read its data.
640                status_t err = mAudioPlayer->start(
641                        true /* sourceAlreadyStarted */);
642
643                if (err != OK) {
644                    delete mAudioPlayer;
645                    mAudioPlayer = NULL;
646
647                    mFlags &= ~(PLAYING | FIRST_FRAME);
648
649                    return err;
650                }
651
652                mTimeSource = mAudioPlayer;
653
654                deferredAudioSeek = true;
655
656                mWatchForAudioSeekComplete = false;
657                mWatchForAudioEOS = true;
658            }
659        } else {
660            mAudioPlayer->resume();
661        }
662
663        postCheckAudioStatusEvent_l();
664    }
665
666    if (mTimeSource == NULL && mAudioPlayer == NULL) {
667        mTimeSource = &mSystemTimeSource;
668    }
669
670    if (mVideoSource != NULL) {
671        // Kick off video playback
672        postVideoEvent_l();
673    }
674
675    if (deferredAudioSeek) {
676        // If there was a seek request while we were paused
677        // and we're just starting up again, honor the request now.
678        seekAudioIfNecessary_l();
679    }
680
681    if (mFlags & AT_EOS) {
682        // Legacy behaviour, if a stream finishes playing and then
683        // is started again, we play from the start...
684        seekTo_l(0);
685    }
686
687    return OK;
688}
689
690void AwesomePlayer::initRenderer_l() {
691    if (mISurface != NULL) {
692        sp<MetaData> meta = mVideoSource->getFormat();
693
694        int32_t format;
695        const char *component;
696        int32_t decodedWidth, decodedHeight;
697        CHECK(meta->findInt32(kKeyColorFormat, &format));
698        CHECK(meta->findCString(kKeyDecoderComponent, &component));
699        CHECK(meta->findInt32(kKeyWidth, &decodedWidth));
700        CHECK(meta->findInt32(kKeyHeight, &decodedHeight));
701
702        mVideoRenderer.clear();
703
704        // Must ensure that mVideoRenderer's destructor is actually executed
705        // before creating a new one.
706        IPCThreadState::self()->flushCommands();
707
708        if (!strncmp("OMX.", component, 4)) {
709            // Our OMX codecs allocate buffers on the media_server side
710            // therefore they require a remote IOMXRenderer that knows how
711            // to display them.
712            mVideoRenderer = new AwesomeRemoteRenderer(
713                mClient.interface()->createRenderer(
714                        mISurface, component,
715                        (OMX_COLOR_FORMATTYPE)format,
716                        decodedWidth, decodedHeight,
717                        mVideoWidth, mVideoHeight));
718        } else {
719            // Other decoders are instantiated locally and as a consequence
720            // allocate their buffers in local address space.
721            mVideoRenderer = new AwesomeLocalRenderer(
722                false,  // previewOnly
723                component,
724                (OMX_COLOR_FORMATTYPE)format,
725                mISurface,
726                mVideoWidth, mVideoHeight,
727                decodedWidth, decodedHeight);
728        }
729    }
730}
731
732status_t AwesomePlayer::pause() {
733    Mutex::Autolock autoLock(mLock);
734
735    mFlags &= ~CACHE_UNDERRUN;
736
737    return pause_l();
738}
739
740status_t AwesomePlayer::pause_l() {
741    if (!(mFlags & PLAYING)) {
742        return OK;
743    }
744
745    cancelPlayerEvents(true /* keepBufferingGoing */);
746
747    if (mAudioPlayer != NULL) {
748        mAudioPlayer->pause();
749    }
750
751    mFlags &= ~PLAYING;
752
753    return OK;
754}
755
756bool AwesomePlayer::isPlaying() const {
757    return (mFlags & PLAYING) || (mFlags & CACHE_UNDERRUN);
758}
759
760void AwesomePlayer::setISurface(const sp<ISurface> &isurface) {
761    Mutex::Autolock autoLock(mLock);
762
763    mISurface = isurface;
764}
765
766void AwesomePlayer::setAudioSink(
767        const sp<MediaPlayerBase::AudioSink> &audioSink) {
768    Mutex::Autolock autoLock(mLock);
769
770    mAudioSink = audioSink;
771}
772
773status_t AwesomePlayer::setLooping(bool shouldLoop) {
774    Mutex::Autolock autoLock(mLock);
775
776    mFlags = mFlags & ~LOOPING;
777
778    if (shouldLoop) {
779        mFlags |= LOOPING;
780    }
781
782    return OK;
783}
784
785status_t AwesomePlayer::getDuration(int64_t *durationUs) {
786    Mutex::Autolock autoLock(mMiscStateLock);
787
788    if (mDurationUs < 0) {
789        return UNKNOWN_ERROR;
790    }
791
792    *durationUs = mDurationUs;
793
794    return OK;
795}
796
797status_t AwesomePlayer::getPosition(int64_t *positionUs) {
798    if (mRTSPController != NULL) {
799        *positionUs = mRTSPController->getNormalPlayTimeUs();
800    }
801    else if (mSeeking) {
802        *positionUs = mSeekTimeUs;
803    } else if (mVideoSource != NULL) {
804        Mutex::Autolock autoLock(mMiscStateLock);
805        *positionUs = mVideoTimeUs;
806    } else if (mAudioPlayer != NULL) {
807        *positionUs = mAudioPlayer->getMediaTimeUs();
808    } else {
809        *positionUs = 0;
810    }
811
812    return OK;
813}
814
815status_t AwesomePlayer::seekTo(int64_t timeUs) {
816    if (mExtractorFlags
817            & (MediaExtractor::CAN_SEEK_FORWARD
818                | MediaExtractor::CAN_SEEK_BACKWARD)) {
819        Mutex::Autolock autoLock(mLock);
820        return seekTo_l(timeUs);
821    }
822
823    return OK;
824}
825
826status_t AwesomePlayer::seekTo_l(int64_t timeUs) {
827    if (mRTSPController != NULL) {
828        mRTSPController->seek(timeUs);
829
830        notifyListener_l(MEDIA_SEEK_COMPLETE);
831        mSeekNotificationSent = true;
832        return OK;
833    }
834
835    if (mFlags & CACHE_UNDERRUN) {
836        mFlags &= ~CACHE_UNDERRUN;
837        play_l();
838    }
839
840    mSeeking = true;
841    mSeekNotificationSent = false;
842    mSeekTimeUs = timeUs;
843    mFlags &= ~(AT_EOS | AUDIO_AT_EOS | VIDEO_AT_EOS);
844
845    seekAudioIfNecessary_l();
846
847    if (!(mFlags & PLAYING)) {
848        LOGV("seeking while paused, sending SEEK_COMPLETE notification"
849             " immediately.");
850
851        notifyListener_l(MEDIA_SEEK_COMPLETE);
852        mSeekNotificationSent = true;
853    }
854
855    return OK;
856}
857
858void AwesomePlayer::seekAudioIfNecessary_l() {
859    if (mSeeking && mVideoSource == NULL && mAudioPlayer != NULL) {
860        mAudioPlayer->seekTo(mSeekTimeUs);
861
862        mWatchForAudioSeekComplete = true;
863        mWatchForAudioEOS = true;
864        mSeekNotificationSent = false;
865    }
866}
867
868status_t AwesomePlayer::getVideoDimensions(
869        int32_t *width, int32_t *height) const {
870    Mutex::Autolock autoLock(mLock);
871
872    if (mVideoWidth < 0 || mVideoHeight < 0) {
873        return UNKNOWN_ERROR;
874    }
875
876    *width = mVideoWidth;
877    *height = mVideoHeight;
878
879    return OK;
880}
881
882void AwesomePlayer::setAudioSource(sp<MediaSource> source) {
883    CHECK(source != NULL);
884
885    mAudioTrack = source;
886}
887
888status_t AwesomePlayer::initAudioDecoder() {
889    sp<MetaData> meta = mAudioTrack->getFormat();
890
891    const char *mime;
892    CHECK(meta->findCString(kKeyMIMEType, &mime));
893
894    if (!strcasecmp(mime, MEDIA_MIMETYPE_AUDIO_RAW)) {
895        mAudioSource = mAudioTrack;
896    } else {
897        mAudioSource = OMXCodec::Create(
898                mClient.interface(), mAudioTrack->getFormat(),
899                false, // createEncoder
900                mAudioTrack);
901    }
902
903    if (mAudioSource != NULL) {
904        int64_t durationUs;
905        if (mAudioTrack->getFormat()->findInt64(kKeyDuration, &durationUs)) {
906            Mutex::Autolock autoLock(mMiscStateLock);
907            if (mDurationUs < 0 || durationUs > mDurationUs) {
908                mDurationUs = durationUs;
909            }
910        }
911
912        status_t err = mAudioSource->start();
913
914        if (err != OK) {
915            mAudioSource.clear();
916            return err;
917        }
918    } else if (!strcasecmp(mime, MEDIA_MIMETYPE_AUDIO_QCELP)) {
919        // For legacy reasons we're simply going to ignore the absence
920        // of an audio decoder for QCELP instead of aborting playback
921        // altogether.
922        return OK;
923    }
924
925    return mAudioSource != NULL ? OK : UNKNOWN_ERROR;
926}
927
928void AwesomePlayer::setVideoSource(sp<MediaSource> source) {
929    CHECK(source != NULL);
930
931    mVideoTrack = source;
932}
933
934status_t AwesomePlayer::initVideoDecoder() {
935    uint32_t flags = 0;
936    mVideoSource = OMXCodec::Create(
937            mClient.interface(), mVideoTrack->getFormat(),
938            false, // createEncoder
939            mVideoTrack,
940            NULL, flags);
941
942    if (mVideoSource != NULL) {
943        int64_t durationUs;
944        if (mVideoTrack->getFormat()->findInt64(kKeyDuration, &durationUs)) {
945            Mutex::Autolock autoLock(mMiscStateLock);
946            if (mDurationUs < 0 || durationUs > mDurationUs) {
947                mDurationUs = durationUs;
948            }
949        }
950
951        CHECK(mVideoTrack->getFormat()->findInt32(kKeyWidth, &mVideoWidth));
952        CHECK(mVideoTrack->getFormat()->findInt32(kKeyHeight, &mVideoHeight));
953
954        status_t err = mVideoSource->start();
955
956        if (err != OK) {
957            mVideoSource.clear();
958            return err;
959        }
960    }
961
962    return mVideoSource != NULL ? OK : UNKNOWN_ERROR;
963}
964
965void AwesomePlayer::onVideoEvent() {
966    Mutex::Autolock autoLock(mLock);
967    if (!mVideoEventPending) {
968        // The event has been cancelled in reset_l() but had already
969        // been scheduled for execution at that time.
970        return;
971    }
972    mVideoEventPending = false;
973
974    if (mSeeking) {
975        if (mLastVideoBuffer) {
976            mLastVideoBuffer->release();
977            mLastVideoBuffer = NULL;
978        }
979
980        if (mVideoBuffer) {
981            mVideoBuffer->release();
982            mVideoBuffer = NULL;
983        }
984
985        if (mCachedSource != NULL && mAudioSource != NULL) {
986            // We're going to seek the video source first, followed by
987            // the audio source.
988            // In order to avoid jumps in the DataSource offset caused by
989            // the audio codec prefetching data from the old locations
990            // while the video codec is already reading data from the new
991            // locations, we'll "pause" the audio source, causing it to
992            // stop reading input data until a subsequent seek.
993
994            if (mAudioPlayer != NULL) {
995                mAudioPlayer->pause();
996            }
997            mAudioSource->pause();
998        }
999    }
1000
1001    if (!mVideoBuffer) {
1002        MediaSource::ReadOptions options;
1003        if (mSeeking) {
1004            LOGV("seeking to %lld us (%.2f secs)", mSeekTimeUs, mSeekTimeUs / 1E6);
1005
1006            options.setSeekTo(
1007                    mSeekTimeUs, MediaSource::ReadOptions::SEEK_CLOSEST_SYNC);
1008        }
1009        for (;;) {
1010            status_t err = mVideoSource->read(&mVideoBuffer, &options);
1011            options.clearSeekTo();
1012
1013            if (err != OK) {
1014                CHECK_EQ(mVideoBuffer, NULL);
1015
1016                if (err == INFO_FORMAT_CHANGED) {
1017                    LOGV("VideoSource signalled format change.");
1018
1019                    if (mVideoRenderer != NULL) {
1020                        mVideoRendererIsPreview = false;
1021                        initRenderer_l();
1022                    }
1023                    continue;
1024                }
1025
1026                mFlags |= VIDEO_AT_EOS;
1027                postStreamDoneEvent_l(err);
1028                return;
1029            }
1030
1031            if (mVideoBuffer->range_length() == 0) {
1032                // Some decoders, notably the PV AVC software decoder
1033                // return spurious empty buffers that we just want to ignore.
1034
1035                mVideoBuffer->release();
1036                mVideoBuffer = NULL;
1037                continue;
1038            }
1039
1040            break;
1041        }
1042    }
1043
1044    int64_t timeUs;
1045    CHECK(mVideoBuffer->meta_data()->findInt64(kKeyTime, &timeUs));
1046
1047    {
1048        Mutex::Autolock autoLock(mMiscStateLock);
1049        mVideoTimeUs = timeUs;
1050    }
1051
1052    if (mSeeking) {
1053        if (mAudioPlayer != NULL) {
1054            LOGV("seeking audio to %lld us (%.2f secs).", timeUs, timeUs / 1E6);
1055
1056            mAudioPlayer->seekTo(timeUs);
1057            mAudioPlayer->resume();
1058            mWatchForAudioSeekComplete = true;
1059            mWatchForAudioEOS = true;
1060        } else if (!mSeekNotificationSent) {
1061            // If we're playing video only, report seek complete now,
1062            // otherwise audio player will notify us later.
1063            notifyListener_l(MEDIA_SEEK_COMPLETE);
1064        }
1065
1066        mFlags |= FIRST_FRAME;
1067        mSeeking = false;
1068        mSeekNotificationSent = false;
1069    }
1070
1071    TimeSource *ts = (mFlags & AUDIO_AT_EOS) ? &mSystemTimeSource : mTimeSource;
1072
1073    if (mFlags & FIRST_FRAME) {
1074        mFlags &= ~FIRST_FRAME;
1075
1076        mTimeSourceDeltaUs = ts->getRealTimeUs() - timeUs;
1077    }
1078
1079    int64_t realTimeUs, mediaTimeUs;
1080    if (!(mFlags & AUDIO_AT_EOS) && mAudioPlayer != NULL
1081        && mAudioPlayer->getMediaTimeMapping(&realTimeUs, &mediaTimeUs)) {
1082        mTimeSourceDeltaUs = realTimeUs - mediaTimeUs;
1083    }
1084
1085    int64_t nowUs = ts->getRealTimeUs() - mTimeSourceDeltaUs;
1086
1087    int64_t latenessUs = nowUs - timeUs;
1088
1089    if (mRTPSession != NULL) {
1090        // We'll completely ignore timestamps for gtalk videochat
1091        // and we'll play incoming video as fast as we get it.
1092        latenessUs = 0;
1093    }
1094
1095    if (latenessUs > 40000) {
1096        // We're more than 40ms late.
1097        LOGV("we're late by %lld us (%.2f secs)", latenessUs, latenessUs / 1E6);
1098
1099        mVideoBuffer->release();
1100        mVideoBuffer = NULL;
1101
1102        postVideoEvent_l();
1103        return;
1104    }
1105
1106    if (latenessUs < -10000) {
1107        // We're more than 10ms early.
1108
1109        postVideoEvent_l(10000);
1110        return;
1111    }
1112
1113    if (mVideoRendererIsPreview || mVideoRenderer == NULL) {
1114        mVideoRendererIsPreview = false;
1115
1116        initRenderer_l();
1117    }
1118
1119    if (mVideoRenderer != NULL) {
1120        mVideoRenderer->render(mVideoBuffer);
1121    }
1122
1123    if (mLastVideoBuffer) {
1124        mLastVideoBuffer->release();
1125        mLastVideoBuffer = NULL;
1126    }
1127    mLastVideoBuffer = mVideoBuffer;
1128    mVideoBuffer = NULL;
1129
1130    postVideoEvent_l();
1131}
1132
1133void AwesomePlayer::postVideoEvent_l(int64_t delayUs) {
1134    if (mVideoEventPending) {
1135        return;
1136    }
1137
1138    mVideoEventPending = true;
1139    mQueue.postEventWithDelay(mVideoEvent, delayUs < 0 ? 10000 : delayUs);
1140}
1141
1142void AwesomePlayer::postStreamDoneEvent_l(status_t status) {
1143    if (mStreamDoneEventPending) {
1144        return;
1145    }
1146    mStreamDoneEventPending = true;
1147
1148    mStreamDoneStatus = status;
1149    mQueue.postEvent(mStreamDoneEvent);
1150}
1151
1152void AwesomePlayer::postBufferingEvent_l() {
1153    if (mBufferingEventPending) {
1154        return;
1155    }
1156    mBufferingEventPending = true;
1157    mQueue.postEventWithDelay(mBufferingEvent, 1000000ll);
1158}
1159
1160void AwesomePlayer::postCheckAudioStatusEvent_l() {
1161    if (mAudioStatusEventPending) {
1162        return;
1163    }
1164    mAudioStatusEventPending = true;
1165    mQueue.postEventWithDelay(mCheckAudioStatusEvent, 100000ll);
1166}
1167
1168void AwesomePlayer::onCheckAudioStatus() {
1169    Mutex::Autolock autoLock(mLock);
1170    if (!mAudioStatusEventPending) {
1171        // Event was dispatched and while we were blocking on the mutex,
1172        // has already been cancelled.
1173        return;
1174    }
1175
1176    mAudioStatusEventPending = false;
1177
1178    if (mWatchForAudioSeekComplete && !mAudioPlayer->isSeeking()) {
1179        mWatchForAudioSeekComplete = false;
1180
1181        if (!mSeekNotificationSent) {
1182            notifyListener_l(MEDIA_SEEK_COMPLETE);
1183            mSeekNotificationSent = true;
1184        }
1185
1186        mSeeking = false;
1187    }
1188
1189    status_t finalStatus;
1190    if (mWatchForAudioEOS && mAudioPlayer->reachedEOS(&finalStatus)) {
1191        mWatchForAudioEOS = false;
1192        mFlags |= AUDIO_AT_EOS;
1193        mFlags |= FIRST_FRAME;
1194        postStreamDoneEvent_l(finalStatus);
1195    }
1196
1197    postCheckAudioStatusEvent_l();
1198}
1199
1200status_t AwesomePlayer::prepare() {
1201    Mutex::Autolock autoLock(mLock);
1202    return prepare_l();
1203}
1204
1205status_t AwesomePlayer::prepare_l() {
1206    if (mFlags & PREPARED) {
1207        return OK;
1208    }
1209
1210    if (mFlags & PREPARING) {
1211        return UNKNOWN_ERROR;
1212    }
1213
1214    mIsAsyncPrepare = false;
1215    status_t err = prepareAsync_l();
1216
1217    if (err != OK) {
1218        return err;
1219    }
1220
1221    while (mFlags & PREPARING) {
1222        mPreparedCondition.wait(mLock);
1223    }
1224
1225    return mPrepareResult;
1226}
1227
1228status_t AwesomePlayer::prepareAsync() {
1229    Mutex::Autolock autoLock(mLock);
1230
1231    if (mFlags & PREPARING) {
1232        return UNKNOWN_ERROR;  // async prepare already pending
1233    }
1234
1235    mIsAsyncPrepare = true;
1236    return prepareAsync_l();
1237}
1238
1239status_t AwesomePlayer::prepareAsync_l() {
1240    if (mFlags & PREPARING) {
1241        return UNKNOWN_ERROR;  // async prepare already pending
1242    }
1243
1244    if (!mQueueStarted) {
1245        mQueue.start();
1246        mQueueStarted = true;
1247    }
1248
1249    mFlags |= PREPARING;
1250    mAsyncPrepareEvent = new AwesomeEvent(
1251            this, &AwesomePlayer::onPrepareAsyncEvent);
1252
1253    mQueue.postEvent(mAsyncPrepareEvent);
1254
1255    return OK;
1256}
1257
1258status_t AwesomePlayer::finishSetDataSource_l() {
1259    sp<DataSource> dataSource;
1260
1261    if (!strncasecmp("http://", mUri.string(), 7)) {
1262        mConnectingDataSource = new NuHTTPDataSource;
1263
1264        mLock.unlock();
1265        status_t err = mConnectingDataSource->connect(mUri, &mUriHeaders);
1266        mLock.lock();
1267
1268        if (err != OK) {
1269            mConnectingDataSource.clear();
1270
1271            LOGI("mConnectingDataSource->connect() returned %d", err);
1272            return err;
1273        }
1274
1275#if 0
1276        mCachedSource = new NuCachedSource2(
1277                new ThrottledSource(
1278                    mConnectingDataSource, 50 * 1024 /* bytes/sec */));
1279#else
1280        mCachedSource = new NuCachedSource2(mConnectingDataSource);
1281#endif
1282        mConnectingDataSource.clear();
1283
1284        dataSource = mCachedSource;
1285    } else if (!strncasecmp(mUri.string(), "httplive://", 11)) {
1286        String8 uri("http://");
1287        uri.append(mUri.string() + 11);
1288
1289        dataSource = new LiveSource(uri.string());
1290
1291        mCachedSource = new NuCachedSource2(dataSource);
1292        dataSource = mCachedSource;
1293
1294        sp<MediaExtractor> extractor =
1295            MediaExtractor::Create(dataSource, MEDIA_MIMETYPE_CONTAINER_MPEG2TS);
1296
1297        return setDataSource_l(extractor);
1298    } else if (!strncmp("rtsp://gtalk/", mUri.string(), 13)) {
1299        if (mLooper == NULL) {
1300            mLooper = new ALooper;
1301            mLooper->setName("gtalk rtp");
1302            mLooper->start(
1303                    false /* runOnCallingThread */,
1304                    false /* canCallJava */,
1305                    PRIORITY_HIGHEST);
1306        }
1307
1308        const char *startOfCodecString = &mUri.string()[13];
1309        const char *startOfSlash1 = strchr(startOfCodecString, '/');
1310        if (startOfSlash1 == NULL) {
1311            return BAD_VALUE;
1312        }
1313        const char *startOfWidthString = &startOfSlash1[1];
1314        const char *startOfSlash2 = strchr(startOfWidthString, '/');
1315        if (startOfSlash2 == NULL) {
1316            return BAD_VALUE;
1317        }
1318        const char *startOfHeightString = &startOfSlash2[1];
1319
1320        String8 codecString(startOfCodecString, startOfSlash1 - startOfCodecString);
1321        String8 widthString(startOfWidthString, startOfSlash2 - startOfWidthString);
1322        String8 heightString(startOfHeightString);
1323
1324#if 0
1325        mRTPPusher = new UDPPusher("/data/misc/rtpout.bin", 5434);
1326        mLooper->registerHandler(mRTPPusher);
1327
1328        mRTCPPusher = new UDPPusher("/data/misc/rtcpout.bin", 5435);
1329        mLooper->registerHandler(mRTCPPusher);
1330#endif
1331
1332        mRTPSession = new ARTPSession;
1333        mLooper->registerHandler(mRTPSession);
1334
1335#if 0
1336        // My AMR SDP
1337        static const char *raw =
1338            "v=0\r\n"
1339            "o=- 64 233572944 IN IP4 127.0.0.0\r\n"
1340            "s=QuickTime\r\n"
1341            "t=0 0\r\n"
1342            "a=range:npt=0-315\r\n"
1343            "a=isma-compliance:2,2.0,2\r\n"
1344            "m=audio 5434 RTP/AVP 97\r\n"
1345            "c=IN IP4 127.0.0.1\r\n"
1346            "b=AS:30\r\n"
1347            "a=rtpmap:97 AMR/8000/1\r\n"
1348            "a=fmtp:97 octet-align\r\n";
1349#elif 1
1350        String8 sdp;
1351        sdp.appendFormat(
1352            "v=0\r\n"
1353            "o=- 64 233572944 IN IP4 127.0.0.0\r\n"
1354            "s=QuickTime\r\n"
1355            "t=0 0\r\n"
1356            "a=range:npt=0-315\r\n"
1357            "a=isma-compliance:2,2.0,2\r\n"
1358            "m=video 5434 RTP/AVP 97\r\n"
1359            "c=IN IP4 127.0.0.1\r\n"
1360            "b=AS:30\r\n"
1361            "a=rtpmap:97 %s/90000\r\n"
1362            "a=cliprect:0,0,%s,%s\r\n"
1363            "a=framesize:97 %s-%s\r\n",
1364
1365            codecString.string(),
1366            heightString.string(), widthString.string(),
1367            widthString.string(), heightString.string()
1368            );
1369        const char *raw = sdp.string();
1370
1371#endif
1372
1373        sp<ASessionDescription> desc = new ASessionDescription;
1374        CHECK(desc->setTo(raw, strlen(raw)));
1375
1376        CHECK_EQ(mRTPSession->setup(desc), (status_t)OK);
1377
1378        if (mRTPPusher != NULL) {
1379            mRTPPusher->start();
1380        }
1381
1382        if (mRTCPPusher != NULL) {
1383            mRTCPPusher->start();
1384        }
1385
1386        CHECK_EQ(mRTPSession->countTracks(), 1u);
1387        sp<MediaSource> source = mRTPSession->trackAt(0);
1388
1389#if 0
1390        bool eos;
1391        while (((APacketSource *)source.get())
1392                ->getQueuedDuration(&eos) < 5000000ll && !eos) {
1393            usleep(100000ll);
1394        }
1395#endif
1396
1397        const char *mime;
1398        CHECK(source->getFormat()->findCString(kKeyMIMEType, &mime));
1399
1400        if (!strncasecmp("video/", mime, 6)) {
1401            setVideoSource(source);
1402        } else {
1403            CHECK(!strncasecmp("audio/", mime, 6));
1404            setAudioSource(source);
1405        }
1406
1407        mExtractorFlags = MediaExtractor::CAN_PAUSE;
1408
1409        return OK;
1410    } else if (!strncasecmp("rtsp://", mUri.string(), 7)) {
1411        if (mLooper == NULL) {
1412            mLooper = new ALooper;
1413            mLooper->setName("rtsp");
1414            mLooper->start();
1415        }
1416        mRTSPController = new ARTSPController(mLooper);
1417        status_t err = mRTSPController->connect(mUri.string());
1418
1419        LOGI("ARTSPController::connect returned %d", err);
1420
1421        if (err != OK) {
1422            mRTSPController.clear();
1423            return err;
1424        }
1425
1426        sp<MediaExtractor> extractor = mRTSPController.get();
1427        return setDataSource_l(extractor);
1428    } else {
1429        dataSource = DataSource::CreateFromURI(mUri.string(), &mUriHeaders);
1430    }
1431
1432    if (dataSource == NULL) {
1433        return UNKNOWN_ERROR;
1434    }
1435
1436    sp<MediaExtractor> extractor = MediaExtractor::Create(dataSource);
1437
1438    if (extractor == NULL) {
1439        return UNKNOWN_ERROR;
1440    }
1441
1442    return setDataSource_l(extractor);
1443}
1444
1445void AwesomePlayer::abortPrepare(status_t err) {
1446    CHECK(err != OK);
1447
1448    if (mIsAsyncPrepare) {
1449        notifyListener_l(MEDIA_ERROR, MEDIA_ERROR_UNKNOWN, err);
1450    }
1451
1452    mPrepareResult = err;
1453    mFlags &= ~(PREPARING|PREPARE_CANCELLED);
1454    mAsyncPrepareEvent = NULL;
1455    mPreparedCondition.broadcast();
1456}
1457
1458// static
1459bool AwesomePlayer::ContinuePreparation(void *cookie) {
1460    AwesomePlayer *me = static_cast<AwesomePlayer *>(cookie);
1461
1462    return (me->mFlags & PREPARE_CANCELLED) == 0;
1463}
1464
1465void AwesomePlayer::onPrepareAsyncEvent() {
1466    Mutex::Autolock autoLock(mLock);
1467
1468    if (mFlags & PREPARE_CANCELLED) {
1469        LOGI("prepare was cancelled before doing anything");
1470        abortPrepare(UNKNOWN_ERROR);
1471        return;
1472    }
1473
1474    if (mUri.size() > 0) {
1475        status_t err = finishSetDataSource_l();
1476
1477        if (err != OK) {
1478            abortPrepare(err);
1479            return;
1480        }
1481    }
1482
1483    if (mVideoTrack != NULL && mVideoSource == NULL) {
1484        status_t err = initVideoDecoder();
1485
1486        if (err != OK) {
1487            abortPrepare(err);
1488            return;
1489        }
1490    }
1491
1492    if (mAudioTrack != NULL && mAudioSource == NULL) {
1493        status_t err = initAudioDecoder();
1494
1495        if (err != OK) {
1496            abortPrepare(err);
1497            return;
1498        }
1499    }
1500
1501    if (mCachedSource != NULL || mRTSPController != NULL) {
1502        postBufferingEvent_l();
1503    } else {
1504        finishAsyncPrepare_l();
1505    }
1506}
1507
1508void AwesomePlayer::finishAsyncPrepare_l() {
1509    if (mIsAsyncPrepare) {
1510        if (mVideoWidth < 0 || mVideoHeight < 0) {
1511            notifyListener_l(MEDIA_SET_VIDEO_SIZE, 0, 0);
1512        } else {
1513            notifyListener_l(MEDIA_SET_VIDEO_SIZE, mVideoWidth, mVideoHeight);
1514        }
1515
1516        notifyListener_l(MEDIA_PREPARED);
1517    }
1518
1519    mPrepareResult = OK;
1520    mFlags &= ~(PREPARING|PREPARE_CANCELLED);
1521    mFlags |= PREPARED;
1522    mAsyncPrepareEvent = NULL;
1523    mPreparedCondition.broadcast();
1524}
1525
1526status_t AwesomePlayer::suspend() {
1527    LOGV("suspend");
1528    Mutex::Autolock autoLock(mLock);
1529
1530    if (mSuspensionState != NULL) {
1531        if (mLastVideoBuffer == NULL) {
1532            //go into here if video is suspended again
1533            //after resuming without being played between
1534            //them
1535            SuspensionState *state = mSuspensionState;
1536            mSuspensionState = NULL;
1537            reset_l();
1538            mSuspensionState = state;
1539            return OK;
1540        }
1541
1542        delete mSuspensionState;
1543        mSuspensionState = NULL;
1544    }
1545
1546    if (mFlags & PREPARING) {
1547        mFlags |= PREPARE_CANCELLED;
1548        if (mConnectingDataSource != NULL) {
1549            LOGI("interrupting the connection process");
1550            mConnectingDataSource->disconnect();
1551        }
1552    }
1553
1554    while (mFlags & PREPARING) {
1555        mPreparedCondition.wait(mLock);
1556    }
1557
1558    SuspensionState *state = new SuspensionState;
1559    state->mUri = mUri;
1560    state->mUriHeaders = mUriHeaders;
1561    state->mFileSource = mFileSource;
1562
1563    state->mFlags = mFlags & (PLAYING | LOOPING | AT_EOS);
1564    getPosition(&state->mPositionUs);
1565
1566    if (mLastVideoBuffer) {
1567        size_t size = mLastVideoBuffer->range_length();
1568        if (size) {
1569            state->mLastVideoFrameSize = size;
1570            state->mLastVideoFrame = malloc(size);
1571            memcpy(state->mLastVideoFrame,
1572                   (const uint8_t *)mLastVideoBuffer->data()
1573                        + mLastVideoBuffer->range_offset(),
1574                   size);
1575
1576            state->mVideoWidth = mVideoWidth;
1577            state->mVideoHeight = mVideoHeight;
1578
1579            sp<MetaData> meta = mVideoSource->getFormat();
1580            CHECK(meta->findInt32(kKeyColorFormat, &state->mColorFormat));
1581            CHECK(meta->findInt32(kKeyWidth, &state->mDecodedWidth));
1582            CHECK(meta->findInt32(kKeyHeight, &state->mDecodedHeight));
1583        }
1584    }
1585
1586    reset_l();
1587
1588    mSuspensionState = state;
1589
1590    return OK;
1591}
1592
1593status_t AwesomePlayer::resume() {
1594    LOGV("resume");
1595    Mutex::Autolock autoLock(mLock);
1596
1597    if (mSuspensionState == NULL) {
1598        return INVALID_OPERATION;
1599    }
1600
1601    SuspensionState *state = mSuspensionState;
1602    mSuspensionState = NULL;
1603
1604    status_t err;
1605    if (state->mFileSource != NULL) {
1606        err = setDataSource_l(state->mFileSource);
1607
1608        if (err == OK) {
1609            mFileSource = state->mFileSource;
1610        }
1611    } else {
1612        err = setDataSource_l(state->mUri, &state->mUriHeaders);
1613    }
1614
1615    if (err != OK) {
1616        delete state;
1617        state = NULL;
1618
1619        return err;
1620    }
1621
1622    seekTo_l(state->mPositionUs);
1623
1624    mFlags = state->mFlags & (LOOPING | AT_EOS);
1625
1626    if (state->mLastVideoFrame && mISurface != NULL) {
1627        mVideoRenderer =
1628            new AwesomeLocalRenderer(
1629                    true,  // previewOnly
1630                    "",
1631                    (OMX_COLOR_FORMATTYPE)state->mColorFormat,
1632                    mISurface,
1633                    state->mVideoWidth,
1634                    state->mVideoHeight,
1635                    state->mDecodedWidth,
1636                    state->mDecodedHeight);
1637
1638        mVideoRendererIsPreview = true;
1639
1640        ((AwesomeLocalRenderer *)mVideoRenderer.get())->render(
1641                state->mLastVideoFrame, state->mLastVideoFrameSize);
1642    }
1643
1644    if (state->mFlags & PLAYING) {
1645        play_l();
1646    }
1647
1648    mSuspensionState = state;
1649    state = NULL;
1650
1651    return OK;
1652}
1653
1654uint32_t AwesomePlayer::flags() const {
1655    return mExtractorFlags;
1656}
1657
1658}  // namespace android
1659
1660