diff options
Diffstat (limited to 'xbmc/cores/dvdplayer/DVDDemuxers/DVDDemuxCC.cpp')
| -rw-r--r-- | xbmc/cores/dvdplayer/DVDDemuxers/DVDDemuxCC.cpp | 404 |
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 | |||
| 29 | class CBitstream | ||
| 30 | { | ||
| 31 | public: | ||
| 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 | |||
| 69 | private: | ||
| 70 | uint8_t *m_data; | ||
| 71 | int m_offset; | ||
| 72 | int m_len; | ||
| 73 | bool m_error; | ||
| 74 | }; | ||
| 75 | |||
| 76 | class CCaptionBlock | ||
| 77 | { | ||
| 78 | public: | ||
| 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 | |||
| 93 | bool reorder_sort (CCaptionBlock *lhs, CCaptionBlock *rhs) | ||
| 94 | { | ||
| 95 | return (lhs->m_pts > rhs->m_pts); | ||
| 96 | } | ||
| 97 | |||
| 98 | CDVDDemuxCC::CDVDDemuxCC(AVCodecID codec) | ||
| 99 | { | ||
| 100 | m_hasData = false; | ||
| 101 | m_curPts = 0; | ||
| 102 | m_ccDecoder = NULL; | ||
| 103 | m_codec = codec; | ||
| 104 | } | ||
| 105 | |||
| 106 | CDVDDemuxCC::~CDVDDemuxCC() | ||
| 107 | { | ||
| 108 | Dispose(); | ||
| 109 | } | ||
| 110 | |||
| 111 | CDemuxStream* CDVDDemuxCC::GetStream(int iStreamId) | ||
| 112 | { | ||
| 113 | return &m_streams[iStreamId]; | ||
| 114 | } | ||
| 115 | |||
| 116 | int CDVDDemuxCC::GetNrOfStreams() | ||
| 117 | { | ||
| 118 | return m_streams.size(); | ||
| 119 | } | ||
| 120 | |||
| 121 | DemuxPacket* 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 | |||
| 277 | void 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 | |||
| 330 | bool CDVDDemuxCC::OpenDecoder() | ||
| 331 | { | ||
| 332 | m_ccDecoder = new CDecoderCC708(); | ||
| 333 | m_ccDecoder->Init(Handler, this); | ||
| 334 | return true; | ||
| 335 | } | ||
| 336 | |||
| 337 | void 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 | |||
| 356 | DemuxPacket* 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 | } | ||
