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