NuPlayer.cpp revision 2546219a54970e0ad53bd218586cdc48d6039b20
1/*
2 * Copyright (C) 2010 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 "NuPlayer"
19#include <utils/Log.h>
20
21#include "NuPlayer.h"
22
23#include "HTTPLiveSource.h"
24#include "NuPlayerDecoder.h"
25#include "NuPlayerDriver.h"
26#include "NuPlayerRenderer.h"
27#include "NuPlayerSource.h"
28#include "RTSPSource.h"
29#include "StreamingSource.h"
30#include "GenericSource.h"
31#include "mp4/MP4Source.h"
32
33#include "ATSParser.h"
34
35#include <cutils/properties.h> // for property_get
36#include <media/stagefright/foundation/hexdump.h>
37#include <media/stagefright/foundation/ABuffer.h>
38#include <media/stagefright/foundation/ADebug.h>
39#include <media/stagefright/foundation/AMessage.h>
40#include <media/stagefright/ACodec.h>
41#include <media/stagefright/MediaDefs.h>
42#include <media/stagefright/MediaErrors.h>
43#include <media/stagefright/MetaData.h>
44#include <gui/ISurfaceTexture.h>
45
46#include "avc_utils.h"
47
48#include "ESDS.h"
49#include <media/stagefright/Utils.h>
50
51namespace android {
52
53////////////////////////////////////////////////////////////////////////////////
54
55NuPlayer::NuPlayer()
56    : mUIDValid(false),
57      mVideoIsAVC(false),
58      mAudioEOS(false),
59      mVideoEOS(false),
60      mScanSourcesPending(false),
61      mScanSourcesGeneration(0),
62      mPollDurationGeneration(0),
63      mTimeDiscontinuityPending(false),
64      mFlushingAudio(NONE),
65      mFlushingVideo(NONE),
66      mResetInProgress(false),
67      mResetPostponed(false),
68      mSkipRenderingAudioUntilMediaTimeUs(-1ll),
69      mSkipRenderingVideoUntilMediaTimeUs(-1ll),
70      mVideoLateByUs(0ll),
71      mNumFramesTotal(0ll),
72      mNumFramesDropped(0ll),
73      mVideoScalingMode(NATIVE_WINDOW_SCALING_MODE_SCALE_TO_WINDOW) {
74}
75
76NuPlayer::~NuPlayer() {
77}
78
79void NuPlayer::setUID(uid_t uid) {
80    mUIDValid = true;
81    mUID = uid;
82}
83
84void NuPlayer::setDriver(const wp<NuPlayerDriver> &driver) {
85    mDriver = driver;
86}
87
88void NuPlayer::setDataSource(const sp<IStreamSource> &source) {
89    sp<AMessage> msg = new AMessage(kWhatSetDataSource, id());
90
91    char prop[PROPERTY_VALUE_MAX];
92    if (property_get("media.stagefright.use-mp4source", prop, NULL)
93            && (!strcmp(prop, "1") || !strcasecmp(prop, "true"))) {
94        msg->setObject("source", new MP4Source(source));
95    } else {
96        msg->setObject("source", new StreamingSource(source));
97    }
98
99    msg->post();
100}
101
102static bool IsHTTPLiveURL(const char *url) {
103    if (!strncasecmp("http://", url, 7)
104            || !strncasecmp("https://", url, 8)) {
105        size_t len = strlen(url);
106        if (len >= 5 && !strcasecmp(".m3u8", &url[len - 5])) {
107            return true;
108        }
109
110        if (strstr(url,"m3u8")) {
111            return true;
112        }
113    }
114
115    return false;
116}
117
118void NuPlayer::setDataSource(
119        const char *url, const KeyedVector<String8, String8> *headers) {
120    sp<AMessage> msg = new AMessage(kWhatSetDataSource, id());
121
122    sp<Source> source;
123    if (IsHTTPLiveURL(url)) {
124        source = new HTTPLiveSource(url, headers, mUIDValid, mUID);
125    } else if (!strncasecmp(url, "rtsp://", 7)) {
126        source = new RTSPSource(url, headers, mUIDValid, mUID);
127    } else {
128        source = new GenericSource(url, headers, mUIDValid, mUID);
129    }
130
131    msg->setObject("source", source);
132    msg->post();
133}
134
135void NuPlayer::setDataSource(int fd, int64_t offset, int64_t length) {
136    sp<AMessage> msg = new AMessage(kWhatSetDataSource, id());
137
138    sp<Source> source = new GenericSource(fd, offset, length);
139    msg->setObject("source", source);
140    msg->post();
141}
142
143void NuPlayer::setVideoSurfaceTexture(const sp<ISurfaceTexture> &surfaceTexture) {
144    sp<AMessage> msg = new AMessage(kWhatSetVideoNativeWindow, id());
145    sp<SurfaceTextureClient> surfaceTextureClient(surfaceTexture != NULL ?
146                new SurfaceTextureClient(surfaceTexture) : NULL);
147    msg->setObject("native-window", new NativeWindowWrapper(surfaceTextureClient));
148    msg->post();
149}
150
151void NuPlayer::setAudioSink(const sp<MediaPlayerBase::AudioSink> &sink) {
152    sp<AMessage> msg = new AMessage(kWhatSetAudioSink, id());
153    msg->setObject("sink", sink);
154    msg->post();
155}
156
157void NuPlayer::start() {
158    (new AMessage(kWhatStart, id()))->post();
159}
160
161void NuPlayer::pause() {
162    (new AMessage(kWhatPause, id()))->post();
163}
164
165void NuPlayer::resume() {
166    (new AMessage(kWhatResume, id()))->post();
167}
168
169void NuPlayer::resetAsync() {
170    (new AMessage(kWhatReset, id()))->post();
171}
172
173void NuPlayer::seekToAsync(int64_t seekTimeUs) {
174    sp<AMessage> msg = new AMessage(kWhatSeek, id());
175    msg->setInt64("seekTimeUs", seekTimeUs);
176    msg->post();
177}
178
179// static
180bool NuPlayer::IsFlushingState(FlushStatus state, bool *needShutdown) {
181    switch (state) {
182        case FLUSHING_DECODER:
183            if (needShutdown != NULL) {
184                *needShutdown = false;
185            }
186            return true;
187
188        case FLUSHING_DECODER_SHUTDOWN:
189            if (needShutdown != NULL) {
190                *needShutdown = true;
191            }
192            return true;
193
194        default:
195            return false;
196    }
197}
198
199void NuPlayer::onMessageReceived(const sp<AMessage> &msg) {
200    switch (msg->what()) {
201        case kWhatSetDataSource:
202        {
203            ALOGV("kWhatSetDataSource");
204
205            CHECK(mSource == NULL);
206
207            sp<RefBase> obj;
208            CHECK(msg->findObject("source", &obj));
209
210            mSource = static_cast<Source *>(obj.get());
211            break;
212        }
213
214        case kWhatPollDuration:
215        {
216            int32_t generation;
217            CHECK(msg->findInt32("generation", &generation));
218
219            if (generation != mPollDurationGeneration) {
220                // stale
221                break;
222            }
223
224            int64_t durationUs;
225            if (mDriver != NULL && mSource->getDuration(&durationUs) == OK) {
226                sp<NuPlayerDriver> driver = mDriver.promote();
227                if (driver != NULL) {
228                    driver->notifyDuration(durationUs);
229                }
230            }
231
232            msg->post(1000000ll);  // poll again in a second.
233            break;
234        }
235
236        case kWhatSetVideoNativeWindow:
237        {
238            ALOGV("kWhatSetVideoNativeWindow");
239
240            sp<RefBase> obj;
241            CHECK(msg->findObject("native-window", &obj));
242
243            mNativeWindow = static_cast<NativeWindowWrapper *>(obj.get());
244
245            // XXX - ignore error from setVideoScalingMode for now
246            setVideoScalingMode(mVideoScalingMode);
247            break;
248        }
249
250        case kWhatSetAudioSink:
251        {
252            ALOGV("kWhatSetAudioSink");
253
254            sp<RefBase> obj;
255            CHECK(msg->findObject("sink", &obj));
256
257            mAudioSink = static_cast<MediaPlayerBase::AudioSink *>(obj.get());
258            break;
259        }
260
261        case kWhatStart:
262        {
263            ALOGV("kWhatStart");
264
265            mVideoIsAVC = false;
266            mAudioEOS = false;
267            mVideoEOS = false;
268            mSkipRenderingAudioUntilMediaTimeUs = -1;
269            mSkipRenderingVideoUntilMediaTimeUs = -1;
270            mVideoLateByUs = 0;
271            mNumFramesTotal = 0;
272            mNumFramesDropped = 0;
273
274            mSource->start();
275
276            mRenderer = new Renderer(
277                    mAudioSink,
278                    new AMessage(kWhatRendererNotify, id()));
279
280            looper()->registerHandler(mRenderer);
281
282            postScanSources();
283            break;
284        }
285
286        case kWhatScanSources:
287        {
288            int32_t generation;
289            CHECK(msg->findInt32("generation", &generation));
290            if (generation != mScanSourcesGeneration) {
291                // Drop obsolete msg.
292                break;
293            }
294
295            mScanSourcesPending = false;
296
297            ALOGV("scanning sources haveAudio=%d, haveVideo=%d",
298                 mAudioDecoder != NULL, mVideoDecoder != NULL);
299
300            bool mHadAnySourcesBefore =
301                (mAudioDecoder != NULL) || (mVideoDecoder != NULL);
302
303            if (mNativeWindow != NULL) {
304                instantiateDecoder(false, &mVideoDecoder);
305            }
306
307            if (mAudioSink != NULL) {
308                instantiateDecoder(true, &mAudioDecoder);
309            }
310
311            if (!mHadAnySourcesBefore
312                    && (mAudioDecoder != NULL || mVideoDecoder != NULL)) {
313                // This is the first time we've found anything playable.
314
315                uint32_t flags = mSource->flags();
316
317                if (flags & Source::FLAG_DYNAMIC_DURATION) {
318                    schedulePollDuration();
319                }
320            }
321
322            status_t err;
323            if ((err = mSource->feedMoreTSData()) != OK) {
324                if (mAudioDecoder == NULL && mVideoDecoder == NULL) {
325                    // We're not currently decoding anything (no audio or
326                    // video tracks found) and we just ran out of input data.
327
328                    if (err == ERROR_END_OF_STREAM) {
329                        notifyListener(MEDIA_PLAYBACK_COMPLETE, 0, 0);
330                    } else {
331                        notifyListener(MEDIA_ERROR, MEDIA_ERROR_UNKNOWN, err);
332                    }
333                }
334                break;
335            }
336
337            if ((mAudioDecoder == NULL && mAudioSink != NULL)
338                    || (mVideoDecoder == NULL && mNativeWindow != NULL)) {
339                msg->post(100000ll);
340                mScanSourcesPending = true;
341            }
342            break;
343        }
344
345        case kWhatVideoNotify:
346        case kWhatAudioNotify:
347        {
348            bool audio = msg->what() == kWhatAudioNotify;
349
350            sp<AMessage> codecRequest;
351            CHECK(msg->findMessage("codec-request", &codecRequest));
352
353            int32_t what;
354            CHECK(codecRequest->findInt32("what", &what));
355
356            if (what == ACodec::kWhatFillThisBuffer) {
357                status_t err = feedDecoderInputData(
358                        audio, codecRequest);
359
360                if (err == -EWOULDBLOCK) {
361                    if (mSource->feedMoreTSData() == OK) {
362                        msg->post(10000ll);
363                    }
364                }
365            } else if (what == ACodec::kWhatEOS) {
366                int32_t err;
367                CHECK(codecRequest->findInt32("err", &err));
368
369                if (err == ERROR_END_OF_STREAM) {
370                    ALOGV("got %s decoder EOS", audio ? "audio" : "video");
371                } else {
372                    ALOGV("got %s decoder EOS w/ error %d",
373                         audio ? "audio" : "video",
374                         err);
375                }
376
377                mRenderer->queueEOS(audio, err);
378            } else if (what == ACodec::kWhatFlushCompleted) {
379                bool needShutdown;
380
381                if (audio) {
382                    CHECK(IsFlushingState(mFlushingAudio, &needShutdown));
383                    mFlushingAudio = FLUSHED;
384                } else {
385                    CHECK(IsFlushingState(mFlushingVideo, &needShutdown));
386                    mFlushingVideo = FLUSHED;
387
388                    mVideoLateByUs = 0;
389                }
390
391                ALOGV("decoder %s flush completed", audio ? "audio" : "video");
392
393                if (needShutdown) {
394                    ALOGV("initiating %s decoder shutdown",
395                         audio ? "audio" : "video");
396
397                    (audio ? mAudioDecoder : mVideoDecoder)->initiateShutdown();
398
399                    if (audio) {
400                        mFlushingAudio = SHUTTING_DOWN_DECODER;
401                    } else {
402                        mFlushingVideo = SHUTTING_DOWN_DECODER;
403                    }
404                }
405
406                finishFlushIfPossible();
407            } else if (what == ACodec::kWhatOutputFormatChanged) {
408                if (audio) {
409                    int32_t numChannels;
410                    CHECK(codecRequest->findInt32("channel-count", &numChannels));
411
412                    int32_t sampleRate;
413                    CHECK(codecRequest->findInt32("sample-rate", &sampleRate));
414
415                    ALOGV("Audio output format changed to %d Hz, %d channels",
416                         sampleRate, numChannels);
417
418                    mAudioSink->close();
419
420                    audio_output_flags_t flags;
421                    int64_t durationUs;
422                    // FIXME: we should handle the case where the video decoder is created after
423                    // we receive the format change indication. Current code will just make that
424                    // we select deep buffer with video which should not be a problem as it should
425                    // not prevent from keeping A/V sync.
426                    if (mVideoDecoder == NULL &&
427                            mSource->getDuration(&durationUs) == OK &&
428                            durationUs > AUDIO_SINK_MIN_DEEP_BUFFER_DURATION_US) {
429                        flags = AUDIO_OUTPUT_FLAG_DEEP_BUFFER;
430                    } else {
431                        flags = AUDIO_OUTPUT_FLAG_NONE;
432                    }
433
434                    int32_t channelMask;
435                    if (!codecRequest->findInt32("channel-mask", &channelMask)) {
436                        channelMask = CHANNEL_MASK_USE_CHANNEL_ORDER;
437                    }
438
439                    CHECK_EQ(mAudioSink->open(
440                                sampleRate,
441                                numChannels,
442                                (audio_channel_mask_t)channelMask,
443                                AUDIO_FORMAT_PCM_16_BIT,
444                                8 /* bufferCount */,
445                                NULL,
446                                NULL,
447                                flags),
448                             (status_t)OK);
449                    mAudioSink->start();
450
451                    mRenderer->signalAudioSinkChanged();
452                } else {
453                    // video
454
455                    int32_t width, height;
456                    CHECK(codecRequest->findInt32("width", &width));
457                    CHECK(codecRequest->findInt32("height", &height));
458
459                    int32_t cropLeft, cropTop, cropRight, cropBottom;
460                    CHECK(codecRequest->findRect(
461                                "crop",
462                                &cropLeft, &cropTop, &cropRight, &cropBottom));
463
464                    ALOGV("Video output format changed to %d x %d "
465                         "(crop: %d x %d @ (%d, %d))",
466                         width, height,
467                         (cropRight - cropLeft + 1),
468                         (cropBottom - cropTop + 1),
469                         cropLeft, cropTop);
470
471                    notifyListener(
472                            MEDIA_SET_VIDEO_SIZE,
473                            cropRight - cropLeft + 1,
474                            cropBottom - cropTop + 1);
475                }
476            } else if (what == ACodec::kWhatShutdownCompleted) {
477                ALOGV("%s shutdown completed", audio ? "audio" : "video");
478                if (audio) {
479                    mAudioDecoder.clear();
480
481                    CHECK_EQ((int)mFlushingAudio, (int)SHUTTING_DOWN_DECODER);
482                    mFlushingAudio = SHUT_DOWN;
483                } else {
484                    mVideoDecoder.clear();
485
486                    CHECK_EQ((int)mFlushingVideo, (int)SHUTTING_DOWN_DECODER);
487                    mFlushingVideo = SHUT_DOWN;
488                }
489
490                finishFlushIfPossible();
491            } else if (what == ACodec::kWhatError) {
492                ALOGE("Received error from %s decoder, aborting playback.",
493                     audio ? "audio" : "video");
494
495                mRenderer->queueEOS(audio, UNKNOWN_ERROR);
496            } else if (what == ACodec::kWhatDrainThisBuffer) {
497                renderBuffer(audio, codecRequest);
498            } else {
499                ALOGV("Unhandled codec notification %d.", what);
500            }
501
502            break;
503        }
504
505        case kWhatRendererNotify:
506        {
507            int32_t what;
508            CHECK(msg->findInt32("what", &what));
509
510            if (what == Renderer::kWhatEOS) {
511                int32_t audio;
512                CHECK(msg->findInt32("audio", &audio));
513
514                int32_t finalResult;
515                CHECK(msg->findInt32("finalResult", &finalResult));
516
517                if (audio) {
518                    mAudioEOS = true;
519                } else {
520                    mVideoEOS = true;
521                }
522
523                if (finalResult == ERROR_END_OF_STREAM) {
524                    ALOGV("reached %s EOS", audio ? "audio" : "video");
525                } else {
526                    ALOGE("%s track encountered an error (%d)",
527                         audio ? "audio" : "video", finalResult);
528
529                    notifyListener(
530                            MEDIA_ERROR, MEDIA_ERROR_UNKNOWN, finalResult);
531                }
532
533                if ((mAudioEOS || mAudioDecoder == NULL)
534                        && (mVideoEOS || mVideoDecoder == NULL)) {
535                    notifyListener(MEDIA_PLAYBACK_COMPLETE, 0, 0);
536                }
537            } else if (what == Renderer::kWhatPosition) {
538                int64_t positionUs;
539                CHECK(msg->findInt64("positionUs", &positionUs));
540
541                CHECK(msg->findInt64("videoLateByUs", &mVideoLateByUs));
542
543                if (mDriver != NULL) {
544                    sp<NuPlayerDriver> driver = mDriver.promote();
545                    if (driver != NULL) {
546                        driver->notifyPosition(positionUs);
547
548                        driver->notifyFrameStats(
549                                mNumFramesTotal, mNumFramesDropped);
550                    }
551                }
552            } else if (what == Renderer::kWhatFlushComplete) {
553                int32_t audio;
554                CHECK(msg->findInt32("audio", &audio));
555
556                ALOGV("renderer %s flush completed.", audio ? "audio" : "video");
557            } else if (what == Renderer::kWhatVideoRenderingStart) {
558                notifyListener(MEDIA_INFO, MEDIA_INFO_RENDERING_START, 0);
559            }
560            break;
561        }
562
563        case kWhatMoreDataQueued:
564        {
565            break;
566        }
567
568        case kWhatReset:
569        {
570            ALOGV("kWhatReset");
571
572            cancelPollDuration();
573
574            if (mRenderer != NULL) {
575                // There's an edge case where the renderer owns all output
576                // buffers and is paused, therefore the decoder will not read
577                // more input data and will never encounter the matching
578                // discontinuity. To avoid this, we resume the renderer.
579
580                if (mFlushingAudio == AWAITING_DISCONTINUITY
581                        || mFlushingVideo == AWAITING_DISCONTINUITY) {
582                    mRenderer->resume();
583                }
584            }
585
586            if (mFlushingAudio != NONE || mFlushingVideo != NONE) {
587                // We're currently flushing, postpone the reset until that's
588                // completed.
589
590                ALOGV("postponing reset mFlushingAudio=%d, mFlushingVideo=%d",
591                      mFlushingAudio, mFlushingVideo);
592
593                mResetPostponed = true;
594                break;
595            }
596
597            if (mAudioDecoder == NULL && mVideoDecoder == NULL) {
598                finishReset();
599                break;
600            }
601
602            mTimeDiscontinuityPending = true;
603
604            if (mAudioDecoder != NULL) {
605                flushDecoder(true /* audio */, true /* needShutdown */);
606            }
607
608            if (mVideoDecoder != NULL) {
609                flushDecoder(false /* audio */, true /* needShutdown */);
610            }
611
612            mResetInProgress = true;
613            break;
614        }
615
616        case kWhatSeek:
617        {
618            int64_t seekTimeUs;
619            CHECK(msg->findInt64("seekTimeUs", &seekTimeUs));
620
621            ALOGV("kWhatSeek seekTimeUs=%lld us (%.2f secs)",
622                 seekTimeUs, seekTimeUs / 1E6);
623
624            mSource->seekTo(seekTimeUs);
625
626            if (mDriver != NULL) {
627                sp<NuPlayerDriver> driver = mDriver.promote();
628                if (driver != NULL) {
629                    driver->notifySeekComplete();
630                }
631            }
632
633            break;
634        }
635
636        case kWhatPause:
637        {
638            CHECK(mRenderer != NULL);
639            mRenderer->pause();
640            break;
641        }
642
643        case kWhatResume:
644        {
645            CHECK(mRenderer != NULL);
646            mRenderer->resume();
647            break;
648        }
649
650        default:
651            TRESPASS();
652            break;
653    }
654}
655
656void NuPlayer::finishFlushIfPossible() {
657    if (mFlushingAudio != FLUSHED && mFlushingAudio != SHUT_DOWN) {
658        return;
659    }
660
661    if (mFlushingVideo != FLUSHED && mFlushingVideo != SHUT_DOWN) {
662        return;
663    }
664
665    ALOGV("both audio and video are flushed now.");
666
667    if (mTimeDiscontinuityPending) {
668        mRenderer->signalTimeDiscontinuity();
669        mTimeDiscontinuityPending = false;
670    }
671
672    if (mAudioDecoder != NULL) {
673        mAudioDecoder->signalResume();
674    }
675
676    if (mVideoDecoder != NULL) {
677        mVideoDecoder->signalResume();
678    }
679
680    mFlushingAudio = NONE;
681    mFlushingVideo = NONE;
682
683    if (mResetInProgress) {
684        ALOGV("reset completed");
685
686        mResetInProgress = false;
687        finishReset();
688    } else if (mResetPostponed) {
689        (new AMessage(kWhatReset, id()))->post();
690        mResetPostponed = false;
691    } else if (mAudioDecoder == NULL || mVideoDecoder == NULL) {
692        postScanSources();
693    }
694}
695
696void NuPlayer::finishReset() {
697    CHECK(mAudioDecoder == NULL);
698    CHECK(mVideoDecoder == NULL);
699
700    ++mScanSourcesGeneration;
701    mScanSourcesPending = false;
702
703    mRenderer.clear();
704
705    if (mSource != NULL) {
706        mSource->stop();
707        mSource.clear();
708    }
709
710    if (mDriver != NULL) {
711        sp<NuPlayerDriver> driver = mDriver.promote();
712        if (driver != NULL) {
713            driver->notifyResetComplete();
714        }
715    }
716}
717
718void NuPlayer::postScanSources() {
719    if (mScanSourcesPending) {
720        return;
721    }
722
723    sp<AMessage> msg = new AMessage(kWhatScanSources, id());
724    msg->setInt32("generation", mScanSourcesGeneration);
725    msg->post();
726
727    mScanSourcesPending = true;
728}
729
730status_t NuPlayer::instantiateDecoder(bool audio, sp<Decoder> *decoder) {
731    if (*decoder != NULL) {
732        return OK;
733    }
734
735    sp<AMessage> format = mSource->getFormat(audio);
736
737    if (format == NULL) {
738        return -EWOULDBLOCK;
739    }
740
741    if (!audio) {
742        AString mime;
743        CHECK(format->findString("mime", &mime));
744        mVideoIsAVC = !strcasecmp(MEDIA_MIMETYPE_VIDEO_AVC, mime.c_str());
745    }
746
747    sp<AMessage> notify =
748        new AMessage(audio ? kWhatAudioNotify : kWhatVideoNotify,
749                     id());
750
751    *decoder = audio ? new Decoder(notify) :
752                       new Decoder(notify, mNativeWindow);
753    looper()->registerHandler(*decoder);
754
755    (*decoder)->configure(format);
756
757    int64_t durationUs;
758    if (mDriver != NULL && mSource->getDuration(&durationUs) == OK) {
759        sp<NuPlayerDriver> driver = mDriver.promote();
760        if (driver != NULL) {
761            driver->notifyDuration(durationUs);
762        }
763    }
764
765    return OK;
766}
767
768status_t NuPlayer::feedDecoderInputData(bool audio, const sp<AMessage> &msg) {
769    sp<AMessage> reply;
770    CHECK(msg->findMessage("reply", &reply));
771
772    if ((audio && IsFlushingState(mFlushingAudio))
773            || (!audio && IsFlushingState(mFlushingVideo))) {
774        reply->setInt32("err", INFO_DISCONTINUITY);
775        reply->post();
776        return OK;
777    }
778
779    sp<ABuffer> accessUnit;
780
781    bool dropAccessUnit;
782    do {
783        status_t err = mSource->dequeueAccessUnit(audio, &accessUnit);
784
785        if (err == -EWOULDBLOCK) {
786            return err;
787        } else if (err != OK) {
788            if (err == INFO_DISCONTINUITY) {
789                int32_t type;
790                CHECK(accessUnit->meta()->findInt32("discontinuity", &type));
791
792                bool formatChange =
793                    (audio &&
794                     (type & ATSParser::DISCONTINUITY_AUDIO_FORMAT))
795                    || (!audio &&
796                            (type & ATSParser::DISCONTINUITY_VIDEO_FORMAT));
797
798                bool timeChange = (type & ATSParser::DISCONTINUITY_TIME) != 0;
799
800                ALOGI("%s discontinuity (formatChange=%d, time=%d)",
801                     audio ? "audio" : "video", formatChange, timeChange);
802
803                if (audio) {
804                    mSkipRenderingAudioUntilMediaTimeUs = -1;
805                } else {
806                    mSkipRenderingVideoUntilMediaTimeUs = -1;
807                }
808
809                if (timeChange) {
810                    sp<AMessage> extra;
811                    if (accessUnit->meta()->findMessage("extra", &extra)
812                            && extra != NULL) {
813                        int64_t resumeAtMediaTimeUs;
814                        if (extra->findInt64(
815                                    "resume-at-mediatimeUs", &resumeAtMediaTimeUs)) {
816                            ALOGI("suppressing rendering of %s until %lld us",
817                                    audio ? "audio" : "video", resumeAtMediaTimeUs);
818
819                            if (audio) {
820                                mSkipRenderingAudioUntilMediaTimeUs =
821                                    resumeAtMediaTimeUs;
822                            } else {
823                                mSkipRenderingVideoUntilMediaTimeUs =
824                                    resumeAtMediaTimeUs;
825                            }
826                        }
827                    }
828                }
829
830                mTimeDiscontinuityPending =
831                    mTimeDiscontinuityPending || timeChange;
832
833                if (formatChange || timeChange) {
834                    flushDecoder(audio, formatChange);
835                } else {
836                    // This stream is unaffected by the discontinuity
837
838                    if (audio) {
839                        mFlushingAudio = FLUSHED;
840                    } else {
841                        mFlushingVideo = FLUSHED;
842                    }
843
844                    finishFlushIfPossible();
845
846                    return -EWOULDBLOCK;
847                }
848            }
849
850            reply->setInt32("err", err);
851            reply->post();
852            return OK;
853        }
854
855        if (!audio) {
856            ++mNumFramesTotal;
857        }
858
859        dropAccessUnit = false;
860        if (!audio
861                && mVideoLateByUs > 100000ll
862                && mVideoIsAVC
863                && !IsAVCReferenceFrame(accessUnit)) {
864            dropAccessUnit = true;
865            ++mNumFramesDropped;
866        }
867    } while (dropAccessUnit);
868
869    // ALOGV("returned a valid buffer of %s data", audio ? "audio" : "video");
870
871#if 0
872    int64_t mediaTimeUs;
873    CHECK(accessUnit->meta()->findInt64("timeUs", &mediaTimeUs));
874    ALOGV("feeding %s input buffer at media time %.2f secs",
875         audio ? "audio" : "video",
876         mediaTimeUs / 1E6);
877#endif
878
879    reply->setBuffer("buffer", accessUnit);
880    reply->post();
881
882    return OK;
883}
884
885void NuPlayer::renderBuffer(bool audio, const sp<AMessage> &msg) {
886    // ALOGV("renderBuffer %s", audio ? "audio" : "video");
887
888    sp<AMessage> reply;
889    CHECK(msg->findMessage("reply", &reply));
890
891    if (IsFlushingState(audio ? mFlushingAudio : mFlushingVideo)) {
892        // We're currently attempting to flush the decoder, in order
893        // to complete this, the decoder wants all its buffers back,
894        // so we don't want any output buffers it sent us (from before
895        // we initiated the flush) to be stuck in the renderer's queue.
896
897        ALOGV("we're still flushing the %s decoder, sending its output buffer"
898             " right back.", audio ? "audio" : "video");
899
900        reply->post();
901        return;
902    }
903
904    sp<ABuffer> buffer;
905    CHECK(msg->findBuffer("buffer", &buffer));
906
907    int64_t &skipUntilMediaTimeUs =
908        audio
909            ? mSkipRenderingAudioUntilMediaTimeUs
910            : mSkipRenderingVideoUntilMediaTimeUs;
911
912    if (skipUntilMediaTimeUs >= 0) {
913        int64_t mediaTimeUs;
914        CHECK(buffer->meta()->findInt64("timeUs", &mediaTimeUs));
915
916        if (mediaTimeUs < skipUntilMediaTimeUs) {
917            ALOGV("dropping %s buffer at time %lld as requested.",
918                 audio ? "audio" : "video",
919                 mediaTimeUs);
920
921            reply->post();
922            return;
923        }
924
925        skipUntilMediaTimeUs = -1;
926    }
927
928    mRenderer->queueBuffer(audio, buffer, reply);
929}
930
931void NuPlayer::notifyListener(int msg, int ext1, int ext2) {
932    if (mDriver == NULL) {
933        return;
934    }
935
936    sp<NuPlayerDriver> driver = mDriver.promote();
937
938    if (driver == NULL) {
939        return;
940    }
941
942    driver->notifyListener(msg, ext1, ext2);
943}
944
945void NuPlayer::flushDecoder(bool audio, bool needShutdown) {
946    if ((audio && mAudioDecoder == NULL) || (!audio && mVideoDecoder == NULL)) {
947        ALOGI("flushDecoder %s without decoder present",
948             audio ? "audio" : "video");
949    }
950
951    // Make sure we don't continue to scan sources until we finish flushing.
952    ++mScanSourcesGeneration;
953    mScanSourcesPending = false;
954
955    (audio ? mAudioDecoder : mVideoDecoder)->signalFlush();
956    mRenderer->flush(audio);
957
958    FlushStatus newStatus =
959        needShutdown ? FLUSHING_DECODER_SHUTDOWN : FLUSHING_DECODER;
960
961    if (audio) {
962        CHECK(mFlushingAudio == NONE
963                || mFlushingAudio == AWAITING_DISCONTINUITY);
964
965        mFlushingAudio = newStatus;
966
967        if (mFlushingVideo == NONE) {
968            mFlushingVideo = (mVideoDecoder != NULL)
969                ? AWAITING_DISCONTINUITY
970                : FLUSHED;
971        }
972    } else {
973        CHECK(mFlushingVideo == NONE
974                || mFlushingVideo == AWAITING_DISCONTINUITY);
975
976        mFlushingVideo = newStatus;
977
978        if (mFlushingAudio == NONE) {
979            mFlushingAudio = (mAudioDecoder != NULL)
980                ? AWAITING_DISCONTINUITY
981                : FLUSHED;
982        }
983    }
984}
985
986sp<AMessage> NuPlayer::Source::getFormat(bool audio) {
987    sp<MetaData> meta = getFormatMeta(audio);
988
989    if (meta == NULL) {
990        return NULL;
991    }
992
993    sp<AMessage> msg = new AMessage;
994
995    if(convertMetaDataToMessage(meta, &msg) == OK) {
996        return msg;
997    }
998    return NULL;
999}
1000
1001status_t NuPlayer::setVideoScalingMode(int32_t mode) {
1002    mVideoScalingMode = mode;
1003    if (mNativeWindow != NULL
1004            && mNativeWindow->getNativeWindow() != NULL) {
1005        status_t ret = native_window_set_scaling_mode(
1006                mNativeWindow->getNativeWindow().get(), mVideoScalingMode);
1007        if (ret != OK) {
1008            ALOGE("Failed to set scaling mode (%d): %s",
1009                -ret, strerror(-ret));
1010            return ret;
1011        }
1012    }
1013    return OK;
1014}
1015
1016void NuPlayer::schedulePollDuration() {
1017    sp<AMessage> msg = new AMessage(kWhatPollDuration, id());
1018    msg->setInt32("generation", mPollDurationGeneration);
1019    msg->post();
1020}
1021
1022void NuPlayer::cancelPollDuration() {
1023    ++mPollDurationGeneration;
1024}
1025
1026}  // namespace android
1027