NuPlayer.cpp revision 5bc087c573c70c84c6a39946457590b42d392a33
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 "NuPlayerRenderer.h"
26#include "NuPlayerSource.h"
27#include "StreamingSource.h"
28
29#include "ATSParser.h"
30
31#include <media/stagefright/foundation/hexdump.h>
32#include <media/stagefright/foundation/ABuffer.h>
33#include <media/stagefright/foundation/ADebug.h>
34#include <media/stagefright/foundation/AMessage.h>
35#include <media/stagefright/ACodec.h>
36#include <media/stagefright/MediaErrors.h>
37#include <media/stagefright/MetaData.h>
38#include <surfaceflinger/Surface.h>
39
40namespace android {
41
42////////////////////////////////////////////////////////////////////////////////
43
44NuPlayer::NuPlayer()
45    : mAudioEOS(false),
46      mVideoEOS(false),
47      mScanSourcesPending(false),
48      mFlushingAudio(NONE),
49      mFlushingVideo(NONE) {
50}
51
52NuPlayer::~NuPlayer() {
53}
54
55void NuPlayer::setListener(const wp<MediaPlayerBase> &listener) {
56    mListener = listener;
57}
58
59void NuPlayer::setDataSource(const sp<IStreamSource> &source) {
60    sp<AMessage> msg = new AMessage(kWhatSetDataSource, id());
61
62    msg->setObject("source", new StreamingSource(source));
63    msg->post();
64}
65
66void NuPlayer::setDataSource(
67        const char *url, const KeyedVector<String8, String8> *headers) {
68    sp<AMessage> msg = new AMessage(kWhatSetDataSource, id());
69
70    msg->setObject("source", new HTTPLiveSource(url));
71    msg->post();
72}
73
74void NuPlayer::setVideoSurface(const sp<Surface> &surface) {
75    sp<AMessage> msg = new AMessage(kWhatSetVideoSurface, id());
76    msg->setObject("surface", surface);
77    msg->post();
78}
79
80void NuPlayer::setAudioSink(const sp<MediaPlayerBase::AudioSink> &sink) {
81    sp<AMessage> msg = new AMessage(kWhatSetAudioSink, id());
82    msg->setObject("sink", sink);
83    msg->post();
84}
85
86void NuPlayer::start() {
87    (new AMessage(kWhatStart, id()))->post();
88}
89
90// static
91bool NuPlayer::IsFlushingState(FlushStatus state, bool *formatChange) {
92    switch (state) {
93        case FLUSHING_DECODER:
94            if (formatChange != NULL) {
95                *formatChange = false;
96            }
97            return true;
98
99        case FLUSHING_DECODER_FORMATCHANGE:
100            if (formatChange != NULL) {
101                *formatChange = true;
102            }
103            return true;
104
105        default:
106            return false;
107    }
108}
109
110void NuPlayer::onMessageReceived(const sp<AMessage> &msg) {
111    switch (msg->what()) {
112        case kWhatSetDataSource:
113        {
114            LOGI("kWhatSetDataSource");
115
116            CHECK(mSource == NULL);
117
118            sp<RefBase> obj;
119            CHECK(msg->findObject("source", &obj));
120
121            mSource = static_cast<Source *>(obj.get());
122            break;
123        }
124
125        case kWhatSetVideoSurface:
126        {
127            LOGI("kWhatSetVideoSurface");
128
129            sp<RefBase> obj;
130            CHECK(msg->findObject("surface", &obj));
131
132            mSurface = static_cast<Surface *>(obj.get());
133            break;
134        }
135
136        case kWhatSetAudioSink:
137        {
138            LOGI("kWhatSetAudioSink");
139
140            sp<RefBase> obj;
141            CHECK(msg->findObject("sink", &obj));
142
143            mAudioSink = static_cast<MediaPlayerBase::AudioSink *>(obj.get());
144            break;
145        }
146
147        case kWhatStart:
148        {
149            mSource->start();
150
151            mRenderer = new Renderer(
152                    mAudioSink,
153                    new AMessage(kWhatRendererNotify, id()));
154
155            looper()->registerHandler(mRenderer);
156
157            (new AMessage(kWhatScanSources, id()))->post();
158            mScanSourcesPending = true;
159            break;
160        }
161
162        case kWhatScanSources:
163        {
164            mScanSourcesPending = false;
165
166            instantiateDecoder(false, &mVideoDecoder);
167
168            if (mAudioSink != NULL) {
169                instantiateDecoder(true, &mAudioDecoder);
170            }
171
172            if (!mSource->feedMoreTSData()) {
173                break;
174            }
175
176            if (mAudioDecoder == NULL || mVideoDecoder == NULL) {
177                msg->post(100000ll);
178                mScanSourcesPending = true;
179            }
180            break;
181        }
182
183        case kWhatVideoNotify:
184        case kWhatAudioNotify:
185        {
186            bool audio = msg->what() == kWhatAudioNotify;
187
188            sp<AMessage> codecRequest;
189            CHECK(msg->findMessage("codec-request", &codecRequest));
190
191            int32_t what;
192            CHECK(codecRequest->findInt32("what", &what));
193
194            if (what == ACodec::kWhatFillThisBuffer) {
195                status_t err = feedDecoderInputData(
196                        audio, codecRequest);
197
198                if (err == -EWOULDBLOCK) {
199                    if (mSource->feedMoreTSData()) {
200                        msg->post();
201                    }
202                }
203            } else if (what == ACodec::kWhatEOS) {
204                mRenderer->queueEOS(audio, ERROR_END_OF_STREAM);
205            } else if (what == ACodec::kWhatFlushCompleted) {
206                bool formatChange;
207
208                if (audio) {
209                    CHECK(IsFlushingState(mFlushingAudio, &formatChange));
210                    mFlushingAudio = FLUSHED;
211                } else {
212                    CHECK(IsFlushingState(mFlushingVideo, &formatChange));
213                    mFlushingVideo = FLUSHED;
214                }
215
216                LOGI("decoder %s flush completed", audio ? "audio" : "video");
217
218                if (formatChange) {
219                    LOGI("initiating %s decoder shutdown",
220                         audio ? "audio" : "video");
221
222                    (audio ? mAudioDecoder : mVideoDecoder)->initiateShutdown();
223
224                    if (audio) {
225                        mFlushingAudio = SHUTTING_DOWN_DECODER;
226                    } else {
227                        mFlushingVideo = SHUTTING_DOWN_DECODER;
228                    }
229                }
230
231                finishFlushIfPossible();
232            } else if (what == ACodec::kWhatOutputFormatChanged) {
233                CHECK(audio);
234
235                int32_t numChannels;
236                CHECK(codecRequest->findInt32("channel-count", &numChannels));
237
238                int32_t sampleRate;
239                CHECK(codecRequest->findInt32("sample-rate", &sampleRate));
240
241                LOGI("Audio output format changed to %d Hz, %d channels",
242                     sampleRate, numChannels);
243
244                mAudioSink->close();
245                CHECK_EQ(mAudioSink->open(sampleRate, numChannels), (status_t)OK);
246                mAudioSink->start();
247
248                mRenderer->signalAudioSinkChanged();
249            } else if (what == ACodec::kWhatShutdownCompleted) {
250                LOGI("%s shutdown completed", audio ? "audio" : "video");
251                if (audio) {
252                    mAudioDecoder.clear();
253
254                    CHECK_EQ((int)mFlushingAudio, (int)SHUTTING_DOWN_DECODER);
255                    mFlushingAudio = SHUT_DOWN;
256                } else {
257                    mVideoDecoder.clear();
258
259                    CHECK_EQ((int)mFlushingVideo, (int)SHUTTING_DOWN_DECODER);
260                    mFlushingVideo = SHUT_DOWN;
261                }
262
263                finishFlushIfPossible();
264            } else {
265                CHECK_EQ((int)what, (int)ACodec::kWhatDrainThisBuffer);
266
267                renderBuffer(audio, codecRequest);
268            }
269
270            break;
271        }
272
273        case kWhatRendererNotify:
274        {
275            int32_t what;
276            CHECK(msg->findInt32("what", &what));
277
278            if (what == Renderer::kWhatEOS) {
279                int32_t audio;
280                CHECK(msg->findInt32("audio", &audio));
281
282                if (audio) {
283                    mAudioEOS = true;
284                } else {
285                    mVideoEOS = true;
286                }
287
288                LOGI("reached %s EOS", audio ? "audio" : "video");
289
290                if ((mAudioEOS || mAudioDecoder == NULL)
291                        && (mVideoEOS || mVideoDecoder == NULL)) {
292                    notifyListener(MEDIA_PLAYBACK_COMPLETE, 0, 0);
293                }
294            } else {
295                CHECK_EQ(what, (int32_t)Renderer::kWhatFlushComplete);
296
297                int32_t audio;
298                CHECK(msg->findInt32("audio", &audio));
299
300                LOGI("renderer %s flush completed.", audio ? "audio" : "video");
301            }
302            break;
303        }
304
305        case kWhatMoreDataQueued:
306        {
307            break;
308        }
309
310        default:
311            TRESPASS();
312            break;
313    }
314}
315
316void NuPlayer::finishFlushIfPossible() {
317    if (mFlushingAudio != FLUSHED && mFlushingAudio != SHUT_DOWN) {
318        return;
319    }
320
321    if (mFlushingVideo != FLUSHED && mFlushingVideo != SHUT_DOWN) {
322        return;
323    }
324
325    LOGI("both audio and video are flushed now.");
326
327    mRenderer->signalTimeDiscontinuity();
328
329    bool scanSourcesAgain = false;
330
331    if (mFlushingAudio == SHUT_DOWN) {
332        scanSourcesAgain = true;
333    } else if (mAudioDecoder != NULL) {
334        mAudioDecoder->signalResume();
335    }
336
337    if (mFlushingVideo == SHUT_DOWN) {
338        scanSourcesAgain = true;
339    } else if (mVideoDecoder != NULL) {
340        mVideoDecoder->signalResume();
341    }
342
343    mFlushingAudio = NONE;
344    mFlushingVideo = NONE;
345
346    if (scanSourcesAgain && !mScanSourcesPending) {
347        mScanSourcesPending = true;
348        (new AMessage(kWhatScanSources, id()))->post();
349    }
350}
351
352status_t NuPlayer::instantiateDecoder(bool audio, sp<Decoder> *decoder) {
353    if (*decoder != NULL) {
354        return OK;
355    }
356
357    sp<MetaData> meta = mSource->getFormat(audio);
358
359    if (meta == NULL) {
360        return -EWOULDBLOCK;
361    }
362
363    sp<AMessage> notify =
364        new AMessage(audio ? kWhatAudioNotify : kWhatVideoNotify,
365                     id());
366
367    *decoder = new Decoder(notify, audio ? NULL : mSurface);
368    looper()->registerHandler(*decoder);
369
370    (*decoder)->configure(meta);
371
372    return OK;
373}
374
375status_t NuPlayer::feedDecoderInputData(bool audio, const sp<AMessage> &msg) {
376    sp<AMessage> reply;
377    CHECK(msg->findMessage("reply", &reply));
378
379    if ((audio && IsFlushingState(mFlushingAudio))
380            || (!audio && IsFlushingState(mFlushingVideo))) {
381        reply->setInt32("err", INFO_DISCONTINUITY);
382        reply->post();
383        return OK;
384    }
385
386    sp<ABuffer> accessUnit;
387    status_t err = mSource->dequeueAccessUnit(audio, &accessUnit);
388
389    if (err == -EWOULDBLOCK) {
390        return err;
391    } else if (err != OK) {
392        if (err == INFO_DISCONTINUITY) {
393            int32_t type;
394            CHECK(accessUnit->meta()->findInt32("discontinuity", &type));
395
396            bool formatChange =
397                type == ATSParser::DISCONTINUITY_FORMATCHANGE;
398
399            LOGI("%s discontinuity (formatChange=%d)",
400                 audio ? "audio" : "video", formatChange);
401
402            (audio ? mAudioDecoder : mVideoDecoder)->signalFlush();
403            mRenderer->flush(audio);
404
405            if (audio) {
406                CHECK(mFlushingAudio == NONE
407                        || mFlushingAudio == AWAITING_DISCONTINUITY);
408
409                mFlushingAudio = formatChange
410                    ? FLUSHING_DECODER_FORMATCHANGE : FLUSHING_DECODER;
411
412                if (mFlushingVideo == NONE) {
413                    mFlushingVideo = (mVideoDecoder != NULL)
414                        ? AWAITING_DISCONTINUITY
415                        : FLUSHED;
416                }
417            } else {
418                CHECK(mFlushingVideo == NONE
419                        || mFlushingVideo == AWAITING_DISCONTINUITY);
420
421                mFlushingVideo = formatChange
422                    ? FLUSHING_DECODER_FORMATCHANGE : FLUSHING_DECODER;
423
424                if (mFlushingAudio == NONE) {
425                    mFlushingAudio = (mAudioDecoder != NULL)
426                        ? AWAITING_DISCONTINUITY
427                        : FLUSHED;
428                }
429            }
430        }
431
432        reply->setInt32("err", err);
433        reply->post();
434        return OK;
435    }
436
437    LOGV("returned a valid buffer of %s data", audio ? "audio" : "video");
438
439#if 0
440    int64_t mediaTimeUs;
441    CHECK(accessUnit->meta()->findInt64("timeUs", &mediaTimeUs));
442    LOGI("feeding %s input buffer at media time %.2f secs",
443         audio ? "audio" : "video",
444         mediaTimeUs / 1E6);
445#endif
446
447    reply->setObject("buffer", accessUnit);
448    reply->post();
449
450    return OK;
451}
452
453void NuPlayer::renderBuffer(bool audio, const sp<AMessage> &msg) {
454    LOGV("renderBuffer %s", audio ? "audio" : "video");
455
456    sp<AMessage> reply;
457    CHECK(msg->findMessage("reply", &reply));
458
459    sp<RefBase> obj;
460    CHECK(msg->findObject("buffer", &obj));
461
462    sp<ABuffer> buffer = static_cast<ABuffer *>(obj.get());
463
464    mRenderer->queueBuffer(audio, buffer, reply);
465}
466
467void NuPlayer::notifyListener(int msg, int ext1, int ext2) {
468    if (mListener == NULL) {
469        return;
470    }
471
472    sp<MediaPlayerBase> listener = mListener.promote();
473
474    if (listener == NULL) {
475        return;
476    }
477
478    listener->sendEvent(msg, ext1, ext2);
479}
480
481}  // namespace android
482