NuPlayer.cpp revision 0bdcaf9c5466cf9c84a8c98e160411ab74f05f4b
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
31#include "ATSParser.h"
32
33#include <media/stagefright/foundation/hexdump.h>
34#include <media/stagefright/foundation/ABuffer.h>
35#include <media/stagefright/foundation/ADebug.h>
36#include <media/stagefright/foundation/AMessage.h>
37#include <media/stagefright/ACodec.h>
38#include <media/stagefright/MediaDefs.h>
39#include <media/stagefright/MediaErrors.h>
40#include <media/stagefright/MetaData.h>
41#include <surfaceflinger/Surface.h>
42#include <gui/ISurfaceTexture.h>
43
44#include "avc_utils.h"
45
46namespace android {
47
48////////////////////////////////////////////////////////////////////////////////
49
50NuPlayer::NuPlayer()
51    : mUIDValid(false),
52      mVideoIsAVC(false),
53      mAudioEOS(false),
54      mVideoEOS(false),
55      mScanSourcesPending(false),
56      mScanSourcesGeneration(0),
57      mFlushingAudio(NONE),
58      mFlushingVideo(NONE),
59      mResetInProgress(false),
60      mResetPostponed(false),
61      mSkipRenderingAudioUntilMediaTimeUs(-1ll),
62      mSkipRenderingVideoUntilMediaTimeUs(-1ll),
63      mVideoLateByUs(0ll),
64      mNumFramesTotal(0ll),
65      mNumFramesDropped(0ll) {
66}
67
68NuPlayer::~NuPlayer() {
69}
70
71void NuPlayer::setUID(uid_t uid) {
72    mUIDValid = true;
73    mUID = uid;
74}
75
76void NuPlayer::setDriver(const wp<NuPlayerDriver> &driver) {
77    mDriver = driver;
78}
79
80void NuPlayer::setDataSource(const sp<IStreamSource> &source) {
81    sp<AMessage> msg = new AMessage(kWhatSetDataSource, id());
82
83    msg->setObject("source", new StreamingSource(source));
84    msg->post();
85}
86
87void NuPlayer::setDataSource(
88        const char *url, const KeyedVector<String8, String8> *headers) {
89    sp<AMessage> msg = new AMessage(kWhatSetDataSource, id());
90
91    if (!strncasecmp(url, "rtsp://", 7)) {
92        msg->setObject(
93                "source", new RTSPSource(url, headers, mUIDValid, mUID));
94    } else {
95        msg->setObject(
96                "source", new HTTPLiveSource(url, headers, mUIDValid, mUID));
97    }
98
99    msg->post();
100}
101
102void NuPlayer::setVideoSurface(const sp<Surface> &surface) {
103    sp<AMessage> msg = new AMessage(kWhatSetVideoNativeWindow, id());
104    msg->setObject("native-window", new NativeWindowWrapper(surface));
105    msg->post();
106}
107
108void NuPlayer::setVideoSurfaceTexture(const sp<ISurfaceTexture> &surfaceTexture) {
109    sp<AMessage> msg = new AMessage(kWhatSetVideoNativeWindow, id());
110    sp<SurfaceTextureClient> surfaceTextureClient(surfaceTexture != NULL ?
111                new SurfaceTextureClient(surfaceTexture) : NULL);
112    msg->setObject("native-window", new NativeWindowWrapper(surfaceTextureClient));
113    msg->post();
114}
115
116void NuPlayer::setAudioSink(const sp<MediaPlayerBase::AudioSink> &sink) {
117    sp<AMessage> msg = new AMessage(kWhatSetAudioSink, id());
118    msg->setObject("sink", sink);
119    msg->post();
120}
121
122void NuPlayer::start() {
123    (new AMessage(kWhatStart, id()))->post();
124}
125
126void NuPlayer::pause() {
127    (new AMessage(kWhatPause, id()))->post();
128}
129
130void NuPlayer::resume() {
131    (new AMessage(kWhatResume, id()))->post();
132}
133
134void NuPlayer::resetAsync() {
135    (new AMessage(kWhatReset, id()))->post();
136}
137
138void NuPlayer::seekToAsync(int64_t seekTimeUs) {
139    sp<AMessage> msg = new AMessage(kWhatSeek, id());
140    msg->setInt64("seekTimeUs", seekTimeUs);
141    msg->post();
142}
143
144// static
145bool NuPlayer::IsFlushingState(FlushStatus state, bool *needShutdown) {
146    switch (state) {
147        case FLUSHING_DECODER:
148            if (needShutdown != NULL) {
149                *needShutdown = false;
150            }
151            return true;
152
153        case FLUSHING_DECODER_SHUTDOWN:
154            if (needShutdown != NULL) {
155                *needShutdown = true;
156            }
157            return true;
158
159        default:
160            return false;
161    }
162}
163
164void NuPlayer::onMessageReceived(const sp<AMessage> &msg) {
165    switch (msg->what()) {
166        case kWhatSetDataSource:
167        {
168            ALOGV("kWhatSetDataSource");
169
170            CHECK(mSource == NULL);
171
172            sp<RefBase> obj;
173            CHECK(msg->findObject("source", &obj));
174
175            mSource = static_cast<Source *>(obj.get());
176            break;
177        }
178
179        case kWhatSetVideoNativeWindow:
180        {
181            ALOGV("kWhatSetVideoNativeWindow");
182
183            sp<RefBase> obj;
184            CHECK(msg->findObject("native-window", &obj));
185
186            mNativeWindow = static_cast<NativeWindowWrapper *>(obj.get());
187            break;
188        }
189
190        case kWhatSetAudioSink:
191        {
192            ALOGV("kWhatSetAudioSink");
193
194            sp<RefBase> obj;
195            CHECK(msg->findObject("sink", &obj));
196
197            mAudioSink = static_cast<MediaPlayerBase::AudioSink *>(obj.get());
198            break;
199        }
200
201        case kWhatStart:
202        {
203            ALOGV("kWhatStart");
204
205            mVideoIsAVC = false;
206            mAudioEOS = false;
207            mVideoEOS = false;
208            mSkipRenderingAudioUntilMediaTimeUs = -1;
209            mSkipRenderingVideoUntilMediaTimeUs = -1;
210            mVideoLateByUs = 0;
211            mNumFramesTotal = 0;
212            mNumFramesDropped = 0;
213
214            mSource->start();
215
216            mRenderer = new Renderer(
217                    mAudioSink,
218                    new AMessage(kWhatRendererNotify, id()));
219
220            looper()->registerHandler(mRenderer);
221
222            postScanSources();
223            break;
224        }
225
226        case kWhatScanSources:
227        {
228            int32_t generation;
229            CHECK(msg->findInt32("generation", &generation));
230            if (generation != mScanSourcesGeneration) {
231                // Drop obsolete msg.
232                break;
233            }
234
235            mScanSourcesPending = false;
236
237            ALOGV("scanning sources haveAudio=%d, haveVideo=%d",
238                 mAudioDecoder != NULL, mVideoDecoder != NULL);
239
240            instantiateDecoder(false, &mVideoDecoder);
241
242            if (mAudioSink != NULL) {
243                instantiateDecoder(true, &mAudioDecoder);
244            }
245
246            status_t err;
247            if ((err = mSource->feedMoreTSData()) != OK) {
248                if (mAudioDecoder == NULL && mVideoDecoder == NULL) {
249                    // We're not currently decoding anything (no audio or
250                    // video tracks found) and we just ran out of input data.
251
252                    if (err == ERROR_END_OF_STREAM) {
253                        notifyListener(MEDIA_PLAYBACK_COMPLETE, 0, 0);
254                    } else {
255                        notifyListener(MEDIA_ERROR, MEDIA_ERROR_UNKNOWN, err);
256                    }
257                }
258                break;
259            }
260
261            if (mAudioDecoder == NULL || mVideoDecoder == NULL) {
262                msg->post(100000ll);
263                mScanSourcesPending = true;
264            }
265            break;
266        }
267
268        case kWhatVideoNotify:
269        case kWhatAudioNotify:
270        {
271            bool audio = msg->what() == kWhatAudioNotify;
272
273            sp<AMessage> codecRequest;
274            CHECK(msg->findMessage("codec-request", &codecRequest));
275
276            int32_t what;
277            CHECK(codecRequest->findInt32("what", &what));
278
279            if (what == ACodec::kWhatFillThisBuffer) {
280                status_t err = feedDecoderInputData(
281                        audio, codecRequest);
282
283                if (err == -EWOULDBLOCK) {
284                    if (mSource->feedMoreTSData() == OK) {
285                        msg->post(10000ll);
286                    }
287                }
288            } else if (what == ACodec::kWhatEOS) {
289                int32_t err;
290                CHECK(codecRequest->findInt32("err", &err));
291
292                if (err == ERROR_END_OF_STREAM) {
293                    ALOGV("got %s decoder EOS", audio ? "audio" : "video");
294                } else {
295                    ALOGV("got %s decoder EOS w/ error %d",
296                         audio ? "audio" : "video",
297                         err);
298                }
299
300                mRenderer->queueEOS(audio, err);
301            } else if (what == ACodec::kWhatFlushCompleted) {
302                bool needShutdown;
303
304                if (audio) {
305                    CHECK(IsFlushingState(mFlushingAudio, &needShutdown));
306                    mFlushingAudio = FLUSHED;
307                } else {
308                    CHECK(IsFlushingState(mFlushingVideo, &needShutdown));
309                    mFlushingVideo = FLUSHED;
310
311                    mVideoLateByUs = 0;
312                }
313
314                ALOGV("decoder %s flush completed", audio ? "audio" : "video");
315
316                if (needShutdown) {
317                    ALOGV("initiating %s decoder shutdown",
318                         audio ? "audio" : "video");
319
320                    (audio ? mAudioDecoder : mVideoDecoder)->initiateShutdown();
321
322                    if (audio) {
323                        mFlushingAudio = SHUTTING_DOWN_DECODER;
324                    } else {
325                        mFlushingVideo = SHUTTING_DOWN_DECODER;
326                    }
327                }
328
329                finishFlushIfPossible();
330            } else if (what == ACodec::kWhatOutputFormatChanged) {
331                if (audio) {
332                    int32_t numChannels;
333                    CHECK(codecRequest->findInt32("channel-count", &numChannels));
334
335                    int32_t sampleRate;
336                    CHECK(codecRequest->findInt32("sample-rate", &sampleRate));
337
338                    ALOGV("Audio output format changed to %d Hz, %d channels",
339                         sampleRate, numChannels);
340
341                    mAudioSink->close();
342                    CHECK_EQ(mAudioSink->open(
343                                sampleRate,
344                                numChannels,
345                                AUDIO_FORMAT_PCM_16_BIT,
346                                8 /* bufferCount */),
347                             (status_t)OK);
348                    mAudioSink->start();
349
350                    mRenderer->signalAudioSinkChanged();
351                } else {
352                    // video
353
354                    int32_t width, height;
355                    CHECK(codecRequest->findInt32("width", &width));
356                    CHECK(codecRequest->findInt32("height", &height));
357
358                    int32_t cropLeft, cropTop, cropRight, cropBottom;
359                    CHECK(codecRequest->findRect(
360                                "crop",
361                                &cropLeft, &cropTop, &cropRight, &cropBottom));
362
363                    ALOGV("Video output format changed to %d x %d "
364                         "(crop: %d x %d @ (%d, %d))",
365                         width, height,
366                         (cropRight - cropLeft + 1),
367                         (cropBottom - cropTop + 1),
368                         cropLeft, cropTop);
369
370                    notifyListener(
371                            MEDIA_SET_VIDEO_SIZE,
372                            cropRight - cropLeft + 1,
373                            cropBottom - cropTop + 1);
374                }
375            } else if (what == ACodec::kWhatShutdownCompleted) {
376                ALOGV("%s shutdown completed", audio ? "audio" : "video");
377                if (audio) {
378                    mAudioDecoder.clear();
379
380                    CHECK_EQ((int)mFlushingAudio, (int)SHUTTING_DOWN_DECODER);
381                    mFlushingAudio = SHUT_DOWN;
382                } else {
383                    mVideoDecoder.clear();
384
385                    CHECK_EQ((int)mFlushingVideo, (int)SHUTTING_DOWN_DECODER);
386                    mFlushingVideo = SHUT_DOWN;
387                }
388
389                finishFlushIfPossible();
390            } else if (what == ACodec::kWhatError) {
391                LOGE("Received error from %s decoder, aborting playback.",
392                     audio ? "audio" : "video");
393
394                mRenderer->queueEOS(audio, UNKNOWN_ERROR);
395            } else {
396                CHECK_EQ((int)what, (int)ACodec::kWhatDrainThisBuffer);
397
398                renderBuffer(audio, codecRequest);
399            }
400
401            break;
402        }
403
404        case kWhatRendererNotify:
405        {
406            int32_t what;
407            CHECK(msg->findInt32("what", &what));
408
409            if (what == Renderer::kWhatEOS) {
410                int32_t audio;
411                CHECK(msg->findInt32("audio", &audio));
412
413                int32_t finalResult;
414                CHECK(msg->findInt32("finalResult", &finalResult));
415
416                if (audio) {
417                    mAudioEOS = true;
418                } else {
419                    mVideoEOS = true;
420                }
421
422                if (finalResult == ERROR_END_OF_STREAM) {
423                    ALOGV("reached %s EOS", audio ? "audio" : "video");
424                } else {
425                    LOGE("%s track encountered an error (%d)",
426                         audio ? "audio" : "video", finalResult);
427
428                    notifyListener(
429                            MEDIA_ERROR, MEDIA_ERROR_UNKNOWN, finalResult);
430                }
431
432                if ((mAudioEOS || mAudioDecoder == NULL)
433                        && (mVideoEOS || mVideoDecoder == NULL)) {
434                    notifyListener(MEDIA_PLAYBACK_COMPLETE, 0, 0);
435                }
436            } else if (what == Renderer::kWhatPosition) {
437                int64_t positionUs;
438                CHECK(msg->findInt64("positionUs", &positionUs));
439
440                CHECK(msg->findInt64("videoLateByUs", &mVideoLateByUs));
441
442                if (mDriver != NULL) {
443                    sp<NuPlayerDriver> driver = mDriver.promote();
444                    if (driver != NULL) {
445                        driver->notifyPosition(positionUs);
446
447                        driver->notifyFrameStats(
448                                mNumFramesTotal, mNumFramesDropped);
449                    }
450                }
451            } else if (what == Renderer::kWhatFlushComplete) {
452                CHECK_EQ(what, (int32_t)Renderer::kWhatFlushComplete);
453
454                int32_t audio;
455                CHECK(msg->findInt32("audio", &audio));
456
457                ALOGV("renderer %s flush completed.", audio ? "audio" : "video");
458            }
459            break;
460        }
461
462        case kWhatMoreDataQueued:
463        {
464            break;
465        }
466
467        case kWhatReset:
468        {
469            ALOGV("kWhatReset");
470
471            if (mFlushingAudio != NONE || mFlushingVideo != NONE) {
472                // We're currently flushing, postpone the reset until that's
473                // completed.
474
475                ALOGV("postponing reset");
476
477                mResetPostponed = true;
478                break;
479            }
480
481            if (mAudioDecoder == NULL && mVideoDecoder == NULL) {
482                finishReset();
483                break;
484            }
485
486            if (mAudioDecoder != NULL) {
487                flushDecoder(true /* audio */, true /* needShutdown */);
488            }
489
490            if (mVideoDecoder != NULL) {
491                flushDecoder(false /* audio */, true /* needShutdown */);
492            }
493
494            mResetInProgress = true;
495            break;
496        }
497
498        case kWhatSeek:
499        {
500            int64_t seekTimeUs;
501            CHECK(msg->findInt64("seekTimeUs", &seekTimeUs));
502
503            ALOGV("kWhatSeek seekTimeUs=%lld us (%.2f secs)",
504                 seekTimeUs, seekTimeUs / 1E6);
505
506            mSource->seekTo(seekTimeUs);
507
508            if (mDriver != NULL) {
509                sp<NuPlayerDriver> driver = mDriver.promote();
510                if (driver != NULL) {
511                    driver->notifySeekComplete();
512                }
513            }
514
515            break;
516        }
517
518        case kWhatPause:
519        {
520            CHECK(mRenderer != NULL);
521            mRenderer->pause();
522            break;
523        }
524
525        case kWhatResume:
526        {
527            CHECK(mRenderer != NULL);
528            mRenderer->resume();
529            break;
530        }
531
532        default:
533            TRESPASS();
534            break;
535    }
536}
537
538void NuPlayer::finishFlushIfPossible() {
539    if (mFlushingAudio != FLUSHED && mFlushingAudio != SHUT_DOWN) {
540        return;
541    }
542
543    if (mFlushingVideo != FLUSHED && mFlushingVideo != SHUT_DOWN) {
544        return;
545    }
546
547    ALOGV("both audio and video are flushed now.");
548
549    mRenderer->signalTimeDiscontinuity();
550
551    if (mAudioDecoder != NULL) {
552        mAudioDecoder->signalResume();
553    }
554
555    if (mVideoDecoder != NULL) {
556        mVideoDecoder->signalResume();
557    }
558
559    mFlushingAudio = NONE;
560    mFlushingVideo = NONE;
561
562    if (mResetInProgress) {
563        ALOGV("reset completed");
564
565        mResetInProgress = false;
566        finishReset();
567    } else if (mResetPostponed) {
568        (new AMessage(kWhatReset, id()))->post();
569        mResetPostponed = false;
570    } else if (mAudioDecoder == NULL || mVideoDecoder == NULL) {
571        postScanSources();
572    }
573}
574
575void NuPlayer::finishReset() {
576    CHECK(mAudioDecoder == NULL);
577    CHECK(mVideoDecoder == NULL);
578
579    ++mScanSourcesGeneration;
580    mScanSourcesPending = false;
581
582    mRenderer.clear();
583
584    if (mSource != NULL) {
585        mSource->stop();
586        mSource.clear();
587    }
588
589    if (mDriver != NULL) {
590        sp<NuPlayerDriver> driver = mDriver.promote();
591        if (driver != NULL) {
592            driver->notifyResetComplete();
593        }
594    }
595}
596
597void NuPlayer::postScanSources() {
598    if (mScanSourcesPending) {
599        return;
600    }
601
602    sp<AMessage> msg = new AMessage(kWhatScanSources, id());
603    msg->setInt32("generation", mScanSourcesGeneration);
604    msg->post();
605
606    mScanSourcesPending = true;
607}
608
609status_t NuPlayer::instantiateDecoder(bool audio, sp<Decoder> *decoder) {
610    if (*decoder != NULL) {
611        return OK;
612    }
613
614    sp<MetaData> meta = mSource->getFormat(audio);
615
616    if (meta == NULL) {
617        return -EWOULDBLOCK;
618    }
619
620    if (!audio) {
621        const char *mime;
622        CHECK(meta->findCString(kKeyMIMEType, &mime));
623        mVideoIsAVC = !strcasecmp(MEDIA_MIMETYPE_VIDEO_AVC, mime);
624    }
625
626    sp<AMessage> notify =
627        new AMessage(audio ? kWhatAudioNotify : kWhatVideoNotify,
628                     id());
629
630    *decoder = audio ? new Decoder(notify) :
631                       new Decoder(notify, mNativeWindow);
632    looper()->registerHandler(*decoder);
633
634    (*decoder)->configure(meta);
635
636    int64_t durationUs;
637    if (mDriver != NULL && mSource->getDuration(&durationUs) == OK) {
638        sp<NuPlayerDriver> driver = mDriver.promote();
639        if (driver != NULL) {
640            driver->notifyDuration(durationUs);
641        }
642    }
643
644    return OK;
645}
646
647status_t NuPlayer::feedDecoderInputData(bool audio, const sp<AMessage> &msg) {
648    sp<AMessage> reply;
649    CHECK(msg->findMessage("reply", &reply));
650
651    if ((audio && IsFlushingState(mFlushingAudio))
652            || (!audio && IsFlushingState(mFlushingVideo))) {
653        reply->setInt32("err", INFO_DISCONTINUITY);
654        reply->post();
655        return OK;
656    }
657
658    sp<ABuffer> accessUnit;
659
660    bool dropAccessUnit;
661    do {
662        status_t err = mSource->dequeueAccessUnit(audio, &accessUnit);
663
664        if (err == -EWOULDBLOCK) {
665            return err;
666        } else if (err != OK) {
667            if (err == INFO_DISCONTINUITY) {
668                int32_t type;
669                CHECK(accessUnit->meta()->findInt32("discontinuity", &type));
670
671                bool formatChange =
672                    type == ATSParser::DISCONTINUITY_FORMATCHANGE;
673
674                ALOGV("%s discontinuity (formatChange=%d)",
675                     audio ? "audio" : "video", formatChange);
676
677                if (audio) {
678                    mSkipRenderingAudioUntilMediaTimeUs = -1;
679                } else {
680                    mSkipRenderingVideoUntilMediaTimeUs = -1;
681                }
682
683                sp<AMessage> extra;
684                if (accessUnit->meta()->findMessage("extra", &extra)
685                        && extra != NULL) {
686                    int64_t resumeAtMediaTimeUs;
687                    if (extra->findInt64(
688                                "resume-at-mediatimeUs", &resumeAtMediaTimeUs)) {
689                        LOGI("suppressing rendering of %s until %lld us",
690                                audio ? "audio" : "video", resumeAtMediaTimeUs);
691
692                        if (audio) {
693                            mSkipRenderingAudioUntilMediaTimeUs =
694                                resumeAtMediaTimeUs;
695                        } else {
696                            mSkipRenderingVideoUntilMediaTimeUs =
697                                resumeAtMediaTimeUs;
698                        }
699                    }
700                }
701
702                flushDecoder(audio, formatChange);
703            }
704
705            reply->setInt32("err", err);
706            reply->post();
707            return OK;
708        }
709
710        if (!audio) {
711            ++mNumFramesTotal;
712        }
713
714        dropAccessUnit = false;
715        if (!audio
716                && mVideoLateByUs > 100000ll
717                && mVideoIsAVC
718                && !IsAVCReferenceFrame(accessUnit)) {
719            dropAccessUnit = true;
720            ++mNumFramesDropped;
721        }
722    } while (dropAccessUnit);
723
724    // ALOGV("returned a valid buffer of %s data", audio ? "audio" : "video");
725
726#if 0
727    int64_t mediaTimeUs;
728    CHECK(accessUnit->meta()->findInt64("timeUs", &mediaTimeUs));
729    ALOGV("feeding %s input buffer at media time %.2f secs",
730         audio ? "audio" : "video",
731         mediaTimeUs / 1E6);
732#endif
733
734    reply->setObject("buffer", accessUnit);
735    reply->post();
736
737    return OK;
738}
739
740void NuPlayer::renderBuffer(bool audio, const sp<AMessage> &msg) {
741    // ALOGV("renderBuffer %s", audio ? "audio" : "video");
742
743    sp<AMessage> reply;
744    CHECK(msg->findMessage("reply", &reply));
745
746    if (IsFlushingState(audio ? mFlushingAudio : mFlushingVideo)) {
747        // We're currently attempting to flush the decoder, in order
748        // to complete this, the decoder wants all its buffers back,
749        // so we don't want any output buffers it sent us (from before
750        // we initiated the flush) to be stuck in the renderer's queue.
751
752        ALOGV("we're still flushing the %s decoder, sending its output buffer"
753             " right back.", audio ? "audio" : "video");
754
755        reply->post();
756        return;
757    }
758
759    sp<RefBase> obj;
760    CHECK(msg->findObject("buffer", &obj));
761
762    sp<ABuffer> buffer = static_cast<ABuffer *>(obj.get());
763
764    int64_t &skipUntilMediaTimeUs =
765        audio
766            ? mSkipRenderingAudioUntilMediaTimeUs
767            : mSkipRenderingVideoUntilMediaTimeUs;
768
769    if (skipUntilMediaTimeUs >= 0) {
770        int64_t mediaTimeUs;
771        CHECK(buffer->meta()->findInt64("timeUs", &mediaTimeUs));
772
773        if (mediaTimeUs < skipUntilMediaTimeUs) {
774            ALOGV("dropping %s buffer at time %lld as requested.",
775                 audio ? "audio" : "video",
776                 mediaTimeUs);
777
778            reply->post();
779            return;
780        }
781
782        skipUntilMediaTimeUs = -1;
783    }
784
785    mRenderer->queueBuffer(audio, buffer, reply);
786}
787
788void NuPlayer::notifyListener(int msg, int ext1, int ext2) {
789    if (mDriver == NULL) {
790        return;
791    }
792
793    sp<NuPlayerDriver> driver = mDriver.promote();
794
795    if (driver == NULL) {
796        return;
797    }
798
799    driver->notifyListener(msg, ext1, ext2);
800}
801
802void NuPlayer::flushDecoder(bool audio, bool needShutdown) {
803    // Make sure we don't continue to scan sources until we finish flushing.
804    ++mScanSourcesGeneration;
805    mScanSourcesPending = false;
806
807    (audio ? mAudioDecoder : mVideoDecoder)->signalFlush();
808    mRenderer->flush(audio);
809
810    FlushStatus newStatus =
811        needShutdown ? FLUSHING_DECODER_SHUTDOWN : FLUSHING_DECODER;
812
813    if (audio) {
814        CHECK(mFlushingAudio == NONE
815                || mFlushingAudio == AWAITING_DISCONTINUITY);
816
817        mFlushingAudio = newStatus;
818
819        if (mFlushingVideo == NONE) {
820            mFlushingVideo = (mVideoDecoder != NULL)
821                ? AWAITING_DISCONTINUITY
822                : FLUSHED;
823        }
824    } else {
825        CHECK(mFlushingVideo == NONE
826                || mFlushingVideo == AWAITING_DISCONTINUITY);
827
828        mFlushingVideo = newStatus;
829
830        if (mFlushingAudio == NONE) {
831            mFlushingAudio = (mAudioDecoder != NULL)
832                ? AWAITING_DISCONTINUITY
833                : FLUSHED;
834        }
835    }
836}
837
838}  // namespace android
839