NuPlayer.cpp revision d9fd6317913c74e1c955eb31978c41e70d5810bc
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            }
1349
1350            reply->setInt32("err", err);
1351            reply->post();
1352            return OK;
1353        }
1354
1355        if (!audio) {
1356            ++mNumFramesTotal;
1357        }
1358
1359        dropAccessUnit = false;
1360        if (!audio
1361                && !(mSourceFlags & Source::FLAG_SECURE)
1362                && mRenderer->getVideoLateByUs() > 100000ll
1363                && mVideoIsAVC
1364                && !IsAVCReferenceFrame(accessUnit)) {
1365            dropAccessUnit = true;
1366            ++mNumFramesDropped;
1367        }
1368
1369        size_t smallSize = accessUnit->size();
1370        needMoreData = false;
1371        if (doBufferAggregation && (mAggregateBuffer == NULL)
1372                // Don't bother if only room for a few small buffers.
1373                && (smallSize < (kAggregateBufferSizeBytes / 3))) {
1374            // Create a larger buffer for combining smaller buffers from the extractor.
1375            mAggregateBuffer = new ABuffer(kAggregateBufferSizeBytes);
1376            mAggregateBuffer->setRange(0, 0); // start empty
1377        }
1378
1379        if (doBufferAggregation && (mAggregateBuffer != NULL)) {
1380            int64_t timeUs;
1381            int64_t dummy;
1382            bool smallTimestampValid = accessUnit->meta()->findInt64("timeUs", &timeUs);
1383            bool bigTimestampValid = mAggregateBuffer->meta()->findInt64("timeUs", &dummy);
1384            // Will the smaller buffer fit?
1385            size_t bigSize = mAggregateBuffer->size();
1386            size_t roomLeft = mAggregateBuffer->capacity() - bigSize;
1387            // Should we save this small buffer for the next big buffer?
1388            // If the first small buffer did not have a timestamp then save
1389            // any buffer that does have a timestamp until the next big buffer.
1390            if ((smallSize > roomLeft)
1391                || (!bigTimestampValid && (bigSize > 0) && smallTimestampValid)) {
1392                mPendingAudioErr = err;
1393                mPendingAudioAccessUnit = accessUnit;
1394                accessUnit.clear();
1395            } else {
1396                // Grab time from first small buffer if available.
1397                if ((bigSize == 0) && smallTimestampValid) {
1398                    mAggregateBuffer->meta()->setInt64("timeUs", timeUs);
1399                }
1400                // Append small buffer to the bigger buffer.
1401                memcpy(mAggregateBuffer->base() + bigSize, accessUnit->data(), smallSize);
1402                bigSize += smallSize;
1403                mAggregateBuffer->setRange(0, bigSize);
1404
1405                // Keep looping until we run out of room in the mAggregateBuffer.
1406                needMoreData = true;
1407
1408                ALOGV("feedDecoderInputData() smallSize = %zu, bigSize = %zu, capacity = %zu",
1409                        smallSize, bigSize, mAggregateBuffer->capacity());
1410            }
1411        }
1412    } while (dropAccessUnit || needMoreData);
1413
1414    // ALOGV("returned a valid buffer of %s data", audio ? "audio" : "video");
1415
1416#if 0
1417    int64_t mediaTimeUs;
1418    CHECK(accessUnit->meta()->findInt64("timeUs", &mediaTimeUs));
1419    ALOGV("feeding %s input buffer at media time %.2f secs",
1420         audio ? "audio" : "video",
1421         mediaTimeUs / 1E6);
1422#endif
1423
1424    if (!audio) {
1425        mCCDecoder->decode(accessUnit);
1426    }
1427
1428    if (doBufferAggregation && (mAggregateBuffer != NULL)) {
1429        ALOGV("feedDecoderInputData() reply with aggregated buffer, %zu",
1430                mAggregateBuffer->size());
1431        reply->setBuffer("buffer", mAggregateBuffer);
1432        mAggregateBuffer.clear();
1433    } else {
1434        reply->setBuffer("buffer", accessUnit);
1435    }
1436
1437    reply->post();
1438
1439    return OK;
1440}
1441
1442void NuPlayer::renderBuffer(bool audio, const sp<AMessage> &msg) {
1443    // ALOGV("renderBuffer %s", audio ? "audio" : "video");
1444
1445    if ((audio && mFlushingAudio != NONE)
1446            || (!audio && mFlushingVideo != NONE)) {
1447        // We're currently attempting to flush the decoder, in order
1448        // to complete this, the decoder wants all its buffers back,
1449        // so we don't want any output buffers it sent us (from before
1450        // we initiated the flush) to be stuck in the renderer's queue.
1451
1452        ALOGV("we're still flushing the %s decoder, sending its output buffer"
1453             " right back.", audio ? "audio" : "video");
1454
1455        return;
1456    }
1457
1458    int64_t mediaTimeUs;
1459    CHECK(msg->findInt64("timeUs", &mediaTimeUs));
1460
1461    if (!audio && mCCDecoder->isSelected()) {
1462        mCCDecoder->display(mediaTimeUs);
1463    }
1464}
1465
1466void NuPlayer::updateVideoSize(
1467        const sp<AMessage> &inputFormat,
1468        const sp<AMessage> &outputFormat) {
1469    if (inputFormat == NULL) {
1470        ALOGW("Unknown video size, reporting 0x0!");
1471        notifyListener(MEDIA_SET_VIDEO_SIZE, 0, 0);
1472        return;
1473    }
1474
1475    int32_t displayWidth, displayHeight;
1476    int32_t cropLeft, cropTop, cropRight, cropBottom;
1477
1478    if (outputFormat != NULL) {
1479        int32_t width, height;
1480        CHECK(outputFormat->findInt32("width", &width));
1481        CHECK(outputFormat->findInt32("height", &height));
1482
1483        int32_t cropLeft, cropTop, cropRight, cropBottom;
1484        CHECK(outputFormat->findRect(
1485                    "crop",
1486                    &cropLeft, &cropTop, &cropRight, &cropBottom));
1487
1488        displayWidth = cropRight - cropLeft + 1;
1489        displayHeight = cropBottom - cropTop + 1;
1490
1491        ALOGV("Video output format changed to %d x %d "
1492             "(crop: %d x %d @ (%d, %d))",
1493             width, height,
1494             displayWidth,
1495             displayHeight,
1496             cropLeft, cropTop);
1497    } else {
1498        CHECK(inputFormat->findInt32("width", &displayWidth));
1499        CHECK(inputFormat->findInt32("height", &displayHeight));
1500
1501        ALOGV("Video input format %d x %d", displayWidth, displayHeight);
1502    }
1503
1504    // Take into account sample aspect ratio if necessary:
1505    int32_t sarWidth, sarHeight;
1506    if (inputFormat->findInt32("sar-width", &sarWidth)
1507            && inputFormat->findInt32("sar-height", &sarHeight)) {
1508        ALOGV("Sample aspect ratio %d : %d", sarWidth, sarHeight);
1509
1510        displayWidth = (displayWidth * sarWidth) / sarHeight;
1511
1512        ALOGV("display dimensions %d x %d", displayWidth, displayHeight);
1513    }
1514
1515    int32_t rotationDegrees;
1516    if (!inputFormat->findInt32("rotation-degrees", &rotationDegrees)) {
1517        rotationDegrees = 0;
1518    }
1519
1520    if (rotationDegrees == 90 || rotationDegrees == 270) {
1521        int32_t tmp = displayWidth;
1522        displayWidth = displayHeight;
1523        displayHeight = tmp;
1524    }
1525
1526    notifyListener(
1527            MEDIA_SET_VIDEO_SIZE,
1528            displayWidth,
1529            displayHeight);
1530}
1531
1532void NuPlayer::notifyListener(int msg, int ext1, int ext2, const Parcel *in) {
1533    if (mDriver == NULL) {
1534        return;
1535    }
1536
1537    sp<NuPlayerDriver> driver = mDriver.promote();
1538
1539    if (driver == NULL) {
1540        return;
1541    }
1542
1543    driver->notifyListener(msg, ext1, ext2, in);
1544}
1545
1546void NuPlayer::flushDecoder(
1547        bool audio, bool needShutdown, const sp<AMessage> &newFormat) {
1548    ALOGV("[%s] flushDecoder needShutdown=%d",
1549          audio ? "audio" : "video", needShutdown);
1550
1551    const sp<Decoder> &decoder = getDecoder(audio);
1552    if (decoder == NULL) {
1553        ALOGI("flushDecoder %s without decoder present",
1554             audio ? "audio" : "video");
1555        return;
1556    }
1557
1558    // Make sure we don't continue to scan sources until we finish flushing.
1559    ++mScanSourcesGeneration;
1560    mScanSourcesPending = false;
1561
1562    decoder->signalFlush(newFormat);
1563
1564    FlushStatus newStatus =
1565        needShutdown ? FLUSHING_DECODER_SHUTDOWN : FLUSHING_DECODER;
1566
1567    mFlushComplete[audio][false /* isDecoder */] = false;
1568    mFlushComplete[audio][true /* isDecoder */] = false;
1569    if (audio) {
1570        ALOGE_IF(mFlushingAudio != NONE,
1571                "audio flushDecoder() is called in state %d", mFlushingAudio);
1572        mFlushingAudio = newStatus;
1573    } else {
1574        ALOGE_IF(mFlushingVideo != NONE,
1575                "video flushDecoder() is called in state %d", mFlushingVideo);
1576        mFlushingVideo = newStatus;
1577
1578        if (mCCDecoder != NULL) {
1579            mCCDecoder->flush();
1580        }
1581    }
1582}
1583
1584void NuPlayer::updateDecoderFormatWithoutFlush(
1585        bool audio, const sp<AMessage> &format) {
1586    ALOGV("[%s] updateDecoderFormatWithoutFlush", audio ? "audio" : "video");
1587
1588    const sp<Decoder> &decoder = getDecoder(audio);
1589    if (decoder == NULL) {
1590        ALOGI("updateDecoderFormatWithoutFlush %s without decoder present",
1591             audio ? "audio" : "video");
1592        return;
1593    }
1594
1595    decoder->signalUpdateFormat(format);
1596}
1597
1598void NuPlayer::queueDecoderShutdown(
1599        bool audio, bool video, const sp<AMessage> &reply) {
1600    ALOGI("queueDecoderShutdown audio=%d, video=%d", audio, video);
1601
1602    mDeferredActions.push_back(
1603            new FlushDecoderAction(
1604                audio ? FLUSH_CMD_SHUTDOWN : FLUSH_CMD_NONE,
1605                video ? FLUSH_CMD_SHUTDOWN : FLUSH_CMD_NONE));
1606
1607    mDeferredActions.push_back(
1608            new SimpleAction(&NuPlayer::performScanSources));
1609
1610    mDeferredActions.push_back(new PostMessageAction(reply));
1611
1612    processDeferredActions();
1613}
1614
1615status_t NuPlayer::setVideoScalingMode(int32_t mode) {
1616    mVideoScalingMode = mode;
1617    if (mNativeWindow != NULL) {
1618        status_t ret = native_window_set_scaling_mode(
1619                mNativeWindow->getNativeWindow().get(), mVideoScalingMode);
1620        if (ret != OK) {
1621            ALOGE("Failed to set scaling mode (%d): %s",
1622                -ret, strerror(-ret));
1623            return ret;
1624        }
1625    }
1626    return OK;
1627}
1628
1629status_t NuPlayer::getTrackInfo(Parcel* reply) const {
1630    sp<AMessage> msg = new AMessage(kWhatGetTrackInfo, id());
1631    msg->setPointer("reply", reply);
1632
1633    sp<AMessage> response;
1634    status_t err = msg->postAndAwaitResponse(&response);
1635    return err;
1636}
1637
1638status_t NuPlayer::getSelectedTrack(int32_t type, Parcel* reply) const {
1639    sp<AMessage> msg = new AMessage(kWhatGetSelectedTrack, id());
1640    msg->setPointer("reply", reply);
1641    msg->setInt32("type", type);
1642
1643    sp<AMessage> response;
1644    status_t err = msg->postAndAwaitResponse(&response);
1645    if (err == OK && response != NULL) {
1646        CHECK(response->findInt32("err", &err));
1647    }
1648    return err;
1649}
1650
1651status_t NuPlayer::selectTrack(size_t trackIndex, bool select, int64_t timeUs) {
1652    sp<AMessage> msg = new AMessage(kWhatSelectTrack, id());
1653    msg->setSize("trackIndex", trackIndex);
1654    msg->setInt32("select", select);
1655    msg->setInt64("timeUs", timeUs);
1656
1657    sp<AMessage> response;
1658    status_t err = msg->postAndAwaitResponse(&response);
1659
1660    if (err != OK) {
1661        return err;
1662    }
1663
1664    if (!response->findInt32("err", &err)) {
1665        err = OK;
1666    }
1667
1668    return err;
1669}
1670
1671status_t NuPlayer::getCurrentPosition(int64_t *mediaUs) {
1672    sp<Renderer> renderer = mRenderer;
1673    if (renderer == NULL) {
1674        return NO_INIT;
1675    }
1676
1677    return renderer->getCurrentPosition(mediaUs);
1678}
1679
1680void NuPlayer::getStats(int64_t *numFramesTotal, int64_t *numFramesDropped) {
1681    *numFramesTotal = mNumFramesTotal;
1682    *numFramesDropped = mNumFramesDropped;
1683}
1684
1685sp<MetaData> NuPlayer::getFileMeta() {
1686    return mSource->getFileFormatMeta();
1687}
1688
1689void NuPlayer::schedulePollDuration() {
1690    sp<AMessage> msg = new AMessage(kWhatPollDuration, id());
1691    msg->setInt32("generation", mPollDurationGeneration);
1692    msg->post();
1693}
1694
1695void NuPlayer::cancelPollDuration() {
1696    ++mPollDurationGeneration;
1697}
1698
1699void NuPlayer::processDeferredActions() {
1700    while (!mDeferredActions.empty()) {
1701        // We won't execute any deferred actions until we're no longer in
1702        // an intermediate state, i.e. one more more decoders are currently
1703        // flushing or shutting down.
1704
1705        if (mFlushingAudio != NONE || mFlushingVideo != NONE) {
1706            // We're currently flushing, postpone the reset until that's
1707            // completed.
1708
1709            ALOGV("postponing action mFlushingAudio=%d, mFlushingVideo=%d",
1710                  mFlushingAudio, mFlushingVideo);
1711
1712            break;
1713        }
1714
1715        sp<Action> action = *mDeferredActions.begin();
1716        mDeferredActions.erase(mDeferredActions.begin());
1717
1718        action->execute(this);
1719    }
1720}
1721
1722void NuPlayer::performSeek(int64_t seekTimeUs, bool needNotify) {
1723    ALOGV("performSeek seekTimeUs=%lld us (%.2f secs), needNotify(%d)",
1724          seekTimeUs,
1725          seekTimeUs / 1E6,
1726          needNotify);
1727
1728    if (mSource == NULL) {
1729        // This happens when reset occurs right before the loop mode
1730        // asynchronously seeks to the start of the stream.
1731        LOG_ALWAYS_FATAL_IF(mAudioDecoder != NULL || mVideoDecoder != NULL,
1732                "mSource is NULL and decoders not NULL audio(%p) video(%p)",
1733                mAudioDecoder.get(), mVideoDecoder.get());
1734        return;
1735    }
1736    mSource->seekTo(seekTimeUs);
1737    ++mTimedTextGeneration;
1738
1739    if (mDriver != NULL) {
1740        sp<NuPlayerDriver> driver = mDriver.promote();
1741        if (driver != NULL) {
1742            if (needNotify) {
1743                driver->notifySeekComplete();
1744            }
1745        }
1746    }
1747
1748    // everything's flushed, continue playback.
1749}
1750
1751void NuPlayer::performDecoderFlush(FlushCommand audio, FlushCommand video) {
1752    ALOGV("performDecoderFlush audio=%d, video=%d", audio, video);
1753
1754    if ((audio == FLUSH_CMD_NONE || mAudioDecoder == NULL)
1755            && (video == FLUSH_CMD_NONE || mVideoDecoder == NULL)) {
1756        return;
1757    }
1758
1759    mTimeDiscontinuityPending = true;
1760
1761    if (audio != FLUSH_CMD_NONE && mAudioDecoder != NULL) {
1762        flushDecoder(true /* audio */, (audio == FLUSH_CMD_SHUTDOWN));
1763    }
1764
1765    if (video != FLUSH_CMD_NONE && mVideoDecoder != NULL) {
1766        flushDecoder(false /* audio */, (video == FLUSH_CMD_SHUTDOWN));
1767    }
1768}
1769
1770void NuPlayer::performReset() {
1771    ALOGV("performReset");
1772
1773    CHECK(mAudioDecoder == NULL);
1774    CHECK(mVideoDecoder == NULL);
1775
1776    cancelPollDuration();
1777
1778    ++mScanSourcesGeneration;
1779    mScanSourcesPending = false;
1780
1781    if (mRendererLooper != NULL) {
1782        if (mRenderer != NULL) {
1783            mRendererLooper->unregisterHandler(mRenderer->id());
1784        }
1785        mRendererLooper->stop();
1786        mRendererLooper.clear();
1787    }
1788    mRenderer.clear();
1789    ++mRendererGeneration;
1790
1791    if (mSource != NULL) {
1792        mSource->stop();
1793
1794        mSource.clear();
1795    }
1796
1797    if (mDriver != NULL) {
1798        sp<NuPlayerDriver> driver = mDriver.promote();
1799        if (driver != NULL) {
1800            driver->notifyResetComplete();
1801        }
1802    }
1803
1804    mStarted = false;
1805}
1806
1807void NuPlayer::performScanSources() {
1808    ALOGV("performScanSources");
1809
1810    if (!mStarted) {
1811        return;
1812    }
1813
1814    if (mAudioDecoder == NULL || mVideoDecoder == NULL) {
1815        postScanSources();
1816    }
1817}
1818
1819void NuPlayer::performSetSurface(const sp<NativeWindowWrapper> &wrapper) {
1820    ALOGV("performSetSurface");
1821
1822    mNativeWindow = wrapper;
1823
1824    // XXX - ignore error from setVideoScalingMode for now
1825    setVideoScalingMode(mVideoScalingMode);
1826
1827    if (mDriver != NULL) {
1828        sp<NuPlayerDriver> driver = mDriver.promote();
1829        if (driver != NULL) {
1830            driver->notifySetSurfaceComplete();
1831        }
1832    }
1833}
1834
1835void NuPlayer::onSourceNotify(const sp<AMessage> &msg) {
1836    int32_t what;
1837    CHECK(msg->findInt32("what", &what));
1838
1839    switch (what) {
1840        case Source::kWhatPrepared:
1841        {
1842            if (mSource == NULL) {
1843                // This is a stale notification from a source that was
1844                // asynchronously preparing when the client called reset().
1845                // We handled the reset, the source is gone.
1846                break;
1847            }
1848
1849            int32_t err;
1850            CHECK(msg->findInt32("err", &err));
1851
1852            sp<NuPlayerDriver> driver = mDriver.promote();
1853            if (driver != NULL) {
1854                // notify duration first, so that it's definitely set when
1855                // the app received the "prepare complete" callback.
1856                int64_t durationUs;
1857                if (mSource->getDuration(&durationUs) == OK) {
1858                    driver->notifyDuration(durationUs);
1859                }
1860                driver->notifyPrepareCompleted(err);
1861            }
1862
1863            break;
1864        }
1865
1866        case Source::kWhatFlagsChanged:
1867        {
1868            uint32_t flags;
1869            CHECK(msg->findInt32("flags", (int32_t *)&flags));
1870
1871            sp<NuPlayerDriver> driver = mDriver.promote();
1872            if (driver != NULL) {
1873                driver->notifyFlagsChanged(flags);
1874            }
1875
1876            if ((mSourceFlags & Source::FLAG_DYNAMIC_DURATION)
1877                    && (!(flags & Source::FLAG_DYNAMIC_DURATION))) {
1878                cancelPollDuration();
1879            } else if (!(mSourceFlags & Source::FLAG_DYNAMIC_DURATION)
1880                    && (flags & Source::FLAG_DYNAMIC_DURATION)
1881                    && (mAudioDecoder != NULL || mVideoDecoder != NULL)) {
1882                schedulePollDuration();
1883            }
1884
1885            mSourceFlags = flags;
1886            break;
1887        }
1888
1889        case Source::kWhatVideoSizeChanged:
1890        {
1891            sp<AMessage> format;
1892            CHECK(msg->findMessage("format", &format));
1893
1894            updateVideoSize(format);
1895            break;
1896        }
1897
1898        case Source::kWhatBufferingUpdate:
1899        {
1900            int32_t percentage;
1901            CHECK(msg->findInt32("percentage", &percentage));
1902
1903            notifyListener(MEDIA_BUFFERING_UPDATE, percentage, 0);
1904            break;
1905        }
1906
1907        case Source::kWhatBufferingStart:
1908        {
1909            notifyListener(MEDIA_INFO, MEDIA_INFO_BUFFERING_START, 0);
1910            break;
1911        }
1912
1913        case Source::kWhatBufferingEnd:
1914        {
1915            notifyListener(MEDIA_INFO, MEDIA_INFO_BUFFERING_END, 0);
1916            break;
1917        }
1918
1919        case Source::kWhatSubtitleData:
1920        {
1921            sp<ABuffer> buffer;
1922            CHECK(msg->findBuffer("buffer", &buffer));
1923
1924            sendSubtitleData(buffer, 0 /* baseIndex */);
1925            break;
1926        }
1927
1928        case Source::kWhatTimedTextData:
1929        {
1930            int32_t generation;
1931            if (msg->findInt32("generation", &generation)
1932                    && generation != mTimedTextGeneration) {
1933                break;
1934            }
1935
1936            sp<ABuffer> buffer;
1937            CHECK(msg->findBuffer("buffer", &buffer));
1938
1939            sp<NuPlayerDriver> driver = mDriver.promote();
1940            if (driver == NULL) {
1941                break;
1942            }
1943
1944            int posMs;
1945            int64_t timeUs, posUs;
1946            driver->getCurrentPosition(&posMs);
1947            posUs = posMs * 1000;
1948            CHECK(buffer->meta()->findInt64("timeUs", &timeUs));
1949
1950            if (posUs < timeUs) {
1951                if (!msg->findInt32("generation", &generation)) {
1952                    msg->setInt32("generation", mTimedTextGeneration);
1953                }
1954                msg->post(timeUs - posUs);
1955            } else {
1956                sendTimedTextData(buffer);
1957            }
1958            break;
1959        }
1960
1961        case Source::kWhatQueueDecoderShutdown:
1962        {
1963            int32_t audio, video;
1964            CHECK(msg->findInt32("audio", &audio));
1965            CHECK(msg->findInt32("video", &video));
1966
1967            sp<AMessage> reply;
1968            CHECK(msg->findMessage("reply", &reply));
1969
1970            queueDecoderShutdown(audio, video, reply);
1971            break;
1972        }
1973
1974        case Source::kWhatDrmNoLicense:
1975        {
1976            notifyListener(MEDIA_ERROR, MEDIA_ERROR_UNKNOWN, ERROR_DRM_NO_LICENSE);
1977            break;
1978        }
1979
1980        default:
1981            TRESPASS();
1982    }
1983}
1984
1985void NuPlayer::onClosedCaptionNotify(const sp<AMessage> &msg) {
1986    int32_t what;
1987    CHECK(msg->findInt32("what", &what));
1988
1989    switch (what) {
1990        case NuPlayer::CCDecoder::kWhatClosedCaptionData:
1991        {
1992            sp<ABuffer> buffer;
1993            CHECK(msg->findBuffer("buffer", &buffer));
1994
1995            size_t inbandTracks = 0;
1996            if (mSource != NULL) {
1997                inbandTracks = mSource->getTrackCount();
1998            }
1999
2000            sendSubtitleData(buffer, inbandTracks);
2001            break;
2002        }
2003
2004        case NuPlayer::CCDecoder::kWhatTrackAdded:
2005        {
2006            notifyListener(MEDIA_INFO, MEDIA_INFO_METADATA_UPDATE, 0);
2007
2008            break;
2009        }
2010
2011        default:
2012            TRESPASS();
2013    }
2014
2015
2016}
2017
2018void NuPlayer::sendSubtitleData(const sp<ABuffer> &buffer, int32_t baseIndex) {
2019    int32_t trackIndex;
2020    int64_t timeUs, durationUs;
2021    CHECK(buffer->meta()->findInt32("trackIndex", &trackIndex));
2022    CHECK(buffer->meta()->findInt64("timeUs", &timeUs));
2023    CHECK(buffer->meta()->findInt64("durationUs", &durationUs));
2024
2025    Parcel in;
2026    in.writeInt32(trackIndex + baseIndex);
2027    in.writeInt64(timeUs);
2028    in.writeInt64(durationUs);
2029    in.writeInt32(buffer->size());
2030    in.writeInt32(buffer->size());
2031    in.write(buffer->data(), buffer->size());
2032
2033    notifyListener(MEDIA_SUBTITLE_DATA, 0, 0, &in);
2034}
2035
2036void NuPlayer::sendTimedTextData(const sp<ABuffer> &buffer) {
2037    const void *data;
2038    size_t size = 0;
2039    int64_t timeUs;
2040    int32_t flag = TextDescriptions::LOCAL_DESCRIPTIONS;
2041
2042    AString mime;
2043    CHECK(buffer->meta()->findString("mime", &mime));
2044    CHECK(strcasecmp(mime.c_str(), MEDIA_MIMETYPE_TEXT_3GPP) == 0);
2045
2046    data = buffer->data();
2047    size = buffer->size();
2048
2049    Parcel parcel;
2050    if (size > 0) {
2051        CHECK(buffer->meta()->findInt64("timeUs", &timeUs));
2052        flag |= TextDescriptions::IN_BAND_TEXT_3GPP;
2053        TextDescriptions::getParcelOfDescriptions(
2054                (const uint8_t *)data, size, flag, timeUs / 1000, &parcel);
2055    }
2056
2057    if ((parcel.dataSize() > 0)) {
2058        notifyListener(MEDIA_TIMED_TEXT, 0, 0, &parcel);
2059    } else {  // send an empty timed text
2060        notifyListener(MEDIA_TIMED_TEXT, 0, 0);
2061    }
2062}
2063////////////////////////////////////////////////////////////////////////////////
2064
2065sp<AMessage> NuPlayer::Source::getFormat(bool audio) {
2066    sp<MetaData> meta = getFormatMeta(audio);
2067
2068    if (meta == NULL) {
2069        return NULL;
2070    }
2071
2072    sp<AMessage> msg = new AMessage;
2073
2074    if(convertMetaDataToMessage(meta, &msg) == OK) {
2075        return msg;
2076    }
2077    return NULL;
2078}
2079
2080void NuPlayer::Source::notifyFlagsChanged(uint32_t flags) {
2081    sp<AMessage> notify = dupNotify();
2082    notify->setInt32("what", kWhatFlagsChanged);
2083    notify->setInt32("flags", flags);
2084    notify->post();
2085}
2086
2087void NuPlayer::Source::notifyVideoSizeChanged(const sp<AMessage> &format) {
2088    sp<AMessage> notify = dupNotify();
2089    notify->setInt32("what", kWhatVideoSizeChanged);
2090    notify->setMessage("format", format);
2091    notify->post();
2092}
2093
2094void NuPlayer::Source::notifyPrepared(status_t err) {
2095    sp<AMessage> notify = dupNotify();
2096    notify->setInt32("what", kWhatPrepared);
2097    notify->setInt32("err", err);
2098    notify->post();
2099}
2100
2101void NuPlayer::Source::onMessageReceived(const sp<AMessage> & /* msg */) {
2102    TRESPASS();
2103}
2104
2105}  // namespace android
2106