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