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