1*ec779b8eSAndroid Build Coastguard Worker /*
2*ec779b8eSAndroid Build Coastguard Worker * Copyright 2014 The Android Open Source Project
3*ec779b8eSAndroid Build Coastguard Worker *
4*ec779b8eSAndroid Build Coastguard Worker * Licensed under the Apache License, Version 2.0 (the "License");
5*ec779b8eSAndroid Build Coastguard Worker * you may not use this file except in compliance with the License.
6*ec779b8eSAndroid Build Coastguard Worker * You may obtain a copy of the License at
7*ec779b8eSAndroid Build Coastguard Worker *
8*ec779b8eSAndroid Build Coastguard Worker * http://www.apache.org/licenses/LICENSE-2.0
9*ec779b8eSAndroid Build Coastguard Worker *
10*ec779b8eSAndroid Build Coastguard Worker * Unless required by applicable law or agreed to in writing, software
11*ec779b8eSAndroid Build Coastguard Worker * distributed under the License is distributed on an "AS IS" BASIS,
12*ec779b8eSAndroid Build Coastguard Worker * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13*ec779b8eSAndroid Build Coastguard Worker * See the License for the specific language governing permissions and
14*ec779b8eSAndroid Build Coastguard Worker * limitations under the License.
15*ec779b8eSAndroid Build Coastguard Worker */
16*ec779b8eSAndroid Build Coastguard Worker
17*ec779b8eSAndroid Build Coastguard Worker //#define LOG_NDEBUG 0
18*ec779b8eSAndroid Build Coastguard Worker #define LOG_TAG "NuPlayerCCDecoder"
19*ec779b8eSAndroid Build Coastguard Worker #include <utils/Log.h>
20*ec779b8eSAndroid Build Coastguard Worker #include <inttypes.h>
21*ec779b8eSAndroid Build Coastguard Worker
22*ec779b8eSAndroid Build Coastguard Worker #include "NuPlayerCCDecoder.h"
23*ec779b8eSAndroid Build Coastguard Worker
24*ec779b8eSAndroid Build Coastguard Worker #include <media/stagefright/foundation/ABitReader.h>
25*ec779b8eSAndroid Build Coastguard Worker #include <media/stagefright/foundation/ABuffer.h>
26*ec779b8eSAndroid Build Coastguard Worker #include <media/stagefright/foundation/ADebug.h>
27*ec779b8eSAndroid Build Coastguard Worker #include <media/stagefright/foundation/AMessage.h>
28*ec779b8eSAndroid Build Coastguard Worker #include <media/stagefright/foundation/avc_utils.h>
29*ec779b8eSAndroid Build Coastguard Worker #include <media/stagefright/MediaDefs.h>
30*ec779b8eSAndroid Build Coastguard Worker
31*ec779b8eSAndroid Build Coastguard Worker namespace android {
32*ec779b8eSAndroid Build Coastguard Worker
33*ec779b8eSAndroid Build Coastguard Worker // In CEA-708B, the maximum bandwidth of CC is set to 9600bps.
34*ec779b8eSAndroid Build Coastguard Worker static const size_t kMaxBandwithSizeBytes = 9600 / 8;
35*ec779b8eSAndroid Build Coastguard Worker
36*ec779b8eSAndroid Build Coastguard Worker struct CCData {
CCDataandroid::CCData37*ec779b8eSAndroid Build Coastguard Worker CCData(uint8_t type, uint8_t data1, uint8_t data2)
38*ec779b8eSAndroid Build Coastguard Worker : mType(type), mData1(data1), mData2(data2) {
39*ec779b8eSAndroid Build Coastguard Worker }
getChannelandroid::CCData40*ec779b8eSAndroid Build Coastguard Worker bool getChannel(size_t *channel) const {
41*ec779b8eSAndroid Build Coastguard Worker if (mData1 >= 0x10 && mData1 <= 0x1f) {
42*ec779b8eSAndroid Build Coastguard Worker *channel = (mData1 >= 0x18 ? 1 : 0) + (mType ? 2 : 0);
43*ec779b8eSAndroid Build Coastguard Worker return true;
44*ec779b8eSAndroid Build Coastguard Worker }
45*ec779b8eSAndroid Build Coastguard Worker return false;
46*ec779b8eSAndroid Build Coastguard Worker }
47*ec779b8eSAndroid Build Coastguard Worker
48*ec779b8eSAndroid Build Coastguard Worker uint8_t mType;
49*ec779b8eSAndroid Build Coastguard Worker uint8_t mData1;
50*ec779b8eSAndroid Build Coastguard Worker uint8_t mData2;
51*ec779b8eSAndroid Build Coastguard Worker };
52*ec779b8eSAndroid Build Coastguard Worker
isNullPad(CCData * cc)53*ec779b8eSAndroid Build Coastguard Worker static bool isNullPad(CCData *cc) {
54*ec779b8eSAndroid Build Coastguard Worker return cc->mData1 < 0x10 && cc->mData2 < 0x10;
55*ec779b8eSAndroid Build Coastguard Worker }
56*ec779b8eSAndroid Build Coastguard Worker
57*ec779b8eSAndroid Build Coastguard Worker static void dumpBytePair(const sp<ABuffer> &ccBuf) __attribute__ ((unused));
dumpBytePair(const sp<ABuffer> & ccBuf)58*ec779b8eSAndroid Build Coastguard Worker static void dumpBytePair(const sp<ABuffer> &ccBuf) {
59*ec779b8eSAndroid Build Coastguard Worker size_t offset = 0;
60*ec779b8eSAndroid Build Coastguard Worker AString out;
61*ec779b8eSAndroid Build Coastguard Worker
62*ec779b8eSAndroid Build Coastguard Worker while (offset < ccBuf->size()) {
63*ec779b8eSAndroid Build Coastguard Worker char tmp[128];
64*ec779b8eSAndroid Build Coastguard Worker
65*ec779b8eSAndroid Build Coastguard Worker CCData *cc = (CCData *) (ccBuf->data() + offset);
66*ec779b8eSAndroid Build Coastguard Worker
67*ec779b8eSAndroid Build Coastguard Worker if (isNullPad(cc)) {
68*ec779b8eSAndroid Build Coastguard Worker // 1 null pad or XDS metadata, ignore
69*ec779b8eSAndroid Build Coastguard Worker offset += sizeof(CCData);
70*ec779b8eSAndroid Build Coastguard Worker continue;
71*ec779b8eSAndroid Build Coastguard Worker }
72*ec779b8eSAndroid Build Coastguard Worker
73*ec779b8eSAndroid Build Coastguard Worker if (cc->mData1 >= 0x20 && cc->mData1 <= 0x7f) {
74*ec779b8eSAndroid Build Coastguard Worker // 2 basic chars
75*ec779b8eSAndroid Build Coastguard Worker snprintf(tmp, sizeof(tmp), "[%d]Basic: %c %c", cc->mType, cc->mData1, cc->mData2);
76*ec779b8eSAndroid Build Coastguard Worker } else if ((cc->mData1 == 0x11 || cc->mData1 == 0x19)
77*ec779b8eSAndroid Build Coastguard Worker && cc->mData2 >= 0x30 && cc->mData2 <= 0x3f) {
78*ec779b8eSAndroid Build Coastguard Worker // 1 special char
79*ec779b8eSAndroid Build Coastguard Worker snprintf(tmp, sizeof(tmp), "[%d]Special: %02x %02x", cc->mType, cc->mData1, cc->mData2);
80*ec779b8eSAndroid Build Coastguard Worker } else if ((cc->mData1 == 0x12 || cc->mData1 == 0x1A)
81*ec779b8eSAndroid Build Coastguard Worker && cc->mData2 >= 0x20 && cc->mData2 <= 0x3f){
82*ec779b8eSAndroid Build Coastguard Worker // 1 Spanish/French char
83*ec779b8eSAndroid Build Coastguard Worker snprintf(tmp, sizeof(tmp), "[%d]Spanish: %02x %02x", cc->mType, cc->mData1, cc->mData2);
84*ec779b8eSAndroid Build Coastguard Worker } else if ((cc->mData1 == 0x13 || cc->mData1 == 0x1B)
85*ec779b8eSAndroid Build Coastguard Worker && cc->mData2 >= 0x20 && cc->mData2 <= 0x3f){
86*ec779b8eSAndroid Build Coastguard Worker // 1 Portuguese/German/Danish char
87*ec779b8eSAndroid Build Coastguard Worker snprintf(tmp, sizeof(tmp), "[%d]German: %02x %02x", cc->mType, cc->mData1, cc->mData2);
88*ec779b8eSAndroid Build Coastguard Worker } else if ((cc->mData1 == 0x11 || cc->mData1 == 0x19)
89*ec779b8eSAndroid Build Coastguard Worker && cc->mData2 >= 0x20 && cc->mData2 <= 0x2f){
90*ec779b8eSAndroid Build Coastguard Worker // Mid-Row Codes (Table 69)
91*ec779b8eSAndroid Build Coastguard Worker snprintf(tmp, sizeof(tmp), "[%d]Mid-row: %02x %02x", cc->mType, cc->mData1, cc->mData2);
92*ec779b8eSAndroid Build Coastguard Worker } else if (((cc->mData1 == 0x14 || cc->mData1 == 0x1c)
93*ec779b8eSAndroid Build Coastguard Worker && cc->mData2 >= 0x20 && cc->mData2 <= 0x2f)
94*ec779b8eSAndroid Build Coastguard Worker ||
95*ec779b8eSAndroid Build Coastguard Worker ((cc->mData1 == 0x17 || cc->mData1 == 0x1f)
96*ec779b8eSAndroid Build Coastguard Worker && cc->mData2 >= 0x21 && cc->mData2 <= 0x23)){
97*ec779b8eSAndroid Build Coastguard Worker // Misc Control Codes (Table 70)
98*ec779b8eSAndroid Build Coastguard Worker snprintf(tmp, sizeof(tmp), "[%d]Ctrl: %02x %02x", cc->mType, cc->mData1, cc->mData2);
99*ec779b8eSAndroid Build Coastguard Worker } else if ((cc->mData1 & 0x70) == 0x10
100*ec779b8eSAndroid Build Coastguard Worker && (cc->mData2 & 0x40) == 0x40
101*ec779b8eSAndroid Build Coastguard Worker && ((cc->mData1 & 0x07) || !(cc->mData2 & 0x20)) ) {
102*ec779b8eSAndroid Build Coastguard Worker // Preamble Address Codes (Table 71)
103*ec779b8eSAndroid Build Coastguard Worker snprintf(tmp, sizeof(tmp), "[%d]PAC: %02x %02x", cc->mType, cc->mData1, cc->mData2);
104*ec779b8eSAndroid Build Coastguard Worker } else {
105*ec779b8eSAndroid Build Coastguard Worker snprintf(tmp, sizeof(tmp), "[%d]Invalid: %02x %02x", cc->mType, cc->mData1, cc->mData2);
106*ec779b8eSAndroid Build Coastguard Worker }
107*ec779b8eSAndroid Build Coastguard Worker
108*ec779b8eSAndroid Build Coastguard Worker if (out.size() > 0) {
109*ec779b8eSAndroid Build Coastguard Worker out.append(", ");
110*ec779b8eSAndroid Build Coastguard Worker }
111*ec779b8eSAndroid Build Coastguard Worker
112*ec779b8eSAndroid Build Coastguard Worker out.append(tmp);
113*ec779b8eSAndroid Build Coastguard Worker
114*ec779b8eSAndroid Build Coastguard Worker offset += sizeof(CCData);
115*ec779b8eSAndroid Build Coastguard Worker }
116*ec779b8eSAndroid Build Coastguard Worker
117*ec779b8eSAndroid Build Coastguard Worker ALOGI("%s", out.c_str());
118*ec779b8eSAndroid Build Coastguard Worker }
119*ec779b8eSAndroid Build Coastguard Worker
CCDecoder(const sp<AMessage> & notify)120*ec779b8eSAndroid Build Coastguard Worker NuPlayer::CCDecoder::CCDecoder(const sp<AMessage> ¬ify)
121*ec779b8eSAndroid Build Coastguard Worker : mNotify(notify),
122*ec779b8eSAndroid Build Coastguard Worker mSelectedTrack(-1),
123*ec779b8eSAndroid Build Coastguard Worker mDTVCCPacket(new ABuffer(kMaxBandwithSizeBytes)) {
124*ec779b8eSAndroid Build Coastguard Worker mDTVCCPacket->setRange(0, 0);
125*ec779b8eSAndroid Build Coastguard Worker
126*ec779b8eSAndroid Build Coastguard Worker // In CEA-608, streams from packets which have the value 0 of cc_type contain CC1 and CC2, and
127*ec779b8eSAndroid Build Coastguard Worker // streams from packets which have the value 1 of cc_type contain CC3 and CC4.
128*ec779b8eSAndroid Build Coastguard Worker // The following array indicates the current transmitting channels for each value of cc_type.
129*ec779b8eSAndroid Build Coastguard Worker mLine21Channels[0] = 0; // CC1
130*ec779b8eSAndroid Build Coastguard Worker mLine21Channels[1] = 2; // CC3
131*ec779b8eSAndroid Build Coastguard Worker }
132*ec779b8eSAndroid Build Coastguard Worker
getTrackCount() const133*ec779b8eSAndroid Build Coastguard Worker size_t NuPlayer::CCDecoder::getTrackCount() const {
134*ec779b8eSAndroid Build Coastguard Worker return mTracks.size();
135*ec779b8eSAndroid Build Coastguard Worker }
136*ec779b8eSAndroid Build Coastguard Worker
getTrackInfo(size_t index) const137*ec779b8eSAndroid Build Coastguard Worker sp<AMessage> NuPlayer::CCDecoder::getTrackInfo(size_t index) const {
138*ec779b8eSAndroid Build Coastguard Worker if (!isTrackValid(index)) {
139*ec779b8eSAndroid Build Coastguard Worker return NULL;
140*ec779b8eSAndroid Build Coastguard Worker }
141*ec779b8eSAndroid Build Coastguard Worker
142*ec779b8eSAndroid Build Coastguard Worker sp<AMessage> format = new AMessage();
143*ec779b8eSAndroid Build Coastguard Worker
144*ec779b8eSAndroid Build Coastguard Worker CCTrack track = mTracks[index];
145*ec779b8eSAndroid Build Coastguard Worker
146*ec779b8eSAndroid Build Coastguard Worker format->setInt32("type", MEDIA_TRACK_TYPE_SUBTITLE);
147*ec779b8eSAndroid Build Coastguard Worker format->setString("language", "und");
148*ec779b8eSAndroid Build Coastguard Worker
149*ec779b8eSAndroid Build Coastguard Worker switch (track.mTrackType) {
150*ec779b8eSAndroid Build Coastguard Worker case kTrackTypeCEA608:
151*ec779b8eSAndroid Build Coastguard Worker format->setString("mime", MEDIA_MIMETYPE_TEXT_CEA_608);
152*ec779b8eSAndroid Build Coastguard Worker break;
153*ec779b8eSAndroid Build Coastguard Worker case kTrackTypeCEA708:
154*ec779b8eSAndroid Build Coastguard Worker format->setString("mime", MEDIA_MIMETYPE_TEXT_CEA_708);
155*ec779b8eSAndroid Build Coastguard Worker break;
156*ec779b8eSAndroid Build Coastguard Worker default:
157*ec779b8eSAndroid Build Coastguard Worker ALOGE("Unknown track type: %d", track.mTrackType);
158*ec779b8eSAndroid Build Coastguard Worker format->setInt32("type", MEDIA_TRACK_TYPE_UNKNOWN);
159*ec779b8eSAndroid Build Coastguard Worker format->setString("mime", "application/octet-stream");
160*ec779b8eSAndroid Build Coastguard Worker return format;
161*ec779b8eSAndroid Build Coastguard Worker }
162*ec779b8eSAndroid Build Coastguard Worker
163*ec779b8eSAndroid Build Coastguard Worker // For CEA-608 CC1, field 0 channel 0
164*ec779b8eSAndroid Build Coastguard Worker bool isDefaultAuto = track.mTrackType == kTrackTypeCEA608
165*ec779b8eSAndroid Build Coastguard Worker && track.mTrackChannel == 0;
166*ec779b8eSAndroid Build Coastguard Worker // For CEA-708, Primary Caption Service.
167*ec779b8eSAndroid Build Coastguard Worker bool isDefaultOnly = track.mTrackType == kTrackTypeCEA708
168*ec779b8eSAndroid Build Coastguard Worker && track.mTrackChannel == 1;
169*ec779b8eSAndroid Build Coastguard Worker format->setInt32("auto", isDefaultAuto);
170*ec779b8eSAndroid Build Coastguard Worker format->setInt32("default", isDefaultAuto || isDefaultOnly);
171*ec779b8eSAndroid Build Coastguard Worker format->setInt32("forced", 0);
172*ec779b8eSAndroid Build Coastguard Worker
173*ec779b8eSAndroid Build Coastguard Worker return format;
174*ec779b8eSAndroid Build Coastguard Worker }
175*ec779b8eSAndroid Build Coastguard Worker
selectTrack(size_t index,bool select)176*ec779b8eSAndroid Build Coastguard Worker status_t NuPlayer::CCDecoder::selectTrack(size_t index, bool select) {
177*ec779b8eSAndroid Build Coastguard Worker if (!isTrackValid(index)) {
178*ec779b8eSAndroid Build Coastguard Worker return BAD_VALUE;
179*ec779b8eSAndroid Build Coastguard Worker }
180*ec779b8eSAndroid Build Coastguard Worker
181*ec779b8eSAndroid Build Coastguard Worker if (select) {
182*ec779b8eSAndroid Build Coastguard Worker if (mSelectedTrack == (ssize_t)index) {
183*ec779b8eSAndroid Build Coastguard Worker ALOGE("track %zu already selected", index);
184*ec779b8eSAndroid Build Coastguard Worker return BAD_VALUE;
185*ec779b8eSAndroid Build Coastguard Worker }
186*ec779b8eSAndroid Build Coastguard Worker ALOGV("selected track %zu", index);
187*ec779b8eSAndroid Build Coastguard Worker mSelectedTrack = index;
188*ec779b8eSAndroid Build Coastguard Worker } else {
189*ec779b8eSAndroid Build Coastguard Worker if (mSelectedTrack != (ssize_t)index) {
190*ec779b8eSAndroid Build Coastguard Worker ALOGE("track %zu is not selected", index);
191*ec779b8eSAndroid Build Coastguard Worker return BAD_VALUE;
192*ec779b8eSAndroid Build Coastguard Worker }
193*ec779b8eSAndroid Build Coastguard Worker ALOGV("unselected track %zu", index);
194*ec779b8eSAndroid Build Coastguard Worker mSelectedTrack = -1;
195*ec779b8eSAndroid Build Coastguard Worker }
196*ec779b8eSAndroid Build Coastguard Worker
197*ec779b8eSAndroid Build Coastguard Worker // Clear the previous track payloads
198*ec779b8eSAndroid Build Coastguard Worker mCCMap.clear();
199*ec779b8eSAndroid Build Coastguard Worker
200*ec779b8eSAndroid Build Coastguard Worker return OK;
201*ec779b8eSAndroid Build Coastguard Worker }
202*ec779b8eSAndroid Build Coastguard Worker
getSelectedTrack(media_track_type type) const203*ec779b8eSAndroid Build Coastguard Worker ssize_t NuPlayer::CCDecoder::getSelectedTrack(media_track_type type) const {
204*ec779b8eSAndroid Build Coastguard Worker if (mSelectedTrack != -1) {
205*ec779b8eSAndroid Build Coastguard Worker CCTrack track = mTracks[mSelectedTrack];
206*ec779b8eSAndroid Build Coastguard Worker if (track.mTrackType == kTrackTypeCEA608 || track.mTrackType == kTrackTypeCEA708) {
207*ec779b8eSAndroid Build Coastguard Worker return (type == MEDIA_TRACK_TYPE_SUBTITLE ? mSelectedTrack : -1);
208*ec779b8eSAndroid Build Coastguard Worker }
209*ec779b8eSAndroid Build Coastguard Worker return (type == MEDIA_TRACK_TYPE_UNKNOWN ? mSelectedTrack : -1);
210*ec779b8eSAndroid Build Coastguard Worker }
211*ec779b8eSAndroid Build Coastguard Worker
212*ec779b8eSAndroid Build Coastguard Worker return -1;
213*ec779b8eSAndroid Build Coastguard Worker }
214*ec779b8eSAndroid Build Coastguard Worker
isSelected() const215*ec779b8eSAndroid Build Coastguard Worker bool NuPlayer::CCDecoder::isSelected() const {
216*ec779b8eSAndroid Build Coastguard Worker return mSelectedTrack >= 0 && mSelectedTrack < (int32_t)getTrackCount();
217*ec779b8eSAndroid Build Coastguard Worker }
218*ec779b8eSAndroid Build Coastguard Worker
isTrackValid(size_t index) const219*ec779b8eSAndroid Build Coastguard Worker bool NuPlayer::CCDecoder::isTrackValid(size_t index) const {
220*ec779b8eSAndroid Build Coastguard Worker return index < getTrackCount();
221*ec779b8eSAndroid Build Coastguard Worker }
222*ec779b8eSAndroid Build Coastguard Worker
223*ec779b8eSAndroid Build Coastguard Worker // returns true if a new CC track is found
extractFromSEI(const sp<ABuffer> & accessUnit)224*ec779b8eSAndroid Build Coastguard Worker bool NuPlayer::CCDecoder::extractFromSEI(const sp<ABuffer> &accessUnit) {
225*ec779b8eSAndroid Build Coastguard Worker sp<ABuffer> sei;
226*ec779b8eSAndroid Build Coastguard Worker if (!accessUnit->meta()->findBuffer("sei", &sei) || sei == NULL) {
227*ec779b8eSAndroid Build Coastguard Worker return false;
228*ec779b8eSAndroid Build Coastguard Worker }
229*ec779b8eSAndroid Build Coastguard Worker
230*ec779b8eSAndroid Build Coastguard Worker int64_t timeUs;
231*ec779b8eSAndroid Build Coastguard Worker CHECK(accessUnit->meta()->findInt64("timeUs", &timeUs));
232*ec779b8eSAndroid Build Coastguard Worker
233*ec779b8eSAndroid Build Coastguard Worker bool trackAdded = false;
234*ec779b8eSAndroid Build Coastguard Worker
235*ec779b8eSAndroid Build Coastguard Worker const NALPosition *nal = (NALPosition *)sei->data();
236*ec779b8eSAndroid Build Coastguard Worker
237*ec779b8eSAndroid Build Coastguard Worker for (size_t i = 0; i < sei->size() / sizeof(NALPosition); ++i, ++nal) {
238*ec779b8eSAndroid Build Coastguard Worker trackAdded |= parseSEINalUnit(
239*ec779b8eSAndroid Build Coastguard Worker timeUs, accessUnit->data() + nal->nalOffset, nal->nalSize);
240*ec779b8eSAndroid Build Coastguard Worker }
241*ec779b8eSAndroid Build Coastguard Worker
242*ec779b8eSAndroid Build Coastguard Worker return trackAdded;
243*ec779b8eSAndroid Build Coastguard Worker }
244*ec779b8eSAndroid Build Coastguard Worker
245*ec779b8eSAndroid Build Coastguard Worker // returns true if a new CC track is found
parseSEINalUnit(int64_t timeUs,const uint8_t * data,size_t size)246*ec779b8eSAndroid Build Coastguard Worker bool NuPlayer::CCDecoder::parseSEINalUnit(int64_t timeUs, const uint8_t *data, size_t size) {
247*ec779b8eSAndroid Build Coastguard Worker unsigned nalType = data[0] & 0x1f;
248*ec779b8eSAndroid Build Coastguard Worker
249*ec779b8eSAndroid Build Coastguard Worker // the buffer should only have SEI in it
250*ec779b8eSAndroid Build Coastguard Worker if (nalType != 6) {
251*ec779b8eSAndroid Build Coastguard Worker return false;
252*ec779b8eSAndroid Build Coastguard Worker }
253*ec779b8eSAndroid Build Coastguard Worker
254*ec779b8eSAndroid Build Coastguard Worker bool trackAdded = false;
255*ec779b8eSAndroid Build Coastguard Worker NALBitReader br(data + 1, size - 1);
256*ec779b8eSAndroid Build Coastguard Worker
257*ec779b8eSAndroid Build Coastguard Worker // sei_message()
258*ec779b8eSAndroid Build Coastguard Worker while (br.atLeastNumBitsLeft(16)) { // at least 16-bit for sei_message()
259*ec779b8eSAndroid Build Coastguard Worker uint32_t payload_type = 0;
260*ec779b8eSAndroid Build Coastguard Worker size_t payload_size = 0;
261*ec779b8eSAndroid Build Coastguard Worker uint8_t last_byte;
262*ec779b8eSAndroid Build Coastguard Worker
263*ec779b8eSAndroid Build Coastguard Worker do {
264*ec779b8eSAndroid Build Coastguard Worker last_byte = br.getBits(8);
265*ec779b8eSAndroid Build Coastguard Worker payload_type += last_byte;
266*ec779b8eSAndroid Build Coastguard Worker } while (last_byte == 0xFF);
267*ec779b8eSAndroid Build Coastguard Worker
268*ec779b8eSAndroid Build Coastguard Worker do {
269*ec779b8eSAndroid Build Coastguard Worker last_byte = br.getBits(8);
270*ec779b8eSAndroid Build Coastguard Worker payload_size += last_byte;
271*ec779b8eSAndroid Build Coastguard Worker } while (last_byte == 0xFF);
272*ec779b8eSAndroid Build Coastguard Worker
273*ec779b8eSAndroid Build Coastguard Worker if (payload_size > SIZE_MAX / 8
274*ec779b8eSAndroid Build Coastguard Worker || !br.atLeastNumBitsLeft(payload_size * 8)) {
275*ec779b8eSAndroid Build Coastguard Worker ALOGV("Malformed SEI payload");
276*ec779b8eSAndroid Build Coastguard Worker break;
277*ec779b8eSAndroid Build Coastguard Worker }
278*ec779b8eSAndroid Build Coastguard Worker
279*ec779b8eSAndroid Build Coastguard Worker // sei_payload()
280*ec779b8eSAndroid Build Coastguard Worker if (payload_type == 4) {
281*ec779b8eSAndroid Build Coastguard Worker bool isCC = false;
282*ec779b8eSAndroid Build Coastguard Worker if (payload_size > 1 + 2 + 4 + 1) {
283*ec779b8eSAndroid Build Coastguard Worker // user_data_registered_itu_t_t35()
284*ec779b8eSAndroid Build Coastguard Worker
285*ec779b8eSAndroid Build Coastguard Worker // ATSC A/72: 6.4.2
286*ec779b8eSAndroid Build Coastguard Worker uint8_t itu_t_t35_country_code = br.getBits(8);
287*ec779b8eSAndroid Build Coastguard Worker uint16_t itu_t_t35_provider_code = br.getBits(16);
288*ec779b8eSAndroid Build Coastguard Worker uint32_t user_identifier = br.getBits(32);
289*ec779b8eSAndroid Build Coastguard Worker uint8_t user_data_type_code = br.getBits(8);
290*ec779b8eSAndroid Build Coastguard Worker
291*ec779b8eSAndroid Build Coastguard Worker payload_size -= 1 + 2 + 4 + 1;
292*ec779b8eSAndroid Build Coastguard Worker
293*ec779b8eSAndroid Build Coastguard Worker isCC = itu_t_t35_country_code == 0xB5
294*ec779b8eSAndroid Build Coastguard Worker && itu_t_t35_provider_code == 0x0031
295*ec779b8eSAndroid Build Coastguard Worker && user_identifier == 'GA94'
296*ec779b8eSAndroid Build Coastguard Worker && user_data_type_code == 0x3;
297*ec779b8eSAndroid Build Coastguard Worker }
298*ec779b8eSAndroid Build Coastguard Worker
299*ec779b8eSAndroid Build Coastguard Worker if (isCC && payload_size > 2) {
300*ec779b8eSAndroid Build Coastguard Worker trackAdded |= parseMPEGCCData(timeUs, br.data(), br.numBitsLeft() / 8);
301*ec779b8eSAndroid Build Coastguard Worker } else {
302*ec779b8eSAndroid Build Coastguard Worker ALOGV("Malformed SEI payload type 4");
303*ec779b8eSAndroid Build Coastguard Worker }
304*ec779b8eSAndroid Build Coastguard Worker } else {
305*ec779b8eSAndroid Build Coastguard Worker ALOGV("Unsupported SEI payload type %d", payload_type);
306*ec779b8eSAndroid Build Coastguard Worker }
307*ec779b8eSAndroid Build Coastguard Worker
308*ec779b8eSAndroid Build Coastguard Worker // skipping remaining bits of this payload
309*ec779b8eSAndroid Build Coastguard Worker br.skipBits(payload_size * 8);
310*ec779b8eSAndroid Build Coastguard Worker }
311*ec779b8eSAndroid Build Coastguard Worker
312*ec779b8eSAndroid Build Coastguard Worker return trackAdded;
313*ec779b8eSAndroid Build Coastguard Worker }
314*ec779b8eSAndroid Build Coastguard Worker
315*ec779b8eSAndroid Build Coastguard Worker // returns true if a new CC track is found
extractFromMPEGUserData(const sp<ABuffer> & accessUnit)316*ec779b8eSAndroid Build Coastguard Worker bool NuPlayer::CCDecoder::extractFromMPEGUserData(const sp<ABuffer> &accessUnit) {
317*ec779b8eSAndroid Build Coastguard Worker sp<ABuffer> mpegUserData;
318*ec779b8eSAndroid Build Coastguard Worker if (!accessUnit->meta()->findBuffer("mpeg-user-data", &mpegUserData)
319*ec779b8eSAndroid Build Coastguard Worker || mpegUserData == NULL) {
320*ec779b8eSAndroid Build Coastguard Worker return false;
321*ec779b8eSAndroid Build Coastguard Worker }
322*ec779b8eSAndroid Build Coastguard Worker
323*ec779b8eSAndroid Build Coastguard Worker int64_t timeUs;
324*ec779b8eSAndroid Build Coastguard Worker CHECK(accessUnit->meta()->findInt64("timeUs", &timeUs));
325*ec779b8eSAndroid Build Coastguard Worker
326*ec779b8eSAndroid Build Coastguard Worker bool trackAdded = false;
327*ec779b8eSAndroid Build Coastguard Worker
328*ec779b8eSAndroid Build Coastguard Worker const size_t *userData = (size_t *)mpegUserData->data();
329*ec779b8eSAndroid Build Coastguard Worker
330*ec779b8eSAndroid Build Coastguard Worker for (size_t i = 0; i < mpegUserData->size() / sizeof(size_t); ++i) {
331*ec779b8eSAndroid Build Coastguard Worker if (accessUnit->size() < userData[i]) {
332*ec779b8eSAndroid Build Coastguard Worker ALOGW("b/129068792, skip invalid offset for user data");
333*ec779b8eSAndroid Build Coastguard Worker android_errorWriteLog(0x534e4554, "129068792");
334*ec779b8eSAndroid Build Coastguard Worker continue;
335*ec779b8eSAndroid Build Coastguard Worker }
336*ec779b8eSAndroid Build Coastguard Worker trackAdded |= parseMPEGUserDataUnit(
337*ec779b8eSAndroid Build Coastguard Worker timeUs, accessUnit->data() + userData[i], accessUnit->size() - userData[i]);
338*ec779b8eSAndroid Build Coastguard Worker }
339*ec779b8eSAndroid Build Coastguard Worker
340*ec779b8eSAndroid Build Coastguard Worker return trackAdded;
341*ec779b8eSAndroid Build Coastguard Worker }
342*ec779b8eSAndroid Build Coastguard Worker
343*ec779b8eSAndroid Build Coastguard Worker // returns true if a new CC track is found
parseMPEGUserDataUnit(int64_t timeUs,const uint8_t * data,size_t size)344*ec779b8eSAndroid Build Coastguard Worker bool NuPlayer::CCDecoder::parseMPEGUserDataUnit(int64_t timeUs, const uint8_t *data, size_t size) {
345*ec779b8eSAndroid Build Coastguard Worker if (size < 9) {
346*ec779b8eSAndroid Build Coastguard Worker ALOGW("b/129068792, MPEG user data size too small %zu", size);
347*ec779b8eSAndroid Build Coastguard Worker android_errorWriteLog(0x534e4554, "129068792");
348*ec779b8eSAndroid Build Coastguard Worker return false;
349*ec779b8eSAndroid Build Coastguard Worker }
350*ec779b8eSAndroid Build Coastguard Worker
351*ec779b8eSAndroid Build Coastguard Worker ABitReader br(data + 4, 5);
352*ec779b8eSAndroid Build Coastguard Worker
353*ec779b8eSAndroid Build Coastguard Worker uint32_t user_identifier = br.getBits(32);
354*ec779b8eSAndroid Build Coastguard Worker uint8_t user_data_type = br.getBits(8);
355*ec779b8eSAndroid Build Coastguard Worker
356*ec779b8eSAndroid Build Coastguard Worker if (user_identifier == 'GA94' && user_data_type == 0x3) {
357*ec779b8eSAndroid Build Coastguard Worker return parseMPEGCCData(timeUs, data + 9, size - 9);
358*ec779b8eSAndroid Build Coastguard Worker }
359*ec779b8eSAndroid Build Coastguard Worker
360*ec779b8eSAndroid Build Coastguard Worker return false;
361*ec779b8eSAndroid Build Coastguard Worker }
362*ec779b8eSAndroid Build Coastguard Worker
363*ec779b8eSAndroid Build Coastguard Worker // returns true if a new CC track is found
parseMPEGCCData(int64_t timeUs,const uint8_t * data,size_t size)364*ec779b8eSAndroid Build Coastguard Worker bool NuPlayer::CCDecoder::parseMPEGCCData(int64_t timeUs, const uint8_t *data, size_t size) {
365*ec779b8eSAndroid Build Coastguard Worker bool trackAdded = false;
366*ec779b8eSAndroid Build Coastguard Worker
367*ec779b8eSAndroid Build Coastguard Worker // MPEG_cc_data()
368*ec779b8eSAndroid Build Coastguard Worker // ATSC A/53 Part 4: 6.2.3.1
369*ec779b8eSAndroid Build Coastguard Worker ABitReader br(data, size);
370*ec779b8eSAndroid Build Coastguard Worker
371*ec779b8eSAndroid Build Coastguard Worker if (br.numBitsLeft() <= 16) {
372*ec779b8eSAndroid Build Coastguard Worker return false;
373*ec779b8eSAndroid Build Coastguard Worker }
374*ec779b8eSAndroid Build Coastguard Worker
375*ec779b8eSAndroid Build Coastguard Worker br.skipBits(1);
376*ec779b8eSAndroid Build Coastguard Worker bool process_cc_data_flag = br.getBits(1);
377*ec779b8eSAndroid Build Coastguard Worker br.skipBits(1);
378*ec779b8eSAndroid Build Coastguard Worker size_t cc_count = br.getBits(5);
379*ec779b8eSAndroid Build Coastguard Worker br.skipBits(8);
380*ec779b8eSAndroid Build Coastguard Worker
381*ec779b8eSAndroid Build Coastguard Worker if (!process_cc_data_flag || 3 * 8 * cc_count >= br.numBitsLeft()) {
382*ec779b8eSAndroid Build Coastguard Worker return false;
383*ec779b8eSAndroid Build Coastguard Worker }
384*ec779b8eSAndroid Build Coastguard Worker
385*ec779b8eSAndroid Build Coastguard Worker sp<ABuffer> line21CCBuf = NULL;
386*ec779b8eSAndroid Build Coastguard Worker
387*ec779b8eSAndroid Build Coastguard Worker for (size_t i = 0; i < cc_count; ++i) {
388*ec779b8eSAndroid Build Coastguard Worker br.skipBits(5);
389*ec779b8eSAndroid Build Coastguard Worker bool cc_valid = br.getBits(1);
390*ec779b8eSAndroid Build Coastguard Worker uint8_t cc_type = br.getBits(2);
391*ec779b8eSAndroid Build Coastguard Worker
392*ec779b8eSAndroid Build Coastguard Worker if (cc_valid) {
393*ec779b8eSAndroid Build Coastguard Worker if (cc_type == 3) {
394*ec779b8eSAndroid Build Coastguard Worker if (mDTVCCPacket->size() > 0) {
395*ec779b8eSAndroid Build Coastguard Worker trackAdded |= parseDTVCCPacket(
396*ec779b8eSAndroid Build Coastguard Worker timeUs, mDTVCCPacket->data(), mDTVCCPacket->size());
397*ec779b8eSAndroid Build Coastguard Worker mDTVCCPacket->setRange(0, 0);
398*ec779b8eSAndroid Build Coastguard Worker }
399*ec779b8eSAndroid Build Coastguard Worker memcpy(mDTVCCPacket->data() + mDTVCCPacket->size(), br.data(), 2);
400*ec779b8eSAndroid Build Coastguard Worker mDTVCCPacket->setRange(0, mDTVCCPacket->size() + 2);
401*ec779b8eSAndroid Build Coastguard Worker br.skipBits(16);
402*ec779b8eSAndroid Build Coastguard Worker } else if (mDTVCCPacket->size() > 0 && cc_type == 2) {
403*ec779b8eSAndroid Build Coastguard Worker if (mDTVCCPacket->capacity() - mDTVCCPacket->size() >= 2) {
404*ec779b8eSAndroid Build Coastguard Worker memcpy(mDTVCCPacket->data() + mDTVCCPacket->size(), br.data(), 2);
405*ec779b8eSAndroid Build Coastguard Worker mDTVCCPacket->setRange(0, mDTVCCPacket->size() + 2);
406*ec779b8eSAndroid Build Coastguard Worker } else {
407*ec779b8eSAndroid Build Coastguard Worker ALOGW("b/129068792, skip CC due to too much data(%zu, %zu)",
408*ec779b8eSAndroid Build Coastguard Worker mDTVCCPacket->capacity(), mDTVCCPacket->size());
409*ec779b8eSAndroid Build Coastguard Worker android_errorWriteLog(0x534e4554, "129068792");
410*ec779b8eSAndroid Build Coastguard Worker }
411*ec779b8eSAndroid Build Coastguard Worker br.skipBits(16);
412*ec779b8eSAndroid Build Coastguard Worker } else if (cc_type == 0 || cc_type == 1) {
413*ec779b8eSAndroid Build Coastguard Worker uint8_t cc_data_1 = br.getBits(8) & 0x7f;
414*ec779b8eSAndroid Build Coastguard Worker uint8_t cc_data_2 = br.getBits(8) & 0x7f;
415*ec779b8eSAndroid Build Coastguard Worker
416*ec779b8eSAndroid Build Coastguard Worker CCData cc(cc_type, cc_data_1, cc_data_2);
417*ec779b8eSAndroid Build Coastguard Worker
418*ec779b8eSAndroid Build Coastguard Worker if (isNullPad(&cc)) {
419*ec779b8eSAndroid Build Coastguard Worker continue;
420*ec779b8eSAndroid Build Coastguard Worker }
421*ec779b8eSAndroid Build Coastguard Worker
422*ec779b8eSAndroid Build Coastguard Worker size_t channel;
423*ec779b8eSAndroid Build Coastguard Worker if (cc.getChannel(&channel)) {
424*ec779b8eSAndroid Build Coastguard Worker mLine21Channels[cc_type] = channel;
425*ec779b8eSAndroid Build Coastguard Worker
426*ec779b8eSAndroid Build Coastguard Worker // create a new track if it does not exist.
427*ec779b8eSAndroid Build Coastguard Worker getTrackIndex(kTrackTypeCEA608, channel, &trackAdded);
428*ec779b8eSAndroid Build Coastguard Worker }
429*ec779b8eSAndroid Build Coastguard Worker
430*ec779b8eSAndroid Build Coastguard Worker if (isSelected() && mTracks[mSelectedTrack].mTrackType == kTrackTypeCEA608
431*ec779b8eSAndroid Build Coastguard Worker && mTracks[mSelectedTrack].mTrackChannel == mLine21Channels[cc_type]) {
432*ec779b8eSAndroid Build Coastguard Worker if (line21CCBuf == NULL) {
433*ec779b8eSAndroid Build Coastguard Worker line21CCBuf = new ABuffer((cc_count - i) * sizeof(CCData));
434*ec779b8eSAndroid Build Coastguard Worker line21CCBuf->setRange(0, 0);
435*ec779b8eSAndroid Build Coastguard Worker }
436*ec779b8eSAndroid Build Coastguard Worker memcpy(line21CCBuf->data() + line21CCBuf->size(), &cc, sizeof(cc));
437*ec779b8eSAndroid Build Coastguard Worker line21CCBuf->setRange(0, line21CCBuf->size() + sizeof(CCData));
438*ec779b8eSAndroid Build Coastguard Worker }
439*ec779b8eSAndroid Build Coastguard Worker } else {
440*ec779b8eSAndroid Build Coastguard Worker br.skipBits(16);
441*ec779b8eSAndroid Build Coastguard Worker }
442*ec779b8eSAndroid Build Coastguard Worker } else {
443*ec779b8eSAndroid Build Coastguard Worker if ((cc_type == 3 || cc_type == 2) && mDTVCCPacket->size() > 0) {
444*ec779b8eSAndroid Build Coastguard Worker trackAdded |= parseDTVCCPacket(timeUs, mDTVCCPacket->data(), mDTVCCPacket->size());
445*ec779b8eSAndroid Build Coastguard Worker mDTVCCPacket->setRange(0, 0);
446*ec779b8eSAndroid Build Coastguard Worker }
447*ec779b8eSAndroid Build Coastguard Worker br.skipBits(16);
448*ec779b8eSAndroid Build Coastguard Worker }
449*ec779b8eSAndroid Build Coastguard Worker }
450*ec779b8eSAndroid Build Coastguard Worker
451*ec779b8eSAndroid Build Coastguard Worker if (isSelected() && mTracks[mSelectedTrack].mTrackType == kTrackTypeCEA608
452*ec779b8eSAndroid Build Coastguard Worker && line21CCBuf != NULL && line21CCBuf->size() > 0) {
453*ec779b8eSAndroid Build Coastguard Worker mCCMap.add(timeUs, line21CCBuf);
454*ec779b8eSAndroid Build Coastguard Worker }
455*ec779b8eSAndroid Build Coastguard Worker
456*ec779b8eSAndroid Build Coastguard Worker return trackAdded;
457*ec779b8eSAndroid Build Coastguard Worker }
458*ec779b8eSAndroid Build Coastguard Worker
459*ec779b8eSAndroid Build Coastguard Worker // returns true if a new CC track is found
parseDTVCCPacket(int64_t timeUs,const uint8_t * data,size_t size)460*ec779b8eSAndroid Build Coastguard Worker bool NuPlayer::CCDecoder::parseDTVCCPacket(int64_t timeUs, const uint8_t *data, size_t size) {
461*ec779b8eSAndroid Build Coastguard Worker // CEA-708B 5 DTVCC Packet Layer.
462*ec779b8eSAndroid Build Coastguard Worker ABitReader br(data, size);
463*ec779b8eSAndroid Build Coastguard Worker br.skipBits(2);
464*ec779b8eSAndroid Build Coastguard Worker
465*ec779b8eSAndroid Build Coastguard Worker size_t packet_size = br.getBits(6);
466*ec779b8eSAndroid Build Coastguard Worker if (packet_size == 0) packet_size = 64;
467*ec779b8eSAndroid Build Coastguard Worker packet_size *= 2;
468*ec779b8eSAndroid Build Coastguard Worker
469*ec779b8eSAndroid Build Coastguard Worker if (size != packet_size) {
470*ec779b8eSAndroid Build Coastguard Worker return false;
471*ec779b8eSAndroid Build Coastguard Worker }
472*ec779b8eSAndroid Build Coastguard Worker
473*ec779b8eSAndroid Build Coastguard Worker bool trackAdded = false;
474*ec779b8eSAndroid Build Coastguard Worker
475*ec779b8eSAndroid Build Coastguard Worker while (br.numBitsLeft() >= 16) {
476*ec779b8eSAndroid Build Coastguard Worker // CEA-708B Figure 5 and 6.
477*ec779b8eSAndroid Build Coastguard Worker uint8_t service_number = br.getBits(3);
478*ec779b8eSAndroid Build Coastguard Worker size_t block_size = br.getBits(5);
479*ec779b8eSAndroid Build Coastguard Worker
480*ec779b8eSAndroid Build Coastguard Worker if (service_number == 64) {
481*ec779b8eSAndroid Build Coastguard Worker br.skipBits(2);
482*ec779b8eSAndroid Build Coastguard Worker service_number = br.getBits(6);
483*ec779b8eSAndroid Build Coastguard Worker
484*ec779b8eSAndroid Build Coastguard Worker if (service_number < 64) {
485*ec779b8eSAndroid Build Coastguard Worker return trackAdded;
486*ec779b8eSAndroid Build Coastguard Worker }
487*ec779b8eSAndroid Build Coastguard Worker }
488*ec779b8eSAndroid Build Coastguard Worker
489*ec779b8eSAndroid Build Coastguard Worker if (br.numBitsLeft() < block_size * 8) {
490*ec779b8eSAndroid Build Coastguard Worker return trackAdded;
491*ec779b8eSAndroid Build Coastguard Worker }
492*ec779b8eSAndroid Build Coastguard Worker
493*ec779b8eSAndroid Build Coastguard Worker if (block_size > 0) {
494*ec779b8eSAndroid Build Coastguard Worker size_t trackIndex = getTrackIndex(kTrackTypeCEA708, service_number, &trackAdded);
495*ec779b8eSAndroid Build Coastguard Worker if (mSelectedTrack == (ssize_t)trackIndex) {
496*ec779b8eSAndroid Build Coastguard Worker sp<ABuffer> ccPacket = new ABuffer(block_size);
497*ec779b8eSAndroid Build Coastguard Worker if (ccPacket->capacity() == 0) {
498*ec779b8eSAndroid Build Coastguard Worker ALOGW("b/129068792, no memory available, %zu", block_size);
499*ec779b8eSAndroid Build Coastguard Worker android_errorWriteLog(0x534e4554, "129068792");
500*ec779b8eSAndroid Build Coastguard Worker return false;
501*ec779b8eSAndroid Build Coastguard Worker }
502*ec779b8eSAndroid Build Coastguard Worker memcpy(ccPacket->data(), br.data(), block_size);
503*ec779b8eSAndroid Build Coastguard Worker mCCMap.add(timeUs, ccPacket);
504*ec779b8eSAndroid Build Coastguard Worker }
505*ec779b8eSAndroid Build Coastguard Worker }
506*ec779b8eSAndroid Build Coastguard Worker br.skipBits(block_size * 8);
507*ec779b8eSAndroid Build Coastguard Worker }
508*ec779b8eSAndroid Build Coastguard Worker
509*ec779b8eSAndroid Build Coastguard Worker return trackAdded;
510*ec779b8eSAndroid Build Coastguard Worker }
511*ec779b8eSAndroid Build Coastguard Worker
512*ec779b8eSAndroid Build Coastguard Worker // return the track index for a given type and channel.
513*ec779b8eSAndroid Build Coastguard Worker // if the track does not exist, creates a new one.
getTrackIndex(int32_t trackType,size_t channel,bool * trackAdded)514*ec779b8eSAndroid Build Coastguard Worker size_t NuPlayer::CCDecoder::getTrackIndex(
515*ec779b8eSAndroid Build Coastguard Worker int32_t trackType, size_t channel, bool *trackAdded) {
516*ec779b8eSAndroid Build Coastguard Worker CCTrack track(trackType, channel);
517*ec779b8eSAndroid Build Coastguard Worker ssize_t index = mTrackIndices.indexOfKey(track);
518*ec779b8eSAndroid Build Coastguard Worker
519*ec779b8eSAndroid Build Coastguard Worker if (index < 0) {
520*ec779b8eSAndroid Build Coastguard Worker // A new track is added.
521*ec779b8eSAndroid Build Coastguard Worker index = mTracks.size();
522*ec779b8eSAndroid Build Coastguard Worker mTrackIndices.add(track, index);
523*ec779b8eSAndroid Build Coastguard Worker mTracks.add(track);
524*ec779b8eSAndroid Build Coastguard Worker *trackAdded = true;
525*ec779b8eSAndroid Build Coastguard Worker return index;
526*ec779b8eSAndroid Build Coastguard Worker }
527*ec779b8eSAndroid Build Coastguard Worker
528*ec779b8eSAndroid Build Coastguard Worker return mTrackIndices.valueAt(index);
529*ec779b8eSAndroid Build Coastguard Worker }
530*ec779b8eSAndroid Build Coastguard Worker
decode(const sp<ABuffer> & accessUnit)531*ec779b8eSAndroid Build Coastguard Worker void NuPlayer::CCDecoder::decode(const sp<ABuffer> &accessUnit) {
532*ec779b8eSAndroid Build Coastguard Worker if (extractFromMPEGUserData(accessUnit) || extractFromSEI(accessUnit)) {
533*ec779b8eSAndroid Build Coastguard Worker sp<AMessage> msg = mNotify->dup();
534*ec779b8eSAndroid Build Coastguard Worker msg->setInt32("what", kWhatTrackAdded);
535*ec779b8eSAndroid Build Coastguard Worker msg->post();
536*ec779b8eSAndroid Build Coastguard Worker }
537*ec779b8eSAndroid Build Coastguard Worker // TODO: extract CC from other sources
538*ec779b8eSAndroid Build Coastguard Worker }
539*ec779b8eSAndroid Build Coastguard Worker
display(int64_t timeUs)540*ec779b8eSAndroid Build Coastguard Worker void NuPlayer::CCDecoder::display(int64_t timeUs) {
541*ec779b8eSAndroid Build Coastguard Worker if (!isSelected()) {
542*ec779b8eSAndroid Build Coastguard Worker return;
543*ec779b8eSAndroid Build Coastguard Worker }
544*ec779b8eSAndroid Build Coastguard Worker
545*ec779b8eSAndroid Build Coastguard Worker ssize_t index = mCCMap.indexOfKey(timeUs);
546*ec779b8eSAndroid Build Coastguard Worker if (index < 0) {
547*ec779b8eSAndroid Build Coastguard Worker ALOGV("cc for timestamp %" PRId64 " not found", timeUs);
548*ec779b8eSAndroid Build Coastguard Worker return;
549*ec779b8eSAndroid Build Coastguard Worker }
550*ec779b8eSAndroid Build Coastguard Worker
551*ec779b8eSAndroid Build Coastguard Worker sp<ABuffer> ccBuf;
552*ec779b8eSAndroid Build Coastguard Worker
553*ec779b8eSAndroid Build Coastguard Worker if (index == 0) {
554*ec779b8eSAndroid Build Coastguard Worker ccBuf = mCCMap.valueAt(index);
555*ec779b8eSAndroid Build Coastguard Worker } else {
556*ec779b8eSAndroid Build Coastguard Worker size_t size = 0;
557*ec779b8eSAndroid Build Coastguard Worker
558*ec779b8eSAndroid Build Coastguard Worker for (ssize_t i = 0; i <= index; ++i) {
559*ec779b8eSAndroid Build Coastguard Worker size += mCCMap.valueAt(i)->size();
560*ec779b8eSAndroid Build Coastguard Worker }
561*ec779b8eSAndroid Build Coastguard Worker
562*ec779b8eSAndroid Build Coastguard Worker ccBuf = new ABuffer(size);
563*ec779b8eSAndroid Build Coastguard Worker ccBuf->setRange(0, 0);
564*ec779b8eSAndroid Build Coastguard Worker
565*ec779b8eSAndroid Build Coastguard Worker for (ssize_t i = 0; i <= index; ++i) {
566*ec779b8eSAndroid Build Coastguard Worker sp<ABuffer> buf = mCCMap.valueAt(i);
567*ec779b8eSAndroid Build Coastguard Worker memcpy(ccBuf->data() + ccBuf->size(), buf->data(), buf->size());
568*ec779b8eSAndroid Build Coastguard Worker ccBuf->setRange(0, ccBuf->size() + buf->size());
569*ec779b8eSAndroid Build Coastguard Worker }
570*ec779b8eSAndroid Build Coastguard Worker }
571*ec779b8eSAndroid Build Coastguard Worker
572*ec779b8eSAndroid Build Coastguard Worker if (ccBuf->size() > 0) {
573*ec779b8eSAndroid Build Coastguard Worker #if 0
574*ec779b8eSAndroid Build Coastguard Worker dumpBytePair(ccBuf);
575*ec779b8eSAndroid Build Coastguard Worker #endif
576*ec779b8eSAndroid Build Coastguard Worker
577*ec779b8eSAndroid Build Coastguard Worker ccBuf->meta()->setInt32("track-index", mSelectedTrack);
578*ec779b8eSAndroid Build Coastguard Worker ccBuf->meta()->setInt64("timeUs", timeUs);
579*ec779b8eSAndroid Build Coastguard Worker ccBuf->meta()->setInt64("durationUs", 0LL);
580*ec779b8eSAndroid Build Coastguard Worker
581*ec779b8eSAndroid Build Coastguard Worker sp<AMessage> msg = mNotify->dup();
582*ec779b8eSAndroid Build Coastguard Worker msg->setInt32("what", kWhatClosedCaptionData);
583*ec779b8eSAndroid Build Coastguard Worker msg->setBuffer("buffer", ccBuf);
584*ec779b8eSAndroid Build Coastguard Worker msg->post();
585*ec779b8eSAndroid Build Coastguard Worker }
586*ec779b8eSAndroid Build Coastguard Worker
587*ec779b8eSAndroid Build Coastguard Worker // remove all entries before timeUs
588*ec779b8eSAndroid Build Coastguard Worker mCCMap.removeItemsAt(0, index + 1);
589*ec779b8eSAndroid Build Coastguard Worker }
590*ec779b8eSAndroid Build Coastguard Worker
flush()591*ec779b8eSAndroid Build Coastguard Worker void NuPlayer::CCDecoder::flush() {
592*ec779b8eSAndroid Build Coastguard Worker mCCMap.clear();
593*ec779b8eSAndroid Build Coastguard Worker mDTVCCPacket->setRange(0, 0);
594*ec779b8eSAndroid Build Coastguard Worker }
595*ec779b8eSAndroid Build Coastguard Worker
compare(const NuPlayer::CCDecoder::CCTrack & rhs) const596*ec779b8eSAndroid Build Coastguard Worker int32_t NuPlayer::CCDecoder::CCTrack::compare(const NuPlayer::CCDecoder::CCTrack& rhs) const {
597*ec779b8eSAndroid Build Coastguard Worker int32_t cmp = mTrackType - rhs.mTrackType;
598*ec779b8eSAndroid Build Coastguard Worker if (cmp != 0) return cmp;
599*ec779b8eSAndroid Build Coastguard Worker return mTrackChannel - rhs.mTrackChannel;
600*ec779b8eSAndroid Build Coastguard Worker }
601*ec779b8eSAndroid Build Coastguard Worker
operator <(const NuPlayer::CCDecoder::CCTrack & rhs) const602*ec779b8eSAndroid Build Coastguard Worker bool NuPlayer::CCDecoder::CCTrack::operator<(const NuPlayer::CCDecoder::CCTrack& rhs) const {
603*ec779b8eSAndroid Build Coastguard Worker return compare(rhs) < 0;
604*ec779b8eSAndroid Build Coastguard Worker }
605*ec779b8eSAndroid Build Coastguard Worker
operator ==(const NuPlayer::CCDecoder::CCTrack & rhs) const606*ec779b8eSAndroid Build Coastguard Worker bool NuPlayer::CCDecoder::CCTrack::operator==(const NuPlayer::CCDecoder::CCTrack& rhs) const {
607*ec779b8eSAndroid Build Coastguard Worker return compare(rhs) == 0;
608*ec779b8eSAndroid Build Coastguard Worker }
609*ec779b8eSAndroid Build Coastguard Worker
operator !=(const NuPlayer::CCDecoder::CCTrack & rhs) const610*ec779b8eSAndroid Build Coastguard Worker bool NuPlayer::CCDecoder::CCTrack::operator!=(const NuPlayer::CCDecoder::CCTrack& rhs) const {
611*ec779b8eSAndroid Build Coastguard Worker return compare(rhs) != 0;
612*ec779b8eSAndroid Build Coastguard Worker }
613*ec779b8eSAndroid Build Coastguard Worker
614*ec779b8eSAndroid Build Coastguard Worker } // namespace android
615*ec779b8eSAndroid Build Coastguard Worker
616