NuPlayerDecoder.cpp revision 1cd139824b2e6832f239cd27d8962d3239053c02
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 "NuPlayerDecoder"
19#include <utils/Log.h>
20#include <inttypes.h>
21
22#include "NuPlayerDecoder.h"
23
24#include <media/ICrypto.h>
25#include <media/stagefright/foundation/ABuffer.h>
26#include <media/stagefright/foundation/ADebug.h>
27#include <media/stagefright/foundation/AMessage.h>
28#include <media/stagefright/MediaCodec.h>
29#include <media/stagefright/MediaDefs.h>
30#include <media/stagefright/MediaErrors.h>
31
32namespace android {
33
34NuPlayer::Decoder::Decoder(
35        const sp<AMessage> &notify,
36        const sp<NativeWindowWrapper> &nativeWindow)
37    : mNotify(notify),
38      mNativeWindow(nativeWindow),
39      mBufferGeneration(0),
40      mComponentName("decoder") {
41    // Every decoder has its own looper because MediaCodec operations
42    // are blocking, but NuPlayer needs asynchronous operations.
43    mDecoderLooper = new ALooper;
44    mDecoderLooper->setName("NuPlayerDecoder");
45    mDecoderLooper->start(false, false, ANDROID_PRIORITY_AUDIO);
46
47    mCodecLooper = new ALooper;
48    mCodecLooper->setName("NuPlayerDecoder-MC");
49    mCodecLooper->start(false, false, ANDROID_PRIORITY_AUDIO);
50}
51
52NuPlayer::Decoder::~Decoder() {
53}
54
55void NuPlayer::Decoder::onConfigure(const sp<AMessage> &format) {
56    CHECK(mCodec == NULL);
57
58    ++mBufferGeneration;
59
60    AString mime;
61    CHECK(format->findString("mime", &mime));
62
63    sp<Surface> surface = NULL;
64    if (mNativeWindow != NULL) {
65        surface = mNativeWindow->getSurfaceTextureClient();
66    }
67
68    mComponentName = mime;
69    mComponentName.append(" decoder");
70    ALOGV("[%s] onConfigure (surface=%p)", mComponentName.c_str(), surface.get());
71
72    mCodec = MediaCodec::CreateByType(mCodecLooper, mime.c_str(), false /* encoder */);
73    if (mCodec == NULL) {
74        ALOGE("Failed to create %s decoder", mime.c_str());
75        handleError(UNKNOWN_ERROR);
76        return;
77    }
78
79    mCodec->getName(&mComponentName);
80
81    if (mNativeWindow != NULL) {
82        // disconnect from surface as MediaCodec will reconnect
83        CHECK_EQ((int)NO_ERROR,
84                native_window_api_disconnect(
85                        surface.get(),
86                        NATIVE_WINDOW_API_MEDIA));
87    }
88    status_t err = mCodec->configure(
89            format, surface, NULL /* crypto */, 0 /* flags */);
90    if (err != OK) {
91        ALOGE("Failed to configure %s decoder (err=%d)", mComponentName.c_str(), err);
92        handleError(err);
93        return;
94    }
95    // the following should work in configured state
96    CHECK_EQ((status_t)OK, mCodec->getOutputFormat(&mOutputFormat));
97    CHECK_EQ((status_t)OK, mCodec->getInputFormat(&mInputFormat));
98
99    err = mCodec->start();
100    if (err != OK) {
101        ALOGE("Failed to start %s decoder (err=%d)", mComponentName.c_str(), err);
102        handleError(err);
103        return;
104    }
105
106    // the following should work after start
107    CHECK_EQ((status_t)OK, mCodec->getInputBuffers(&mInputBuffers));
108    CHECK_EQ((status_t)OK, mCodec->getOutputBuffers(&mOutputBuffers));
109    ALOGV("[%s] got %zu input and %zu output buffers",
110            mComponentName.c_str(),
111            mInputBuffers.size(),
112            mOutputBuffers.size());
113
114    requestCodecNotification();
115}
116
117void NuPlayer::Decoder::requestCodecNotification() {
118    if (mCodec != NULL) {
119        sp<AMessage> reply = new AMessage(kWhatCodecNotify, id());
120        reply->setInt32("generation", mBufferGeneration);
121        mCodec->requestActivityNotification(reply);
122    }
123}
124
125bool NuPlayer::Decoder::isStaleReply(const sp<AMessage> &msg) {
126    int32_t generation;
127    CHECK(msg->findInt32("generation", &generation));
128    return generation != mBufferGeneration;
129}
130
131void NuPlayer::Decoder::init() {
132    mDecoderLooper->registerHandler(this);
133}
134
135void NuPlayer::Decoder::configure(const sp<AMessage> &format) {
136    sp<AMessage> msg = new AMessage(kWhatConfigure, id());
137    msg->setMessage("format", format);
138    msg->post();
139}
140
141void NuPlayer::Decoder::handleError(int32_t err)
142{
143    sp<AMessage> notify = mNotify->dup();
144    notify->setInt32("what", kWhatError);
145    notify->setInt32("err", err);
146    notify->post();
147}
148
149bool NuPlayer::Decoder::handleAnInputBuffer() {
150    size_t bufferIx = -1;
151    status_t res = mCodec->dequeueInputBuffer(&bufferIx);
152    ALOGV("[%s] dequeued input: %d",
153            mComponentName.c_str(), res == OK ? (int)bufferIx : res);
154    if (res != OK) {
155        if (res != -EAGAIN) {
156            handleError(res);
157        }
158        return false;
159    }
160
161    CHECK_LT(bufferIx, mInputBuffers.size());
162
163    sp<AMessage> reply = new AMessage(kWhatInputBufferFilled, id());
164    reply->setSize("buffer-ix", bufferIx);
165    reply->setInt32("generation", mBufferGeneration);
166
167    sp<AMessage> notify = mNotify->dup();
168    notify->setInt32("what", kWhatFillThisBuffer);
169    notify->setBuffer("buffer", mInputBuffers[bufferIx]);
170    notify->setMessage("reply", reply);
171    notify->post();
172    return true;
173}
174
175void android::NuPlayer::Decoder::onInputBufferFilled(const sp<AMessage> &msg) {
176    size_t bufferIx;
177    CHECK(msg->findSize("buffer-ix", &bufferIx));
178    CHECK_LT(bufferIx, mInputBuffers.size());
179    sp<ABuffer> codecBuffer = mInputBuffers[bufferIx];
180
181    sp<ABuffer> buffer;
182    bool hasBuffer = msg->findBuffer("buffer", &buffer);
183    if (buffer == NULL /* includes !hasBuffer */) {
184        int32_t streamErr = ERROR_END_OF_STREAM;
185        CHECK(msg->findInt32("err", &streamErr) || !hasBuffer);
186
187        if (streamErr == OK) {
188            /* buffers are returned to hold on to */
189            return;
190        }
191
192        // attempt to queue EOS
193        status_t err = mCodec->queueInputBuffer(
194                bufferIx,
195                0,
196                0,
197                0,
198                MediaCodec::BUFFER_FLAG_EOS);
199        if (streamErr == ERROR_END_OF_STREAM && err != OK) {
200            streamErr = err;
201            // err will not be ERROR_END_OF_STREAM
202        }
203
204        if (streamErr != ERROR_END_OF_STREAM) {
205            handleError(streamErr);
206        }
207    } else {
208        int64_t timeUs = 0;
209        uint32_t flags = 0;
210        CHECK(buffer->meta()->findInt64("timeUs", &timeUs));
211
212        int32_t eos;
213        // we do not expect CODECCONFIG or SYNCFRAME for decoder
214        if (buffer->meta()->findInt32("eos", &eos) && eos) {
215            flags |= MediaCodec::BUFFER_FLAG_EOS;
216        }
217
218        // copy into codec buffer
219        if (buffer != codecBuffer) {
220            CHECK_LE(buffer->size(), codecBuffer->capacity());
221            codecBuffer->setRange(0, buffer->size());
222            memcpy(codecBuffer->data(), buffer->data(), buffer->size());
223        }
224
225        status_t err = mCodec->queueInputBuffer(
226                        bufferIx,
227                        codecBuffer->offset(),
228                        codecBuffer->size(),
229                        timeUs,
230                        flags);
231        if (err != OK) {
232            ALOGE("Failed to queue input buffer for %s (err=%d)",
233                    mComponentName.c_str(), err);
234            handleError(err);
235        }
236    }
237}
238
239bool NuPlayer::Decoder::handleAnOutputBuffer() {
240    size_t bufferIx = -1;
241    size_t offset;
242    size_t size;
243    int64_t timeUs;
244    uint32_t flags;
245    status_t res = mCodec->dequeueOutputBuffer(
246            &bufferIx, &offset, &size, &timeUs, &flags);
247
248    if (res != OK) {
249        ALOGV("[%s] dequeued output: %d", mComponentName.c_str(), res);
250    } else {
251        ALOGV("[%s] dequeued output: %d (time=%lld flags=%" PRIu32 ")",
252                mComponentName.c_str(), (int)bufferIx, timeUs, flags);
253    }
254
255    if (res == INFO_OUTPUT_BUFFERS_CHANGED) {
256        res = mCodec->getOutputBuffers(&mOutputBuffers);
257        if (res != OK) {
258            ALOGE("Failed to get output buffers for %s after INFO event (err=%d)",
259                    mComponentName.c_str(), res);
260            handleError(res);
261            return false;
262        }
263        // NuPlayer ignores this
264        return true;
265    } else if (res == INFO_FORMAT_CHANGED) {
266        sp<AMessage> format = new AMessage();
267        res = mCodec->getOutputFormat(&format);
268        if (res != OK) {
269            ALOGE("Failed to get output format for %s after INFO event (err=%d)",
270                    mComponentName.c_str(), res);
271            handleError(res);
272            return false;
273        }
274
275        sp<AMessage> notify = mNotify->dup();
276        notify->setInt32("what", kWhatOutputFormatChanged);
277        notify->setMessage("format", format);
278        notify->post();
279        return true;
280    } else if (res == INFO_DISCONTINUITY) {
281        // nothing to do
282        return true;
283    } else if (res != OK) {
284        if (res != -EAGAIN) {
285            handleError(res);
286        }
287        return false;
288    }
289
290    CHECK_LT(bufferIx, mOutputBuffers.size());
291    sp<ABuffer> buffer = mOutputBuffers[bufferIx];
292    buffer->setRange(offset, size);
293    buffer->meta()->clear();
294    buffer->meta()->setInt64("timeUs", timeUs);
295    if (flags & MediaCodec::BUFFER_FLAG_EOS) {
296        buffer->meta()->setInt32("eos", true);
297    }
298    // we do not expect CODECCONFIG or SYNCFRAME for decoder
299
300    sp<AMessage> reply = new AMessage(kWhatRenderBuffer, id());
301    reply->setSize("buffer-ix", bufferIx);
302    reply->setInt32("generation", mBufferGeneration);
303
304    sp<AMessage> notify = mNotify->dup();
305    notify->setInt32("what", kWhatDrainThisBuffer);
306    notify->setBuffer("buffer", buffer);
307    notify->setMessage("reply", reply);
308    notify->post();
309
310    // FIXME: This should be handled after rendering is complete,
311    // but Renderer needs it now
312    if (flags & MediaCodec::BUFFER_FLAG_EOS) {
313        ALOGV("queueing eos [%s]", mComponentName.c_str());
314        sp<AMessage> notify = mNotify->dup();
315        notify->setInt32("what", kWhatEOS);
316        notify->setInt32("err", ERROR_END_OF_STREAM);
317        notify->post();
318    }
319    return true;
320}
321
322void NuPlayer::Decoder::onRenderBuffer(const sp<AMessage> &msg) {
323    status_t err;
324    int32_t render;
325    size_t bufferIx;
326    CHECK(msg->findSize("buffer-ix", &bufferIx));
327    if (msg->findInt32("render", &render) && render) {
328        err = mCodec->renderOutputBufferAndRelease(bufferIx);
329    } else {
330        err = mCodec->releaseOutputBuffer(bufferIx);
331    }
332    if (err != OK) {
333        ALOGE("failed to release output buffer for %s (err=%d)",
334                mComponentName.c_str(), err);
335        handleError(err);
336    }
337}
338
339void NuPlayer::Decoder::onFlush() {
340    status_t err = OK;
341    if (mCodec != NULL) {
342        err = mCodec->flush();
343        ++mBufferGeneration;
344    }
345
346    if (err != OK) {
347        ALOGE("failed to flush %s (err=%d)", mComponentName.c_str(), err);
348        handleError(err);
349        return;
350    }
351
352    sp<AMessage> notify = mNotify->dup();
353    notify->setInt32("what", kWhatFlushCompleted);
354    notify->post();
355}
356
357void NuPlayer::Decoder::onShutdown() {
358    status_t err = OK;
359    if (mCodec != NULL) {
360        err = mCodec->release();
361        mCodec = NULL;
362        ++mBufferGeneration;
363
364        if (mNativeWindow != NULL) {
365            // reconnect to surface as MediaCodec disconnected from it
366            CHECK_EQ((int)NO_ERROR,
367                    native_window_api_connect(
368                            mNativeWindow->getNativeWindow().get(),
369                            NATIVE_WINDOW_API_MEDIA));
370        }
371        mComponentName = "decoder";
372    }
373
374    if (err != OK) {
375        ALOGE("failed to release %s (err=%d)", mComponentName.c_str(), err);
376        handleError(err);
377        return;
378    }
379
380    sp<AMessage> notify = mNotify->dup();
381    notify->setInt32("what", kWhatShutdownCompleted);
382    notify->post();
383}
384
385void NuPlayer::Decoder::onMessageReceived(const sp<AMessage> &msg) {
386    ALOGV("[%s] onMessage: %s", mComponentName.c_str(), msg->debugString().c_str());
387
388    switch (msg->what()) {
389        case kWhatConfigure:
390        {
391            sp<AMessage> format;
392            CHECK(msg->findMessage("format", &format));
393            onConfigure(format);
394            break;
395        }
396
397        case kWhatCodecNotify:
398        {
399            if (!isStaleReply(msg)) {
400                while (handleAnInputBuffer()) {
401                }
402
403                while (handleAnOutputBuffer()) {
404                }
405            }
406
407            requestCodecNotification();
408            break;
409        }
410
411        case kWhatInputBufferFilled:
412        {
413            if (!isStaleReply(msg)) {
414                onInputBufferFilled(msg);
415            }
416            break;
417        }
418
419        case kWhatRenderBuffer:
420        {
421            if (!isStaleReply(msg)) {
422                onRenderBuffer(msg);
423            }
424            break;
425        }
426
427        case kWhatFlush:
428        {
429            onFlush();
430            break;
431        }
432
433        case kWhatShutdown:
434        {
435            onShutdown();
436            break;
437        }
438
439        default:
440            TRESPASS();
441            break;
442    }
443}
444
445void NuPlayer::Decoder::signalFlush() {
446    (new AMessage(kWhatFlush, id()))->post();
447}
448
449void NuPlayer::Decoder::signalResume() {
450    // nothing to do
451}
452
453void NuPlayer::Decoder::initiateShutdown() {
454    (new AMessage(kWhatShutdown, id()))->post();
455}
456
457bool NuPlayer::Decoder::supportsSeamlessAudioFormatChange(const sp<AMessage> &targetFormat) const {
458    if (targetFormat == NULL) {
459        return true;
460    }
461
462    AString mime;
463    if (!targetFormat->findString("mime", &mime)) {
464        return false;
465    }
466
467    if (!strcasecmp(mime.c_str(), MEDIA_MIMETYPE_AUDIO_AAC)) {
468        // field-by-field comparison
469        const char * keys[] = { "channel-count", "sample-rate", "is-adts" };
470        for (unsigned int i = 0; i < sizeof(keys) / sizeof(keys[0]); i++) {
471            int32_t oldVal, newVal;
472            if (!mOutputFormat->findInt32(keys[i], &oldVal) ||
473                    !targetFormat->findInt32(keys[i], &newVal) ||
474                    oldVal != newVal) {
475                return false;
476            }
477        }
478
479        sp<ABuffer> oldBuf, newBuf;
480        if (mOutputFormat->findBuffer("csd-0", &oldBuf) &&
481                targetFormat->findBuffer("csd-0", &newBuf)) {
482            if (oldBuf->size() != newBuf->size()) {
483                return false;
484            }
485            return !memcmp(oldBuf->data(), newBuf->data(), oldBuf->size());
486        }
487    }
488    return false;
489}
490
491bool NuPlayer::Decoder::supportsSeamlessFormatChange(const sp<AMessage> &targetFormat) const {
492    if (mOutputFormat == NULL) {
493        return false;
494    }
495
496    if (targetFormat == NULL) {
497        return true;
498    }
499
500    AString oldMime, newMime;
501    if (!mOutputFormat->findString("mime", &oldMime)
502            || !targetFormat->findString("mime", &newMime)
503            || !(oldMime == newMime)) {
504        return false;
505    }
506
507    bool audio = !strncasecmp(oldMime.c_str(), "audio/", strlen("audio/"));
508    bool seamless;
509    if (audio) {
510        seamless = supportsSeamlessAudioFormatChange(targetFormat);
511    } else {
512        int32_t isAdaptive;
513        seamless = (mCodec != NULL &&
514                mInputFormat->findInt32("adaptive-playback", &isAdaptive) &&
515                isAdaptive);
516    }
517
518    ALOGV("%s seamless support for %s", seamless ? "yes" : "no", oldMime.c_str());
519    return seamless;
520}
521
522}  // namespace android
523
524