NuPlayerDecoder.cpp revision 4923cee4fb3b29538d8f46bceeea7d5128242a71
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/ABitReader.h>
26#include <media/stagefright/foundation/ABuffer.h>
27#include <media/stagefright/foundation/ADebug.h>
28#include <media/stagefright/foundation/AMessage.h>
29#include <media/stagefright/MediaBuffer.h>
30#include <media/stagefright/MediaCodec.h>
31#include <media/stagefright/MediaDefs.h>
32#include <media/stagefright/MediaErrors.h>
33
34namespace android {
35
36NuPlayer::Decoder::Decoder(
37        const sp<AMessage> &notify,
38        const sp<NativeWindowWrapper> &nativeWindow)
39    : mNotify(notify),
40      mNativeWindow(nativeWindow),
41      mBufferGeneration(0),
42      mPaused(true),
43      mComponentName("decoder") {
44    // Every decoder has its own looper because MediaCodec operations
45    // are blocking, but NuPlayer needs asynchronous operations.
46    mDecoderLooper = new ALooper;
47    mDecoderLooper->setName("NPDecoder");
48    mDecoderLooper->start(false, false, ANDROID_PRIORITY_AUDIO);
49
50    mCodecLooper = new ALooper;
51    mCodecLooper->setName("NPDecoder-CL");
52    mCodecLooper->start(false, false, ANDROID_PRIORITY_AUDIO);
53}
54
55NuPlayer::Decoder::~Decoder() {
56    mDecoderLooper->unregisterHandler(id());
57    mDecoderLooper->stop();
58
59    releaseAndResetMediaBuffers();
60}
61
62static
63status_t PostAndAwaitResponse(
64        const sp<AMessage> &msg, sp<AMessage> *response) {
65    status_t err = msg->postAndAwaitResponse(response);
66
67    if (err != OK) {
68        return err;
69    }
70
71    if (!(*response)->findInt32("err", &err)) {
72        err = OK;
73    }
74
75    return err;
76}
77
78void NuPlayer::Decoder::rememberCodecSpecificData(const sp<AMessage> &format) {
79    mCSDsForCurrentFormat.clear();
80    for (int32_t i = 0; ; ++i) {
81        AString tag = "csd-";
82        tag.append(i);
83        sp<ABuffer> buffer;
84        if (!format->findBuffer(tag.c_str(), &buffer)) {
85            break;
86        }
87        mCSDsForCurrentFormat.push(buffer);
88    }
89}
90
91void NuPlayer::Decoder::onConfigure(const sp<AMessage> &format) {
92    CHECK(mCodec == NULL);
93
94    ++mBufferGeneration;
95
96    AString mime;
97    CHECK(format->findString("mime", &mime));
98
99    sp<Surface> surface = NULL;
100    if (mNativeWindow != NULL) {
101        surface = mNativeWindow->getSurfaceTextureClient();
102    }
103
104    mComponentName = mime;
105    mComponentName.append(" decoder");
106    ALOGV("[%s] onConfigure (surface=%p)", mComponentName.c_str(), surface.get());
107
108    mCodec = MediaCodec::CreateByType(mCodecLooper, mime.c_str(), false /* encoder */);
109    int32_t secure = 0;
110    if (format->findInt32("secure", &secure) && secure != 0) {
111        if (mCodec != NULL) {
112            mCodec->getName(&mComponentName);
113            mComponentName.append(".secure");
114            mCodec->release();
115            ALOGI("[%s] creating", mComponentName.c_str());
116            mCodec = MediaCodec::CreateByComponentName(
117                    mCodecLooper, mComponentName.c_str());
118        }
119    }
120    if (mCodec == NULL) {
121        ALOGE("Failed to create %s%s decoder",
122                (secure ? "secure " : ""), mime.c_str());
123        handleError(UNKNOWN_ERROR);
124        return;
125    }
126
127    mCodec->getName(&mComponentName);
128
129    status_t err;
130    if (mNativeWindow != NULL) {
131        // disconnect from surface as MediaCodec will reconnect
132        err = native_window_api_disconnect(
133                surface.get(), NATIVE_WINDOW_API_MEDIA);
134        // We treat this as a warning, as this is a preparatory step.
135        // Codec will try to connect to the surface, which is where
136        // any error signaling will occur.
137        ALOGW_IF(err != OK, "failed to disconnect from surface: %d", err);
138    }
139    err = mCodec->configure(
140            format, surface, NULL /* crypto */, 0 /* flags */);
141    if (err != OK) {
142        ALOGE("Failed to configure %s decoder (err=%d)", mComponentName.c_str(), err);
143        handleError(err);
144        return;
145    }
146    rememberCodecSpecificData(format);
147
148    // the following should work in configured state
149    CHECK_EQ((status_t)OK, mCodec->getOutputFormat(&mOutputFormat));
150    CHECK_EQ((status_t)OK, mCodec->getInputFormat(&mInputFormat));
151
152    err = mCodec->start();
153    if (err != OK) {
154        ALOGE("Failed to start %s decoder (err=%d)", mComponentName.c_str(), err);
155        handleError(err);
156        return;
157    }
158
159    // the following should work after start
160    CHECK_EQ((status_t)OK, mCodec->getInputBuffers(&mInputBuffers));
161    releaseAndResetMediaBuffers();
162    CHECK_EQ((status_t)OK, mCodec->getOutputBuffers(&mOutputBuffers));
163    ALOGV("[%s] got %zu input and %zu output buffers",
164            mComponentName.c_str(),
165            mInputBuffers.size(),
166            mOutputBuffers.size());
167
168    requestCodecNotification();
169    mPaused = false;
170}
171
172void NuPlayer::Decoder::releaseAndResetMediaBuffers() {
173    for (size_t i = 0; i < mMediaBuffers.size(); i++) {
174        if (mMediaBuffers[i] != NULL) {
175            mMediaBuffers[i]->release();
176            mMediaBuffers.editItemAt(i) = NULL;
177        }
178    }
179    mMediaBuffers.resize(mInputBuffers.size());
180    for (size_t i = 0; i < mMediaBuffers.size(); i++) {
181        mMediaBuffers.editItemAt(i) = NULL;
182    }
183    mInputBufferIsDequeued.clear();
184    mInputBufferIsDequeued.resize(mInputBuffers.size());
185    for (size_t i = 0; i < mInputBufferIsDequeued.size(); i++) {
186        mInputBufferIsDequeued.editItemAt(i) = false;
187    }
188}
189
190void NuPlayer::Decoder::requestCodecNotification() {
191    if (mCodec != NULL) {
192        sp<AMessage> reply = new AMessage(kWhatCodecNotify, id());
193        reply->setInt32("generation", mBufferGeneration);
194        mCodec->requestActivityNotification(reply);
195    }
196}
197
198bool NuPlayer::Decoder::isStaleReply(const sp<AMessage> &msg) {
199    int32_t generation;
200    CHECK(msg->findInt32("generation", &generation));
201    return generation != mBufferGeneration;
202}
203
204void NuPlayer::Decoder::init() {
205    mDecoderLooper->registerHandler(this);
206}
207
208void NuPlayer::Decoder::configure(const sp<AMessage> &format) {
209    sp<AMessage> msg = new AMessage(kWhatConfigure, id());
210    msg->setMessage("format", format);
211    msg->post();
212}
213
214void NuPlayer::Decoder::signalUpdateFormat(const sp<AMessage> &format) {
215    sp<AMessage> msg = new AMessage(kWhatUpdateFormat, id());
216    msg->setMessage("format", format);
217    msg->post();
218}
219
220status_t NuPlayer::Decoder::getInputBuffers(Vector<sp<ABuffer> > *buffers) const {
221    sp<AMessage> msg = new AMessage(kWhatGetInputBuffers, id());
222    msg->setPointer("buffers", buffers);
223
224    sp<AMessage> response;
225    return PostAndAwaitResponse(msg, &response);
226}
227
228void NuPlayer::Decoder::handleError(int32_t err)
229{
230    mCodec->release();
231
232    sp<AMessage> notify = mNotify->dup();
233    notify->setInt32("what", kWhatError);
234    notify->setInt32("err", err);
235    notify->post();
236}
237
238bool NuPlayer::Decoder::handleAnInputBuffer() {
239    size_t bufferIx = -1;
240    status_t res = mCodec->dequeueInputBuffer(&bufferIx);
241    ALOGV("[%s] dequeued input: %d",
242            mComponentName.c_str(), res == OK ? (int)bufferIx : res);
243    if (res != OK) {
244        if (res != -EAGAIN) {
245            handleError(res);
246        }
247        return false;
248    }
249
250    CHECK_LT(bufferIx, mInputBuffers.size());
251
252    if (mMediaBuffers[bufferIx] != NULL) {
253        mMediaBuffers[bufferIx]->release();
254        mMediaBuffers.editItemAt(bufferIx) = NULL;
255    }
256    mInputBufferIsDequeued.editItemAt(bufferIx) = true;
257
258    sp<AMessage> reply = new AMessage(kWhatInputBufferFilled, id());
259    reply->setSize("buffer-ix", bufferIx);
260    reply->setInt32("generation", mBufferGeneration);
261
262    if (!mCSDsToSubmit.isEmpty()) {
263        sp<ABuffer> buffer = mCSDsToSubmit.itemAt(0);
264        ALOGI("[%s] resubmitting CSD", mComponentName.c_str());
265        reply->setBuffer("buffer", buffer);
266        mCSDsToSubmit.removeAt(0);
267        reply->post();
268        return true;
269    }
270
271    sp<AMessage> notify = mNotify->dup();
272    notify->setInt32("what", kWhatFillThisBuffer);
273    notify->setBuffer("buffer", mInputBuffers[bufferIx]);
274    notify->setMessage("reply", reply);
275    notify->post();
276    return true;
277}
278
279void android::NuPlayer::Decoder::onInputBufferFilled(const sp<AMessage> &msg) {
280    size_t bufferIx;
281    CHECK(msg->findSize("buffer-ix", &bufferIx));
282    CHECK_LT(bufferIx, mInputBuffers.size());
283    sp<ABuffer> codecBuffer = mInputBuffers[bufferIx];
284
285    sp<ABuffer> buffer;
286    bool hasBuffer = msg->findBuffer("buffer", &buffer);
287
288    // handle widevine classic source - that fills an arbitrary input buffer
289    MediaBuffer *mediaBuffer = NULL;
290    if (hasBuffer) {
291        mediaBuffer = (MediaBuffer *)(buffer->getMediaBufferBase());
292        if (mediaBuffer != NULL) {
293            // likely filled another buffer than we requested: adjust buffer index
294            size_t ix;
295            for (ix = 0; ix < mInputBuffers.size(); ix++) {
296                const sp<ABuffer> &buf = mInputBuffers[ix];
297                if (buf->data() == mediaBuffer->data()) {
298                    // all input buffers are dequeued on start, hence the check
299                    CHECK(mInputBufferIsDequeued[ix]);
300                    ALOGV("[%s] received MediaBuffer for #%zu instead of #%zu",
301                            mComponentName.c_str(), ix, bufferIx);
302
303                    // TRICKY: need buffer for the metadata, so instead, set
304                    // codecBuffer to the same (though incorrect) buffer to
305                    // avoid a memcpy into the codecBuffer
306                    codecBuffer = buffer;
307                    codecBuffer->setRange(
308                            mediaBuffer->range_offset(),
309                            mediaBuffer->range_length());
310                    bufferIx = ix;
311                    break;
312                }
313            }
314            CHECK(ix < mInputBuffers.size());
315        }
316    }
317
318    mInputBufferIsDequeued.editItemAt(bufferIx) = false;
319
320    if (buffer == NULL /* includes !hasBuffer */) {
321        int32_t streamErr = ERROR_END_OF_STREAM;
322        CHECK(msg->findInt32("err", &streamErr) || !hasBuffer);
323
324        if (streamErr == OK) {
325            /* buffers are returned to hold on to */
326            return;
327        }
328
329        // attempt to queue EOS
330        status_t err = mCodec->queueInputBuffer(
331                bufferIx,
332                0,
333                0,
334                0,
335                MediaCodec::BUFFER_FLAG_EOS);
336        if (streamErr == ERROR_END_OF_STREAM && err != OK) {
337            streamErr = err;
338            // err will not be ERROR_END_OF_STREAM
339        }
340
341        if (streamErr != ERROR_END_OF_STREAM) {
342            handleError(streamErr);
343        }
344    } else {
345        int64_t timeUs = 0;
346        uint32_t flags = 0;
347        CHECK(buffer->meta()->findInt64("timeUs", &timeUs));
348
349        int32_t eos, csd;
350        // we do not expect SYNCFRAME for decoder
351        if (buffer->meta()->findInt32("eos", &eos) && eos) {
352            flags |= MediaCodec::BUFFER_FLAG_EOS;
353        } else if (buffer->meta()->findInt32("csd", &csd) && csd) {
354            flags |= MediaCodec::BUFFER_FLAG_CODECCONFIG;
355        }
356
357        // copy into codec buffer
358        if (buffer != codecBuffer) {
359            CHECK_LE(buffer->size(), codecBuffer->capacity());
360            codecBuffer->setRange(0, buffer->size());
361            memcpy(codecBuffer->data(), buffer->data(), buffer->size());
362        }
363
364        status_t err = mCodec->queueInputBuffer(
365                        bufferIx,
366                        codecBuffer->offset(),
367                        codecBuffer->size(),
368                        timeUs,
369                        flags);
370        if (err != OK) {
371            ALOGE("Failed to queue input buffer for %s (err=%d)",
372                    mComponentName.c_str(), err);
373            handleError(err);
374        }
375
376        if (mediaBuffer != NULL) {
377            CHECK(mMediaBuffers[bufferIx] == NULL);
378            mMediaBuffers.editItemAt(bufferIx) = mediaBuffer;
379        }
380    }
381}
382
383bool NuPlayer::Decoder::handleAnOutputBuffer() {
384    size_t bufferIx = -1;
385    size_t offset;
386    size_t size;
387    int64_t timeUs;
388    uint32_t flags;
389    status_t res = mCodec->dequeueOutputBuffer(
390            &bufferIx, &offset, &size, &timeUs, &flags);
391
392    if (res != OK) {
393        ALOGV("[%s] dequeued output: %d", mComponentName.c_str(), res);
394    } else {
395        ALOGV("[%s] dequeued output: %d (time=%lld flags=%" PRIu32 ")",
396                mComponentName.c_str(), (int)bufferIx, timeUs, flags);
397    }
398
399    if (res == INFO_OUTPUT_BUFFERS_CHANGED) {
400        res = mCodec->getOutputBuffers(&mOutputBuffers);
401        if (res != OK) {
402            ALOGE("Failed to get output buffers for %s after INFO event (err=%d)",
403                    mComponentName.c_str(), res);
404            handleError(res);
405            return false;
406        }
407        // NuPlayer ignores this
408        return true;
409    } else if (res == INFO_FORMAT_CHANGED) {
410        sp<AMessage> format = new AMessage();
411        res = mCodec->getOutputFormat(&format);
412        if (res != OK) {
413            ALOGE("Failed to get output format for %s after INFO event (err=%d)",
414                    mComponentName.c_str(), res);
415            handleError(res);
416            return false;
417        }
418
419        sp<AMessage> notify = mNotify->dup();
420        notify->setInt32("what", kWhatOutputFormatChanged);
421        notify->setMessage("format", format);
422        notify->post();
423        return true;
424    } else if (res == INFO_DISCONTINUITY) {
425        // nothing to do
426        return true;
427    } else if (res != OK) {
428        if (res != -EAGAIN) {
429            handleError(res);
430        }
431        return false;
432    }
433
434    CHECK_LT(bufferIx, mOutputBuffers.size());
435    sp<ABuffer> buffer = mOutputBuffers[bufferIx];
436    buffer->setRange(offset, size);
437    buffer->meta()->clear();
438    buffer->meta()->setInt64("timeUs", timeUs);
439    if (flags & MediaCodec::BUFFER_FLAG_EOS) {
440        buffer->meta()->setInt32("eos", true);
441    }
442    // we do not expect CODECCONFIG or SYNCFRAME for decoder
443
444    sp<AMessage> reply = new AMessage(kWhatRenderBuffer, id());
445    reply->setSize("buffer-ix", bufferIx);
446    reply->setInt32("generation", mBufferGeneration);
447
448    sp<AMessage> notify = mNotify->dup();
449    notify->setInt32("what", kWhatDrainThisBuffer);
450    notify->setBuffer("buffer", buffer);
451    notify->setMessage("reply", reply);
452    notify->post();
453
454    // FIXME: This should be handled after rendering is complete,
455    // but Renderer needs it now
456    if (flags & MediaCodec::BUFFER_FLAG_EOS) {
457        ALOGV("queueing eos [%s]", mComponentName.c_str());
458        sp<AMessage> notify = mNotify->dup();
459        notify->setInt32("what", kWhatEOS);
460        notify->setInt32("err", ERROR_END_OF_STREAM);
461        notify->post();
462    }
463    return true;
464}
465
466void NuPlayer::Decoder::onRenderBuffer(const sp<AMessage> &msg) {
467    status_t err;
468    int32_t render;
469    size_t bufferIx;
470    CHECK(msg->findSize("buffer-ix", &bufferIx));
471    if (msg->findInt32("render", &render) && render) {
472        int64_t timestampNs;
473        CHECK(msg->findInt64("timestampNs", &timestampNs));
474        err = mCodec->renderOutputBufferAndRelease(bufferIx, timestampNs);
475    } else {
476        err = mCodec->releaseOutputBuffer(bufferIx);
477    }
478    if (err != OK) {
479        ALOGE("failed to release output buffer for %s (err=%d)",
480                mComponentName.c_str(), err);
481        handleError(err);
482    }
483}
484
485void NuPlayer::Decoder::onFlush() {
486    status_t err = OK;
487    if (mCodec != NULL) {
488        err = mCodec->flush();
489        mCSDsToSubmit = mCSDsForCurrentFormat; // copy operator
490        ++mBufferGeneration;
491    }
492
493    if (err != OK) {
494        ALOGE("failed to flush %s (err=%d)", mComponentName.c_str(), err);
495        handleError(err);
496        return;
497    }
498
499    releaseAndResetMediaBuffers();
500
501    sp<AMessage> notify = mNotify->dup();
502    notify->setInt32("what", kWhatFlushCompleted);
503    notify->post();
504    mPaused = true;
505}
506
507void NuPlayer::Decoder::onResume() {
508    mPaused = false;
509}
510
511void NuPlayer::Decoder::onShutdown() {
512    status_t err = OK;
513    if (mCodec != NULL) {
514        err = mCodec->release();
515        mCodec = NULL;
516        ++mBufferGeneration;
517
518        if (mNativeWindow != NULL) {
519            // reconnect to surface as MediaCodec disconnected from it
520            status_t error =
521                    native_window_api_connect(
522                            mNativeWindow->getNativeWindow().get(),
523                            NATIVE_WINDOW_API_MEDIA);
524            ALOGW_IF(error != NO_ERROR,
525                    "[%s] failed to connect to native window, error=%d",
526                    mComponentName.c_str(), error);
527        }
528        mComponentName = "decoder";
529    }
530
531    releaseAndResetMediaBuffers();
532
533    if (err != OK) {
534        ALOGE("failed to release %s (err=%d)", mComponentName.c_str(), err);
535        handleError(err);
536        return;
537    }
538
539    sp<AMessage> notify = mNotify->dup();
540    notify->setInt32("what", kWhatShutdownCompleted);
541    notify->post();
542    mPaused = true;
543}
544
545void NuPlayer::Decoder::onMessageReceived(const sp<AMessage> &msg) {
546    ALOGV("[%s] onMessage: %s", mComponentName.c_str(), msg->debugString().c_str());
547
548    switch (msg->what()) {
549        case kWhatConfigure:
550        {
551            sp<AMessage> format;
552            CHECK(msg->findMessage("format", &format));
553            onConfigure(format);
554            break;
555        }
556
557        case kWhatUpdateFormat:
558        {
559            sp<AMessage> format;
560            CHECK(msg->findMessage("format", &format));
561            rememberCodecSpecificData(format);
562            break;
563        }
564
565        case kWhatGetInputBuffers:
566        {
567            uint32_t replyID;
568            CHECK(msg->senderAwaitsResponse(&replyID));
569
570            Vector<sp<ABuffer> > *dstBuffers;
571            CHECK(msg->findPointer("buffers", (void **)&dstBuffers));
572
573            dstBuffers->clear();
574            for (size_t i = 0; i < mInputBuffers.size(); i++) {
575                dstBuffers->push(mInputBuffers[i]);
576            }
577
578            (new AMessage)->postReply(replyID);
579            break;
580        }
581
582        case kWhatCodecNotify:
583        {
584            if (!isStaleReply(msg)) {
585                if (!mPaused) {
586                    while (handleAnInputBuffer()) {
587                    }
588                }
589
590                while (handleAnOutputBuffer()) {
591                }
592            }
593
594            requestCodecNotification();
595            break;
596        }
597
598        case kWhatInputBufferFilled:
599        {
600            if (!isStaleReply(msg)) {
601                onInputBufferFilled(msg);
602            }
603
604            break;
605        }
606
607        case kWhatRenderBuffer:
608        {
609            if (!isStaleReply(msg)) {
610                onRenderBuffer(msg);
611            }
612            break;
613        }
614
615        case kWhatFlush:
616        {
617            sp<AMessage> format;
618            if (msg->findMessage("new-format", &format)) {
619                rememberCodecSpecificData(format);
620            }
621            onFlush();
622            break;
623        }
624
625        case kWhatResume:
626        {
627            onResume();
628            break;
629        }
630
631        case kWhatShutdown:
632        {
633            onShutdown();
634            break;
635        }
636
637        default:
638            TRESPASS();
639            break;
640    }
641}
642
643void NuPlayer::Decoder::signalFlush(const sp<AMessage> &format) {
644    sp<AMessage> msg = new AMessage(kWhatFlush, id());
645    if (format != NULL) {
646        msg->setMessage("new-format", format);
647    }
648    msg->post();
649}
650
651void NuPlayer::Decoder::signalResume() {
652    (new AMessage(kWhatResume, id()))->post();
653}
654
655void NuPlayer::Decoder::initiateShutdown() {
656    (new AMessage(kWhatShutdown, id()))->post();
657}
658
659bool NuPlayer::Decoder::supportsSeamlessAudioFormatChange(const sp<AMessage> &targetFormat) const {
660    if (targetFormat == NULL) {
661        return true;
662    }
663
664    AString mime;
665    if (!targetFormat->findString("mime", &mime)) {
666        return false;
667    }
668
669    if (!strcasecmp(mime.c_str(), MEDIA_MIMETYPE_AUDIO_AAC)) {
670        // field-by-field comparison
671        const char * keys[] = { "channel-count", "sample-rate", "is-adts" };
672        for (unsigned int i = 0; i < sizeof(keys) / sizeof(keys[0]); i++) {
673            int32_t oldVal, newVal;
674            if (!mOutputFormat->findInt32(keys[i], &oldVal) ||
675                    !targetFormat->findInt32(keys[i], &newVal) ||
676                    oldVal != newVal) {
677                return false;
678            }
679        }
680
681        sp<ABuffer> oldBuf, newBuf;
682        if (mOutputFormat->findBuffer("csd-0", &oldBuf) &&
683                targetFormat->findBuffer("csd-0", &newBuf)) {
684            if (oldBuf->size() != newBuf->size()) {
685                return false;
686            }
687            return !memcmp(oldBuf->data(), newBuf->data(), oldBuf->size());
688        }
689    }
690    return false;
691}
692
693bool NuPlayer::Decoder::supportsSeamlessFormatChange(const sp<AMessage> &targetFormat) const {
694    if (mOutputFormat == NULL) {
695        return false;
696    }
697
698    if (targetFormat == NULL) {
699        return true;
700    }
701
702    AString oldMime, newMime;
703    if (!mOutputFormat->findString("mime", &oldMime)
704            || !targetFormat->findString("mime", &newMime)
705            || !(oldMime == newMime)) {
706        return false;
707    }
708
709    bool audio = !strncasecmp(oldMime.c_str(), "audio/", strlen("audio/"));
710    bool seamless;
711    if (audio) {
712        seamless = supportsSeamlessAudioFormatChange(targetFormat);
713    } else {
714        int32_t isAdaptive;
715        seamless = (mCodec != NULL &&
716                mInputFormat->findInt32("adaptive-playback", &isAdaptive) &&
717                isAdaptive);
718    }
719
720    ALOGV("%s seamless support for %s", seamless ? "yes" : "no", oldMime.c_str());
721    return seamless;
722}
723
724struct CCData {
725    CCData(uint8_t type, uint8_t data1, uint8_t data2)
726        : mType(type), mData1(data1), mData2(data2) {
727    }
728    bool getChannel(size_t *channel) const {
729        if (mData1 >= 0x10 && mData1 <= 0x1f) {
730            *channel = (mData1 >= 0x18 ? 1 : 0) + (mType ? 2 : 0);
731            return true;
732        }
733        return false;
734    }
735
736    uint8_t mType;
737    uint8_t mData1;
738    uint8_t mData2;
739};
740
741static bool isNullPad(CCData *cc) {
742    return cc->mData1 < 0x10 && cc->mData2 < 0x10;
743}
744
745static void dumpBytePair(const sp<ABuffer> &ccBuf) {
746    size_t offset = 0;
747    AString out;
748
749    while (offset < ccBuf->size()) {
750        char tmp[128];
751
752        CCData *cc = (CCData *) (ccBuf->data() + offset);
753
754        if (isNullPad(cc)) {
755            // 1 null pad or XDS metadata, ignore
756            offset += sizeof(CCData);
757            continue;
758        }
759
760        if (cc->mData1 >= 0x20 && cc->mData1 <= 0x7f) {
761            // 2 basic chars
762            sprintf(tmp, "[%d]Basic: %c %c", cc->mType, cc->mData1, cc->mData2);
763        } else if ((cc->mData1 == 0x11 || cc->mData1 == 0x19)
764                 && cc->mData2 >= 0x30 && cc->mData2 <= 0x3f) {
765            // 1 special char
766            sprintf(tmp, "[%d]Special: %02x %02x", cc->mType, cc->mData1, cc->mData2);
767        } else if ((cc->mData1 == 0x12 || cc->mData1 == 0x1A)
768                 && cc->mData2 >= 0x20 && cc->mData2 <= 0x3f){
769            // 1 Spanish/French char
770            sprintf(tmp, "[%d]Spanish: %02x %02x", cc->mType, cc->mData1, cc->mData2);
771        } else if ((cc->mData1 == 0x13 || cc->mData1 == 0x1B)
772                 && cc->mData2 >= 0x20 && cc->mData2 <= 0x3f){
773            // 1 Portuguese/German/Danish char
774            sprintf(tmp, "[%d]German: %02x %02x", cc->mType, cc->mData1, cc->mData2);
775        } else if ((cc->mData1 == 0x11 || cc->mData1 == 0x19)
776                 && cc->mData2 >= 0x20 && cc->mData2 <= 0x2f){
777            // Mid-Row Codes (Table 69)
778            sprintf(tmp, "[%d]Mid-row: %02x %02x", cc->mType, cc->mData1, cc->mData2);
779        } else if (((cc->mData1 == 0x14 || cc->mData1 == 0x1c)
780                  && cc->mData2 >= 0x20 && cc->mData2 <= 0x2f)
781                  ||
782                   ((cc->mData1 == 0x17 || cc->mData1 == 0x1f)
783                  && cc->mData2 >= 0x21 && cc->mData2 <= 0x23)){
784            // Misc Control Codes (Table 70)
785            sprintf(tmp, "[%d]Ctrl: %02x %02x", cc->mType, cc->mData1, cc->mData2);
786        } else if ((cc->mData1 & 0x70) == 0x10
787                && (cc->mData2 & 0x40) == 0x40
788                && ((cc->mData1 & 0x07) || !(cc->mData2 & 0x20)) ) {
789            // Preamble Address Codes (Table 71)
790            sprintf(tmp, "[%d]PAC: %02x %02x", cc->mType, cc->mData1, cc->mData2);
791        } else {
792            sprintf(tmp, "[%d]Invalid: %02x %02x", cc->mType, cc->mData1, cc->mData2);
793        }
794
795        if (out.size() > 0) {
796            out.append(", ");
797        }
798
799        out.append(tmp);
800
801        offset += sizeof(CCData);
802    }
803
804    ALOGI("%s", out.c_str());
805}
806
807NuPlayer::CCDecoder::CCDecoder(const sp<AMessage> &notify)
808    : mNotify(notify),
809      mCurrentChannel(0),
810      mSelectedTrack(-1) {
811      for (size_t i = 0; i < sizeof(mTrackIndices)/sizeof(mTrackIndices[0]); ++i) {
812          mTrackIndices[i] = -1;
813      }
814}
815
816size_t NuPlayer::CCDecoder::getTrackCount() const {
817    return mFoundChannels.size();
818}
819
820sp<AMessage> NuPlayer::CCDecoder::getTrackInfo(size_t index) const {
821    if (!isTrackValid(index)) {
822        return NULL;
823    }
824
825    sp<AMessage> format = new AMessage();
826
827    format->setInt32("type", MEDIA_TRACK_TYPE_SUBTITLE);
828    format->setString("language", "und");
829    format->setString("mime", MEDIA_MIMETYPE_TEXT_CEA_608);
830    //CC1, field 0 channel 0
831    bool isDefaultAuto = (mFoundChannels[index] == 0);
832    format->setInt32("auto", isDefaultAuto);
833    format->setInt32("default", isDefaultAuto);
834    format->setInt32("forced", 0);
835
836    return format;
837}
838
839status_t NuPlayer::CCDecoder::selectTrack(size_t index, bool select) {
840    if (!isTrackValid(index)) {
841        return BAD_VALUE;
842    }
843
844    if (select) {
845        if (mSelectedTrack == (ssize_t)index) {
846            ALOGE("track %zu already selected", index);
847            return BAD_VALUE;
848        }
849        ALOGV("selected track %zu", index);
850        mSelectedTrack = index;
851    } else {
852        if (mSelectedTrack != (ssize_t)index) {
853            ALOGE("track %zu is not selected", index);
854            return BAD_VALUE;
855        }
856        ALOGV("unselected track %zu", index);
857        mSelectedTrack = -1;
858    }
859
860    return OK;
861}
862
863bool NuPlayer::CCDecoder::isSelected() const {
864    return mSelectedTrack >= 0 && mSelectedTrack < (int32_t) getTrackCount();
865}
866
867bool NuPlayer::CCDecoder::isTrackValid(size_t index) const {
868    return index < getTrackCount();
869}
870
871int32_t NuPlayer::CCDecoder::getTrackIndex(size_t channel) const {
872    if (channel < sizeof(mTrackIndices)/sizeof(mTrackIndices[0])) {
873        return mTrackIndices[channel];
874    }
875    return -1;
876}
877
878// returns true if a new CC track is found
879bool NuPlayer::CCDecoder::extractFromSEI(const sp<ABuffer> &accessUnit) {
880    int64_t timeUs;
881    CHECK(accessUnit->meta()->findInt64("timeUs", &timeUs));
882
883    sp<ABuffer> sei;
884    if (!accessUnit->meta()->findBuffer("sei", &sei) || sei == NULL) {
885        return false;
886    }
887
888    bool trackAdded = false;
889
890    NALBitReader br(sei->data() + 1, sei->size() - 1);
891    // sei_message()
892    while (br.atLeastNumBitsLeft(16)) { // at least 16-bit for sei_message()
893        uint32_t payload_type = 0;
894        size_t payload_size = 0;
895        uint8_t last_byte;
896
897        do {
898            last_byte = br.getBits(8);
899            payload_type += last_byte;
900        } while (last_byte == 0xFF);
901
902        do {
903            last_byte = br.getBits(8);
904            payload_size += last_byte;
905        } while (last_byte == 0xFF);
906
907        // sei_payload()
908        if (payload_type == 4) {
909            // user_data_registered_itu_t_t35()
910
911            // ATSC A/72: 6.4.2
912            uint8_t itu_t_t35_country_code = br.getBits(8);
913            uint16_t itu_t_t35_provider_code = br.getBits(16);
914            uint32_t user_identifier = br.getBits(32);
915            uint8_t user_data_type_code = br.getBits(8);
916
917            payload_size -= 1 + 2 + 4 + 1;
918
919            if (itu_t_t35_country_code == 0xB5
920                    && itu_t_t35_provider_code == 0x0031
921                    && user_identifier == 'GA94'
922                    && user_data_type_code == 0x3) {
923                // MPEG_cc_data()
924                // ATSC A/53 Part 4: 6.2.3.1
925                br.skipBits(1); //process_em_data_flag
926                bool process_cc_data_flag = br.getBits(1);
927                br.skipBits(1); //additional_data_flag
928                size_t cc_count = br.getBits(5);
929                br.skipBits(8); // em_data;
930                payload_size -= 2;
931
932                if (process_cc_data_flag) {
933                    AString out;
934
935                    sp<ABuffer> ccBuf = new ABuffer(cc_count * sizeof(CCData));
936                    ccBuf->setRange(0, 0);
937
938                    for (size_t i = 0; i < cc_count; i++) {
939                        uint8_t marker = br.getBits(5);
940                        CHECK_EQ(marker, 0x1f);
941
942                        bool cc_valid = br.getBits(1);
943                        uint8_t cc_type = br.getBits(2);
944                        // remove odd parity bit
945                        uint8_t cc_data_1 = br.getBits(8) & 0x7f;
946                        uint8_t cc_data_2 = br.getBits(8) & 0x7f;
947
948                        if (cc_valid
949                                && (cc_type == 0 || cc_type == 1)) {
950                            CCData cc(cc_type, cc_data_1, cc_data_2);
951                            if (!isNullPad(&cc)) {
952                                size_t channel;
953                                if (cc.getChannel(&channel) && getTrackIndex(channel) < 0) {
954                                    mTrackIndices[channel] = mFoundChannels.size();
955                                    mFoundChannels.push_back(channel);
956                                    trackAdded = true;
957                                }
958                                memcpy(ccBuf->data() + ccBuf->size(),
959                                        (void *)&cc, sizeof(cc));
960                                ccBuf->setRange(0, ccBuf->size() + sizeof(CCData));
961                            }
962                        }
963                    }
964                    payload_size -= cc_count * 3;
965
966                    mCCMap.add(timeUs, ccBuf);
967                    break;
968                }
969            } else {
970                ALOGV("Malformed SEI payload type 4");
971            }
972        } else {
973            ALOGV("Unsupported SEI payload type %d", payload_type);
974        }
975
976        // skipping remaining bits of this payload
977        br.skipBits(payload_size * 8);
978    }
979
980    return trackAdded;
981}
982
983sp<ABuffer> NuPlayer::CCDecoder::filterCCBuf(
984        const sp<ABuffer> &ccBuf, size_t index) {
985    sp<ABuffer> filteredCCBuf = new ABuffer(ccBuf->size());
986    filteredCCBuf->setRange(0, 0);
987
988    size_t cc_count = ccBuf->size() / sizeof(CCData);
989    const CCData* cc_data = (const CCData*)ccBuf->data();
990    for (size_t i = 0; i < cc_count; ++i) {
991        size_t channel;
992        if (cc_data[i].getChannel(&channel)) {
993            mCurrentChannel = channel;
994        }
995        if (mCurrentChannel == mFoundChannels[index]) {
996            memcpy(filteredCCBuf->data() + filteredCCBuf->size(),
997                    (void *)&cc_data[i], sizeof(CCData));
998            filteredCCBuf->setRange(0, filteredCCBuf->size() + sizeof(CCData));
999        }
1000    }
1001
1002    return filteredCCBuf;
1003}
1004
1005void NuPlayer::CCDecoder::decode(const sp<ABuffer> &accessUnit) {
1006    if (extractFromSEI(accessUnit)) {
1007        ALOGI("Found CEA-608 track");
1008        sp<AMessage> msg = mNotify->dup();
1009        msg->setInt32("what", kWhatTrackAdded);
1010        msg->post();
1011    }
1012    // TODO: extract CC from other sources
1013}
1014
1015void NuPlayer::CCDecoder::display(int64_t timeUs) {
1016    if (!isTrackValid(mSelectedTrack)) {
1017        ALOGE("Could not find current track(index=%d)", mSelectedTrack);
1018        return;
1019    }
1020
1021    ssize_t index = mCCMap.indexOfKey(timeUs);
1022    if (index < 0) {
1023        ALOGV("cc for timestamp %" PRId64 " not found", timeUs);
1024        return;
1025    }
1026
1027    sp<ABuffer> ccBuf = filterCCBuf(mCCMap.valueAt(index), mSelectedTrack);
1028
1029    if (ccBuf->size() > 0) {
1030#if 0
1031        dumpBytePair(ccBuf);
1032#endif
1033
1034        ccBuf->meta()->setInt32("trackIndex", mSelectedTrack);
1035        ccBuf->meta()->setInt64("timeUs", timeUs);
1036        ccBuf->meta()->setInt64("durationUs", 0ll);
1037
1038        sp<AMessage> msg = mNotify->dup();
1039        msg->setInt32("what", kWhatClosedCaptionData);
1040        msg->setBuffer("buffer", ccBuf);
1041        msg->post();
1042    }
1043
1044    // remove all entries before timeUs
1045    mCCMap.removeItemsAt(0, index + 1);
1046}
1047
1048void NuPlayer::CCDecoder::flush() {
1049    mCCMap.clear();
1050}
1051
1052}  // namespace android
1053
1054