summaryrefslogtreecommitdiffstats
path: root/xbmc/cores/dvdplayer/DVDDemuxers/DVDDemuxCC.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'xbmc/cores/dvdplayer/DVDDemuxers/DVDDemuxCC.cpp')
-rw-r--r--xbmc/cores/dvdplayer/DVDDemuxers/DVDDemuxCC.cpp404
1 files changed, 0 insertions, 404 deletions
diff --git a/xbmc/cores/dvdplayer/DVDDemuxers/DVDDemuxCC.cpp b/xbmc/cores/dvdplayer/DVDDemuxers/DVDDemuxCC.cpp
deleted file mode 100644
index 24d56da..0000000
--- a/xbmc/cores/dvdplayer/DVDDemuxers/DVDDemuxCC.cpp
+++ /dev/null
@@ -1,404 +0,0 @@
1/*
2 * Copyright (C) 2005-2014 Team XBMC
3 * http://xbmc.org
4 *
5 * This Program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2, or (at your option)
8 * any later version.
9 *
10 * This Program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License
16 * along with XBMC; see the file COPYING. If not, see
17 * <http://www.gnu.org/licenses/>.
18 *
19 */
20
21#include "DVDDemuxUtils.h"
22#include "DVDClock.h"
23#include "DVDDemuxCC.h"
24#include "cores/dvdplayer/DVDCodecs/Overlay/contrib/cc_decoder708.h"
25#include "utils/log.h"
26
27#include <algorithm>
28
29class CBitstream
30{
31public:
32 CBitstream(uint8_t *data, int bits)
33 {
34 m_data = data;
35 m_offset = 0;
36 m_len = bits;
37 m_error = false;
38 }
39 unsigned int readBits(int num)
40 {
41 int r = 0;
42 while (num > 0)
43 {
44 if (m_offset >= m_len)
45 {
46 m_error = true;
47 return 0;
48 }
49 num--;
50 if (m_data[m_offset / 8] & (1 << (7 - (m_offset & 7))))
51 r |= 1 << num;
52 m_offset++;
53 }
54 return r;
55 }
56 unsigned int readGolombUE(int maxbits = 32)
57 {
58 int lzb = -1;
59 int bits = 0;
60 for (int b = 0; !b; lzb++, bits++)
61 {
62 if (bits > maxbits)
63 return 0;
64 b = readBits(1);
65 }
66 return (1 << lzb) - 1 + readBits(lzb);
67 }
68
69private:
70 uint8_t *m_data;
71 int m_offset;
72 int m_len;
73 bool m_error;
74};
75
76class CCaptionBlock
77{
78public:
79 CCaptionBlock(int size)
80 {
81 m_data = (uint8_t*)malloc(size);
82 m_size = size;
83 }
84 virtual ~CCaptionBlock()
85 {
86 free(m_data);
87 }
88 double m_pts;
89 uint8_t *m_data;
90 int m_size;
91};
92
93bool reorder_sort (CCaptionBlock *lhs, CCaptionBlock *rhs)
94{
95 return (lhs->m_pts > rhs->m_pts);
96}
97
98CDVDDemuxCC::CDVDDemuxCC(AVCodecID codec)
99{
100 m_hasData = false;
101 m_curPts = 0;
102 m_ccDecoder = NULL;
103 m_codec = codec;
104}
105
106CDVDDemuxCC::~CDVDDemuxCC()
107{
108 Dispose();
109}
110
111CDemuxStream* CDVDDemuxCC::GetStream(int iStreamId)
112{
113 return &m_streams[iStreamId];
114}
115
116int CDVDDemuxCC::GetNrOfStreams()
117{
118 return m_streams.size();
119}
120
121DemuxPacket* CDVDDemuxCC::Read(DemuxPacket *pSrcPacket)
122{
123 DemuxPacket *pPacket = NULL;
124 uint32_t startcode = 0xffffffff;
125 int picType = 0;
126 int p = 0;
127 int len;
128
129 if (!pSrcPacket)
130 {
131 pPacket = Decode();
132 return pPacket;
133 }
134 if (pSrcPacket->pts == DVD_NOPTS_VALUE)
135 {
136 return pPacket;
137 }
138
139 while (!m_ccTempBuffer.empty())
140 {
141 m_ccReorderBuffer.push_back(m_ccTempBuffer.back());
142 m_ccTempBuffer.pop_back();
143 }
144
145 while ((len = pSrcPacket->iSize - p) > 3)
146 {
147 if ((startcode & 0xffffff00) == 0x00000100)
148 {
149 if (m_codec == AV_CODEC_ID_MPEG2VIDEO)
150 {
151 int scode = startcode & 0xFF;
152 if (scode == 0x00)
153 {
154 if (len > 4)
155 {
156 uint8_t *buf = pSrcPacket->pData + p;
157 picType = (buf[1] & 0x38) >> 3;
158 }
159 }
160 else if (scode == 0xb2) // user data
161 {
162 uint8_t *buf = pSrcPacket->pData + p;
163 if (len >= 6 &&
164 buf[0] == 'G' && buf[1] == 'A' && buf[2] == '9' && buf[3] == '4' &&
165 buf[4] == 3 && (buf[5] & 0x40))
166 {
167 int cc_count = buf[5] & 0x1f;
168 if (cc_count > 0 && len >= 7 + cc_count * 3)
169 {
170 CCaptionBlock *cc = new CCaptionBlock(cc_count * 3);
171 memcpy(cc->m_data, buf + 7, cc_count * 3);
172 cc->m_pts = pSrcPacket->pts;
173 if (picType == 1 || picType == 2)
174 m_ccTempBuffer.push_back(cc);
175 else
176 m_ccReorderBuffer.push_back(cc);
177 }
178 }
179 else if (len >= 6 &&
180 buf[0] == 'C' && buf[1] == 'C' && buf[2] == 1)
181 {
182 int oddidx = (buf[4] & 0x80) ? 0 : 1;
183 int cc_count = (buf[4] & 0x3e) >> 1;
184 int extrafield = buf[4] & 0x01;
185 if (extrafield)
186 cc_count++;
187
188 if (cc_count > 0 && len >= 5 + cc_count * 3 * 2)
189 {
190 CCaptionBlock *cc = new CCaptionBlock(cc_count * 3);
191 uint8_t *src = buf + 5;
192 uint8_t *dst = cc->m_data;
193
194 for (int i = 0; i < cc_count; i++)
195 {
196 for (int j = 0; j < 2; j++)
197 {
198 if (i == cc_count - 1 && extrafield && j == 1)
199 break;
200
201 if ((oddidx == j) && (src[0] == 0xFF))
202 {
203 dst[0] = 0x04;
204 dst[1] = src[1];
205 dst[2] = src[2];
206 dst += 3;
207 }
208 src += 3;
209 }
210 }
211 cc->m_pts = pSrcPacket->pts;
212 m_ccReorderBuffer.push_back(cc);
213 picType = 1;
214 }
215 }
216 }
217 }
218 else if (m_codec == AV_CODEC_ID_H264)
219 {
220 int scode = startcode & 0x9F;
221 // slice data comes after SEI
222 if (scode >= 1 && scode <= 5)
223 {
224 uint8_t *buf = pSrcPacket->pData + p;
225 CBitstream bs(buf, len * 8);
226 bs.readGolombUE();
227 int sliceType = bs.readGolombUE();
228 if (sliceType == 2 || sliceType == 7) // I slice
229 picType = 1;
230 else if (sliceType == 0 || sliceType == 5) // P slice
231 picType = 2;
232 if (picType == 0)
233 {
234 while (!m_ccTempBuffer.empty())
235 {
236 m_ccReorderBuffer.push_back(m_ccTempBuffer.back());
237 m_ccTempBuffer.pop_back();
238 }
239 }
240 }
241 if (scode == 0x06) // SEI
242 {
243 uint8_t *buf = pSrcPacket->pData + p;
244 if (len >= 12 &&
245 buf[3] == 0 && buf[4] == 49 &&
246 buf[5] == 'G' && buf[6] == 'A' && buf[7] == '9' && buf[8] == '4' && buf[9] == 3)
247 {
248 uint8_t *userdata = buf + 10;
249 int cc_count = userdata[0] & 0x1f;
250 if (len >= cc_count * 3 + 10)
251 {
252 CCaptionBlock *cc = new CCaptionBlock(cc_count * 3);
253 memcpy(cc->m_data, userdata + 2, cc_count * 3);
254 cc->m_pts = pSrcPacket->pts;
255 m_ccTempBuffer.push_back(cc);
256 }
257 }
258 }
259 }
260 }
261 startcode = startcode << 8 | pSrcPacket->pData[p++];
262 }
263
264 if ((picType == 1 || picType == 2) && !m_ccReorderBuffer.empty())
265 {
266 if (!m_ccDecoder)
267 {
268 if (!OpenDecoder())
269 return NULL;
270 }
271 std::sort(m_ccReorderBuffer.begin(), m_ccReorderBuffer.end(), reorder_sort);
272 pPacket = Decode();
273 }
274 return pPacket;
275}
276
277void CDVDDemuxCC::Handler(int service, void *userdata)
278{
279 CDVDDemuxCC *ctx = (CDVDDemuxCC*)userdata;
280
281 unsigned int idx;
282
283 // switch back from 608 fallback if we got 708
284 if (ctx->m_ccDecoder->m_seen608 && ctx->m_ccDecoder->m_seen708)
285 {
286 for (idx = 0; idx < ctx->m_streamdata.size(); idx++)
287 {
288 if (ctx->m_streamdata[idx].service == 0)
289 break;
290 }
291 if (idx < ctx->m_streamdata.size())
292 {
293 ctx->m_streamdata.erase(ctx->m_streamdata.begin() + idx);
294 ctx->m_ccDecoder->m_seen608 = false;
295 }
296 if (service == 0)
297 return;
298 }
299
300 for (idx = 0; idx < ctx->m_streamdata.size(); idx++)
301 {
302 if (ctx->m_streamdata[idx].service == service)
303 break;
304 }
305 if (idx >= ctx->m_streamdata.size())
306 {
307 CDemuxStreamSubtitle stream;
308 strcpy(stream.language, "cc");
309 stream.codec = AV_CODEC_ID_TEXT;
310 stream.iPhysicalId = service;
311 stream.iId = idx;
312 ctx->m_streams.push_back(stream);
313
314 streamdata data;
315 data.streamIdx = idx;
316 data.service = service;
317 ctx->m_streamdata.push_back(data);
318
319 if (service == 0)
320 ctx->m_ccDecoder->m_seen608 = true;
321 else
322 ctx->m_ccDecoder->m_seen708 = true;
323 }
324
325 ctx->m_streamdata[idx].pts = ctx->m_curPts;
326 ctx->m_streamdata[idx].hasData = true;
327 ctx->m_hasData = true;
328}
329
330bool CDVDDemuxCC::OpenDecoder()
331{
332 m_ccDecoder = new CDecoderCC708();
333 m_ccDecoder->Init(Handler, this);
334 return true;
335}
336
337void CDVDDemuxCC::Dispose()
338{
339 m_streams.clear();
340 m_streamdata.clear();
341 delete m_ccDecoder;
342 m_ccDecoder = NULL;
343
344 while (!m_ccReorderBuffer.empty())
345 {
346 delete m_ccReorderBuffer.back();
347 m_ccReorderBuffer.pop_back();
348 }
349 while (!m_ccTempBuffer.empty())
350 {
351 delete m_ccTempBuffer.back();
352 m_ccTempBuffer.pop_back();
353 }
354}
355
356DemuxPacket* CDVDDemuxCC::Decode()
357{
358 DemuxPacket *pPacket = NULL;
359
360 while(!m_hasData && !m_ccReorderBuffer.empty())
361 {
362 CCaptionBlock *cc = m_ccReorderBuffer.back();
363 m_ccReorderBuffer.pop_back();
364 m_curPts = cc->m_pts;
365 m_ccDecoder->Decode(cc->m_data, cc->m_size);
366 delete cc;
367 }
368
369 if (m_hasData)
370 {
371 for (unsigned int i=0; i<m_streamdata.size(); i++)
372 {
373 if (m_streamdata[i].hasData)
374 {
375 int service = m_streamdata[i].service;
376
377 char *data;
378 int len;
379 if (service == 0)
380 {
381 data = m_ccDecoder->m_cc608decoder->text;
382 len = m_ccDecoder->m_cc608decoder->textlen;
383 }
384 else
385 {
386 data = m_ccDecoder->m_cc708decoders[service].text;
387 len = m_ccDecoder->m_cc708decoders[service].textlen;
388 }
389
390 pPacket = CDVDDemuxUtils::AllocateDemuxPacket(len);
391 pPacket->iSize = len;
392 memcpy(pPacket->pData, data, pPacket->iSize);
393
394 pPacket->iStreamId = i;
395 pPacket->pts = m_streamdata[i].pts;
396 pPacket->duration = 0;
397 m_streamdata[i].hasData = false;
398 break;
399 }
400 m_hasData = false;
401 }
402 }
403 return pPacket;
404}