AwesomePlayer.cpp revision 0e4d896cb9ab813131c45b3b1fcd4cc66d341468
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::partial_reset_l() {
568    // Only reset the video renderer and shut down the video decoder.
569    // Then instantiate a new video decoder and resume video playback.
570
571    mVideoRenderer.clear();
572
573    if (mLastVideoBuffer) {
574        mLastVideoBuffer->release();
575        mLastVideoBuffer = NULL;
576    }
577
578    if (mVideoBuffer) {
579        mVideoBuffer->release();
580        mVideoBuffer = NULL;
581    }
582
583    {
584        mVideoSource->stop();
585
586        // The following hack is necessary to ensure that the OMX
587        // component is completely released by the time we may try
588        // to instantiate it again.
589        wp<MediaSource> tmp = mVideoSource;
590        mVideoSource.clear();
591        while (tmp.promote() != NULL) {
592            usleep(1000);
593        }
594        IPCThreadState::self()->flushCommands();
595    }
596
597    CHECK_EQ(OK, initVideoDecoder(OMXCodec::kIgnoreCodecSpecificData));
598}
599
600void AwesomePlayer::onStreamDone() {
601    // Posted whenever any stream finishes playing.
602
603    Mutex::Autolock autoLock(mLock);
604    if (!mStreamDoneEventPending) {
605        return;
606    }
607    mStreamDoneEventPending = false;
608
609    if (mStreamDoneStatus == INFO_DISCONTINUITY) {
610        // This special status is returned because an http live stream's
611        // video stream switched to a different bandwidth at this point
612        // and future data may have been encoded using different parameters.
613        // This requires us to shutdown the video decoder and reinstantiate
614        // a fresh one.
615
616        LOGV("INFO_DISCONTINUITY");
617
618        CHECK(mVideoSource != NULL);
619
620        partial_reset_l();
621        postVideoEvent_l();
622        return;
623    } else if (mStreamDoneStatus != ERROR_END_OF_STREAM) {
624        LOGV("MEDIA_ERROR %d", mStreamDoneStatus);
625
626        notifyListener_l(
627                MEDIA_ERROR, MEDIA_ERROR_UNKNOWN, mStreamDoneStatus);
628
629        pause_l(true /* at eos */);
630
631        mFlags |= AT_EOS;
632        return;
633    }
634
635    const bool allDone =
636        (mVideoSource == NULL || (mFlags & VIDEO_AT_EOS))
637            && (mAudioSource == NULL || (mFlags & AUDIO_AT_EOS));
638
639    if (!allDone) {
640        return;
641    }
642
643    if (mFlags & (LOOPING | AUTO_LOOPING)) {
644        seekTo_l(0);
645
646        if (mVideoSource != NULL) {
647            postVideoEvent_l();
648        }
649    } else {
650        LOGV("MEDIA_PLAYBACK_COMPLETE");
651        notifyListener_l(MEDIA_PLAYBACK_COMPLETE);
652
653        pause_l(true /* at eos */);
654
655        mFlags |= AT_EOS;
656    }
657}
658
659status_t AwesomePlayer::play() {
660    Mutex::Autolock autoLock(mLock);
661
662    mFlags &= ~CACHE_UNDERRUN;
663
664    return play_l();
665}
666
667status_t AwesomePlayer::play_l() {
668    if (mFlags & PLAYING) {
669        return OK;
670    }
671
672    if (!(mFlags & PREPARED)) {
673        status_t err = prepare_l();
674
675        if (err != OK) {
676            return err;
677        }
678    }
679
680    mFlags |= PLAYING;
681    mFlags |= FIRST_FRAME;
682
683    bool deferredAudioSeek = false;
684
685    if (mAudioSource != NULL) {
686        if (mAudioPlayer == NULL) {
687            if (mAudioSink != NULL) {
688                mAudioPlayer = new AudioPlayer(mAudioSink, this);
689                mAudioPlayer->setSource(mAudioSource);
690
691                // We've already started the MediaSource in order to enable
692                // the prefetcher to read its data.
693                status_t err = mAudioPlayer->start(
694                        true /* sourceAlreadyStarted */);
695
696                if (err != OK) {
697                    delete mAudioPlayer;
698                    mAudioPlayer = NULL;
699
700                    mFlags &= ~(PLAYING | FIRST_FRAME);
701
702                    return err;
703                }
704
705                mTimeSource = mAudioPlayer;
706
707                deferredAudioSeek = true;
708
709                mWatchForAudioSeekComplete = false;
710                mWatchForAudioEOS = true;
711            }
712        } else {
713            mAudioPlayer->resume();
714        }
715    }
716
717    if (mTimeSource == NULL && mAudioPlayer == NULL) {
718        mTimeSource = &mSystemTimeSource;
719    }
720
721    if (mVideoSource != NULL) {
722        // Kick off video playback
723        postVideoEvent_l();
724    }
725
726    if (deferredAudioSeek) {
727        // If there was a seek request while we were paused
728        // and we're just starting up again, honor the request now.
729        seekAudioIfNecessary_l();
730    }
731
732    if (mFlags & AT_EOS) {
733        // Legacy behaviour, if a stream finishes playing and then
734        // is started again, we play from the start...
735        seekTo_l(0);
736    }
737
738    return OK;
739}
740
741void AwesomePlayer::notifyVideoSize_l() {
742    sp<MetaData> meta = mVideoSource->getFormat();
743
744    int32_t decodedWidth, decodedHeight;
745    CHECK(meta->findInt32(kKeyWidth, &decodedWidth));
746    CHECK(meta->findInt32(kKeyHeight, &decodedHeight));
747
748    notifyListener_l(MEDIA_SET_VIDEO_SIZE, decodedWidth, decodedHeight);
749}
750
751void AwesomePlayer::initRenderer_l() {
752    if (mSurface != NULL || mISurface != NULL) {
753        sp<MetaData> meta = mVideoSource->getFormat();
754
755        int32_t format;
756        const char *component;
757        int32_t decodedWidth, decodedHeight;
758        CHECK(meta->findInt32(kKeyColorFormat, &format));
759        CHECK(meta->findCString(kKeyDecoderComponent, &component));
760        CHECK(meta->findInt32(kKeyWidth, &decodedWidth));
761        CHECK(meta->findInt32(kKeyHeight, &decodedHeight));
762
763        mVideoRenderer.clear();
764
765        // Must ensure that mVideoRenderer's destructor is actually executed
766        // before creating a new one.
767        IPCThreadState::self()->flushCommands();
768
769        if (mSurface != NULL) {
770            // Other decoders are instantiated locally and as a consequence
771            // allocate their buffers in local address space.
772            mVideoRenderer = new AwesomeLocalRenderer(
773                false,  // previewOnly
774                component,
775                (OMX_COLOR_FORMATTYPE)format,
776                mISurface,
777                mSurface,
778                mVideoWidth, mVideoHeight,
779                decodedWidth, decodedHeight);
780        } else {
781            // Our OMX codecs allocate buffers on the media_server side
782            // therefore they require a remote IOMXRenderer that knows how
783            // to display them.
784            mVideoRenderer = new AwesomeRemoteRenderer(
785                mClient.interface()->createRenderer(
786                        mISurface, component,
787                        (OMX_COLOR_FORMATTYPE)format,
788                        decodedWidth, decodedHeight,
789                        mVideoWidth, mVideoHeight));
790        }
791    }
792}
793
794status_t AwesomePlayer::pause() {
795    Mutex::Autolock autoLock(mLock);
796
797    mFlags &= ~CACHE_UNDERRUN;
798
799    return pause_l();
800}
801
802status_t AwesomePlayer::pause_l(bool at_eos) {
803    if (!(mFlags & PLAYING)) {
804        return OK;
805    }
806
807    cancelPlayerEvents(true /* keepBufferingGoing */);
808
809    if (mAudioPlayer != NULL) {
810        if (at_eos) {
811            // If we played the audio stream to completion we
812            // want to make sure that all samples remaining in the audio
813            // track's queue are played out.
814            mAudioPlayer->pause(true /* playPendingSamples */);
815        } else {
816            mAudioPlayer->pause();
817        }
818    }
819
820    mFlags &= ~PLAYING;
821
822    return OK;
823}
824
825bool AwesomePlayer::isPlaying() const {
826    return (mFlags & PLAYING) || (mFlags & CACHE_UNDERRUN);
827}
828
829void AwesomePlayer::setISurface(const sp<ISurface> &isurface) {
830    Mutex::Autolock autoLock(mLock);
831
832    mISurface = isurface;
833}
834
835void AwesomePlayer::setSurface(const sp<Surface> &surface) {
836    Mutex::Autolock autoLock(mLock);
837
838    mSurface = surface;
839}
840
841void AwesomePlayer::setAudioSink(
842        const sp<MediaPlayerBase::AudioSink> &audioSink) {
843    Mutex::Autolock autoLock(mLock);
844
845    mAudioSink = audioSink;
846}
847
848status_t AwesomePlayer::setLooping(bool shouldLoop) {
849    Mutex::Autolock autoLock(mLock);
850
851    mFlags = mFlags & ~LOOPING;
852
853    if (shouldLoop) {
854        mFlags |= LOOPING;
855    }
856
857    return OK;
858}
859
860status_t AwesomePlayer::getDuration(int64_t *durationUs) {
861    Mutex::Autolock autoLock(mMiscStateLock);
862
863    if (mDurationUs < 0) {
864        return UNKNOWN_ERROR;
865    }
866
867    *durationUs = mDurationUs;
868
869    return OK;
870}
871
872status_t AwesomePlayer::getPosition(int64_t *positionUs) {
873    if (mRTSPController != NULL) {
874        *positionUs = mRTSPController->getNormalPlayTimeUs();
875    }
876    else if (mSeeking) {
877        *positionUs = mSeekTimeUs;
878    } else if (mVideoSource != NULL) {
879        Mutex::Autolock autoLock(mMiscStateLock);
880        *positionUs = mVideoTimeUs;
881    } else if (mAudioPlayer != NULL) {
882        *positionUs = mAudioPlayer->getMediaTimeUs();
883    } else {
884        *positionUs = 0;
885    }
886
887    return OK;
888}
889
890status_t AwesomePlayer::seekTo(int64_t timeUs) {
891    if (mExtractorFlags
892            & (MediaExtractor::CAN_SEEK_FORWARD
893                | MediaExtractor::CAN_SEEK_BACKWARD)) {
894        Mutex::Autolock autoLock(mLock);
895        return seekTo_l(timeUs);
896    }
897
898    return OK;
899}
900
901status_t AwesomePlayer::seekTo_l(int64_t timeUs) {
902    if (mRTSPController != NULL) {
903        mRTSPController->seek(timeUs);
904
905        notifyListener_l(MEDIA_SEEK_COMPLETE);
906        mSeekNotificationSent = true;
907        return OK;
908    }
909
910    if (mFlags & CACHE_UNDERRUN) {
911        mFlags &= ~CACHE_UNDERRUN;
912        play_l();
913    }
914
915    mSeeking = true;
916    mSeekNotificationSent = false;
917    mSeekTimeUs = timeUs;
918    mFlags &= ~(AT_EOS | AUDIO_AT_EOS | VIDEO_AT_EOS);
919
920    seekAudioIfNecessary_l();
921
922    if (!(mFlags & PLAYING)) {
923        LOGV("seeking while paused, sending SEEK_COMPLETE notification"
924             " immediately.");
925
926        notifyListener_l(MEDIA_SEEK_COMPLETE);
927        mSeekNotificationSent = true;
928    }
929
930    return OK;
931}
932
933void AwesomePlayer::seekAudioIfNecessary_l() {
934    if (mSeeking && mVideoSource == NULL && mAudioPlayer != NULL) {
935        mAudioPlayer->seekTo(mSeekTimeUs);
936
937        mWatchForAudioSeekComplete = true;
938        mWatchForAudioEOS = true;
939        mSeekNotificationSent = false;
940    }
941}
942
943status_t AwesomePlayer::getVideoDimensions(
944        int32_t *width, int32_t *height) const {
945    Mutex::Autolock autoLock(mLock);
946
947    if (mVideoWidth < 0 || mVideoHeight < 0) {
948        return UNKNOWN_ERROR;
949    }
950
951    *width = mVideoWidth;
952    *height = mVideoHeight;
953
954    return OK;
955}
956
957void AwesomePlayer::setAudioSource(sp<MediaSource> source) {
958    CHECK(source != NULL);
959
960    mAudioTrack = source;
961}
962
963status_t AwesomePlayer::initAudioDecoder() {
964    sp<MetaData> meta = mAudioTrack->getFormat();
965
966    const char *mime;
967    CHECK(meta->findCString(kKeyMIMEType, &mime));
968
969    if (!strcasecmp(mime, MEDIA_MIMETYPE_AUDIO_RAW)) {
970        mAudioSource = mAudioTrack;
971    } else {
972        mAudioSource = OMXCodec::Create(
973                mClient.interface(), mAudioTrack->getFormat(),
974                false, // createEncoder
975                mAudioTrack);
976    }
977
978    if (mAudioSource != NULL) {
979        int64_t durationUs;
980        if (mAudioTrack->getFormat()->findInt64(kKeyDuration, &durationUs)) {
981            Mutex::Autolock autoLock(mMiscStateLock);
982            if (mDurationUs < 0 || durationUs > mDurationUs) {
983                mDurationUs = durationUs;
984            }
985        }
986
987        status_t err = mAudioSource->start();
988
989        if (err != OK) {
990            mAudioSource.clear();
991            return err;
992        }
993    } else if (!strcasecmp(mime, MEDIA_MIMETYPE_AUDIO_QCELP)) {
994        // For legacy reasons we're simply going to ignore the absence
995        // of an audio decoder for QCELP instead of aborting playback
996        // altogether.
997        return OK;
998    }
999
1000    return mAudioSource != NULL ? OK : UNKNOWN_ERROR;
1001}
1002
1003void AwesomePlayer::setVideoSource(sp<MediaSource> source) {
1004    CHECK(source != NULL);
1005
1006    mVideoTrack = source;
1007}
1008
1009status_t AwesomePlayer::initVideoDecoder(uint32_t flags) {
1010    mVideoSource = OMXCodec::Create(
1011            mClient.interface(), mVideoTrack->getFormat(),
1012            false, // createEncoder
1013            mVideoTrack,
1014            NULL, flags);
1015
1016    if (mVideoSource != NULL) {
1017        int64_t durationUs;
1018        if (mVideoTrack->getFormat()->findInt64(kKeyDuration, &durationUs)) {
1019            Mutex::Autolock autoLock(mMiscStateLock);
1020            if (mDurationUs < 0 || durationUs > mDurationUs) {
1021                mDurationUs = durationUs;
1022            }
1023        }
1024
1025        CHECK(mVideoTrack->getFormat()->findInt32(kKeyWidth, &mVideoWidth));
1026        CHECK(mVideoTrack->getFormat()->findInt32(kKeyHeight, &mVideoHeight));
1027
1028        status_t err = mVideoSource->start();
1029
1030        if (err != OK) {
1031            mVideoSource.clear();
1032            return err;
1033        }
1034    }
1035
1036    return mVideoSource != NULL ? OK : UNKNOWN_ERROR;
1037}
1038
1039void AwesomePlayer::onVideoEvent() {
1040    Mutex::Autolock autoLock(mLock);
1041    if (!mVideoEventPending) {
1042        // The event has been cancelled in reset_l() but had already
1043        // been scheduled for execution at that time.
1044        return;
1045    }
1046    mVideoEventPending = false;
1047
1048    if (mSeeking) {
1049        if (mLastVideoBuffer) {
1050            mLastVideoBuffer->release();
1051            mLastVideoBuffer = NULL;
1052        }
1053
1054        if (mVideoBuffer) {
1055            mVideoBuffer->release();
1056            mVideoBuffer = NULL;
1057        }
1058
1059        if (mCachedSource != NULL && mAudioSource != NULL) {
1060            // We're going to seek the video source first, followed by
1061            // the audio source.
1062            // In order to avoid jumps in the DataSource offset caused by
1063            // the audio codec prefetching data from the old locations
1064            // while the video codec is already reading data from the new
1065            // locations, we'll "pause" the audio source, causing it to
1066            // stop reading input data until a subsequent seek.
1067
1068            if (mAudioPlayer != NULL) {
1069                mAudioPlayer->pause();
1070            }
1071            mAudioSource->pause();
1072        }
1073    }
1074
1075    if (!mVideoBuffer) {
1076        MediaSource::ReadOptions options;
1077        if (mSeeking) {
1078            LOGV("seeking to %lld us (%.2f secs)", mSeekTimeUs, mSeekTimeUs / 1E6);
1079
1080            options.setSeekTo(
1081                    mSeekTimeUs, MediaSource::ReadOptions::SEEK_CLOSEST_SYNC);
1082        }
1083        for (;;) {
1084            status_t err = mVideoSource->read(&mVideoBuffer, &options);
1085            options.clearSeekTo();
1086
1087            if (err != OK) {
1088                CHECK_EQ(mVideoBuffer, NULL);
1089
1090                if (err == INFO_FORMAT_CHANGED) {
1091                    LOGV("VideoSource signalled format change.");
1092
1093                    notifyVideoSize_l();
1094
1095                    if (mVideoRenderer != NULL) {
1096                        mVideoRendererIsPreview = false;
1097                        initRenderer_l();
1098                    }
1099                    continue;
1100                }
1101
1102                mFlags |= VIDEO_AT_EOS;
1103                postStreamDoneEvent_l(err);
1104                return;
1105            }
1106
1107            if (mVideoBuffer->range_length() == 0) {
1108                // Some decoders, notably the PV AVC software decoder
1109                // return spurious empty buffers that we just want to ignore.
1110
1111                mVideoBuffer->release();
1112                mVideoBuffer = NULL;
1113                continue;
1114            }
1115
1116            break;
1117        }
1118    }
1119
1120    int64_t timeUs;
1121    CHECK(mVideoBuffer->meta_data()->findInt64(kKeyTime, &timeUs));
1122
1123    {
1124        Mutex::Autolock autoLock(mMiscStateLock);
1125        mVideoTimeUs = timeUs;
1126    }
1127
1128    if (mSeeking) {
1129        if (mAudioPlayer != NULL) {
1130            LOGV("seeking audio to %lld us (%.2f secs).", timeUs, timeUs / 1E6);
1131
1132            mAudioPlayer->seekTo(timeUs);
1133            mAudioPlayer->resume();
1134            mWatchForAudioSeekComplete = true;
1135            mWatchForAudioEOS = true;
1136        } else if (!mSeekNotificationSent) {
1137            // If we're playing video only, report seek complete now,
1138            // otherwise audio player will notify us later.
1139            notifyListener_l(MEDIA_SEEK_COMPLETE);
1140        }
1141
1142        mFlags |= FIRST_FRAME;
1143        mSeeking = false;
1144        mSeekNotificationSent = false;
1145    }
1146
1147    TimeSource *ts = (mFlags & AUDIO_AT_EOS) ? &mSystemTimeSource : mTimeSource;
1148
1149    if (mFlags & FIRST_FRAME) {
1150        mFlags &= ~FIRST_FRAME;
1151
1152        mTimeSourceDeltaUs = ts->getRealTimeUs() - timeUs;
1153    }
1154
1155    int64_t realTimeUs, mediaTimeUs;
1156    if (!(mFlags & AUDIO_AT_EOS) && mAudioPlayer != NULL
1157        && mAudioPlayer->getMediaTimeMapping(&realTimeUs, &mediaTimeUs)) {
1158        mTimeSourceDeltaUs = realTimeUs - mediaTimeUs;
1159    }
1160
1161    int64_t nowUs = ts->getRealTimeUs() - mTimeSourceDeltaUs;
1162
1163    int64_t latenessUs = nowUs - timeUs;
1164
1165    if (mRTPSession != NULL) {
1166        // We'll completely ignore timestamps for gtalk videochat
1167        // and we'll play incoming video as fast as we get it.
1168        latenessUs = 0;
1169    }
1170
1171    if (latenessUs > 40000) {
1172        // We're more than 40ms late.
1173        LOGV("we're late by %lld us (%.2f secs)", latenessUs, latenessUs / 1E6);
1174
1175        mVideoBuffer->release();
1176        mVideoBuffer = NULL;
1177
1178        postVideoEvent_l();
1179        return;
1180    }
1181
1182    if (latenessUs < -10000) {
1183        // We're more than 10ms early.
1184
1185        postVideoEvent_l(10000);
1186        return;
1187    }
1188
1189    if (mVideoRendererIsPreview || mVideoRenderer == NULL) {
1190        mVideoRendererIsPreview = false;
1191
1192        initRenderer_l();
1193    }
1194
1195    if (mVideoRenderer != NULL) {
1196        mVideoRenderer->render(mVideoBuffer);
1197    }
1198
1199    if (mLastVideoBuffer) {
1200        mLastVideoBuffer->release();
1201        mLastVideoBuffer = NULL;
1202    }
1203    mLastVideoBuffer = mVideoBuffer;
1204    mVideoBuffer = NULL;
1205
1206    postVideoEvent_l();
1207}
1208
1209void AwesomePlayer::postVideoEvent_l(int64_t delayUs) {
1210    if (mVideoEventPending) {
1211        return;
1212    }
1213
1214    mVideoEventPending = true;
1215    mQueue.postEventWithDelay(mVideoEvent, delayUs < 0 ? 10000 : delayUs);
1216}
1217
1218void AwesomePlayer::postStreamDoneEvent_l(status_t status) {
1219    if (mStreamDoneEventPending) {
1220        return;
1221    }
1222    mStreamDoneEventPending = true;
1223
1224    mStreamDoneStatus = status;
1225    mQueue.postEvent(mStreamDoneEvent);
1226}
1227
1228void AwesomePlayer::postBufferingEvent_l() {
1229    if (mBufferingEventPending) {
1230        return;
1231    }
1232    mBufferingEventPending = true;
1233    mQueue.postEventWithDelay(mBufferingEvent, 1000000ll);
1234}
1235
1236void AwesomePlayer::postCheckAudioStatusEvent_l() {
1237    if (mAudioStatusEventPending) {
1238        return;
1239    }
1240    mAudioStatusEventPending = true;
1241    mQueue.postEvent(mCheckAudioStatusEvent);
1242}
1243
1244void AwesomePlayer::onCheckAudioStatus() {
1245    Mutex::Autolock autoLock(mLock);
1246    if (!mAudioStatusEventPending) {
1247        // Event was dispatched and while we were blocking on the mutex,
1248        // has already been cancelled.
1249        return;
1250    }
1251
1252    mAudioStatusEventPending = false;
1253
1254    if (mWatchForAudioSeekComplete && !mAudioPlayer->isSeeking()) {
1255        mWatchForAudioSeekComplete = false;
1256
1257        if (!mSeekNotificationSent) {
1258            notifyListener_l(MEDIA_SEEK_COMPLETE);
1259            mSeekNotificationSent = true;
1260        }
1261
1262        mSeeking = false;
1263    }
1264
1265    status_t finalStatus;
1266    if (mWatchForAudioEOS && mAudioPlayer->reachedEOS(&finalStatus)) {
1267        mWatchForAudioEOS = false;
1268        mFlags |= AUDIO_AT_EOS;
1269        mFlags |= FIRST_FRAME;
1270        postStreamDoneEvent_l(finalStatus);
1271    }
1272}
1273
1274status_t AwesomePlayer::prepare() {
1275    Mutex::Autolock autoLock(mLock);
1276    return prepare_l();
1277}
1278
1279status_t AwesomePlayer::prepare_l() {
1280    if (mFlags & PREPARED) {
1281        return OK;
1282    }
1283
1284    if (mFlags & PREPARING) {
1285        return UNKNOWN_ERROR;
1286    }
1287
1288    mIsAsyncPrepare = false;
1289    status_t err = prepareAsync_l();
1290
1291    if (err != OK) {
1292        return err;
1293    }
1294
1295    while (mFlags & PREPARING) {
1296        mPreparedCondition.wait(mLock);
1297    }
1298
1299    return mPrepareResult;
1300}
1301
1302status_t AwesomePlayer::prepareAsync() {
1303    Mutex::Autolock autoLock(mLock);
1304
1305    if (mFlags & PREPARING) {
1306        return UNKNOWN_ERROR;  // async prepare already pending
1307    }
1308
1309    mIsAsyncPrepare = true;
1310    return prepareAsync_l();
1311}
1312
1313status_t AwesomePlayer::prepareAsync_l() {
1314    if (mFlags & PREPARING) {
1315        return UNKNOWN_ERROR;  // async prepare already pending
1316    }
1317
1318    if (!mQueueStarted) {
1319        mQueue.start();
1320        mQueueStarted = true;
1321    }
1322
1323    mFlags |= PREPARING;
1324    mAsyncPrepareEvent = new AwesomeEvent(
1325            this, &AwesomePlayer::onPrepareAsyncEvent);
1326
1327    mQueue.postEvent(mAsyncPrepareEvent);
1328
1329    return OK;
1330}
1331
1332status_t AwesomePlayer::finishSetDataSource_l() {
1333    sp<DataSource> dataSource;
1334
1335    if (!strncasecmp("http://", mUri.string(), 7)) {
1336        mConnectingDataSource = new NuHTTPDataSource;
1337
1338        mLock.unlock();
1339        status_t err = mConnectingDataSource->connect(mUri, &mUriHeaders);
1340        mLock.lock();
1341
1342        if (err != OK) {
1343            mConnectingDataSource.clear();
1344
1345            LOGI("mConnectingDataSource->connect() returned %d", err);
1346            return err;
1347        }
1348
1349#if 0
1350        mCachedSource = new NuCachedSource2(
1351                new ThrottledSource(
1352                    mConnectingDataSource, 50 * 1024 /* bytes/sec */));
1353#else
1354        mCachedSource = new NuCachedSource2(mConnectingDataSource);
1355#endif
1356        mConnectingDataSource.clear();
1357
1358        dataSource = mCachedSource;
1359    } else if (!strncasecmp(mUri.string(), "httplive://", 11)) {
1360        String8 uri("http://");
1361        uri.append(mUri.string() + 11);
1362
1363        dataSource = new LiveSource(uri.string());
1364
1365        mCachedSource = new NuCachedSource2(dataSource);
1366        dataSource = mCachedSource;
1367
1368        sp<MediaExtractor> extractor =
1369            MediaExtractor::Create(dataSource, MEDIA_MIMETYPE_CONTAINER_MPEG2TS);
1370
1371        return setDataSource_l(extractor);
1372    } else if (!strncmp("rtsp://gtalk/", mUri.string(), 13)) {
1373        if (mLooper == NULL) {
1374            mLooper = new ALooper;
1375            mLooper->setName("gtalk rtp");
1376            mLooper->start(
1377                    false /* runOnCallingThread */,
1378                    false /* canCallJava */,
1379                    PRIORITY_HIGHEST);
1380        }
1381
1382        const char *startOfCodecString = &mUri.string()[13];
1383        const char *startOfSlash1 = strchr(startOfCodecString, '/');
1384        if (startOfSlash1 == NULL) {
1385            return BAD_VALUE;
1386        }
1387        const char *startOfWidthString = &startOfSlash1[1];
1388        const char *startOfSlash2 = strchr(startOfWidthString, '/');
1389        if (startOfSlash2 == NULL) {
1390            return BAD_VALUE;
1391        }
1392        const char *startOfHeightString = &startOfSlash2[1];
1393
1394        String8 codecString(startOfCodecString, startOfSlash1 - startOfCodecString);
1395        String8 widthString(startOfWidthString, startOfSlash2 - startOfWidthString);
1396        String8 heightString(startOfHeightString);
1397
1398#if 0
1399        mRTPPusher = new UDPPusher("/data/misc/rtpout.bin", 5434);
1400        mLooper->registerHandler(mRTPPusher);
1401
1402        mRTCPPusher = new UDPPusher("/data/misc/rtcpout.bin", 5435);
1403        mLooper->registerHandler(mRTCPPusher);
1404#endif
1405
1406        mRTPSession = new ARTPSession;
1407        mLooper->registerHandler(mRTPSession);
1408
1409#if 0
1410        // My AMR SDP
1411        static const char *raw =
1412            "v=0\r\n"
1413            "o=- 64 233572944 IN IP4 127.0.0.0\r\n"
1414            "s=QuickTime\r\n"
1415            "t=0 0\r\n"
1416            "a=range:npt=0-315\r\n"
1417            "a=isma-compliance:2,2.0,2\r\n"
1418            "m=audio 5434 RTP/AVP 97\r\n"
1419            "c=IN IP4 127.0.0.1\r\n"
1420            "b=AS:30\r\n"
1421            "a=rtpmap:97 AMR/8000/1\r\n"
1422            "a=fmtp:97 octet-align\r\n";
1423#elif 1
1424        String8 sdp;
1425        sdp.appendFormat(
1426            "v=0\r\n"
1427            "o=- 64 233572944 IN IP4 127.0.0.0\r\n"
1428            "s=QuickTime\r\n"
1429            "t=0 0\r\n"
1430            "a=range:npt=0-315\r\n"
1431            "a=isma-compliance:2,2.0,2\r\n"
1432            "m=video 5434 RTP/AVP 97\r\n"
1433            "c=IN IP4 127.0.0.1\r\n"
1434            "b=AS:30\r\n"
1435            "a=rtpmap:97 %s/90000\r\n"
1436            "a=cliprect:0,0,%s,%s\r\n"
1437            "a=framesize:97 %s-%s\r\n",
1438
1439            codecString.string(),
1440            heightString.string(), widthString.string(),
1441            widthString.string(), heightString.string()
1442            );
1443        const char *raw = sdp.string();
1444
1445#endif
1446
1447        sp<ASessionDescription> desc = new ASessionDescription;
1448        CHECK(desc->setTo(raw, strlen(raw)));
1449
1450        CHECK_EQ(mRTPSession->setup(desc), (status_t)OK);
1451
1452        if (mRTPPusher != NULL) {
1453            mRTPPusher->start();
1454        }
1455
1456        if (mRTCPPusher != NULL) {
1457            mRTCPPusher->start();
1458        }
1459
1460        CHECK_EQ(mRTPSession->countTracks(), 1u);
1461        sp<MediaSource> source = mRTPSession->trackAt(0);
1462
1463#if 0
1464        bool eos;
1465        while (((APacketSource *)source.get())
1466                ->getQueuedDuration(&eos) < 5000000ll && !eos) {
1467            usleep(100000ll);
1468        }
1469#endif
1470
1471        const char *mime;
1472        CHECK(source->getFormat()->findCString(kKeyMIMEType, &mime));
1473
1474        if (!strncasecmp("video/", mime, 6)) {
1475            setVideoSource(source);
1476        } else {
1477            CHECK(!strncasecmp("audio/", mime, 6));
1478            setAudioSource(source);
1479        }
1480
1481        mExtractorFlags = MediaExtractor::CAN_PAUSE;
1482
1483        return OK;
1484    } else if (!strncasecmp("rtsp://", mUri.string(), 7)) {
1485        if (mLooper == NULL) {
1486            mLooper = new ALooper;
1487            mLooper->setName("rtsp");
1488            mLooper->start();
1489        }
1490        mRTSPController = new ARTSPController(mLooper);
1491        status_t err = mRTSPController->connect(mUri.string());
1492
1493        LOGI("ARTSPController::connect returned %d", err);
1494
1495        if (err != OK) {
1496            mRTSPController.clear();
1497            return err;
1498        }
1499
1500        sp<MediaExtractor> extractor = mRTSPController.get();
1501        return setDataSource_l(extractor);
1502    } else {
1503        dataSource = DataSource::CreateFromURI(mUri.string(), &mUriHeaders);
1504    }
1505
1506    if (dataSource == NULL) {
1507        return UNKNOWN_ERROR;
1508    }
1509
1510    sp<MediaExtractor> extractor = MediaExtractor::Create(dataSource);
1511
1512    if (extractor == NULL) {
1513        return UNKNOWN_ERROR;
1514    }
1515
1516    return setDataSource_l(extractor);
1517}
1518
1519void AwesomePlayer::abortPrepare(status_t err) {
1520    CHECK(err != OK);
1521
1522    if (mIsAsyncPrepare) {
1523        notifyListener_l(MEDIA_ERROR, MEDIA_ERROR_UNKNOWN, err);
1524    }
1525
1526    mPrepareResult = err;
1527    mFlags &= ~(PREPARING|PREPARE_CANCELLED);
1528    mAsyncPrepareEvent = NULL;
1529    mPreparedCondition.broadcast();
1530}
1531
1532// static
1533bool AwesomePlayer::ContinuePreparation(void *cookie) {
1534    AwesomePlayer *me = static_cast<AwesomePlayer *>(cookie);
1535
1536    return (me->mFlags & PREPARE_CANCELLED) == 0;
1537}
1538
1539void AwesomePlayer::onPrepareAsyncEvent() {
1540    Mutex::Autolock autoLock(mLock);
1541
1542    if (mFlags & PREPARE_CANCELLED) {
1543        LOGI("prepare was cancelled before doing anything");
1544        abortPrepare(UNKNOWN_ERROR);
1545        return;
1546    }
1547
1548    if (mUri.size() > 0) {
1549        status_t err = finishSetDataSource_l();
1550
1551        if (err != OK) {
1552            abortPrepare(err);
1553            return;
1554        }
1555    }
1556
1557    if (mVideoTrack != NULL && mVideoSource == NULL) {
1558        status_t err = initVideoDecoder();
1559
1560        if (err != OK) {
1561            abortPrepare(err);
1562            return;
1563        }
1564    }
1565
1566    if (mAudioTrack != NULL && mAudioSource == NULL) {
1567        status_t err = initAudioDecoder();
1568
1569        if (err != OK) {
1570            abortPrepare(err);
1571            return;
1572        }
1573    }
1574
1575    if (mCachedSource != NULL || mRTSPController != NULL) {
1576        postBufferingEvent_l();
1577    } else {
1578        finishAsyncPrepare_l();
1579    }
1580}
1581
1582void AwesomePlayer::finishAsyncPrepare_l() {
1583    if (mIsAsyncPrepare) {
1584        if (mVideoSource == NULL) {
1585            notifyListener_l(MEDIA_SET_VIDEO_SIZE, 0, 0);
1586        } else {
1587            notifyVideoSize_l();
1588        }
1589
1590        notifyListener_l(MEDIA_PREPARED);
1591    }
1592
1593    mPrepareResult = OK;
1594    mFlags &= ~(PREPARING|PREPARE_CANCELLED);
1595    mFlags |= PREPARED;
1596    mAsyncPrepareEvent = NULL;
1597    mPreparedCondition.broadcast();
1598}
1599
1600status_t AwesomePlayer::suspend() {
1601    LOGV("suspend");
1602    Mutex::Autolock autoLock(mLock);
1603
1604    if (mSuspensionState != NULL) {
1605        if (mLastVideoBuffer == NULL) {
1606            //go into here if video is suspended again
1607            //after resuming without being played between
1608            //them
1609            SuspensionState *state = mSuspensionState;
1610            mSuspensionState = NULL;
1611            reset_l();
1612            mSuspensionState = state;
1613            return OK;
1614        }
1615
1616        delete mSuspensionState;
1617        mSuspensionState = NULL;
1618    }
1619
1620    if (mFlags & PREPARING) {
1621        mFlags |= PREPARE_CANCELLED;
1622        if (mConnectingDataSource != NULL) {
1623            LOGI("interrupting the connection process");
1624            mConnectingDataSource->disconnect();
1625        }
1626    }
1627
1628    while (mFlags & PREPARING) {
1629        mPreparedCondition.wait(mLock);
1630    }
1631
1632    SuspensionState *state = new SuspensionState;
1633    state->mUri = mUri;
1634    state->mUriHeaders = mUriHeaders;
1635    state->mFileSource = mFileSource;
1636
1637    state->mFlags = mFlags & (PLAYING | AUTO_LOOPING | LOOPING | AT_EOS);
1638    getPosition(&state->mPositionUs);
1639
1640    if (mLastVideoBuffer) {
1641        size_t size = mLastVideoBuffer->range_length();
1642
1643        if (size) {
1644            int32_t unreadable;
1645            if (!mLastVideoBuffer->meta_data()->findInt32(
1646                        kKeyIsUnreadable, &unreadable)
1647                    || unreadable == 0) {
1648                state->mLastVideoFrameSize = size;
1649                state->mLastVideoFrame = malloc(size);
1650                memcpy(state->mLastVideoFrame,
1651                       (const uint8_t *)mLastVideoBuffer->data()
1652                            + mLastVideoBuffer->range_offset(),
1653                       size);
1654
1655                state->mVideoWidth = mVideoWidth;
1656                state->mVideoHeight = mVideoHeight;
1657
1658                sp<MetaData> meta = mVideoSource->getFormat();
1659                CHECK(meta->findInt32(kKeyColorFormat, &state->mColorFormat));
1660                CHECK(meta->findInt32(kKeyWidth, &state->mDecodedWidth));
1661                CHECK(meta->findInt32(kKeyHeight, &state->mDecodedHeight));
1662            } else {
1663                LOGV("Unable to save last video frame, we have no access to "
1664                     "the decoded video data.");
1665            }
1666        }
1667    }
1668
1669    reset_l();
1670
1671    mSuspensionState = state;
1672
1673    return OK;
1674}
1675
1676status_t AwesomePlayer::resume() {
1677    LOGV("resume");
1678    Mutex::Autolock autoLock(mLock);
1679
1680    if (mSuspensionState == NULL) {
1681        return INVALID_OPERATION;
1682    }
1683
1684    SuspensionState *state = mSuspensionState;
1685    mSuspensionState = NULL;
1686
1687    status_t err;
1688    if (state->mFileSource != NULL) {
1689        err = setDataSource_l(state->mFileSource);
1690
1691        if (err == OK) {
1692            mFileSource = state->mFileSource;
1693        }
1694    } else {
1695        err = setDataSource_l(state->mUri, &state->mUriHeaders);
1696    }
1697
1698    if (err != OK) {
1699        delete state;
1700        state = NULL;
1701
1702        return err;
1703    }
1704
1705    seekTo_l(state->mPositionUs);
1706
1707    mFlags = state->mFlags & (AUTO_LOOPING | LOOPING | AT_EOS);
1708
1709    if (state->mLastVideoFrame && (mSurface != NULL || mISurface != NULL)) {
1710        mVideoRenderer =
1711            new AwesomeLocalRenderer(
1712                    true,  // previewOnly
1713                    "",
1714                    (OMX_COLOR_FORMATTYPE)state->mColorFormat,
1715                    mISurface,
1716                    mSurface,
1717                    state->mVideoWidth,
1718                    state->mVideoHeight,
1719                    state->mDecodedWidth,
1720                    state->mDecodedHeight);
1721
1722        mVideoRendererIsPreview = true;
1723
1724        ((AwesomeLocalRenderer *)mVideoRenderer.get())->render(
1725                state->mLastVideoFrame, state->mLastVideoFrameSize);
1726    }
1727
1728    if (state->mFlags & PLAYING) {
1729        play_l();
1730    }
1731
1732    mSuspensionState = state;
1733    state = NULL;
1734
1735    return OK;
1736}
1737
1738uint32_t AwesomePlayer::flags() const {
1739    return mExtractorFlags;
1740}
1741
1742void AwesomePlayer::postAudioEOS() {
1743    postCheckAudioStatusEvent_l();
1744}
1745
1746void AwesomePlayer::postAudioSeekComplete() {
1747    postCheckAudioStatusEvent_l();
1748}
1749
1750}  // namespace android
1751
1752