NuPlayer.cpp revision 7314fa17093d514199fedcb55ac41136a1b31cb3
1/*
2 * Copyright (C) 2010 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 *      http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17//#define LOG_NDEBUG 0
18#define LOG_TAG "NuPlayer"
19#include <utils/Log.h>
20
21#include "NuPlayer.h"
22
23#include "HTTPLiveSource.h"
24#include "NuPlayerDecoder.h"
25#include "NuPlayerDriver.h"
26#include "NuPlayerRenderer.h"
27#include "NuPlayerSource.h"
28#include "StreamingSource.h"
29
30#include "ATSParser.h"
31
32#include <media/stagefright/foundation/hexdump.h>
33#include <media/stagefright/foundation/ABuffer.h>
34#include <media/stagefright/foundation/ADebug.h>
35#include <media/stagefright/foundation/AMessage.h>
36#include <media/stagefright/ACodec.h>
37#include <media/stagefright/MediaErrors.h>
38#include <media/stagefright/MetaData.h>
39#include <surfaceflinger/Surface.h>
40
41namespace android {
42
43////////////////////////////////////////////////////////////////////////////////
44
45NuPlayer::NuPlayer()
46    : mAudioEOS(false),
47      mVideoEOS(false),
48      mScanSourcesPending(false),
49      mScanSourcesGeneration(0),
50      mFlushingAudio(NONE),
51      mFlushingVideo(NONE),
52      mResetInProgress(false),
53      mResetPostponed(false) {
54}
55
56NuPlayer::~NuPlayer() {
57}
58
59void NuPlayer::setDriver(const wp<NuPlayerDriver> &driver) {
60    mDriver = driver;
61}
62
63void NuPlayer::setDataSource(const sp<IStreamSource> &source) {
64    sp<AMessage> msg = new AMessage(kWhatSetDataSource, id());
65
66    msg->setObject("source", new StreamingSource(source));
67    msg->post();
68}
69
70void NuPlayer::setDataSource(
71        const char *url, const KeyedVector<String8, String8> *headers) {
72    sp<AMessage> msg = new AMessage(kWhatSetDataSource, id());
73
74    uint32_t flags = 0;
75
76    if (headers) {
77        ssize_t index = headers->indexOfKey(String8("x-hide-urls-from-log"));
78
79        if (index >= 0) {
80            flags |= HTTPLiveSource::kFlagIncognito;
81        }
82    }
83
84    msg->setObject("source", new HTTPLiveSource(url, flags));
85    msg->post();
86}
87
88void NuPlayer::setVideoSurface(const sp<Surface> &surface) {
89    sp<AMessage> msg = new AMessage(kWhatSetVideoSurface, id());
90    msg->setObject("surface", surface);
91    msg->post();
92}
93
94void NuPlayer::setAudioSink(const sp<MediaPlayerBase::AudioSink> &sink) {
95    sp<AMessage> msg = new AMessage(kWhatSetAudioSink, id());
96    msg->setObject("sink", sink);
97    msg->post();
98}
99
100void NuPlayer::start() {
101    (new AMessage(kWhatStart, id()))->post();
102}
103
104void NuPlayer::pause() {
105    (new AMessage(kWhatPause, id()))->post();
106}
107
108void NuPlayer::resume() {
109    (new AMessage(kWhatResume, id()))->post();
110}
111
112void NuPlayer::resetAsync() {
113    (new AMessage(kWhatReset, id()))->post();
114}
115
116void NuPlayer::seekToAsync(int64_t seekTimeUs) {
117    sp<AMessage> msg = new AMessage(kWhatSeek, id());
118    msg->setInt64("seekTimeUs", seekTimeUs);
119    msg->post();
120}
121
122// static
123bool NuPlayer::IsFlushingState(FlushStatus state, bool *needShutdown) {
124    switch (state) {
125        case FLUSHING_DECODER:
126            if (needShutdown != NULL) {
127                *needShutdown = false;
128            }
129            return true;
130
131        case FLUSHING_DECODER_SHUTDOWN:
132            if (needShutdown != NULL) {
133                *needShutdown = true;
134            }
135            return true;
136
137        default:
138            return false;
139    }
140}
141
142void NuPlayer::onMessageReceived(const sp<AMessage> &msg) {
143    switch (msg->what()) {
144        case kWhatSetDataSource:
145        {
146            LOGV("kWhatSetDataSource");
147
148            CHECK(mSource == NULL);
149
150            sp<RefBase> obj;
151            CHECK(msg->findObject("source", &obj));
152
153            mSource = static_cast<Source *>(obj.get());
154            break;
155        }
156
157        case kWhatSetVideoSurface:
158        {
159            LOGV("kWhatSetVideoSurface");
160
161            sp<RefBase> obj;
162            CHECK(msg->findObject("surface", &obj));
163
164            mSurface = static_cast<Surface *>(obj.get());
165            break;
166        }
167
168        case kWhatSetAudioSink:
169        {
170            LOGV("kWhatSetAudioSink");
171
172            sp<RefBase> obj;
173            CHECK(msg->findObject("sink", &obj));
174
175            mAudioSink = static_cast<MediaPlayerBase::AudioSink *>(obj.get());
176            break;
177        }
178
179        case kWhatStart:
180        {
181            LOGV("kWhatStart");
182
183            mAudioEOS = false;
184            mVideoEOS = false;
185
186            mSource->start();
187
188            mRenderer = new Renderer(
189                    mAudioSink,
190                    new AMessage(kWhatRendererNotify, id()));
191
192            looper()->registerHandler(mRenderer);
193
194            postScanSources();
195            break;
196        }
197
198        case kWhatScanSources:
199        {
200            int32_t generation;
201            CHECK(msg->findInt32("generation", &generation));
202            if (generation != mScanSourcesGeneration) {
203                // Drop obsolete msg.
204                break;
205            }
206
207            mScanSourcesPending = false;
208
209            LOGV("scanning sources haveAudio=%d, haveVideo=%d",
210                 mAudioDecoder != NULL, mVideoDecoder != NULL);
211
212            instantiateDecoder(false, &mVideoDecoder);
213
214            if (mAudioSink != NULL) {
215                instantiateDecoder(true, &mAudioDecoder);
216            }
217
218            if (!mSource->feedMoreTSData()) {
219                if (mAudioDecoder == NULL && mVideoDecoder == NULL) {
220                    // We're not currently decoding anything (no audio or
221                    // video tracks found) and we just ran out of input data.
222                    notifyListener(MEDIA_PLAYBACK_COMPLETE, 0, 0);
223                }
224                break;
225            }
226
227            if (mAudioDecoder == NULL || mVideoDecoder == NULL) {
228                msg->post(100000ll);
229                mScanSourcesPending = true;
230            }
231            break;
232        }
233
234        case kWhatVideoNotify:
235        case kWhatAudioNotify:
236        {
237            bool audio = msg->what() == kWhatAudioNotify;
238
239            sp<AMessage> codecRequest;
240            CHECK(msg->findMessage("codec-request", &codecRequest));
241
242            int32_t what;
243            CHECK(codecRequest->findInt32("what", &what));
244
245            if (what == ACodec::kWhatFillThisBuffer) {
246                status_t err = feedDecoderInputData(
247                        audio, codecRequest);
248
249                if (err == -EWOULDBLOCK) {
250                    if (mSource->feedMoreTSData()) {
251                        msg->post();
252                    }
253                }
254            } else if (what == ACodec::kWhatEOS) {
255                mRenderer->queueEOS(audio, ERROR_END_OF_STREAM);
256            } else if (what == ACodec::kWhatFlushCompleted) {
257                bool needShutdown;
258
259                if (audio) {
260                    CHECK(IsFlushingState(mFlushingAudio, &needShutdown));
261                    mFlushingAudio = FLUSHED;
262                } else {
263                    CHECK(IsFlushingState(mFlushingVideo, &needShutdown));
264                    mFlushingVideo = FLUSHED;
265                }
266
267                LOGV("decoder %s flush completed", audio ? "audio" : "video");
268
269                if (needShutdown) {
270                    LOGV("initiating %s decoder shutdown",
271                         audio ? "audio" : "video");
272
273                    (audio ? mAudioDecoder : mVideoDecoder)->initiateShutdown();
274
275                    if (audio) {
276                        mFlushingAudio = SHUTTING_DOWN_DECODER;
277                    } else {
278                        mFlushingVideo = SHUTTING_DOWN_DECODER;
279                    }
280                }
281
282                finishFlushIfPossible();
283            } else if (what == ACodec::kWhatOutputFormatChanged) {
284                if (audio) {
285                    int32_t numChannels;
286                    CHECK(codecRequest->findInt32("channel-count", &numChannels));
287
288                    int32_t sampleRate;
289                    CHECK(codecRequest->findInt32("sample-rate", &sampleRate));
290
291                    LOGV("Audio output format changed to %d Hz, %d channels",
292                         sampleRate, numChannels);
293
294                    mAudioSink->close();
295                    CHECK_EQ(mAudioSink->open(sampleRate, numChannels), (status_t)OK);
296                    mAudioSink->start();
297
298                    mRenderer->signalAudioSinkChanged();
299                } else {
300                    // video
301
302                    int32_t width, height;
303                    CHECK(codecRequest->findInt32("width", &width));
304                    CHECK(codecRequest->findInt32("height", &height));
305
306                    int32_t cropLeft, cropTop, cropRight, cropBottom;
307                    CHECK(codecRequest->findRect(
308                                "crop",
309                                &cropLeft, &cropTop, &cropRight, &cropBottom));
310
311                    LOGV("Video output format changed to %d x %d "
312                         "(crop: %d, %d, %d, %d)",
313                         width, height,
314                         cropLeft, cropTop, cropRight, cropBottom);
315
316                    notifyListener(
317                            MEDIA_SET_VIDEO_SIZE,
318                            cropRight - cropLeft + 1,
319                            cropBottom - cropTop + 1);
320                }
321            } else if (what == ACodec::kWhatShutdownCompleted) {
322                LOGV("%s shutdown completed", audio ? "audio" : "video");
323                if (audio) {
324                    mAudioDecoder.clear();
325
326                    CHECK_EQ((int)mFlushingAudio, (int)SHUTTING_DOWN_DECODER);
327                    mFlushingAudio = SHUT_DOWN;
328                } else {
329                    mVideoDecoder.clear();
330
331                    CHECK_EQ((int)mFlushingVideo, (int)SHUTTING_DOWN_DECODER);
332                    mFlushingVideo = SHUT_DOWN;
333                }
334
335                finishFlushIfPossible();
336            } else {
337                CHECK_EQ((int)what, (int)ACodec::kWhatDrainThisBuffer);
338
339                renderBuffer(audio, codecRequest);
340            }
341
342            break;
343        }
344
345        case kWhatRendererNotify:
346        {
347            int32_t what;
348            CHECK(msg->findInt32("what", &what));
349
350            if (what == Renderer::kWhatEOS) {
351                int32_t audio;
352                CHECK(msg->findInt32("audio", &audio));
353
354                if (audio) {
355                    mAudioEOS = true;
356                } else {
357                    mVideoEOS = true;
358                }
359
360                LOGV("reached %s EOS", audio ? "audio" : "video");
361
362                if ((mAudioEOS || mAudioDecoder == NULL)
363                        && (mVideoEOS || mVideoDecoder == NULL)) {
364                    notifyListener(MEDIA_PLAYBACK_COMPLETE, 0, 0);
365                }
366            } else if (what == Renderer::kWhatPosition) {
367                int64_t positionUs;
368                CHECK(msg->findInt64("positionUs", &positionUs));
369
370                if (mDriver != NULL) {
371                    sp<NuPlayerDriver> driver = mDriver.promote();
372                    if (driver != NULL) {
373                        driver->notifyPosition(positionUs);
374                    }
375                }
376            } else {
377                CHECK_EQ(what, (int32_t)Renderer::kWhatFlushComplete);
378
379                int32_t audio;
380                CHECK(msg->findInt32("audio", &audio));
381
382                LOGV("renderer %s flush completed.", audio ? "audio" : "video");
383            }
384            break;
385        }
386
387        case kWhatMoreDataQueued:
388        {
389            break;
390        }
391
392        case kWhatReset:
393        {
394            LOGV("kWhatReset");
395
396            if (mFlushingAudio != NONE || mFlushingVideo != NONE) {
397                // We're currently flushing, postpone the reset until that's
398                // completed.
399
400                LOGV("postponing reset");
401
402                mResetPostponed = true;
403                break;
404            }
405
406            if (mAudioDecoder == NULL && mVideoDecoder == NULL) {
407                finishReset();
408                break;
409            }
410
411            if (mAudioDecoder != NULL) {
412                flushDecoder(true /* audio */, true /* needShutdown */);
413            }
414
415            if (mVideoDecoder != NULL) {
416                flushDecoder(false /* audio */, true /* needShutdown */);
417            }
418
419            mResetInProgress = true;
420            break;
421        }
422
423        case kWhatSeek:
424        {
425            int64_t seekTimeUs;
426            CHECK(msg->findInt64("seekTimeUs", &seekTimeUs));
427
428            LOGV("kWhatSeek seekTimeUs=%lld us (%.2f secs)",
429                 seekTimeUs, seekTimeUs / 1E6);
430
431            mSource->seekTo(seekTimeUs);
432
433            if (mDriver != NULL) {
434                sp<NuPlayerDriver> driver = mDriver.promote();
435                if (driver != NULL) {
436                    driver->notifySeekComplete();
437                }
438            }
439
440            break;
441        }
442
443        case kWhatPause:
444        {
445            CHECK(mRenderer != NULL);
446            mRenderer->pause();
447            break;
448        }
449
450        case kWhatResume:
451        {
452            CHECK(mRenderer != NULL);
453            mRenderer->resume();
454            break;
455        }
456
457        default:
458            TRESPASS();
459            break;
460    }
461}
462
463void NuPlayer::finishFlushIfPossible() {
464    if (mFlushingAudio != FLUSHED && mFlushingAudio != SHUT_DOWN) {
465        return;
466    }
467
468    if (mFlushingVideo != FLUSHED && mFlushingVideo != SHUT_DOWN) {
469        return;
470    }
471
472    LOGV("both audio and video are flushed now.");
473
474    mRenderer->signalTimeDiscontinuity();
475
476    if (mAudioDecoder != NULL) {
477        mAudioDecoder->signalResume();
478    }
479
480    if (mVideoDecoder != NULL) {
481        mVideoDecoder->signalResume();
482    }
483
484    mFlushingAudio = NONE;
485    mFlushingVideo = NONE;
486
487    if (mResetInProgress) {
488        LOGV("reset completed");
489
490        mResetInProgress = false;
491        finishReset();
492    } else if (mResetPostponed) {
493        (new AMessage(kWhatReset, id()))->post();
494        mResetPostponed = false;
495    } else if (mAudioDecoder == NULL || mVideoDecoder == NULL) {
496        postScanSources();
497    }
498}
499
500void NuPlayer::finishReset() {
501    CHECK(mAudioDecoder == NULL);
502    CHECK(mVideoDecoder == NULL);
503
504    mRenderer.clear();
505    mSource.clear();
506
507    if (mDriver != NULL) {
508        sp<NuPlayerDriver> driver = mDriver.promote();
509        if (driver != NULL) {
510            driver->notifyResetComplete();
511        }
512    }
513}
514
515void NuPlayer::postScanSources() {
516    if (mScanSourcesPending) {
517        return;
518    }
519
520    sp<AMessage> msg = new AMessage(kWhatScanSources, id());
521    msg->setInt32("generation", mScanSourcesGeneration);
522    msg->post();
523
524    mScanSourcesPending = true;
525}
526
527status_t NuPlayer::instantiateDecoder(bool audio, sp<Decoder> *decoder) {
528    if (*decoder != NULL) {
529        return OK;
530    }
531
532    sp<MetaData> meta = mSource->getFormat(audio);
533
534    if (meta == NULL) {
535        return -EWOULDBLOCK;
536    }
537
538    sp<AMessage> notify =
539        new AMessage(audio ? kWhatAudioNotify : kWhatVideoNotify,
540                     id());
541
542    *decoder = new Decoder(notify, audio ? NULL : mSurface);
543    looper()->registerHandler(*decoder);
544
545    (*decoder)->configure(meta);
546
547    int64_t durationUs;
548    if (mDriver != NULL && mSource->getDuration(&durationUs) == OK) {
549        sp<NuPlayerDriver> driver = mDriver.promote();
550        if (driver != NULL) {
551            driver->notifyDuration(durationUs);
552        }
553    }
554
555    return OK;
556}
557
558status_t NuPlayer::feedDecoderInputData(bool audio, const sp<AMessage> &msg) {
559    sp<AMessage> reply;
560    CHECK(msg->findMessage("reply", &reply));
561
562    if ((audio && IsFlushingState(mFlushingAudio))
563            || (!audio && IsFlushingState(mFlushingVideo))) {
564        reply->setInt32("err", INFO_DISCONTINUITY);
565        reply->post();
566        return OK;
567    }
568
569    sp<ABuffer> accessUnit;
570    status_t err = mSource->dequeueAccessUnit(audio, &accessUnit);
571
572    if (err == -EWOULDBLOCK) {
573        return err;
574    } else if (err != OK) {
575        if (err == INFO_DISCONTINUITY) {
576            int32_t type;
577            CHECK(accessUnit->meta()->findInt32("discontinuity", &type));
578
579            bool formatChange =
580                type == ATSParser::DISCONTINUITY_FORMATCHANGE;
581
582            LOGV("%s discontinuity (formatChange=%d)",
583                 audio ? "audio" : "video", formatChange);
584
585            flushDecoder(audio, formatChange);
586        }
587
588        reply->setInt32("err", err);
589        reply->post();
590        return OK;
591    }
592
593    // LOGV("returned a valid buffer of %s data", audio ? "audio" : "video");
594
595#if 0
596    int64_t mediaTimeUs;
597    CHECK(accessUnit->meta()->findInt64("timeUs", &mediaTimeUs));
598    LOGV("feeding %s input buffer at media time %.2f secs",
599         audio ? "audio" : "video",
600         mediaTimeUs / 1E6);
601#endif
602
603    reply->setObject("buffer", accessUnit);
604    reply->post();
605
606    return OK;
607}
608
609void NuPlayer::renderBuffer(bool audio, const sp<AMessage> &msg) {
610    // LOGV("renderBuffer %s", audio ? "audio" : "video");
611
612    sp<AMessage> reply;
613    CHECK(msg->findMessage("reply", &reply));
614
615    sp<RefBase> obj;
616    CHECK(msg->findObject("buffer", &obj));
617
618    sp<ABuffer> buffer = static_cast<ABuffer *>(obj.get());
619
620    mRenderer->queueBuffer(audio, buffer, reply);
621}
622
623void NuPlayer::notifyListener(int msg, int ext1, int ext2) {
624    if (mDriver == NULL) {
625        return;
626    }
627
628    sp<NuPlayerDriver> driver = mDriver.promote();
629
630    if (driver == NULL) {
631        return;
632    }
633
634    driver->sendEvent(msg, ext1, ext2);
635}
636
637void NuPlayer::flushDecoder(bool audio, bool needShutdown) {
638    // Make sure we don't continue to scan sources until we finish flushing.
639    ++mScanSourcesGeneration;
640    mScanSourcesPending = false;
641
642    (audio ? mAudioDecoder : mVideoDecoder)->signalFlush();
643    mRenderer->flush(audio);
644
645    FlushStatus newStatus =
646        needShutdown ? FLUSHING_DECODER_SHUTDOWN : FLUSHING_DECODER;
647
648    if (audio) {
649        CHECK(mFlushingAudio == NONE
650                || mFlushingAudio == AWAITING_DISCONTINUITY);
651
652        mFlushingAudio = newStatus;
653
654        if (mFlushingVideo == NONE) {
655            mFlushingVideo = (mVideoDecoder != NULL)
656                ? AWAITING_DISCONTINUITY
657                : FLUSHED;
658        }
659    } else {
660        CHECK(mFlushingVideo == NONE
661                || mFlushingVideo == AWAITING_DISCONTINUITY);
662
663        mFlushingVideo = newStatus;
664
665        if (mFlushingAudio == NONE) {
666            mFlushingAudio = (mAudioDecoder != NULL)
667                ? AWAITING_DISCONTINUITY
668                : FLUSHED;
669        }
670    }
671}
672
673}  // namespace android
674