NuPlayer.cpp revision 574aed902443d41581684dc8bc5ddd2e067f4cdf
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 "NuPlayerDecoderPassThrough.h"
26#include "NuPlayerDriver.h"
27#include "NuPlayerRenderer.h"
28#include "NuPlayerSource.h"
29#include "RTSPSource.h"
30#include "StreamingSource.h"
31#include "GenericSource.h"
32#include "TextDescriptions.h"
33
34#include "ATSParser.h"
35
36#include <cutils/properties.h>
37
38#include <media/stagefright/foundation/hexdump.h>
39#include <media/stagefright/foundation/ABuffer.h>
40#include <media/stagefright/foundation/ADebug.h>
41#include <media/stagefright/foundation/AMessage.h>
42#include <media/stagefright/MediaBuffer.h>
43#include <media/stagefright/MediaDefs.h>
44#include <media/stagefright/MediaErrors.h>
45#include <media/stagefright/MetaData.h>
46#include <gui/IGraphicBufferProducer.h>
47
48#include "avc_utils.h"
49
50#include "ESDS.h"
51#include <media/stagefright/Utils.h>
52
53namespace android {
54
55// TODO optimize buffer size for power consumption
56// The offload read buffer size is 32 KB but 24 KB uses less power.
57const size_t NuPlayer::kAggregateBufferSizeBytes = 24 * 1024;
58
59struct NuPlayer::Action : public RefBase {
60    Action() {}
61
62    virtual void execute(NuPlayer *player) = 0;
63
64private:
65    DISALLOW_EVIL_CONSTRUCTORS(Action);
66};
67
68struct NuPlayer::SeekAction : public Action {
69    SeekAction(int64_t seekTimeUs, bool needNotify)
70        : mSeekTimeUs(seekTimeUs),
71          mNeedNotify(needNotify) {
72    }
73
74    virtual void execute(NuPlayer *player) {
75        player->performSeek(mSeekTimeUs, mNeedNotify);
76    }
77
78private:
79    int64_t mSeekTimeUs;
80    bool mNeedNotify;
81
82    DISALLOW_EVIL_CONSTRUCTORS(SeekAction);
83};
84
85struct NuPlayer::SetSurfaceAction : public Action {
86    SetSurfaceAction(const sp<NativeWindowWrapper> &wrapper)
87        : mWrapper(wrapper) {
88    }
89
90    virtual void execute(NuPlayer *player) {
91        player->performSetSurface(mWrapper);
92    }
93
94private:
95    sp<NativeWindowWrapper> mWrapper;
96
97    DISALLOW_EVIL_CONSTRUCTORS(SetSurfaceAction);
98};
99
100struct NuPlayer::FlushDecoderAction : public Action {
101    FlushDecoderAction(FlushCommand audio, FlushCommand video)
102        : mAudio(audio),
103          mVideo(video) {
104    }
105
106    virtual void execute(NuPlayer *player) {
107        player->performDecoderFlush(mAudio, mVideo);
108    }
109
110private:
111    FlushCommand mAudio;
112    FlushCommand mVideo;
113
114    DISALLOW_EVIL_CONSTRUCTORS(FlushDecoderAction);
115};
116
117struct NuPlayer::PostMessageAction : public Action {
118    PostMessageAction(const sp<AMessage> &msg)
119        : mMessage(msg) {
120    }
121
122    virtual void execute(NuPlayer *) {
123        mMessage->post();
124    }
125
126private:
127    sp<AMessage> mMessage;
128
129    DISALLOW_EVIL_CONSTRUCTORS(PostMessageAction);
130};
131
132// Use this if there's no state necessary to save in order to execute
133// the action.
134struct NuPlayer::SimpleAction : public Action {
135    typedef void (NuPlayer::*ActionFunc)();
136
137    SimpleAction(ActionFunc func)
138        : mFunc(func) {
139    }
140
141    virtual void execute(NuPlayer *player) {
142        (player->*mFunc)();
143    }
144
145private:
146    ActionFunc mFunc;
147
148    DISALLOW_EVIL_CONSTRUCTORS(SimpleAction);
149};
150
151////////////////////////////////////////////////////////////////////////////////
152
153NuPlayer::NuPlayer()
154    : mUIDValid(false),
155      mSourceFlags(0),
156      mVideoIsAVC(false),
157      mOffloadAudio(false),
158      mAudioDecoderGeneration(0),
159      mVideoDecoderGeneration(0),
160      mRendererGeneration(0),
161      mAudioEOS(false),
162      mVideoEOS(false),
163      mScanSourcesPending(false),
164      mScanSourcesGeneration(0),
165      mPollDurationGeneration(0),
166      mTimedTextGeneration(0),
167      mTimeDiscontinuityPending(false),
168      mFlushingAudio(NONE),
169      mFlushingVideo(NONE),
170      mNumFramesTotal(0ll),
171      mNumFramesDropped(0ll),
172      mVideoScalingMode(NATIVE_WINDOW_SCALING_MODE_SCALE_TO_WINDOW),
173      mStarted(false) {
174    clearFlushComplete();
175}
176
177NuPlayer::~NuPlayer() {
178}
179
180void NuPlayer::setUID(uid_t uid) {
181    mUIDValid = true;
182    mUID = uid;
183}
184
185void NuPlayer::setDriver(const wp<NuPlayerDriver> &driver) {
186    mDriver = driver;
187}
188
189void NuPlayer::setDataSourceAsync(const sp<IStreamSource> &source) {
190    sp<AMessage> msg = new AMessage(kWhatSetDataSource, id());
191
192    sp<AMessage> notify = new AMessage(kWhatSourceNotify, id());
193
194    msg->setObject("source", new StreamingSource(notify, source));
195    msg->post();
196}
197
198static bool IsHTTPLiveURL(const char *url) {
199    if (!strncasecmp("http://", url, 7)
200            || !strncasecmp("https://", url, 8)
201            || !strncasecmp("file://", url, 7)) {
202        size_t len = strlen(url);
203        if (len >= 5 && !strcasecmp(".m3u8", &url[len - 5])) {
204            return true;
205        }
206
207        if (strstr(url,"m3u8")) {
208            return true;
209        }
210    }
211
212    return false;
213}
214
215void NuPlayer::setDataSourceAsync(
216        const sp<IMediaHTTPService> &httpService,
217        const char *url,
218        const KeyedVector<String8, String8> *headers) {
219
220    sp<AMessage> msg = new AMessage(kWhatSetDataSource, id());
221    size_t len = strlen(url);
222
223    sp<AMessage> notify = new AMessage(kWhatSourceNotify, id());
224
225    sp<Source> source;
226    if (IsHTTPLiveURL(url)) {
227        source = new HTTPLiveSource(notify, httpService, url, headers);
228    } else if (!strncasecmp(url, "rtsp://", 7)) {
229        source = new RTSPSource(
230                notify, httpService, url, headers, mUIDValid, mUID);
231    } else if ((!strncasecmp(url, "http://", 7)
232                || !strncasecmp(url, "https://", 8))
233                    && ((len >= 4 && !strcasecmp(".sdp", &url[len - 4]))
234                    || strstr(url, ".sdp?"))) {
235        source = new RTSPSource(
236                notify, httpService, url, headers, mUIDValid, mUID, true);
237    } else {
238        sp<GenericSource> genericSource =
239                new GenericSource(notify, mUIDValid, mUID);
240        // Don't set FLAG_SECURE on mSourceFlags here for widevine.
241        // The correct flags will be updated in Source::kWhatFlagsChanged
242        // handler when  GenericSource is prepared.
243
244        status_t err = genericSource->setDataSource(httpService, url, headers);
245
246        if (err == OK) {
247            source = genericSource;
248        } else {
249            ALOGE("Failed to set data source!");
250        }
251    }
252    msg->setObject("source", source);
253    msg->post();
254}
255
256void NuPlayer::setDataSourceAsync(int fd, int64_t offset, int64_t length) {
257    sp<AMessage> msg = new AMessage(kWhatSetDataSource, id());
258
259    sp<AMessage> notify = new AMessage(kWhatSourceNotify, id());
260
261    sp<GenericSource> source =
262            new GenericSource(notify, mUIDValid, mUID);
263
264    status_t err = source->setDataSource(fd, offset, length);
265
266    if (err != OK) {
267        ALOGE("Failed to set data source!");
268        source = NULL;
269    }
270
271    msg->setObject("source", source);
272    msg->post();
273}
274
275void NuPlayer::prepareAsync() {
276    (new AMessage(kWhatPrepare, id()))->post();
277}
278
279void NuPlayer::setVideoSurfaceTextureAsync(
280        const sp<IGraphicBufferProducer> &bufferProducer) {
281    sp<AMessage> msg = new AMessage(kWhatSetVideoNativeWindow, id());
282
283    if (bufferProducer == NULL) {
284        msg->setObject("native-window", NULL);
285    } else {
286        msg->setObject(
287                "native-window",
288                new NativeWindowWrapper(
289                    new Surface(bufferProducer, true /* controlledByApp */)));
290    }
291
292    msg->post();
293}
294
295void NuPlayer::setAudioSink(const sp<MediaPlayerBase::AudioSink> &sink) {
296    sp<AMessage> msg = new AMessage(kWhatSetAudioSink, id());
297    msg->setObject("sink", sink);
298    msg->post();
299}
300
301void NuPlayer::start() {
302    (new AMessage(kWhatStart, id()))->post();
303}
304
305void NuPlayer::pause() {
306    (new AMessage(kWhatPause, id()))->post();
307}
308
309void NuPlayer::resetAsync() {
310    if (mSource != NULL) {
311        // During a reset, the data source might be unresponsive already, we need to
312        // disconnect explicitly so that reads exit promptly.
313        // We can't queue the disconnect request to the looper, as it might be
314        // queued behind a stuck read and never gets processed.
315        // Doing a disconnect outside the looper to allows the pending reads to exit
316        // (either successfully or with error).
317        mSource->disconnect();
318    }
319
320    (new AMessage(kWhatReset, id()))->post();
321}
322
323void NuPlayer::seekToAsync(int64_t seekTimeUs, bool needNotify) {
324    sp<AMessage> msg = new AMessage(kWhatSeek, id());
325    msg->setInt64("seekTimeUs", seekTimeUs);
326    msg->setInt32("needNotify", needNotify);
327    msg->post();
328}
329
330
331void NuPlayer::writeTrackInfo(
332        Parcel* reply, const sp<AMessage> format) const {
333    int32_t trackType;
334    CHECK(format->findInt32("type", &trackType));
335
336    AString lang;
337    CHECK(format->findString("language", &lang));
338
339    reply->writeInt32(2); // write something non-zero
340    reply->writeInt32(trackType);
341    reply->writeString16(String16(lang.c_str()));
342
343    if (trackType == MEDIA_TRACK_TYPE_SUBTITLE) {
344        AString mime;
345        CHECK(format->findString("mime", &mime));
346
347        int32_t isAuto, isDefault, isForced;
348        CHECK(format->findInt32("auto", &isAuto));
349        CHECK(format->findInt32("default", &isDefault));
350        CHECK(format->findInt32("forced", &isForced));
351
352        reply->writeString16(String16(mime.c_str()));
353        reply->writeInt32(isAuto);
354        reply->writeInt32(isDefault);
355        reply->writeInt32(isForced);
356    }
357}
358
359void NuPlayer::onMessageReceived(const sp<AMessage> &msg) {
360    switch (msg->what()) {
361        case kWhatSetDataSource:
362        {
363            ALOGV("kWhatSetDataSource");
364
365            CHECK(mSource == NULL);
366
367            status_t err = OK;
368            sp<RefBase> obj;
369            CHECK(msg->findObject("source", &obj));
370            if (obj != NULL) {
371                mSource = static_cast<Source *>(obj.get());
372            } else {
373                err = UNKNOWN_ERROR;
374            }
375
376            CHECK(mDriver != NULL);
377            sp<NuPlayerDriver> driver = mDriver.promote();
378            if (driver != NULL) {
379                driver->notifySetDataSourceCompleted(err);
380            }
381            break;
382        }
383
384        case kWhatPrepare:
385        {
386            mSource->prepareAsync();
387            break;
388        }
389
390        case kWhatGetTrackInfo:
391        {
392            uint32_t replyID;
393            CHECK(msg->senderAwaitsResponse(&replyID));
394
395            Parcel* reply;
396            CHECK(msg->findPointer("reply", (void**)&reply));
397
398            size_t inbandTracks = 0;
399            if (mSource != NULL) {
400                inbandTracks = mSource->getTrackCount();
401            }
402
403            size_t ccTracks = 0;
404            if (mCCDecoder != NULL) {
405                ccTracks = mCCDecoder->getTrackCount();
406            }
407
408            // total track count
409            reply->writeInt32(inbandTracks + ccTracks);
410
411            // write inband tracks
412            for (size_t i = 0; i < inbandTracks; ++i) {
413                writeTrackInfo(reply, mSource->getTrackInfo(i));
414            }
415
416            // write CC track
417            for (size_t i = 0; i < ccTracks; ++i) {
418                writeTrackInfo(reply, mCCDecoder->getTrackInfo(i));
419            }
420
421            sp<AMessage> response = new AMessage;
422            response->postReply(replyID);
423            break;
424        }
425
426        case kWhatGetSelectedTrack:
427        {
428            status_t err = INVALID_OPERATION;
429            if (mSource != NULL) {
430                err = OK;
431
432                int32_t type32;
433                CHECK(msg->findInt32("type", (int32_t*)&type32));
434                media_track_type type = (media_track_type)type32;
435                ssize_t selectedTrack = mSource->getSelectedTrack(type);
436
437                Parcel* reply;
438                CHECK(msg->findPointer("reply", (void**)&reply));
439                reply->writeInt32(selectedTrack);
440            }
441
442            sp<AMessage> response = new AMessage;
443            response->setInt32("err", err);
444
445            uint32_t replyID;
446            CHECK(msg->senderAwaitsResponse(&replyID));
447            response->postReply(replyID);
448            break;
449        }
450
451        case kWhatSelectTrack:
452        {
453            uint32_t replyID;
454            CHECK(msg->senderAwaitsResponse(&replyID));
455
456            size_t trackIndex;
457            int32_t select;
458            int64_t timeUs;
459            CHECK(msg->findSize("trackIndex", &trackIndex));
460            CHECK(msg->findInt32("select", &select));
461            CHECK(msg->findInt64("timeUs", &timeUs));
462
463            status_t err = INVALID_OPERATION;
464
465            size_t inbandTracks = 0;
466            if (mSource != NULL) {
467                inbandTracks = mSource->getTrackCount();
468            }
469            size_t ccTracks = 0;
470            if (mCCDecoder != NULL) {
471                ccTracks = mCCDecoder->getTrackCount();
472            }
473
474            if (trackIndex < inbandTracks) {
475                err = mSource->selectTrack(trackIndex, select, timeUs);
476
477                if (!select && err == OK) {
478                    int32_t type;
479                    sp<AMessage> info = mSource->getTrackInfo(trackIndex);
480                    if (info != NULL
481                            && info->findInt32("type", &type)
482                            && type == MEDIA_TRACK_TYPE_TIMEDTEXT) {
483                        ++mTimedTextGeneration;
484                    }
485                }
486            } else {
487                trackIndex -= inbandTracks;
488
489                if (trackIndex < ccTracks) {
490                    err = mCCDecoder->selectTrack(trackIndex, select);
491                }
492            }
493
494            sp<AMessage> response = new AMessage;
495            response->setInt32("err", err);
496
497            response->postReply(replyID);
498            break;
499        }
500
501        case kWhatPollDuration:
502        {
503            int32_t generation;
504            CHECK(msg->findInt32("generation", &generation));
505
506            if (generation != mPollDurationGeneration) {
507                // stale
508                break;
509            }
510
511            int64_t durationUs;
512            if (mDriver != NULL && mSource->getDuration(&durationUs) == OK) {
513                sp<NuPlayerDriver> driver = mDriver.promote();
514                if (driver != NULL) {
515                    driver->notifyDuration(durationUs);
516                }
517            }
518
519            msg->post(1000000ll);  // poll again in a second.
520            break;
521        }
522
523        case kWhatSetVideoNativeWindow:
524        {
525            ALOGV("kWhatSetVideoNativeWindow");
526
527            sp<RefBase> obj;
528            CHECK(msg->findObject("native-window", &obj));
529
530            if (mSource->getFormat(false /* audio */) == NULL) {
531                performSetSurface(static_cast<NativeWindowWrapper *>(obj.get()));
532                break;
533            }
534
535            mDeferredActions.push_back(
536                    new FlushDecoderAction(FLUSH_CMD_FLUSH /* audio */,
537                                           FLUSH_CMD_SHUTDOWN /* video */));
538
539            mDeferredActions.push_back(
540                    new SetSurfaceAction(
541                        static_cast<NativeWindowWrapper *>(obj.get())));
542
543            if (obj != NULL) {
544                if (mStarted) {
545                    // Issue a seek to refresh the video screen only if started otherwise
546                    // the extractor may not yet be started and will assert.
547                    // If the video decoder is not set (perhaps audio only in this case)
548                    // do not perform a seek as it is not needed.
549                    int64_t currentPositionUs = 0;
550                    if (getCurrentPosition(&currentPositionUs) == OK) {
551                        mDeferredActions.push_back(
552                                new SeekAction(currentPositionUs, false /* needNotify */));
553                    }
554                }
555
556                // If there is a new surface texture, instantiate decoders
557                // again if possible.
558                mDeferredActions.push_back(
559                        new SimpleAction(&NuPlayer::performScanSources));
560            }
561
562            processDeferredActions();
563            break;
564        }
565
566        case kWhatSetAudioSink:
567        {
568            ALOGV("kWhatSetAudioSink");
569
570            sp<RefBase> obj;
571            CHECK(msg->findObject("sink", &obj));
572
573            mAudioSink = static_cast<MediaPlayerBase::AudioSink *>(obj.get());
574            break;
575        }
576
577        case kWhatStart:
578        {
579            ALOGV("kWhatStart");
580            if (mStarted) {
581                onResume();
582            } else {
583                onStart();
584            }
585            break;
586        }
587
588        case kWhatScanSources:
589        {
590            int32_t generation;
591            CHECK(msg->findInt32("generation", &generation));
592            if (generation != mScanSourcesGeneration) {
593                // Drop obsolete msg.
594                break;
595            }
596
597            mScanSourcesPending = false;
598
599            ALOGV("scanning sources haveAudio=%d, haveVideo=%d",
600                 mAudioDecoder != NULL, mVideoDecoder != NULL);
601
602            bool mHadAnySourcesBefore =
603                (mAudioDecoder != NULL) || (mVideoDecoder != NULL);
604
605            // initialize video before audio because successful initialization of
606            // video may change deep buffer mode of audio.
607            if (mNativeWindow != NULL) {
608                instantiateDecoder(false, &mVideoDecoder);
609            }
610
611            // Don't try to re-open audio sink if there's an existing decoder.
612            if (mAudioSink != NULL && mAudioDecoder == NULL) {
613                sp<MetaData> audioMeta = mSource->getFormatMeta(true /* audio */);
614                sp<AMessage> videoFormat = mSource->getFormat(false /* audio */);
615                audio_stream_type_t streamType = mAudioSink->getAudioStreamType();
616                bool canOffload = canOffloadStream(audioMeta, (videoFormat != NULL),
617                         true /* is_streaming */, streamType);
618                if (canOffload) {
619                    if (!mOffloadAudio) {
620                        mRenderer->signalEnableOffloadAudio();
621                    }
622                    // open audio sink early under offload mode.
623                    sp<AMessage> format = mSource->getFormat(true /*audio*/);
624                    openAudioSink(format, true /*offloadOnly*/);
625                }
626                instantiateDecoder(true, &mAudioDecoder);
627            }
628
629            if (!mHadAnySourcesBefore
630                    && (mAudioDecoder != NULL || mVideoDecoder != NULL)) {
631                // This is the first time we've found anything playable.
632
633                if (mSourceFlags & Source::FLAG_DYNAMIC_DURATION) {
634                    schedulePollDuration();
635                }
636            }
637
638            status_t err;
639            if ((err = mSource->feedMoreTSData()) != OK) {
640                if (mAudioDecoder == NULL && mVideoDecoder == NULL) {
641                    // We're not currently decoding anything (no audio or
642                    // video tracks found) and we just ran out of input data.
643
644                    if (err == ERROR_END_OF_STREAM) {
645                        notifyListener(MEDIA_PLAYBACK_COMPLETE, 0, 0);
646                    } else {
647                        notifyListener(MEDIA_ERROR, MEDIA_ERROR_UNKNOWN, err);
648                    }
649                }
650                break;
651            }
652
653            if ((mAudioDecoder == NULL && mAudioSink != NULL)
654                    || (mVideoDecoder == NULL && mNativeWindow != NULL)) {
655                msg->post(100000ll);
656                mScanSourcesPending = true;
657            }
658            break;
659        }
660
661        case kWhatVideoNotify:
662        case kWhatAudioNotify:
663        {
664            bool audio = msg->what() == kWhatAudioNotify;
665
666            int32_t currentDecoderGeneration =
667                (audio? mAudioDecoderGeneration : mVideoDecoderGeneration);
668            int32_t requesterGeneration = currentDecoderGeneration - 1;
669            CHECK(msg->findInt32("generation", &requesterGeneration));
670
671            if (requesterGeneration != currentDecoderGeneration) {
672                ALOGV("got message from old %s decoder, generation(%d:%d)",
673                        audio ? "audio" : "video", requesterGeneration,
674                        currentDecoderGeneration);
675                sp<AMessage> reply;
676                if (!(msg->findMessage("reply", &reply))) {
677                    return;
678                }
679
680                reply->setInt32("err", INFO_DISCONTINUITY);
681                reply->post();
682                return;
683            }
684
685            int32_t what;
686            CHECK(msg->findInt32("what", &what));
687
688            if (what == Decoder::kWhatFillThisBuffer) {
689                status_t err = feedDecoderInputData(
690                        audio, msg);
691
692                if (err == -EWOULDBLOCK) {
693                    if (mSource->feedMoreTSData() == OK) {
694                        msg->post(10 * 1000ll);
695                    }
696                }
697            } else if (what == Decoder::kWhatEOS) {
698                int32_t err;
699                CHECK(msg->findInt32("err", &err));
700
701                if (err == ERROR_END_OF_STREAM) {
702                    ALOGV("got %s decoder EOS", audio ? "audio" : "video");
703                } else {
704                    ALOGV("got %s decoder EOS w/ error %d",
705                         audio ? "audio" : "video",
706                         err);
707                }
708
709                mRenderer->queueEOS(audio, err);
710            } else if (what == Decoder::kWhatFlushCompleted) {
711                ALOGV("decoder %s flush completed", audio ? "audio" : "video");
712
713                handleFlushComplete(audio, true /* isDecoder */);
714                finishFlushIfPossible();
715            } else if (what == Decoder::kWhatVideoSizeChanged) {
716                sp<AMessage> format;
717                CHECK(msg->findMessage("format", &format));
718
719                sp<AMessage> inputFormat =
720                        mSource->getFormat(false /* audio */);
721
722                updateVideoSize(inputFormat, format);
723            } else if (what == Decoder::kWhatShutdownCompleted) {
724                ALOGV("%s shutdown completed", audio ? "audio" : "video");
725                if (audio) {
726                    mAudioDecoder.clear();
727                    ++mAudioDecoderGeneration;
728
729                    CHECK_EQ((int)mFlushingAudio, (int)SHUTTING_DOWN_DECODER);
730                    mFlushingAudio = SHUT_DOWN;
731                } else {
732                    mVideoDecoder.clear();
733                    ++mVideoDecoderGeneration;
734
735                    CHECK_EQ((int)mFlushingVideo, (int)SHUTTING_DOWN_DECODER);
736                    mFlushingVideo = SHUT_DOWN;
737                }
738
739                finishFlushIfPossible();
740            } else if (what == Decoder::kWhatError) {
741                status_t err;
742                if (!msg->findInt32("err", &err) || err == OK) {
743                    err = UNKNOWN_ERROR;
744                }
745
746                // Decoder errors can be due to Source (e.g. from streaming),
747                // or from decoding corrupted bitstreams, or from other decoder
748                // MediaCodec operations (e.g. from an ongoing reset or seek).
749                //
750                // We try to gracefully shut down the affected decoder if possible,
751                // rather than trying to force the shutdown with something
752                // similar to performReset(). This method can lead to a hang
753                // if MediaCodec functions block after an error, but they should
754                // typically return INVALID_OPERATION instead of blocking.
755
756                FlushStatus *flushing = audio ? &mFlushingAudio : &mFlushingVideo;
757                ALOGE("received error(%#x) from %s decoder, flushing(%d), now shutting down",
758                        err, audio ? "audio" : "video", *flushing);
759
760                switch (*flushing) {
761                    case NONE:
762                        mDeferredActions.push_back(
763                                new FlushDecoderAction(
764                                    audio ? FLUSH_CMD_SHUTDOWN : FLUSH_CMD_NONE,
765                                    audio ? FLUSH_CMD_NONE : FLUSH_CMD_SHUTDOWN));
766                        processDeferredActions();
767                        break;
768                    case FLUSHING_DECODER:
769                        *flushing = FLUSHING_DECODER_SHUTDOWN; // initiate shutdown after flush.
770                        break; // Wait for flush to complete.
771                    case FLUSHING_DECODER_SHUTDOWN:
772                        break; // Wait for flush to complete.
773                    case SHUTTING_DOWN_DECODER:
774                        break; // Wait for shutdown to complete.
775                    case FLUSHED:
776                        // Widevine source reads must stop before releasing the video decoder.
777                        if (!audio && mSource != NULL && mSourceFlags & Source::FLAG_SECURE) {
778                            mSource->stop();
779                        }
780                        getDecoder(audio)->initiateShutdown(); // In the middle of a seek.
781                        *flushing = SHUTTING_DOWN_DECODER;     // Shut down.
782                        break;
783                    case SHUT_DOWN:
784                        finishFlushIfPossible();  // Should not occur.
785                        break;                    // Finish anyways.
786                }
787                notifyListener(MEDIA_ERROR, MEDIA_ERROR_UNKNOWN, err);
788            } else if (what == Decoder::kWhatRenderBufferTime) {
789                renderBuffer(audio, msg);
790            } else {
791                ALOGV("Unhandled decoder notification %d '%c%c%c%c'.",
792                      what,
793                      what >> 24,
794                      (what >> 16) & 0xff,
795                      (what >> 8) & 0xff,
796                      what & 0xff);
797            }
798
799            break;
800        }
801
802        case kWhatRendererNotify:
803        {
804            int32_t requesterGeneration = mRendererGeneration - 1;
805            CHECK(msg->findInt32("generation", &requesterGeneration));
806            if (requesterGeneration != mRendererGeneration) {
807                ALOGV("got message from old renderer, generation(%d:%d)",
808                        requesterGeneration, mRendererGeneration);
809                return;
810            }
811
812            int32_t what;
813            CHECK(msg->findInt32("what", &what));
814
815            if (what == Renderer::kWhatEOS) {
816                int32_t audio;
817                CHECK(msg->findInt32("audio", &audio));
818
819                int32_t finalResult;
820                CHECK(msg->findInt32("finalResult", &finalResult));
821
822                if (audio) {
823                    mAudioEOS = true;
824                } else {
825                    mVideoEOS = true;
826                }
827
828                if (finalResult == ERROR_END_OF_STREAM) {
829                    ALOGV("reached %s EOS", audio ? "audio" : "video");
830                } else {
831                    ALOGE("%s track encountered an error (%d)",
832                         audio ? "audio" : "video", finalResult);
833
834                    notifyListener(
835                            MEDIA_ERROR, MEDIA_ERROR_UNKNOWN, finalResult);
836                }
837
838                if ((mAudioEOS || mAudioDecoder == NULL)
839                        && (mVideoEOS || mVideoDecoder == NULL)) {
840                    notifyListener(MEDIA_PLAYBACK_COMPLETE, 0, 0);
841                }
842            } else if (what == Renderer::kWhatFlushComplete) {
843                int32_t audio;
844                CHECK(msg->findInt32("audio", &audio));
845
846                ALOGV("renderer %s flush completed.", audio ? "audio" : "video");
847                handleFlushComplete(audio, false /* isDecoder */);
848                finishFlushIfPossible();
849            } else if (what == Renderer::kWhatVideoRenderingStart) {
850                notifyListener(MEDIA_INFO, MEDIA_INFO_RENDERING_START, 0);
851            } else if (what == Renderer::kWhatMediaRenderingStart) {
852                ALOGV("media rendering started");
853                notifyListener(MEDIA_STARTED, 0, 0);
854            } else if (what == Renderer::kWhatAudioOffloadTearDown) {
855                ALOGV("Tear down audio offload, fall back to s/w path if due to error.");
856                int64_t positionUs;
857                CHECK(msg->findInt64("positionUs", &positionUs));
858                int32_t reason;
859                CHECK(msg->findInt32("reason", &reason));
860                closeAudioSink();
861                mAudioDecoder.clear();
862                ++mAudioDecoderGeneration;
863                mRenderer->flush(true /* audio */);
864                if (mVideoDecoder != NULL) {
865                    mRenderer->flush(false /* audio */);
866                }
867
868                performSeek(positionUs, false /* needNotify */);
869                if (reason == Renderer::kDueToError) {
870                    mRenderer->signalDisableOffloadAudio();
871                    mOffloadAudio = false;
872                    instantiateDecoder(true /* audio */, &mAudioDecoder);
873                }
874            }
875            break;
876        }
877
878        case kWhatMoreDataQueued:
879        {
880            break;
881        }
882
883        case kWhatReset:
884        {
885            ALOGV("kWhatReset");
886
887            mDeferredActions.push_back(
888                    new FlushDecoderAction(
889                        FLUSH_CMD_SHUTDOWN /* audio */,
890                        FLUSH_CMD_SHUTDOWN /* video */));
891
892            mDeferredActions.push_back(
893                    new SimpleAction(&NuPlayer::performReset));
894
895            processDeferredActions();
896            break;
897        }
898
899        case kWhatSeek:
900        {
901            int64_t seekTimeUs;
902            int32_t needNotify;
903            CHECK(msg->findInt64("seekTimeUs", &seekTimeUs));
904            CHECK(msg->findInt32("needNotify", &needNotify));
905
906            ALOGV("kWhatSeek seekTimeUs=%lld us, needNotify=%d",
907                    seekTimeUs, needNotify);
908
909            mDeferredActions.push_back(
910                    new FlushDecoderAction(FLUSH_CMD_FLUSH /* audio */,
911                                           FLUSH_CMD_FLUSH /* video */));
912
913            mDeferredActions.push_back(
914                    new SeekAction(seekTimeUs, needNotify));
915
916            processDeferredActions();
917            break;
918        }
919
920        case kWhatPause:
921        {
922            if (mSource != NULL) {
923                mSource->pause();
924            } else {
925                ALOGW("pause called when source is gone or not set");
926            }
927            if (mRenderer != NULL) {
928                mRenderer->pause();
929            } else {
930                ALOGW("pause called when renderer is gone or not set");
931            }
932            break;
933        }
934
935        case kWhatSourceNotify:
936        {
937            onSourceNotify(msg);
938            break;
939        }
940
941        case kWhatClosedCaptionNotify:
942        {
943            onClosedCaptionNotify(msg);
944            break;
945        }
946
947        default:
948            TRESPASS();
949            break;
950    }
951}
952
953void NuPlayer::onResume() {
954    if (mSource != NULL) {
955        mSource->resume();
956    } else {
957        ALOGW("resume called when source is gone or not set");
958    }
959    // |mAudioDecoder| may have been released due to the pause timeout, so re-create it if
960    // needed.
961    if (audioDecoderStillNeeded() && mAudioDecoder == NULL) {
962        instantiateDecoder(true /* audio */, &mAudioDecoder);
963    }
964    if (mRenderer != NULL) {
965        mRenderer->resume();
966    } else {
967        ALOGW("resume called when renderer is gone or not set");
968    }
969}
970
971void NuPlayer::onStart() {
972    mVideoIsAVC = false;
973    mOffloadAudio = false;
974    mAudioEOS = false;
975    mVideoEOS = false;
976    mNumFramesTotal = 0;
977    mNumFramesDropped = 0;
978    mStarted = true;
979
980    /* instantiate decoders now for secure playback */
981    if (mSourceFlags & Source::FLAG_SECURE) {
982        if (mNativeWindow != NULL) {
983            instantiateDecoder(false, &mVideoDecoder);
984        }
985
986        if (mAudioSink != NULL) {
987            instantiateDecoder(true, &mAudioDecoder);
988        }
989    }
990
991    mSource->start();
992
993    uint32_t flags = 0;
994
995    if (mSource->isRealTime()) {
996        flags |= Renderer::FLAG_REAL_TIME;
997    }
998
999    sp<MetaData> audioMeta = mSource->getFormatMeta(true /* audio */);
1000    audio_stream_type_t streamType = AUDIO_STREAM_MUSIC;
1001    if (mAudioSink != NULL) {
1002        streamType = mAudioSink->getAudioStreamType();
1003    }
1004
1005    sp<AMessage> videoFormat = mSource->getFormat(false /* audio */);
1006
1007    mOffloadAudio =
1008        canOffloadStream(audioMeta, (videoFormat != NULL),
1009                         true /* is_streaming */, streamType);
1010    if (mOffloadAudio) {
1011        flags |= Renderer::FLAG_OFFLOAD_AUDIO;
1012    }
1013
1014    sp<AMessage> notify = new AMessage(kWhatRendererNotify, id());
1015    ++mRendererGeneration;
1016    notify->setInt32("generation", mRendererGeneration);
1017    mRenderer = new Renderer(mAudioSink, notify, flags);
1018
1019    mRendererLooper = new ALooper;
1020    mRendererLooper->setName("NuPlayerRenderer");
1021    mRendererLooper->start(false, false, ANDROID_PRIORITY_AUDIO);
1022    mRendererLooper->registerHandler(mRenderer);
1023
1024    sp<MetaData> meta = getFileMeta();
1025    int32_t rate;
1026    if (meta != NULL
1027            && meta->findInt32(kKeyFrameRate, &rate) && rate > 0) {
1028        mRenderer->setVideoFrameRate(rate);
1029    }
1030
1031    if (mVideoDecoder != NULL) {
1032        mVideoDecoder->setRenderer(mRenderer);
1033    }
1034    if (mAudioDecoder != NULL) {
1035        mAudioDecoder->setRenderer(mRenderer);
1036    }
1037
1038    postScanSources();
1039}
1040
1041bool NuPlayer::audioDecoderStillNeeded() {
1042    // Audio decoder is no longer needed if it's in shut/shutting down status.
1043    return ((mFlushingAudio != SHUT_DOWN) && (mFlushingAudio != SHUTTING_DOWN_DECODER));
1044}
1045
1046void NuPlayer::handleFlushComplete(bool audio, bool isDecoder) {
1047    // We wait for both the decoder flush and the renderer flush to complete
1048    // before entering either the FLUSHED or the SHUTTING_DOWN_DECODER state.
1049
1050    mFlushComplete[audio][isDecoder] = true;
1051    if (!mFlushComplete[audio][!isDecoder]) {
1052        return;
1053    }
1054
1055    FlushStatus *state = audio ? &mFlushingAudio : &mFlushingVideo;
1056    switch (*state) {
1057        case FLUSHING_DECODER:
1058        {
1059            *state = FLUSHED;
1060            break;
1061        }
1062
1063        case FLUSHING_DECODER_SHUTDOWN:
1064        {
1065            *state = SHUTTING_DOWN_DECODER;
1066
1067            ALOGV("initiating %s decoder shutdown", audio ? "audio" : "video");
1068            if (!audio) {
1069                // Widevine source reads must stop before releasing the video decoder.
1070                if (mSource != NULL && mSourceFlags & Source::FLAG_SECURE) {
1071                    mSource->stop();
1072                }
1073            }
1074            getDecoder(audio)->initiateShutdown();
1075            break;
1076        }
1077
1078        default:
1079            // decoder flush completes only occur in a flushing state.
1080            LOG_ALWAYS_FATAL_IF(isDecoder, "decoder flush in invalid state %d", *state);
1081            break;
1082    }
1083}
1084
1085void NuPlayer::finishFlushIfPossible() {
1086    if (mFlushingAudio != NONE && mFlushingAudio != FLUSHED
1087            && mFlushingAudio != SHUT_DOWN) {
1088        return;
1089    }
1090
1091    if (mFlushingVideo != NONE && mFlushingVideo != FLUSHED
1092            && mFlushingVideo != SHUT_DOWN) {
1093        return;
1094    }
1095
1096    ALOGV("both audio and video are flushed now.");
1097
1098    mPendingAudioAccessUnit.clear();
1099    mAggregateBuffer.clear();
1100
1101    if (mTimeDiscontinuityPending) {
1102        mRenderer->signalTimeDiscontinuity();
1103        mTimeDiscontinuityPending = false;
1104    }
1105
1106    if (mAudioDecoder != NULL && mFlushingAudio == FLUSHED) {
1107        mAudioDecoder->signalResume();
1108    }
1109
1110    if (mVideoDecoder != NULL && mFlushingVideo == FLUSHED) {
1111        mVideoDecoder->signalResume();
1112    }
1113
1114    mFlushingAudio = NONE;
1115    mFlushingVideo = NONE;
1116
1117    clearFlushComplete();
1118
1119    processDeferredActions();
1120}
1121
1122void NuPlayer::postScanSources() {
1123    if (mScanSourcesPending) {
1124        return;
1125    }
1126
1127    sp<AMessage> msg = new AMessage(kWhatScanSources, id());
1128    msg->setInt32("generation", mScanSourcesGeneration);
1129    msg->post();
1130
1131    mScanSourcesPending = true;
1132}
1133
1134void NuPlayer::openAudioSink(const sp<AMessage> &format, bool offloadOnly) {
1135    uint32_t flags;
1136    int64_t durationUs;
1137    bool hasVideo = (mVideoDecoder != NULL);
1138    // FIXME: we should handle the case where the video decoder
1139    // is created after we receive the format change indication.
1140    // Current code will just make that we select deep buffer
1141    // with video which should not be a problem as it should
1142    // not prevent from keeping A/V sync.
1143    if (!hasVideo &&
1144            mSource->getDuration(&durationUs) == OK &&
1145            durationUs
1146                > AUDIO_SINK_MIN_DEEP_BUFFER_DURATION_US) {
1147        flags = AUDIO_OUTPUT_FLAG_DEEP_BUFFER;
1148    } else {
1149        flags = AUDIO_OUTPUT_FLAG_NONE;
1150    }
1151
1152    mOffloadAudio = mRenderer->openAudioSink(
1153            format, offloadOnly, hasVideo, flags);
1154
1155    if (mOffloadAudio) {
1156        sp<MetaData> audioMeta =
1157                mSource->getFormatMeta(true /* audio */);
1158        sendMetaDataToHal(mAudioSink, audioMeta);
1159    }
1160}
1161
1162void NuPlayer::closeAudioSink() {
1163    mRenderer->closeAudioSink();
1164}
1165
1166status_t NuPlayer::instantiateDecoder(bool audio, sp<Decoder> *decoder) {
1167    if (*decoder != NULL) {
1168        return OK;
1169    }
1170
1171    sp<AMessage> format = mSource->getFormat(audio);
1172
1173    if (format == NULL) {
1174        return -EWOULDBLOCK;
1175    }
1176
1177    if (!audio) {
1178        AString mime;
1179        CHECK(format->findString("mime", &mime));
1180        mVideoIsAVC = !strcasecmp(MEDIA_MIMETYPE_VIDEO_AVC, mime.c_str());
1181
1182        sp<AMessage> ccNotify = new AMessage(kWhatClosedCaptionNotify, id());
1183        mCCDecoder = new CCDecoder(ccNotify);
1184
1185        if (mSourceFlags & Source::FLAG_SECURE) {
1186            format->setInt32("secure", true);
1187        }
1188    }
1189
1190    if (audio) {
1191        sp<AMessage> notify = new AMessage(kWhatAudioNotify, id());
1192        ++mAudioDecoderGeneration;
1193        notify->setInt32("generation", mAudioDecoderGeneration);
1194
1195        if (mOffloadAudio) {
1196            *decoder = new DecoderPassThrough(notify, mSource, mRenderer);
1197        } else {
1198            *decoder = new Decoder(notify, mSource, mRenderer);
1199        }
1200    } else {
1201        sp<AMessage> notify = new AMessage(kWhatVideoNotify, id());
1202        ++mVideoDecoderGeneration;
1203        notify->setInt32("generation", mVideoDecoderGeneration);
1204
1205        *decoder = new Decoder(notify, mSource, mRenderer, mNativeWindow);
1206
1207        // enable FRC if high-quality AV sync is requested, even if not
1208        // queuing to native window, as this will even improve textureview
1209        // playback.
1210        {
1211            char value[PROPERTY_VALUE_MAX];
1212            if (property_get("persist.sys.media.avsync", value, NULL) &&
1213                    (!strcmp("1", value) || !strcasecmp("true", value))) {
1214                format->setInt32("auto-frc", 1);
1215            }
1216        }
1217    }
1218    (*decoder)->init();
1219    (*decoder)->configure(format);
1220
1221    // allocate buffers to decrypt widevine source buffers
1222    if (!audio && (mSourceFlags & Source::FLAG_SECURE)) {
1223        Vector<sp<ABuffer> > inputBufs;
1224        CHECK_EQ((*decoder)->getInputBuffers(&inputBufs), (status_t)OK);
1225
1226        Vector<MediaBuffer *> mediaBufs;
1227        for (size_t i = 0; i < inputBufs.size(); i++) {
1228            const sp<ABuffer> &buffer = inputBufs[i];
1229            MediaBuffer *mbuf = new MediaBuffer(buffer->data(), buffer->size());
1230            mediaBufs.push(mbuf);
1231        }
1232
1233        status_t err = mSource->setBuffers(audio, mediaBufs);
1234        if (err != OK) {
1235            for (size_t i = 0; i < mediaBufs.size(); ++i) {
1236                mediaBufs[i]->release();
1237            }
1238            mediaBufs.clear();
1239            ALOGE("Secure source didn't support secure mediaBufs.");
1240            return err;
1241        }
1242    }
1243    return OK;
1244}
1245
1246status_t NuPlayer::feedDecoderInputData(bool audio, const sp<AMessage> &msg) {
1247    sp<AMessage> reply;
1248    CHECK(msg->findMessage("reply", &reply));
1249
1250    if ((audio && mFlushingAudio != NONE)
1251            || (!audio && mFlushingVideo != NONE)
1252            || mSource == NULL) {
1253        reply->setInt32("err", INFO_DISCONTINUITY);
1254        reply->post();
1255        return OK;
1256    }
1257
1258    sp<ABuffer> accessUnit;
1259
1260    // Aggregate smaller buffers into a larger buffer.
1261    // The goal is to reduce power consumption.
1262    // Note this will not work if the decoder requires one frame per buffer.
1263    bool doBufferAggregation = (audio && mOffloadAudio);
1264    bool needMoreData = false;
1265
1266    bool dropAccessUnit;
1267    do {
1268        status_t err;
1269        // Did we save an accessUnit earlier because of a discontinuity?
1270        if (audio && (mPendingAudioAccessUnit != NULL)) {
1271            accessUnit = mPendingAudioAccessUnit;
1272            mPendingAudioAccessUnit.clear();
1273            err = mPendingAudioErr;
1274            ALOGV("feedDecoderInputData() use mPendingAudioAccessUnit");
1275        } else {
1276            err = mSource->dequeueAccessUnit(audio, &accessUnit);
1277        }
1278
1279        if (err == -EWOULDBLOCK) {
1280            return err;
1281        } else if (err != OK) {
1282            if (err == INFO_DISCONTINUITY) {
1283                if (doBufferAggregation && (mAggregateBuffer != NULL)) {
1284                    // We already have some data so save this for later.
1285                    mPendingAudioErr = err;
1286                    mPendingAudioAccessUnit = accessUnit;
1287                    accessUnit.clear();
1288                    ALOGD("feedDecoderInputData() save discontinuity for later");
1289                    break;
1290                }
1291                int32_t type;
1292                CHECK(accessUnit->meta()->findInt32("discontinuity", &type));
1293
1294                bool formatChange =
1295                    (audio &&
1296                     (type & ATSParser::DISCONTINUITY_AUDIO_FORMAT))
1297                    || (!audio &&
1298                            (type & ATSParser::DISCONTINUITY_VIDEO_FORMAT));
1299
1300                bool timeChange = (type & ATSParser::DISCONTINUITY_TIME) != 0;
1301
1302                ALOGI("%s discontinuity (formatChange=%d, time=%d)",
1303                     audio ? "audio" : "video", formatChange, timeChange);
1304
1305                mTimeDiscontinuityPending =
1306                    mTimeDiscontinuityPending || timeChange;
1307
1308                bool seamlessFormatChange = false;
1309                sp<AMessage> newFormat = mSource->getFormat(audio);
1310                if (formatChange) {
1311                    seamlessFormatChange =
1312                        getDecoder(audio)->supportsSeamlessFormatChange(newFormat);
1313                    // treat seamless format change separately
1314                    formatChange = !seamlessFormatChange;
1315                }
1316                bool shutdownOrFlush = formatChange || timeChange;
1317
1318                // We want to queue up scan-sources only once per discontinuity.
1319                // We control this by doing it only if neither audio nor video are
1320                // flushing or shutting down.  (After handling 1st discontinuity, one
1321                // of the flushing states will not be NONE.)
1322                // No need to scan sources if this discontinuity does not result
1323                // in a flush or shutdown, as the flushing state will stay NONE.
1324                if (mFlushingAudio == NONE && mFlushingVideo == NONE &&
1325                        shutdownOrFlush) {
1326                    // And we'll resume scanning sources once we're done
1327                    // flushing.
1328                    mDeferredActions.push_front(
1329                            new SimpleAction(
1330                                &NuPlayer::performScanSources));
1331                }
1332
1333                if (formatChange /* not seamless */) {
1334                    // must change decoder
1335                    flushDecoder(audio, /* needShutdown = */ true);
1336                } else if (timeChange) {
1337                    // need to flush
1338                    flushDecoder(audio, /* needShutdown = */ false, newFormat);
1339                    err = OK;
1340                } else if (seamlessFormatChange) {
1341                    // reuse existing decoder and don't flush
1342                    updateDecoderFormatWithoutFlush(audio, newFormat);
1343                    err = OK;
1344                } else {
1345                    // This stream is unaffected by the discontinuity
1346                    return -EWOULDBLOCK;
1347                }
1348            } else if (err == ERROR_END_OF_STREAM
1349                    && doBufferAggregation && (mAggregateBuffer != NULL)) {
1350                // send out the last bit of aggregated data
1351                reply->setBuffer("buffer", mAggregateBuffer);
1352                mAggregateBuffer.clear();
1353                err = OK;
1354            }
1355
1356            reply->setInt32("err", err);
1357            reply->post();
1358            return OK;
1359        }
1360
1361        if (!audio) {
1362            ++mNumFramesTotal;
1363        }
1364
1365        dropAccessUnit = false;
1366        if (!audio
1367                && !(mSourceFlags & Source::FLAG_SECURE)
1368                && mRenderer->getVideoLateByUs() > 100000ll
1369                && mVideoIsAVC
1370                && !IsAVCReferenceFrame(accessUnit)) {
1371            dropAccessUnit = true;
1372            ++mNumFramesDropped;
1373        }
1374
1375        size_t smallSize = accessUnit->size();
1376        needMoreData = false;
1377        if (doBufferAggregation && (mAggregateBuffer == NULL)
1378                // Don't bother if only room for a few small buffers.
1379                && (smallSize < (kAggregateBufferSizeBytes / 3))) {
1380            // Create a larger buffer for combining smaller buffers from the extractor.
1381            mAggregateBuffer = new ABuffer(kAggregateBufferSizeBytes);
1382            mAggregateBuffer->setRange(0, 0); // start empty
1383        }
1384
1385        if (doBufferAggregation && (mAggregateBuffer != NULL)) {
1386            int64_t timeUs;
1387            int64_t dummy;
1388            bool smallTimestampValid = accessUnit->meta()->findInt64("timeUs", &timeUs);
1389            bool bigTimestampValid = mAggregateBuffer->meta()->findInt64("timeUs", &dummy);
1390            // Will the smaller buffer fit?
1391            size_t bigSize = mAggregateBuffer->size();
1392            size_t roomLeft = mAggregateBuffer->capacity() - bigSize;
1393            // Should we save this small buffer for the next big buffer?
1394            // If the first small buffer did not have a timestamp then save
1395            // any buffer that does have a timestamp until the next big buffer.
1396            if ((smallSize > roomLeft)
1397                || (!bigTimestampValid && (bigSize > 0) && smallTimestampValid)) {
1398                mPendingAudioErr = err;
1399                mPendingAudioAccessUnit = accessUnit;
1400                accessUnit.clear();
1401            } else {
1402                // Grab time from first small buffer if available.
1403                if ((bigSize == 0) && smallTimestampValid) {
1404                    mAggregateBuffer->meta()->setInt64("timeUs", timeUs);
1405                }
1406                // Append small buffer to the bigger buffer.
1407                memcpy(mAggregateBuffer->base() + bigSize, accessUnit->data(), smallSize);
1408                bigSize += smallSize;
1409                mAggregateBuffer->setRange(0, bigSize);
1410
1411                // Keep looping until we run out of room in the mAggregateBuffer.
1412                needMoreData = true;
1413
1414                ALOGV("feedDecoderInputData() smallSize = %zu, bigSize = %zu, capacity = %zu",
1415                        smallSize, bigSize, mAggregateBuffer->capacity());
1416            }
1417        }
1418    } while (dropAccessUnit || needMoreData);
1419
1420    // ALOGV("returned a valid buffer of %s data", audio ? "audio" : "video");
1421
1422#if 0
1423    int64_t mediaTimeUs;
1424    CHECK(accessUnit->meta()->findInt64("timeUs", &mediaTimeUs));
1425    ALOGV("feeding %s input buffer at media time %.2f secs",
1426         audio ? "audio" : "video",
1427         mediaTimeUs / 1E6);
1428#endif
1429
1430    if (!audio) {
1431        mCCDecoder->decode(accessUnit);
1432    }
1433
1434    if (doBufferAggregation && (mAggregateBuffer != NULL)) {
1435        ALOGV("feedDecoderInputData() reply with aggregated buffer, %zu",
1436                mAggregateBuffer->size());
1437        reply->setBuffer("buffer", mAggregateBuffer);
1438        mAggregateBuffer.clear();
1439    } else {
1440        reply->setBuffer("buffer", accessUnit);
1441    }
1442
1443    reply->post();
1444
1445    return OK;
1446}
1447
1448void NuPlayer::renderBuffer(bool audio, const sp<AMessage> &msg) {
1449    // ALOGV("renderBuffer %s", audio ? "audio" : "video");
1450
1451    if ((audio && mFlushingAudio != NONE)
1452            || (!audio && mFlushingVideo != NONE)) {
1453        // We're currently attempting to flush the decoder, in order
1454        // to complete this, the decoder wants all its buffers back,
1455        // so we don't want any output buffers it sent us (from before
1456        // we initiated the flush) to be stuck in the renderer's queue.
1457
1458        ALOGV("we're still flushing the %s decoder, sending its output buffer"
1459             " right back.", audio ? "audio" : "video");
1460
1461        return;
1462    }
1463
1464    int64_t mediaTimeUs;
1465    CHECK(msg->findInt64("timeUs", &mediaTimeUs));
1466
1467    if (!audio && mCCDecoder->isSelected()) {
1468        mCCDecoder->display(mediaTimeUs);
1469    }
1470}
1471
1472void NuPlayer::updateVideoSize(
1473        const sp<AMessage> &inputFormat,
1474        const sp<AMessage> &outputFormat) {
1475    if (inputFormat == NULL) {
1476        ALOGW("Unknown video size, reporting 0x0!");
1477        notifyListener(MEDIA_SET_VIDEO_SIZE, 0, 0);
1478        return;
1479    }
1480
1481    int32_t displayWidth, displayHeight;
1482    int32_t cropLeft, cropTop, cropRight, cropBottom;
1483
1484    if (outputFormat != NULL) {
1485        int32_t width, height;
1486        CHECK(outputFormat->findInt32("width", &width));
1487        CHECK(outputFormat->findInt32("height", &height));
1488
1489        int32_t cropLeft, cropTop, cropRight, cropBottom;
1490        CHECK(outputFormat->findRect(
1491                    "crop",
1492                    &cropLeft, &cropTop, &cropRight, &cropBottom));
1493
1494        displayWidth = cropRight - cropLeft + 1;
1495        displayHeight = cropBottom - cropTop + 1;
1496
1497        ALOGV("Video output format changed to %d x %d "
1498             "(crop: %d x %d @ (%d, %d))",
1499             width, height,
1500             displayWidth,
1501             displayHeight,
1502             cropLeft, cropTop);
1503    } else {
1504        CHECK(inputFormat->findInt32("width", &displayWidth));
1505        CHECK(inputFormat->findInt32("height", &displayHeight));
1506
1507        ALOGV("Video input format %d x %d", displayWidth, displayHeight);
1508    }
1509
1510    // Take into account sample aspect ratio if necessary:
1511    int32_t sarWidth, sarHeight;
1512    if (inputFormat->findInt32("sar-width", &sarWidth)
1513            && inputFormat->findInt32("sar-height", &sarHeight)) {
1514        ALOGV("Sample aspect ratio %d : %d", sarWidth, sarHeight);
1515
1516        displayWidth = (displayWidth * sarWidth) / sarHeight;
1517
1518        ALOGV("display dimensions %d x %d", displayWidth, displayHeight);
1519    }
1520
1521    int32_t rotationDegrees;
1522    if (!inputFormat->findInt32("rotation-degrees", &rotationDegrees)) {
1523        rotationDegrees = 0;
1524    }
1525
1526    if (rotationDegrees == 90 || rotationDegrees == 270) {
1527        int32_t tmp = displayWidth;
1528        displayWidth = displayHeight;
1529        displayHeight = tmp;
1530    }
1531
1532    notifyListener(
1533            MEDIA_SET_VIDEO_SIZE,
1534            displayWidth,
1535            displayHeight);
1536}
1537
1538void NuPlayer::notifyListener(int msg, int ext1, int ext2, const Parcel *in) {
1539    if (mDriver == NULL) {
1540        return;
1541    }
1542
1543    sp<NuPlayerDriver> driver = mDriver.promote();
1544
1545    if (driver == NULL) {
1546        return;
1547    }
1548
1549    driver->notifyListener(msg, ext1, ext2, in);
1550}
1551
1552void NuPlayer::flushDecoder(
1553        bool audio, bool needShutdown, const sp<AMessage> &newFormat) {
1554    ALOGV("[%s] flushDecoder needShutdown=%d",
1555          audio ? "audio" : "video", needShutdown);
1556
1557    const sp<Decoder> &decoder = getDecoder(audio);
1558    if (decoder == NULL) {
1559        ALOGI("flushDecoder %s without decoder present",
1560             audio ? "audio" : "video");
1561        return;
1562    }
1563
1564    // Make sure we don't continue to scan sources until we finish flushing.
1565    ++mScanSourcesGeneration;
1566    mScanSourcesPending = false;
1567
1568    decoder->signalFlush(newFormat);
1569
1570    FlushStatus newStatus =
1571        needShutdown ? FLUSHING_DECODER_SHUTDOWN : FLUSHING_DECODER;
1572
1573    mFlushComplete[audio][false /* isDecoder */] = false;
1574    mFlushComplete[audio][true /* isDecoder */] = false;
1575    if (audio) {
1576        ALOGE_IF(mFlushingAudio != NONE,
1577                "audio flushDecoder() is called in state %d", mFlushingAudio);
1578        mFlushingAudio = newStatus;
1579    } else {
1580        ALOGE_IF(mFlushingVideo != NONE,
1581                "video flushDecoder() is called in state %d", mFlushingVideo);
1582        mFlushingVideo = newStatus;
1583
1584        if (mCCDecoder != NULL) {
1585            mCCDecoder->flush();
1586        }
1587    }
1588}
1589
1590void NuPlayer::updateDecoderFormatWithoutFlush(
1591        bool audio, const sp<AMessage> &format) {
1592    ALOGV("[%s] updateDecoderFormatWithoutFlush", audio ? "audio" : "video");
1593
1594    const sp<Decoder> &decoder = getDecoder(audio);
1595    if (decoder == NULL) {
1596        ALOGI("updateDecoderFormatWithoutFlush %s without decoder present",
1597             audio ? "audio" : "video");
1598        return;
1599    }
1600
1601    decoder->signalUpdateFormat(format);
1602}
1603
1604void NuPlayer::queueDecoderShutdown(
1605        bool audio, bool video, const sp<AMessage> &reply) {
1606    ALOGI("queueDecoderShutdown audio=%d, video=%d", audio, video);
1607
1608    mDeferredActions.push_back(
1609            new FlushDecoderAction(
1610                audio ? FLUSH_CMD_SHUTDOWN : FLUSH_CMD_NONE,
1611                video ? FLUSH_CMD_SHUTDOWN : FLUSH_CMD_NONE));
1612
1613    mDeferredActions.push_back(
1614            new SimpleAction(&NuPlayer::performScanSources));
1615
1616    mDeferredActions.push_back(new PostMessageAction(reply));
1617
1618    processDeferredActions();
1619}
1620
1621status_t NuPlayer::setVideoScalingMode(int32_t mode) {
1622    mVideoScalingMode = mode;
1623    if (mNativeWindow != NULL) {
1624        status_t ret = native_window_set_scaling_mode(
1625                mNativeWindow->getNativeWindow().get(), mVideoScalingMode);
1626        if (ret != OK) {
1627            ALOGE("Failed to set scaling mode (%d): %s",
1628                -ret, strerror(-ret));
1629            return ret;
1630        }
1631    }
1632    return OK;
1633}
1634
1635status_t NuPlayer::getTrackInfo(Parcel* reply) const {
1636    sp<AMessage> msg = new AMessage(kWhatGetTrackInfo, id());
1637    msg->setPointer("reply", reply);
1638
1639    sp<AMessage> response;
1640    status_t err = msg->postAndAwaitResponse(&response);
1641    return err;
1642}
1643
1644status_t NuPlayer::getSelectedTrack(int32_t type, Parcel* reply) const {
1645    sp<AMessage> msg = new AMessage(kWhatGetSelectedTrack, id());
1646    msg->setPointer("reply", reply);
1647    msg->setInt32("type", type);
1648
1649    sp<AMessage> response;
1650    status_t err = msg->postAndAwaitResponse(&response);
1651    if (err == OK && response != NULL) {
1652        CHECK(response->findInt32("err", &err));
1653    }
1654    return err;
1655}
1656
1657status_t NuPlayer::selectTrack(size_t trackIndex, bool select, int64_t timeUs) {
1658    sp<AMessage> msg = new AMessage(kWhatSelectTrack, id());
1659    msg->setSize("trackIndex", trackIndex);
1660    msg->setInt32("select", select);
1661    msg->setInt64("timeUs", timeUs);
1662
1663    sp<AMessage> response;
1664    status_t err = msg->postAndAwaitResponse(&response);
1665
1666    if (err != OK) {
1667        return err;
1668    }
1669
1670    if (!response->findInt32("err", &err)) {
1671        err = OK;
1672    }
1673
1674    return err;
1675}
1676
1677status_t NuPlayer::getCurrentPosition(int64_t *mediaUs) {
1678    sp<Renderer> renderer = mRenderer;
1679    if (renderer == NULL) {
1680        return NO_INIT;
1681    }
1682
1683    return renderer->getCurrentPosition(mediaUs);
1684}
1685
1686void NuPlayer::getStats(int64_t *numFramesTotal, int64_t *numFramesDropped) {
1687    *numFramesTotal = mNumFramesTotal;
1688    *numFramesDropped = mNumFramesDropped;
1689}
1690
1691sp<MetaData> NuPlayer::getFileMeta() {
1692    return mSource->getFileFormatMeta();
1693}
1694
1695void NuPlayer::schedulePollDuration() {
1696    sp<AMessage> msg = new AMessage(kWhatPollDuration, id());
1697    msg->setInt32("generation", mPollDurationGeneration);
1698    msg->post();
1699}
1700
1701void NuPlayer::cancelPollDuration() {
1702    ++mPollDurationGeneration;
1703}
1704
1705void NuPlayer::processDeferredActions() {
1706    while (!mDeferredActions.empty()) {
1707        // We won't execute any deferred actions until we're no longer in
1708        // an intermediate state, i.e. one more more decoders are currently
1709        // flushing or shutting down.
1710
1711        if (mFlushingAudio != NONE || mFlushingVideo != NONE) {
1712            // We're currently flushing, postpone the reset until that's
1713            // completed.
1714
1715            ALOGV("postponing action mFlushingAudio=%d, mFlushingVideo=%d",
1716                  mFlushingAudio, mFlushingVideo);
1717
1718            break;
1719        }
1720
1721        sp<Action> action = *mDeferredActions.begin();
1722        mDeferredActions.erase(mDeferredActions.begin());
1723
1724        action->execute(this);
1725    }
1726}
1727
1728void NuPlayer::performSeek(int64_t seekTimeUs, bool needNotify) {
1729    ALOGV("performSeek seekTimeUs=%lld us (%.2f secs), needNotify(%d)",
1730          seekTimeUs,
1731          seekTimeUs / 1E6,
1732          needNotify);
1733
1734    if (mSource == NULL) {
1735        // This happens when reset occurs right before the loop mode
1736        // asynchronously seeks to the start of the stream.
1737        LOG_ALWAYS_FATAL_IF(mAudioDecoder != NULL || mVideoDecoder != NULL,
1738                "mSource is NULL and decoders not NULL audio(%p) video(%p)",
1739                mAudioDecoder.get(), mVideoDecoder.get());
1740        return;
1741    }
1742    mSource->seekTo(seekTimeUs);
1743    ++mTimedTextGeneration;
1744
1745    if (mDriver != NULL) {
1746        sp<NuPlayerDriver> driver = mDriver.promote();
1747        if (driver != NULL) {
1748            if (needNotify) {
1749                driver->notifySeekComplete();
1750            }
1751        }
1752    }
1753
1754    // everything's flushed, continue playback.
1755}
1756
1757void NuPlayer::performDecoderFlush(FlushCommand audio, FlushCommand video) {
1758    ALOGV("performDecoderFlush audio=%d, video=%d", audio, video);
1759
1760    if ((audio == FLUSH_CMD_NONE || mAudioDecoder == NULL)
1761            && (video == FLUSH_CMD_NONE || mVideoDecoder == NULL)) {
1762        return;
1763    }
1764
1765    mTimeDiscontinuityPending = true;
1766
1767    if (audio != FLUSH_CMD_NONE && mAudioDecoder != NULL) {
1768        flushDecoder(true /* audio */, (audio == FLUSH_CMD_SHUTDOWN));
1769    }
1770
1771    if (video != FLUSH_CMD_NONE && mVideoDecoder != NULL) {
1772        flushDecoder(false /* audio */, (video == FLUSH_CMD_SHUTDOWN));
1773    }
1774}
1775
1776void NuPlayer::performReset() {
1777    ALOGV("performReset");
1778
1779    CHECK(mAudioDecoder == NULL);
1780    CHECK(mVideoDecoder == NULL);
1781
1782    cancelPollDuration();
1783
1784    ++mScanSourcesGeneration;
1785    mScanSourcesPending = false;
1786
1787    if (mRendererLooper != NULL) {
1788        if (mRenderer != NULL) {
1789            mRendererLooper->unregisterHandler(mRenderer->id());
1790        }
1791        mRendererLooper->stop();
1792        mRendererLooper.clear();
1793    }
1794    mRenderer.clear();
1795    ++mRendererGeneration;
1796
1797    if (mSource != NULL) {
1798        mSource->stop();
1799
1800        mSource.clear();
1801    }
1802
1803    if (mDriver != NULL) {
1804        sp<NuPlayerDriver> driver = mDriver.promote();
1805        if (driver != NULL) {
1806            driver->notifyResetComplete();
1807        }
1808    }
1809
1810    mStarted = false;
1811}
1812
1813void NuPlayer::performScanSources() {
1814    ALOGV("performScanSources");
1815
1816    if (!mStarted) {
1817        return;
1818    }
1819
1820    if (mAudioDecoder == NULL || mVideoDecoder == NULL) {
1821        postScanSources();
1822    }
1823}
1824
1825void NuPlayer::performSetSurface(const sp<NativeWindowWrapper> &wrapper) {
1826    ALOGV("performSetSurface");
1827
1828    mNativeWindow = wrapper;
1829
1830    // XXX - ignore error from setVideoScalingMode for now
1831    setVideoScalingMode(mVideoScalingMode);
1832
1833    if (mDriver != NULL) {
1834        sp<NuPlayerDriver> driver = mDriver.promote();
1835        if (driver != NULL) {
1836            driver->notifySetSurfaceComplete();
1837        }
1838    }
1839}
1840
1841void NuPlayer::onSourceNotify(const sp<AMessage> &msg) {
1842    int32_t what;
1843    CHECK(msg->findInt32("what", &what));
1844
1845    switch (what) {
1846        case Source::kWhatPrepared:
1847        {
1848            if (mSource == NULL) {
1849                // This is a stale notification from a source that was
1850                // asynchronously preparing when the client called reset().
1851                // We handled the reset, the source is gone.
1852                break;
1853            }
1854
1855            int32_t err;
1856            CHECK(msg->findInt32("err", &err));
1857
1858            sp<NuPlayerDriver> driver = mDriver.promote();
1859            if (driver != NULL) {
1860                // notify duration first, so that it's definitely set when
1861                // the app received the "prepare complete" callback.
1862                int64_t durationUs;
1863                if (mSource->getDuration(&durationUs) == OK) {
1864                    driver->notifyDuration(durationUs);
1865                }
1866                driver->notifyPrepareCompleted(err);
1867            }
1868
1869            break;
1870        }
1871
1872        case Source::kWhatFlagsChanged:
1873        {
1874            uint32_t flags;
1875            CHECK(msg->findInt32("flags", (int32_t *)&flags));
1876
1877            sp<NuPlayerDriver> driver = mDriver.promote();
1878            if (driver != NULL) {
1879                driver->notifyFlagsChanged(flags);
1880            }
1881
1882            if ((mSourceFlags & Source::FLAG_DYNAMIC_DURATION)
1883                    && (!(flags & Source::FLAG_DYNAMIC_DURATION))) {
1884                cancelPollDuration();
1885            } else if (!(mSourceFlags & Source::FLAG_DYNAMIC_DURATION)
1886                    && (flags & Source::FLAG_DYNAMIC_DURATION)
1887                    && (mAudioDecoder != NULL || mVideoDecoder != NULL)) {
1888                schedulePollDuration();
1889            }
1890
1891            mSourceFlags = flags;
1892            break;
1893        }
1894
1895        case Source::kWhatVideoSizeChanged:
1896        {
1897            sp<AMessage> format;
1898            CHECK(msg->findMessage("format", &format));
1899
1900            updateVideoSize(format);
1901            break;
1902        }
1903
1904        case Source::kWhatBufferingUpdate:
1905        {
1906            int32_t percentage;
1907            CHECK(msg->findInt32("percentage", &percentage));
1908
1909            notifyListener(MEDIA_BUFFERING_UPDATE, percentage, 0);
1910            break;
1911        }
1912
1913        case Source::kWhatBufferingStart:
1914        {
1915            notifyListener(MEDIA_INFO, MEDIA_INFO_BUFFERING_START, 0);
1916            break;
1917        }
1918
1919        case Source::kWhatBufferingEnd:
1920        {
1921            notifyListener(MEDIA_INFO, MEDIA_INFO_BUFFERING_END, 0);
1922            break;
1923        }
1924
1925        case Source::kWhatSubtitleData:
1926        {
1927            sp<ABuffer> buffer;
1928            CHECK(msg->findBuffer("buffer", &buffer));
1929
1930            sendSubtitleData(buffer, 0 /* baseIndex */);
1931            break;
1932        }
1933
1934        case Source::kWhatTimedTextData:
1935        {
1936            int32_t generation;
1937            if (msg->findInt32("generation", &generation)
1938                    && generation != mTimedTextGeneration) {
1939                break;
1940            }
1941
1942            sp<ABuffer> buffer;
1943            CHECK(msg->findBuffer("buffer", &buffer));
1944
1945            sp<NuPlayerDriver> driver = mDriver.promote();
1946            if (driver == NULL) {
1947                break;
1948            }
1949
1950            int posMs;
1951            int64_t timeUs, posUs;
1952            driver->getCurrentPosition(&posMs);
1953            posUs = posMs * 1000;
1954            CHECK(buffer->meta()->findInt64("timeUs", &timeUs));
1955
1956            if (posUs < timeUs) {
1957                if (!msg->findInt32("generation", &generation)) {
1958                    msg->setInt32("generation", mTimedTextGeneration);
1959                }
1960                msg->post(timeUs - posUs);
1961            } else {
1962                sendTimedTextData(buffer);
1963            }
1964            break;
1965        }
1966
1967        case Source::kWhatQueueDecoderShutdown:
1968        {
1969            int32_t audio, video;
1970            CHECK(msg->findInt32("audio", &audio));
1971            CHECK(msg->findInt32("video", &video));
1972
1973            sp<AMessage> reply;
1974            CHECK(msg->findMessage("reply", &reply));
1975
1976            queueDecoderShutdown(audio, video, reply);
1977            break;
1978        }
1979
1980        case Source::kWhatDrmNoLicense:
1981        {
1982            notifyListener(MEDIA_ERROR, MEDIA_ERROR_UNKNOWN, ERROR_DRM_NO_LICENSE);
1983            break;
1984        }
1985
1986        default:
1987            TRESPASS();
1988    }
1989}
1990
1991void NuPlayer::onClosedCaptionNotify(const sp<AMessage> &msg) {
1992    int32_t what;
1993    CHECK(msg->findInt32("what", &what));
1994
1995    switch (what) {
1996        case NuPlayer::CCDecoder::kWhatClosedCaptionData:
1997        {
1998            sp<ABuffer> buffer;
1999            CHECK(msg->findBuffer("buffer", &buffer));
2000
2001            size_t inbandTracks = 0;
2002            if (mSource != NULL) {
2003                inbandTracks = mSource->getTrackCount();
2004            }
2005
2006            sendSubtitleData(buffer, inbandTracks);
2007            break;
2008        }
2009
2010        case NuPlayer::CCDecoder::kWhatTrackAdded:
2011        {
2012            notifyListener(MEDIA_INFO, MEDIA_INFO_METADATA_UPDATE, 0);
2013
2014            break;
2015        }
2016
2017        default:
2018            TRESPASS();
2019    }
2020
2021
2022}
2023
2024void NuPlayer::sendSubtitleData(const sp<ABuffer> &buffer, int32_t baseIndex) {
2025    int32_t trackIndex;
2026    int64_t timeUs, durationUs;
2027    CHECK(buffer->meta()->findInt32("trackIndex", &trackIndex));
2028    CHECK(buffer->meta()->findInt64("timeUs", &timeUs));
2029    CHECK(buffer->meta()->findInt64("durationUs", &durationUs));
2030
2031    Parcel in;
2032    in.writeInt32(trackIndex + baseIndex);
2033    in.writeInt64(timeUs);
2034    in.writeInt64(durationUs);
2035    in.writeInt32(buffer->size());
2036    in.writeInt32(buffer->size());
2037    in.write(buffer->data(), buffer->size());
2038
2039    notifyListener(MEDIA_SUBTITLE_DATA, 0, 0, &in);
2040}
2041
2042void NuPlayer::sendTimedTextData(const sp<ABuffer> &buffer) {
2043    const void *data;
2044    size_t size = 0;
2045    int64_t timeUs;
2046    int32_t flag = TextDescriptions::LOCAL_DESCRIPTIONS;
2047
2048    AString mime;
2049    CHECK(buffer->meta()->findString("mime", &mime));
2050    CHECK(strcasecmp(mime.c_str(), MEDIA_MIMETYPE_TEXT_3GPP) == 0);
2051
2052    data = buffer->data();
2053    size = buffer->size();
2054
2055    Parcel parcel;
2056    if (size > 0) {
2057        CHECK(buffer->meta()->findInt64("timeUs", &timeUs));
2058        flag |= TextDescriptions::IN_BAND_TEXT_3GPP;
2059        TextDescriptions::getParcelOfDescriptions(
2060                (const uint8_t *)data, size, flag, timeUs / 1000, &parcel);
2061    }
2062
2063    if ((parcel.dataSize() > 0)) {
2064        notifyListener(MEDIA_TIMED_TEXT, 0, 0, &parcel);
2065    } else {  // send an empty timed text
2066        notifyListener(MEDIA_TIMED_TEXT, 0, 0);
2067    }
2068}
2069////////////////////////////////////////////////////////////////////////////////
2070
2071sp<AMessage> NuPlayer::Source::getFormat(bool audio) {
2072    sp<MetaData> meta = getFormatMeta(audio);
2073
2074    if (meta == NULL) {
2075        return NULL;
2076    }
2077
2078    sp<AMessage> msg = new AMessage;
2079
2080    if(convertMetaDataToMessage(meta, &msg) == OK) {
2081        return msg;
2082    }
2083    return NULL;
2084}
2085
2086void NuPlayer::Source::notifyFlagsChanged(uint32_t flags) {
2087    sp<AMessage> notify = dupNotify();
2088    notify->setInt32("what", kWhatFlagsChanged);
2089    notify->setInt32("flags", flags);
2090    notify->post();
2091}
2092
2093void NuPlayer::Source::notifyVideoSizeChanged(const sp<AMessage> &format) {
2094    sp<AMessage> notify = dupNotify();
2095    notify->setInt32("what", kWhatVideoSizeChanged);
2096    notify->setMessage("format", format);
2097    notify->post();
2098}
2099
2100void NuPlayer::Source::notifyPrepared(status_t err) {
2101    sp<AMessage> notify = dupNotify();
2102    notify->setInt32("what", kWhatPrepared);
2103    notify->setInt32("err", err);
2104    notify->post();
2105}
2106
2107void NuPlayer::Source::onMessageReceived(const sp<AMessage> & /* msg */) {
2108    TRESPASS();
2109}
2110
2111}  // namespace android
2112