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