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