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