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