NuPlayerDecoder.cpp revision 862f8455eaacc1ffb5d8911f0bc7ecc3cf7ec46c
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/MediaCodec.h>
30#include <media/stagefright/MediaDefs.h>
31#include <media/stagefright/MediaErrors.h>
32
33namespace android {
34
35NuPlayer::Decoder::Decoder(
36        const sp<AMessage> &notify,
37        const sp<NativeWindowWrapper> &nativeWindow)
38    : mNotify(notify),
39      mNativeWindow(nativeWindow),
40      mBufferGeneration(0),
41      mPaused(true),
42      mComponentName("decoder") {
43    // Every decoder has its own looper because MediaCodec operations
44    // are blocking, but NuPlayer needs asynchronous operations.
45    mDecoderLooper = new ALooper;
46    mDecoderLooper->setName("NuPlayerDecoder");
47    mDecoderLooper->start(false, false, ANDROID_PRIORITY_AUDIO);
48
49    mCodecLooper = new ALooper;
50    mCodecLooper->setName("NuPlayerDecoder-MC");
51    mCodecLooper->start(false, false, ANDROID_PRIORITY_AUDIO);
52}
53
54NuPlayer::Decoder::~Decoder() {
55}
56
57void NuPlayer::Decoder::onConfigure(const sp<AMessage> &format) {
58    CHECK(mCodec == NULL);
59
60    ++mBufferGeneration;
61
62    AString mime;
63    CHECK(format->findString("mime", &mime));
64
65    sp<Surface> surface = NULL;
66    if (mNativeWindow != NULL) {
67        surface = mNativeWindow->getSurfaceTextureClient();
68    }
69
70    mComponentName = mime;
71    mComponentName.append(" decoder");
72    ALOGV("[%s] onConfigure (surface=%p)", mComponentName.c_str(), surface.get());
73
74    mCodec = MediaCodec::CreateByType(mCodecLooper, mime.c_str(), false /* encoder */);
75    if (mCodec == NULL) {
76        ALOGE("Failed to create %s decoder", mime.c_str());
77        handleError(UNKNOWN_ERROR);
78        return;
79    }
80
81    mCodec->getName(&mComponentName);
82
83    if (mNativeWindow != NULL) {
84        // disconnect from surface as MediaCodec will reconnect
85        CHECK_EQ((int)NO_ERROR,
86                native_window_api_disconnect(
87                        surface.get(),
88                        NATIVE_WINDOW_API_MEDIA));
89    }
90    status_t err = mCodec->configure(
91            format, surface, NULL /* crypto */, 0 /* flags */);
92    if (err != OK) {
93        ALOGE("Failed to configure %s decoder (err=%d)", mComponentName.c_str(), err);
94        handleError(err);
95        return;
96    }
97    // the following should work in configured state
98    CHECK_EQ((status_t)OK, mCodec->getOutputFormat(&mOutputFormat));
99    CHECK_EQ((status_t)OK, mCodec->getInputFormat(&mInputFormat));
100
101    err = mCodec->start();
102    if (err != OK) {
103        ALOGE("Failed to start %s decoder (err=%d)", mComponentName.c_str(), err);
104        handleError(err);
105        return;
106    }
107
108    // the following should work after start
109    CHECK_EQ((status_t)OK, mCodec->getInputBuffers(&mInputBuffers));
110    CHECK_EQ((status_t)OK, mCodec->getOutputBuffers(&mOutputBuffers));
111    ALOGV("[%s] got %zu input and %zu output buffers",
112            mComponentName.c_str(),
113            mInputBuffers.size(),
114            mOutputBuffers.size());
115
116    requestCodecNotification();
117    mPaused = false;
118}
119
120void NuPlayer::Decoder::requestCodecNotification() {
121    if (mCodec != NULL) {
122        sp<AMessage> reply = new AMessage(kWhatCodecNotify, id());
123        reply->setInt32("generation", mBufferGeneration);
124        mCodec->requestActivityNotification(reply);
125    }
126}
127
128bool NuPlayer::Decoder::isStaleReply(const sp<AMessage> &msg) {
129    int32_t generation;
130    CHECK(msg->findInt32("generation", &generation));
131    return generation != mBufferGeneration;
132}
133
134void NuPlayer::Decoder::init() {
135    mDecoderLooper->registerHandler(this);
136}
137
138void NuPlayer::Decoder::configure(const sp<AMessage> &format) {
139    sp<AMessage> msg = new AMessage(kWhatConfigure, id());
140    msg->setMessage("format", format);
141    msg->post();
142}
143
144void NuPlayer::Decoder::handleError(int32_t err)
145{
146    sp<AMessage> notify = mNotify->dup();
147    notify->setInt32("what", kWhatError);
148    notify->setInt32("err", err);
149    notify->post();
150}
151
152bool NuPlayer::Decoder::handleAnInputBuffer() {
153    size_t bufferIx = -1;
154    status_t res = mCodec->dequeueInputBuffer(&bufferIx);
155    ALOGV("[%s] dequeued input: %d",
156            mComponentName.c_str(), res == OK ? (int)bufferIx : res);
157    if (res != OK) {
158        if (res != -EAGAIN) {
159            handleError(res);
160        }
161        return false;
162    }
163
164    CHECK_LT(bufferIx, mInputBuffers.size());
165
166    sp<AMessage> reply = new AMessage(kWhatInputBufferFilled, id());
167    reply->setSize("buffer-ix", bufferIx);
168    reply->setInt32("generation", mBufferGeneration);
169
170    sp<AMessage> notify = mNotify->dup();
171    notify->setInt32("what", kWhatFillThisBuffer);
172    notify->setBuffer("buffer", mInputBuffers[bufferIx]);
173    notify->setMessage("reply", reply);
174    notify->post();
175    return true;
176}
177
178void android::NuPlayer::Decoder::onInputBufferFilled(const sp<AMessage> &msg) {
179    size_t bufferIx;
180    CHECK(msg->findSize("buffer-ix", &bufferIx));
181    CHECK_LT(bufferIx, mInputBuffers.size());
182    sp<ABuffer> codecBuffer = mInputBuffers[bufferIx];
183
184    sp<ABuffer> buffer;
185    bool hasBuffer = msg->findBuffer("buffer", &buffer);
186    if (buffer == NULL /* includes !hasBuffer */) {
187        int32_t streamErr = ERROR_END_OF_STREAM;
188        CHECK(msg->findInt32("err", &streamErr) || !hasBuffer);
189
190        if (streamErr == OK) {
191            /* buffers are returned to hold on to */
192            return;
193        }
194
195        // attempt to queue EOS
196        status_t err = mCodec->queueInputBuffer(
197                bufferIx,
198                0,
199                0,
200                0,
201                MediaCodec::BUFFER_FLAG_EOS);
202        if (streamErr == ERROR_END_OF_STREAM && err != OK) {
203            streamErr = err;
204            // err will not be ERROR_END_OF_STREAM
205        }
206
207        if (streamErr != ERROR_END_OF_STREAM) {
208            handleError(streamErr);
209        }
210    } else {
211        int64_t timeUs = 0;
212        uint32_t flags = 0;
213        CHECK(buffer->meta()->findInt64("timeUs", &timeUs));
214
215        int32_t eos;
216        // we do not expect CODECCONFIG or SYNCFRAME for decoder
217        if (buffer->meta()->findInt32("eos", &eos) && eos) {
218            flags |= MediaCodec::BUFFER_FLAG_EOS;
219        }
220
221        // copy into codec buffer
222        if (buffer != codecBuffer) {
223            CHECK_LE(buffer->size(), codecBuffer->capacity());
224            codecBuffer->setRange(0, buffer->size());
225            memcpy(codecBuffer->data(), buffer->data(), buffer->size());
226        }
227
228        status_t err = mCodec->queueInputBuffer(
229                        bufferIx,
230                        codecBuffer->offset(),
231                        codecBuffer->size(),
232                        timeUs,
233                        flags);
234        if (err != OK) {
235            ALOGE("Failed to queue input buffer for %s (err=%d)",
236                    mComponentName.c_str(), err);
237            handleError(err);
238        }
239    }
240}
241
242bool NuPlayer::Decoder::handleAnOutputBuffer() {
243    size_t bufferIx = -1;
244    size_t offset;
245    size_t size;
246    int64_t timeUs;
247    uint32_t flags;
248    status_t res = mCodec->dequeueOutputBuffer(
249            &bufferIx, &offset, &size, &timeUs, &flags);
250
251    if (res != OK) {
252        ALOGV("[%s] dequeued output: %d", mComponentName.c_str(), res);
253    } else {
254        ALOGV("[%s] dequeued output: %d (time=%lld flags=%" PRIu32 ")",
255                mComponentName.c_str(), (int)bufferIx, timeUs, flags);
256    }
257
258    if (res == INFO_OUTPUT_BUFFERS_CHANGED) {
259        res = mCodec->getOutputBuffers(&mOutputBuffers);
260        if (res != OK) {
261            ALOGE("Failed to get output buffers for %s after INFO event (err=%d)",
262                    mComponentName.c_str(), res);
263            handleError(res);
264            return false;
265        }
266        // NuPlayer ignores this
267        return true;
268    } else if (res == INFO_FORMAT_CHANGED) {
269        sp<AMessage> format = new AMessage();
270        res = mCodec->getOutputFormat(&format);
271        if (res != OK) {
272            ALOGE("Failed to get output format for %s after INFO event (err=%d)",
273                    mComponentName.c_str(), res);
274            handleError(res);
275            return false;
276        }
277
278        sp<AMessage> notify = mNotify->dup();
279        notify->setInt32("what", kWhatOutputFormatChanged);
280        notify->setMessage("format", format);
281        notify->post();
282        return true;
283    } else if (res == INFO_DISCONTINUITY) {
284        // nothing to do
285        return true;
286    } else if (res != OK) {
287        if (res != -EAGAIN) {
288            handleError(res);
289        }
290        return false;
291    }
292
293    CHECK_LT(bufferIx, mOutputBuffers.size());
294    sp<ABuffer> buffer = mOutputBuffers[bufferIx];
295    buffer->setRange(offset, size);
296    buffer->meta()->clear();
297    buffer->meta()->setInt64("timeUs", timeUs);
298    if (flags & MediaCodec::BUFFER_FLAG_EOS) {
299        buffer->meta()->setInt32("eos", true);
300    }
301    // we do not expect CODECCONFIG or SYNCFRAME for decoder
302
303    sp<AMessage> reply = new AMessage(kWhatRenderBuffer, id());
304    reply->setSize("buffer-ix", bufferIx);
305    reply->setInt32("generation", mBufferGeneration);
306
307    sp<AMessage> notify = mNotify->dup();
308    notify->setInt32("what", kWhatDrainThisBuffer);
309    notify->setBuffer("buffer", buffer);
310    notify->setMessage("reply", reply);
311    notify->post();
312
313    // FIXME: This should be handled after rendering is complete,
314    // but Renderer needs it now
315    if (flags & MediaCodec::BUFFER_FLAG_EOS) {
316        ALOGV("queueing eos [%s]", mComponentName.c_str());
317        sp<AMessage> notify = mNotify->dup();
318        notify->setInt32("what", kWhatEOS);
319        notify->setInt32("err", ERROR_END_OF_STREAM);
320        notify->post();
321    }
322    return true;
323}
324
325void NuPlayer::Decoder::onRenderBuffer(const sp<AMessage> &msg) {
326    status_t err;
327    int32_t render;
328    size_t bufferIx;
329    CHECK(msg->findSize("buffer-ix", &bufferIx));
330    if (msg->findInt32("render", &render) && render) {
331        err = mCodec->renderOutputBufferAndRelease(bufferIx);
332    } else {
333        err = mCodec->releaseOutputBuffer(bufferIx);
334    }
335    if (err != OK) {
336        ALOGE("failed to release output buffer for %s (err=%d)",
337                mComponentName.c_str(), err);
338        handleError(err);
339    }
340}
341
342void NuPlayer::Decoder::onFlush() {
343    status_t err = OK;
344    if (mCodec != NULL) {
345        err = mCodec->flush();
346        ++mBufferGeneration;
347    }
348
349    if (err != OK) {
350        ALOGE("failed to flush %s (err=%d)", mComponentName.c_str(), err);
351        handleError(err);
352        return;
353    }
354
355    sp<AMessage> notify = mNotify->dup();
356    notify->setInt32("what", kWhatFlushCompleted);
357    notify->post();
358    mPaused = true;
359}
360
361void NuPlayer::Decoder::onResume() {
362    mPaused = false;
363}
364
365void NuPlayer::Decoder::onShutdown() {
366    status_t err = OK;
367    if (mCodec != NULL) {
368        err = mCodec->release();
369        mCodec = NULL;
370        ++mBufferGeneration;
371
372        if (mNativeWindow != NULL) {
373            // reconnect to surface as MediaCodec disconnected from it
374            CHECK_EQ((int)NO_ERROR,
375                    native_window_api_connect(
376                            mNativeWindow->getNativeWindow().get(),
377                            NATIVE_WINDOW_API_MEDIA));
378        }
379        mComponentName = "decoder";
380    }
381
382    if (err != OK) {
383        ALOGE("failed to release %s (err=%d)", mComponentName.c_str(), err);
384        handleError(err);
385        return;
386    }
387
388    sp<AMessage> notify = mNotify->dup();
389    notify->setInt32("what", kWhatShutdownCompleted);
390    notify->post();
391    mPaused = true;
392}
393
394void NuPlayer::Decoder::onMessageReceived(const sp<AMessage> &msg) {
395    ALOGV("[%s] onMessage: %s", mComponentName.c_str(), msg->debugString().c_str());
396
397    switch (msg->what()) {
398        case kWhatConfigure:
399        {
400            sp<AMessage> format;
401            CHECK(msg->findMessage("format", &format));
402            onConfigure(format);
403            break;
404        }
405
406        case kWhatCodecNotify:
407        {
408            if (!isStaleReply(msg)) {
409                if (!mPaused) {
410                    while (handleAnInputBuffer()) {
411                    }
412                }
413
414                while (handleAnOutputBuffer()) {
415                }
416            }
417
418            requestCodecNotification();
419            break;
420        }
421
422        case kWhatInputBufferFilled:
423        {
424            if (!isStaleReply(msg)) {
425                onInputBufferFilled(msg);
426            }
427            break;
428        }
429
430        case kWhatRenderBuffer:
431        {
432            if (!isStaleReply(msg)) {
433                onRenderBuffer(msg);
434            }
435            break;
436        }
437
438        case kWhatFlush:
439        {
440            onFlush();
441            break;
442        }
443
444        case kWhatResume:
445        {
446            onResume();
447            break;
448        }
449
450        case kWhatShutdown:
451        {
452            onShutdown();
453            break;
454        }
455
456        default:
457            TRESPASS();
458            break;
459    }
460}
461
462void NuPlayer::Decoder::signalFlush() {
463    (new AMessage(kWhatFlush, id()))->post();
464}
465
466void NuPlayer::Decoder::signalResume() {
467    (new AMessage(kWhatResume, id()))->post();
468}
469
470void NuPlayer::Decoder::initiateShutdown() {
471    (new AMessage(kWhatShutdown, id()))->post();
472}
473
474bool NuPlayer::Decoder::supportsSeamlessAudioFormatChange(const sp<AMessage> &targetFormat) const {
475    if (targetFormat == NULL) {
476        return true;
477    }
478
479    AString mime;
480    if (!targetFormat->findString("mime", &mime)) {
481        return false;
482    }
483
484    if (!strcasecmp(mime.c_str(), MEDIA_MIMETYPE_AUDIO_AAC)) {
485        // field-by-field comparison
486        const char * keys[] = { "channel-count", "sample-rate", "is-adts" };
487        for (unsigned int i = 0; i < sizeof(keys) / sizeof(keys[0]); i++) {
488            int32_t oldVal, newVal;
489            if (!mOutputFormat->findInt32(keys[i], &oldVal) ||
490                    !targetFormat->findInt32(keys[i], &newVal) ||
491                    oldVal != newVal) {
492                return false;
493            }
494        }
495
496        sp<ABuffer> oldBuf, newBuf;
497        if (mOutputFormat->findBuffer("csd-0", &oldBuf) &&
498                targetFormat->findBuffer("csd-0", &newBuf)) {
499            if (oldBuf->size() != newBuf->size()) {
500                return false;
501            }
502            return !memcmp(oldBuf->data(), newBuf->data(), oldBuf->size());
503        }
504    }
505    return false;
506}
507
508bool NuPlayer::Decoder::supportsSeamlessFormatChange(const sp<AMessage> &targetFormat) const {
509    if (mOutputFormat == NULL) {
510        return false;
511    }
512
513    if (targetFormat == NULL) {
514        return true;
515    }
516
517    AString oldMime, newMime;
518    if (!mOutputFormat->findString("mime", &oldMime)
519            || !targetFormat->findString("mime", &newMime)
520            || !(oldMime == newMime)) {
521        return false;
522    }
523
524    bool audio = !strncasecmp(oldMime.c_str(), "audio/", strlen("audio/"));
525    bool seamless;
526    if (audio) {
527        seamless = supportsSeamlessAudioFormatChange(targetFormat);
528    } else {
529        int32_t isAdaptive;
530        seamless = (mCodec != NULL &&
531                mInputFormat->findInt32("adaptive-playback", &isAdaptive) &&
532                isAdaptive);
533    }
534
535    ALOGV("%s seamless support for %s", seamless ? "yes" : "no", oldMime.c_str());
536    return seamless;
537}
538
539struct NuPlayer::CCDecoder::CCData {
540    CCData(uint8_t type, uint8_t data1, uint8_t data2)
541        : mType(type), mData1(data1), mData2(data2) {
542    }
543
544    uint8_t mType;
545    uint8_t mData1;
546    uint8_t mData2;
547};
548
549NuPlayer::CCDecoder::CCDecoder(const sp<AMessage> &notify)
550    : mNotify(notify),
551      mTrackCount(0),
552      mSelectedTrack(-1) {
553}
554
555size_t NuPlayer::CCDecoder::getTrackCount() const {
556    return mTrackCount;
557}
558
559sp<AMessage> NuPlayer::CCDecoder::getTrackInfo(size_t index) const {
560    CHECK(index == 0);
561
562    sp<AMessage> format = new AMessage();
563
564    format->setInt32("type", MEDIA_TRACK_TYPE_SUBTITLE);
565    format->setString("language", "und");
566    format->setString("mime", MEDIA_MIMETYPE_TEXT_CEA_608);
567    format->setInt32("auto", 1);
568    format->setInt32("default", 1);
569    format->setInt32("forced", 0);
570
571    return format;
572}
573
574status_t NuPlayer::CCDecoder::selectTrack(size_t index, bool select) {
575    CHECK(index < mTrackCount);
576
577    if (select) {
578        if (mSelectedTrack == (ssize_t)index) {
579            ALOGE("track %zu already selected", index);
580            return BAD_VALUE;
581        }
582        ALOGV("selected track %zu", index);
583        mSelectedTrack = index;
584    } else {
585        if (mSelectedTrack != (ssize_t)index) {
586            ALOGE("track %zu is not selected", index);
587            return BAD_VALUE;
588        }
589        ALOGV("unselected track %zu", index);
590        mSelectedTrack = -1;
591    }
592
593    return OK;
594}
595
596bool NuPlayer::CCDecoder::isSelected() const {
597    return mSelectedTrack >= 0 && mSelectedTrack < (int32_t)mTrackCount;
598}
599
600bool NuPlayer::CCDecoder::isNullPad(CCData *cc) const {
601    return cc->mData1 < 0x10 && cc->mData2 < 0x10;
602}
603
604void NuPlayer::CCDecoder::dumpBytePair(const sp<ABuffer> &ccBuf) const {
605    size_t offset = 0;
606    AString out;
607
608    while (offset < ccBuf->size()) {
609        char tmp[128];
610
611        CCData *cc = (CCData *) (ccBuf->data() + offset);
612
613        if (isNullPad(cc)) {
614            // 1 null pad or XDS metadata, ignore
615            offset += sizeof(CCData);
616            continue;
617        }
618
619        if (cc->mData1 >= 0x20 && cc->mData1 <= 0x7f) {
620            // 2 basic chars
621            sprintf(tmp, "[%d]Basic: %c %c", cc->mType, cc->mData1, cc->mData2);
622        } else if ((cc->mData1 == 0x11 || cc->mData1 == 0x19)
623                 && cc->mData2 >= 0x30 && cc->mData2 <= 0x3f) {
624            // 1 special char
625            sprintf(tmp, "[%d]Special: %02x %02x", cc->mType, cc->mData1, cc->mData2);
626        } else if ((cc->mData1 == 0x12 || cc->mData1 == 0x1A)
627                 && cc->mData2 >= 0x20 && cc->mData2 <= 0x3f){
628            // 1 Spanish/French char
629            sprintf(tmp, "[%d]Spanish: %02x %02x", cc->mType, cc->mData1, cc->mData2);
630        } else if ((cc->mData1 == 0x13 || cc->mData1 == 0x1B)
631                 && cc->mData2 >= 0x20 && cc->mData2 <= 0x3f){
632            // 1 Portuguese/German/Danish char
633            sprintf(tmp, "[%d]German: %02x %02x", cc->mType, cc->mData1, cc->mData2);
634        } else if ((cc->mData1 == 0x11 || cc->mData1 == 0x19)
635                 && cc->mData2 >= 0x20 && cc->mData2 <= 0x2f){
636            // Mid-Row Codes (Table 69)
637            sprintf(tmp, "[%d]Mid-row: %02x %02x", cc->mType, cc->mData1, cc->mData2);
638        } else if (((cc->mData1 == 0x14 || cc->mData1 == 0x1c)
639                  && cc->mData2 >= 0x20 && cc->mData2 <= 0x2f)
640                  ||
641                   ((cc->mData1 == 0x17 || cc->mData1 == 0x1f)
642                  && cc->mData2 >= 0x21 && cc->mData2 <= 0x23)){
643            // Misc Control Codes (Table 70)
644            sprintf(tmp, "[%d]Ctrl: %02x %02x", cc->mType, cc->mData1, cc->mData2);
645        } else if ((cc->mData1 & 0x70) == 0x10
646                && (cc->mData2 & 0x40) == 0x40
647                && ((cc->mData1 & 0x07) || !(cc->mData2 & 0x20)) ) {
648            // Preamble Address Codes (Table 71)
649            sprintf(tmp, "[%d]PAC: %02x %02x", cc->mType, cc->mData1, cc->mData2);
650        } else {
651            sprintf(tmp, "[%d]Invalid: %02x %02x", cc->mType, cc->mData1, cc->mData2);
652        }
653
654        if (out.size() > 0) {
655            out.append(", ");
656        }
657
658        out.append(tmp);
659
660        offset += sizeof(CCData);
661    }
662
663    ALOGI("%s", out.c_str());
664}
665
666bool NuPlayer::CCDecoder::extractFromSEI(const sp<ABuffer> &accessUnit) {
667    int64_t timeUs;
668    CHECK(accessUnit->meta()->findInt64("timeUs", &timeUs));
669
670    sp<ABuffer> sei;
671    if (!accessUnit->meta()->findBuffer("sei", &sei) || sei == NULL) {
672        return false;
673    }
674
675    bool hasCC = false;
676
677    NALBitReader br(sei->data() + 1, sei->size() - 1);
678    // sei_message()
679    while (br.atLeastNumBitsLeft(16)) { // at least 16-bit for sei_message()
680        uint32_t payload_type = 0;
681        size_t payload_size = 0;
682        uint8_t last_byte;
683
684        do {
685            last_byte = br.getBits(8);
686            payload_type += last_byte;
687        } while (last_byte == 0xFF);
688
689        do {
690            last_byte = br.getBits(8);
691            payload_size += last_byte;
692        } while (last_byte == 0xFF);
693
694        // sei_payload()
695        if (payload_type == 4) {
696            // user_data_registered_itu_t_t35()
697
698            // ATSC A/72: 6.4.2
699            uint8_t itu_t_t35_country_code = br.getBits(8);
700            uint16_t itu_t_t35_provider_code = br.getBits(16);
701            uint32_t user_identifier = br.getBits(32);
702            uint8_t user_data_type_code = br.getBits(8);
703
704            payload_size -= 1 + 2 + 4 + 1;
705
706            if (itu_t_t35_country_code == 0xB5
707                    && itu_t_t35_provider_code == 0x0031
708                    && user_identifier == 'GA94'
709                    && user_data_type_code == 0x3) {
710                hasCC = true;
711
712                // MPEG_cc_data()
713                // ATSC A/53 Part 4: 6.2.3.1
714                br.skipBits(1); //process_em_data_flag
715                bool process_cc_data_flag = br.getBits(1);
716                br.skipBits(1); //additional_data_flag
717                size_t cc_count = br.getBits(5);
718                br.skipBits(8); // em_data;
719                payload_size -= 2;
720
721                if (process_cc_data_flag) {
722                    AString out;
723
724                    sp<ABuffer> ccBuf = new ABuffer(cc_count * sizeof(CCData));
725                    ccBuf->setRange(0, 0);
726
727                    for (size_t i = 0; i < cc_count; i++) {
728                        uint8_t marker = br.getBits(5);
729                        CHECK_EQ(marker, 0x1f);
730
731                        bool cc_valid = br.getBits(1);
732                        uint8_t cc_type = br.getBits(2);
733                        // remove odd parity bit
734                        uint8_t cc_data_1 = br.getBits(8) & 0x7f;
735                        uint8_t cc_data_2 = br.getBits(8) & 0x7f;
736
737                        if (cc_valid
738                                && (cc_type == 0 || cc_type == 1)) {
739                            CCData cc(cc_type, cc_data_1, cc_data_2);
740                            if (!isNullPad(&cc)) {
741                                memcpy(ccBuf->data() + ccBuf->size(),
742                                        (void *)&cc, sizeof(cc));
743                                ccBuf->setRange(0, ccBuf->size() + sizeof(CCData));
744                            }
745                        }
746                    }
747                    payload_size -= cc_count * 3;
748
749                    mCCMap.add(timeUs, ccBuf);
750                    break;
751                }
752            } else {
753                ALOGV("Malformed SEI payload type 4");
754            }
755        } else {
756            ALOGV("Unsupported SEI payload type %d", payload_type);
757        }
758
759        // skipping remaining bits of this payload
760        br.skipBits(payload_size * 8);
761    }
762
763    return hasCC;
764}
765
766void NuPlayer::CCDecoder::decode(const sp<ABuffer> &accessUnit) {
767    if (extractFromSEI(accessUnit) && mTrackCount == 0) {
768        mTrackCount++;
769
770        ALOGI("Found CEA-608 track");
771        sp<AMessage> msg = mNotify->dup();
772        msg->setInt32("what", kWhatTrackAdded);
773        msg->post();
774    }
775    // TODO: extract CC from other sources
776}
777
778void NuPlayer::CCDecoder::display(int64_t timeUs) {
779    ssize_t index = mCCMap.indexOfKey(timeUs);
780    if (index < 0) {
781        ALOGV("cc for timestamp %" PRId64 " not found", timeUs);
782        return;
783    }
784
785    sp<ABuffer> &ccBuf = mCCMap.editValueAt(index);
786
787    if (ccBuf->size() > 0) {
788#if 0
789        dumpBytePair(ccBuf);
790#endif
791
792        ccBuf->meta()->setInt32("trackIndex", mSelectedTrack);
793        ccBuf->meta()->setInt64("timeUs", timeUs);
794        ccBuf->meta()->setInt64("durationUs", 0ll);
795
796        sp<AMessage> msg = mNotify->dup();
797        msg->setInt32("what", kWhatClosedCaptionData);
798        msg->setBuffer("buffer", ccBuf);
799        msg->post();
800    }
801
802    // remove all entries before timeUs
803    mCCMap.removeItemsAt(0, index + 1);
804}
805
806}  // namespace android
807
808