/xbmc/cores/dvdplayer/DVDPlayerTeletext.cpp

http://github.com/xbmc/xbmc · C++ · 771 lines · 621 code · 96 blank · 54 comment · 217 complexity · a4b775bf486ad0021f7ea81f87fdb3dd MD5 · raw file

  1. /*
  2. * Copyright (C) 2005-2013 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. #include "DVDPlayerTeletext.h"
  21. #include "DVDClock.h"
  22. #include "DVDStreamInfo.h"
  23. #include "DVDCodecs/DVDCodecs.h"
  24. #include "utils/log.h"
  25. #include "threads/SingleLock.h"
  26. using namespace std;
  27. const uint8_t rev_lut[32] =
  28. {
  29. 0x00,0x08,0x04,0x0c, /* upper nibble */
  30. 0x02,0x0a,0x06,0x0e,
  31. 0x01,0x09,0x05,0x0d,
  32. 0x03,0x0b,0x07,0x0f,
  33. 0x00,0x80,0x40,0xc0, /* lower nibble */
  34. 0x20,0xa0,0x60,0xe0,
  35. 0x10,0x90,0x50,0xd0,
  36. 0x30,0xb0,0x70,0xf0
  37. };
  38. void CDVDTeletextTools::NextDec(int *i) /* skip to next decimal */
  39. {
  40. (*i)++;
  41. if ((*i & 0x0F) > 0x09)
  42. *i += 0x06;
  43. if ((*i & 0xF0) > 0x90)
  44. *i += 0x60;
  45. if (*i > 0x899)
  46. *i = 0x100;
  47. }
  48. void CDVDTeletextTools::PrevDec(int *i) /* counting down */
  49. {
  50. (*i)--;
  51. if ((*i & 0x0F) > 0x09)
  52. *i -= 0x06;
  53. if ((*i & 0xF0) > 0x90)
  54. *i -= 0x60;
  55. if (*i < 0x100)
  56. *i = 0x899;
  57. }
  58. /* print hex-number into string, s points to last digit, caller has to provide enough space, no termination */
  59. void CDVDTeletextTools::Hex2Str(char *s, unsigned int n)
  60. {
  61. do {
  62. char c = (n & 0xF);
  63. *s-- = number2char(c);
  64. n >>= 4;
  65. } while (n);
  66. }
  67. signed int CDVDTeletextTools::deh24(unsigned char *p)
  68. {
  69. int e = hamm24par[0][p[0]]
  70. ^ hamm24par[1][p[1]]
  71. ^ hamm24par[2][p[2]];
  72. int x = hamm24val[p[0]]
  73. + (p[1] & 127) * 16
  74. + (p[2] & 127) * 2048;
  75. return (x ^ hamm24cor[e]) | hamm24err[e];
  76. }
  77. CDVDTeletextData::CDVDTeletextData()
  78. : CThread("DVDTeletextData")
  79. , m_messageQueue("teletext")
  80. {
  81. m_speed = DVD_PLAYSPEED_NORMAL;
  82. m_messageQueue.SetMaxDataSize(40 * 256 * 1024);
  83. /* Initialize Data structures */
  84. memset(&m_TXTCache.astCachetable, 0, sizeof(m_TXTCache.astCachetable));
  85. memset(&m_TXTCache.astP29, 0, sizeof(m_TXTCache.astP29));
  86. ResetTeletextCache();
  87. }
  88. CDVDTeletextData::~CDVDTeletextData()
  89. {
  90. StopThread();
  91. ResetTeletextCache();
  92. }
  93. bool CDVDTeletextData::CheckStream(CDVDStreamInfo &hints)
  94. {
  95. if (hints.codec == AV_CODEC_ID_DVB_TELETEXT)
  96. return true;
  97. return false;
  98. }
  99. bool CDVDTeletextData::OpenStream(CDVDStreamInfo &hints)
  100. {
  101. m_messageQueue.Init();
  102. if (hints.codec == AV_CODEC_ID_DVB_TELETEXT)
  103. {
  104. CLog::Log(LOGNOTICE, "Creating teletext data thread");
  105. Create();
  106. return true;
  107. }
  108. return false;
  109. }
  110. void CDVDTeletextData::CloseStream(bool bWaitForBuffers)
  111. {
  112. // wait until buffers are empty
  113. if (bWaitForBuffers && m_speed > 0) m_messageQueue.WaitUntilEmpty();
  114. m_messageQueue.Abort();
  115. // wait for decode_video thread to end
  116. CLog::Log(LOGNOTICE, "waiting for teletext data thread to exit");
  117. StopThread(); // will set this->m_bStop to true
  118. m_messageQueue.End();
  119. ResetTeletextCache();
  120. }
  121. void CDVDTeletextData::ResetTeletextCache()
  122. {
  123. CSingleLock lock(m_critSection);
  124. /* Reset Data structures */
  125. for (int i = 0; i < 0x900; i++)
  126. {
  127. for (int j = 0; j < 0x80; j++)
  128. {
  129. if (m_TXTCache.astCachetable[i][j])
  130. {
  131. TextPageinfo_t *p = &(m_TXTCache.astCachetable[i][j]->pageinfo);
  132. if (p->p24)
  133. free(p->p24);
  134. if (p->ext)
  135. {
  136. if (p->ext->p27)
  137. free(p->ext->p27);
  138. for (int d26 = 0; d26 < 16; d26++)
  139. {
  140. if (p->ext->p26[d26])
  141. free(p->ext->p26[d26]);
  142. }
  143. free(p->ext);
  144. }
  145. delete m_TXTCache.astCachetable[i][j];
  146. m_TXTCache.astCachetable[i][j] = 0;
  147. }
  148. }
  149. }
  150. for (int i = 0; i < 9; i++)
  151. {
  152. if (m_TXTCache.astP29[i])
  153. {
  154. if (m_TXTCache.astP29[i]->p27)
  155. free(m_TXTCache.astP29[i]->p27);
  156. for (int d26 = 0; d26 < 16; d26++)
  157. {
  158. if (m_TXTCache.astP29[i]->p26[d26])
  159. free(m_TXTCache.astP29[i]->p26[d26]);
  160. }
  161. free(m_TXTCache.astP29[i]);
  162. m_TXTCache.astP29[i] = 0;
  163. }
  164. m_TXTCache.CurrentPage[i] = -1;
  165. m_TXTCache.CurrentSubPage[i] = -1;
  166. }
  167. memset(&m_TXTCache.SubPageTable, 0xFF, sizeof(m_TXTCache.SubPageTable));
  168. memset(&m_TXTCache.astP29, 0, sizeof(m_TXTCache.astP29));
  169. memset(&m_TXTCache.BasicTop, 0, sizeof(m_TXTCache.BasicTop));
  170. memset(&m_TXTCache.ADIPTable, 0, sizeof(m_TXTCache.ADIPTable));
  171. memset(&m_TXTCache.FlofPages, 0, sizeof(m_TXTCache.FlofPages));
  172. memset(&m_TXTCache.SubtitlePages, 0, sizeof(m_TXTCache.SubtitlePages));
  173. memset(&m_TXTCache.astCachetable, 0, sizeof(m_TXTCache.astCachetable));
  174. memset(&m_TXTCache.TimeString, 0x20, 8);
  175. m_TXTCache.NationalSubset = NAT_DEFAULT;/* default */
  176. m_TXTCache.NationalSubsetSecondary = NAT_DEFAULT;
  177. m_TXTCache.ZapSubpageManual = false;
  178. m_TXTCache.PageUpdate = false;
  179. m_TXTCache.ADIP_PgMax = -1;
  180. m_TXTCache.BTTok = false;
  181. m_TXTCache.CachedPages = 0;
  182. m_TXTCache.PageReceiving = -1;
  183. m_TXTCache.Page = 0x100;
  184. m_TXTCache.SubPage = m_TXTCache.SubPageTable[m_TXTCache.Page];
  185. m_TXTCache.line30 = "";
  186. if (m_TXTCache.SubPage == 0xff)
  187. m_TXTCache.SubPage = 0;
  188. }
  189. void CDVDTeletextData::Process()
  190. {
  191. int b1, b2, b3, b4;
  192. int packet_number;
  193. TextPageinfo_t *pageinfo_thread;
  194. unsigned char vtxt_row[42];
  195. unsigned char pagedata[9][23*40];
  196. unsigned char magazine = 0xff;
  197. // int doupdate = 0;
  198. CLog::Log(LOGNOTICE, "running thread: CDVDTeletextData");
  199. while (!m_bStop)
  200. {
  201. CDVDMsg* pMsg;
  202. int iPriority = (m_speed == DVD_PLAYSPEED_PAUSE) ? 1 : 0;
  203. MsgQueueReturnCode ret = m_messageQueue.Get(&pMsg, 2000, iPriority);
  204. if (ret == MSGQ_TIMEOUT)
  205. {
  206. /* Timeout for Teletext is not a bad thing, so we continue without error */
  207. continue;
  208. }
  209. if (MSGQ_IS_ERROR(ret))
  210. {
  211. CLog::Log(LOGERROR, "Got MSGQ_ABORT or MSGO_IS_ERROR return true (%i)", ret);
  212. break;
  213. }
  214. if (pMsg->IsType(CDVDMsg::DEMUXER_PACKET))
  215. {
  216. CSingleLock lock(m_critSection);
  217. DemuxPacket* pPacket = ((CDVDMsgDemuxerPacket*)pMsg)->GetPacket();
  218. uint8_t *Datai = pPacket->pData;
  219. int rows = (pPacket->iSize - 1) / 46;
  220. /* Is it a ITU-R System B Teletext stream in acc. to EN 300 472 */
  221. if (Datai[0] >= 0x10 && Datai[0] <= 0x1F) /* Check we have a valid data identifier */
  222. {
  223. /* Go thru the pages stored inside this frame */
  224. for (int row=0; row < rows; row++)
  225. {
  226. uint8_t *vtx_rowbyte = &Datai[(row*46)+1];
  227. /* Check for valid data_unit_id */
  228. if ((vtx_rowbyte[0] == 0x02 || vtx_rowbyte[0] == 0x03) && (vtx_rowbyte[1] == 0x2C))
  229. {
  230. /* clear rowbuffer */
  231. /* convert row from lsb to msb (begin with magazin number) */
  232. for (int i = 4; i < 46; i++)
  233. {
  234. uint8_t upper = (vtx_rowbyte[i] >> 4) & 0xf;
  235. uint8_t lower = vtx_rowbyte[i] & 0xf;
  236. vtxt_row[i-4] = (rev_lut[upper]) | (rev_lut[lower+16]);
  237. }
  238. /* get packet number */
  239. b1 = dehamming[vtxt_row[0]];
  240. b2 = dehamming[vtxt_row[1]];
  241. if (b1 == 0xFF || b2 == 0xFF)
  242. continue;
  243. b1 &= 8;
  244. /* get packet and magazine number */
  245. packet_number = b1>>3 | b2<<1;
  246. magazine = dehamming[vtxt_row[0]] & 7;
  247. if (!magazine) magazine = 8;
  248. if (packet_number == 0 && m_TXTCache.CurrentPage[magazine] != -1 && m_TXTCache.CurrentSubPage[magazine] != -1)
  249. SavePage(m_TXTCache.CurrentPage[magazine], m_TXTCache.CurrentSubPage[magazine], pagedata[magazine]);
  250. /* analyze row */
  251. if (packet_number == 0)
  252. {
  253. /* get pagenumber */
  254. b2 = dehamming[vtxt_row[3]];
  255. b3 = dehamming[vtxt_row[2]];
  256. if (b2 == 0xFF || b3 == 0xFF)
  257. {
  258. m_TXTCache.CurrentPage[magazine] = m_TXTCache.PageReceiving = -1;
  259. continue;
  260. }
  261. m_TXTCache.CurrentPage[magazine] = m_TXTCache.PageReceiving = magazine<<8 | b2<<4 | b3;
  262. if (b2 == 0x0f && b3 == 0x0f)
  263. {
  264. m_TXTCache.CurrentSubPage[magazine] = -1; /* ?ff: ignore data transmissions */
  265. continue;
  266. }
  267. /* get subpagenumber */
  268. b1 = dehamming[vtxt_row[7]];
  269. b2 = dehamming[vtxt_row[6]];
  270. b3 = dehamming[vtxt_row[5]];
  271. b4 = dehamming[vtxt_row[4]];
  272. if (b1 == 0xFF || b2 == 0xFF || b3 == 0xFF || b4 == 0xFF)
  273. {
  274. m_TXTCache.CurrentSubPage[magazine] = -1;
  275. continue;
  276. }
  277. b1 &= 3;
  278. b3 &= 7;
  279. if (IsDec(m_TXTCache.PageReceiving)) /* ignore other subpage bits for hex pages */
  280. m_TXTCache.CurrentSubPage[magazine] = b3<<4 | b4;
  281. else
  282. m_TXTCache.CurrentSubPage[magazine] = b4; /* max 16 subpages for hex pages */
  283. /* store current subpage for this page */
  284. m_TXTCache.SubPageTable[m_TXTCache.CurrentPage[magazine]] = m_TXTCache.CurrentSubPage[magazine];
  285. AllocateCache(magazine);
  286. LoadPage(m_TXTCache.CurrentPage[magazine], m_TXTCache.CurrentSubPage[magazine], pagedata[magazine]);
  287. pageinfo_thread = &(m_TXTCache.astCachetable[m_TXTCache.CurrentPage[magazine]][m_TXTCache.CurrentSubPage[magazine]]->pageinfo);
  288. if (!pageinfo_thread)
  289. continue;
  290. if ((m_TXTCache.PageReceiving & 0xff) == 0xfe) /* ?fe: magazine organization table (MOT) */
  291. pageinfo_thread->function = FUNC_MOT;
  292. /* check controlbits */
  293. if (dehamming[vtxt_row[5]] & 8) /* C4 -> erase page */
  294. {
  295. memset(m_TXTCache.astCachetable[m_TXTCache.CurrentPage[magazine]][m_TXTCache.CurrentSubPage[magazine]]->data, ' ', 23*40);
  296. memset(pagedata[magazine],' ', 23*40);
  297. }
  298. // if (dehamming[vtxt_row[9]] & 8) /* C8 -> update page */
  299. // doupdate = m_TXTCache.PageReceiving;
  300. pageinfo_thread->boxed = !!(dehamming[vtxt_row[7]] & 0x0c);
  301. /* get country control bits */
  302. b1 = dehamming[vtxt_row[9]];
  303. if (b1 != 0xFF)
  304. {
  305. pageinfo_thread->nationalvalid = 1;
  306. pageinfo_thread->national = rev_lut[b1] & 0x07;
  307. }
  308. if (dehamming[vtxt_row[7]] & 0x08)// subtitle page
  309. {
  310. int i = 0, found = -1, use = -1;
  311. for (; i < 8; i++)
  312. {
  313. if (use == -1 && !m_TXTCache.SubtitlePages[i].page)
  314. use = i;
  315. else if (m_TXTCache.SubtitlePages[i].page == m_TXTCache.PageReceiving)
  316. {
  317. found = i;
  318. use = i;
  319. break;
  320. }
  321. }
  322. if (found == -1 && use != -1)
  323. m_TXTCache.SubtitlePages[use].page = m_TXTCache.PageReceiving;
  324. if (use != -1)
  325. m_TXTCache.SubtitlePages[use].language = CountryConversionTable[pageinfo_thread->national];
  326. }
  327. /* check parity, copy line 0 to cache (start and end 8 bytes are not needed and used otherwise) */
  328. unsigned char *p = m_TXTCache.astCachetable[m_TXTCache.CurrentPage[magazine]][m_TXTCache.CurrentSubPage[magazine]]->p0;
  329. for (int i = 10; i < 42-8; i++)
  330. *p++ = deparity[vtxt_row[i]];
  331. if (!IsDec(m_TXTCache.PageReceiving))
  332. continue; /* valid hex page number: just copy headline, ignore TimeString */
  333. /* copy TimeString */
  334. p = m_TXTCache.TimeString;
  335. for (int i = 42-8; i < 42; i++)
  336. *p++ = deparity[vtxt_row[i]];
  337. }
  338. else if (packet_number == 29 && dehamming[vtxt_row[2]]== 0) /* packet 29/0 replaces 28/0 for a whole magazine */
  339. {
  340. Decode_p2829(vtxt_row, &(m_TXTCache.astP29[magazine]));
  341. }
  342. else if (m_TXTCache.CurrentPage[magazine] != -1 && m_TXTCache.CurrentSubPage[magazine] != -1)
  343. /* packet>0, 0 has been correctly received, buffer allocated */
  344. {
  345. pageinfo_thread = &(m_TXTCache.astCachetable[m_TXTCache.CurrentPage[magazine]][m_TXTCache.CurrentSubPage[magazine]]->pageinfo);
  346. if (!pageinfo_thread)
  347. continue;
  348. /* pointer to current info struct */
  349. if (packet_number <= 25)
  350. {
  351. unsigned char *p = NULL;
  352. if (packet_number < 24)
  353. {
  354. p = pagedata[magazine] + 40*(packet_number-1);
  355. }
  356. else
  357. {
  358. if (!(pageinfo_thread->p24))
  359. pageinfo_thread->p24 = (unsigned char*) calloc(2, 40);
  360. if (pageinfo_thread->p24)
  361. p = pageinfo_thread->p24 + (packet_number - 24) * 40;
  362. }
  363. if (p)
  364. {
  365. if (IsDec(m_TXTCache.CurrentPage[magazine]))
  366. {
  367. for (int i = 2; i < 42; i++)
  368. {
  369. *p++ = vtxt_row[i] & 0x7f; /* allow values with parity errors as some channels don't care :( */
  370. }
  371. }
  372. else if ((m_TXTCache.CurrentPage[magazine] & 0xff) == 0xfe)
  373. {
  374. for (int i = 2; i < 42; i++)
  375. {
  376. *p++ = dehamming[vtxt_row[i]]; /* decode hamming 8/4 */
  377. }
  378. }
  379. else /* other hex page: no parity check, just copy */
  380. memcpy(p, &vtxt_row[2], 40);
  381. }
  382. }
  383. else if (packet_number == 27)
  384. {
  385. int descode = dehamming[vtxt_row[2]]; /* designation code (0..15) */
  386. if (descode == 0xff)
  387. continue;
  388. if (descode == 0) // reading FLOF-Pagelinks
  389. {
  390. b1 = dehamming[vtxt_row[0]];
  391. if (b1 != 0xff)
  392. {
  393. b1 &= 7;
  394. for (int i = 0; i < FLOFSIZE; i++)
  395. {
  396. b2 = dehamming[vtxt_row[4+i*6]];
  397. b3 = dehamming[vtxt_row[3+i*6]];
  398. if (b2 != 0xff && b3 != 0xff)
  399. {
  400. b4 = ((b1 ^ (dehamming[vtxt_row[8+i*6]]>>1)) & 6) | ((b1 ^ (dehamming[vtxt_row[6+i*6]]>>3)) & 1);
  401. if (b4 == 0)
  402. b4 = 8;
  403. if (b2 <= 9 && b3 <= 9)
  404. m_TXTCache.FlofPages[m_TXTCache.CurrentPage[magazine] ][i] = b4<<8 | b2<<4 | b3;
  405. }
  406. }
  407. /* copy last 2 links to ADIPTable for TOP-Index */
  408. if (pageinfo_thread->p24) /* packet 24 received */
  409. {
  410. int a, a1, e=39, l=3;
  411. unsigned char *p = pageinfo_thread->p24;
  412. do
  413. {
  414. for (;
  415. l >= 2 && 0 == m_TXTCache.FlofPages[m_TXTCache.CurrentPage[magazine]][l];
  416. l--)
  417. ; /* find used linkindex */
  418. for (;
  419. e >= 1 && !isalnum(p[e]);
  420. e--)
  421. ; /* find end */
  422. for (a = a1 = e - 1;
  423. a >= 0 && p[a] >= ' ';
  424. a--) /* find start */
  425. if (p[a] > ' ')
  426. a1 = a; /* first non-space */
  427. if (a >= 0 && l >= 2)
  428. {
  429. strncpy(m_TXTCache.ADIPTable[m_TXTCache.FlofPages[m_TXTCache.CurrentPage[magazine]][l]], (const char*) &p[a1], 12);
  430. if (e-a1 < 11)
  431. m_TXTCache.ADIPTable[m_TXTCache.FlofPages[m_TXTCache.CurrentPage[magazine]][l]][e-a1+1] = '\0';
  432. }
  433. e = a - 1;
  434. l--;
  435. } while (l >= 2);
  436. }
  437. }
  438. }
  439. else if (descode == 4) /* level 2.5 links (ignore level 3.5 links of /4 and /5) */
  440. {
  441. int i;
  442. Textp27_t *p;
  443. if (!pageinfo_thread->ext)
  444. pageinfo_thread->ext = (TextExtData_t*) calloc(1, sizeof(TextExtData_t));
  445. if (!pageinfo_thread->ext)
  446. continue;
  447. if (!(pageinfo_thread->ext->p27))
  448. pageinfo_thread->ext->p27 = (Textp27_t*) calloc(4, sizeof(Textp27_t));
  449. if (!(pageinfo_thread->ext->p27))
  450. continue;
  451. p = pageinfo_thread->ext->p27;
  452. for (i = 0; i < 4; i++)
  453. {
  454. int d1 = CDVDTeletextTools::deh24(&vtxt_row[6*i + 3]);
  455. int d2 = CDVDTeletextTools::deh24(&vtxt_row[6*i + 6]);
  456. if (d1 < 0 || d2 < 0)
  457. continue;
  458. p->local = i & 0x01;
  459. p->drcs = !!(i & 0x02);
  460. p->l25 = !!(d1 & 0x04);
  461. p->l35 = !!(d1 & 0x08);
  462. p->page =
  463. (((d1 & 0x000003c0) >> 6) |
  464. ((d1 & 0x0003c000) >> (14-4)) |
  465. ((d1 & 0x00003800) >> (11-8))) ^
  466. (dehamming[vtxt_row[0]] << 8);
  467. if (p->page < 0x100)
  468. p->page += 0x800;
  469. p->subpage = d2 >> 2;
  470. if ((p->page & 0xff) == 0xff)
  471. p->page = 0;
  472. else if (p->page > 0x899)
  473. {
  474. // workaround for crash on RTL Shop ...
  475. // sorry.. i dont understand whats going wrong here :)
  476. continue;
  477. }
  478. else if (m_TXTCache.astCachetable[p->page][0]) /* link valid && linked page cached */
  479. {
  480. TextPageinfo_t *pageinfo_link = &(m_TXTCache.astCachetable[p->page][0]->pageinfo);
  481. if (p->local)
  482. pageinfo_link->function = p->drcs ? FUNC_DRCS : FUNC_POP;
  483. else
  484. pageinfo_link->function = p->drcs ? FUNC_GDRCS : FUNC_GPOP;
  485. }
  486. p++; /* */
  487. }
  488. }
  489. }
  490. else if (packet_number == 26)
  491. {
  492. int descode = dehamming[vtxt_row[2]]; /* designation code (0..15) */
  493. if (descode == 0xff)
  494. continue;
  495. if (!pageinfo_thread->ext)
  496. pageinfo_thread->ext = (TextExtData_t*) calloc(1, sizeof(TextExtData_t));
  497. if (!pageinfo_thread->ext)
  498. continue;
  499. if (!(pageinfo_thread->ext->p26[descode]))
  500. pageinfo_thread->ext->p26[descode] = (unsigned char*) malloc(13 * 3);
  501. if (pageinfo_thread->ext->p26[descode])
  502. memcpy(pageinfo_thread->ext->p26[descode], &vtxt_row[3], 13 * 3);
  503. }
  504. else if (packet_number == 28)
  505. {
  506. int descode = dehamming[vtxt_row[2]]; /* designation code (0..15) */
  507. if (descode == 0xff)
  508. continue;
  509. if (descode != 2)
  510. {
  511. int t1 = CDVDTeletextTools::deh24(&vtxt_row[7-4]);
  512. pageinfo_thread->function = t1 & 0x0f;
  513. if (!pageinfo_thread->nationalvalid)
  514. {
  515. pageinfo_thread->nationalvalid = 1;
  516. pageinfo_thread->national = (t1>>4) & 0x07;
  517. }
  518. }
  519. switch (descode) /* designation code */
  520. {
  521. case 0: /* basic level 1 page */
  522. Decode_p2829(vtxt_row, &(pageinfo_thread->ext));
  523. break;
  524. case 1: /* G0/G1 designation for older decoders, level 3.5: DCLUT4/16, colors for multicolored bitmaps */
  525. break; /* ignore */
  526. case 2: /* page key */
  527. break; /* ignore */
  528. case 3: /* types of PTUs in DRCS */
  529. break; /* TODO */
  530. case 4: /* CLUTs 0/1, only level 3.5 */
  531. break; /* ignore */
  532. default:
  533. break; /* invalid, ignore */
  534. } /* switch designation code */
  535. }
  536. else if (packet_number == 30)
  537. {
  538. m_TXTCache.line30 = "";
  539. for (int i=26-4; i <= 45-4; i++) /* station ID */
  540. m_TXTCache.line30.append(1, deparity[vtxt_row[i]]);
  541. }
  542. }
  543. /* set update flag */
  544. if (m_TXTCache.CurrentPage[magazine] == m_TXTCache.Page && m_TXTCache.CurrentSubPage[magazine] != -1)
  545. {
  546. SavePage(m_TXTCache.CurrentPage[magazine], m_TXTCache.CurrentSubPage[magazine], pagedata[magazine]);
  547. m_TXTCache.PageUpdate = true;
  548. // doupdate = 0;
  549. if (!m_TXTCache.ZapSubpageManual)
  550. m_TXTCache.SubPage = m_TXTCache.CurrentSubPage[magazine];
  551. }
  552. }
  553. }
  554. }
  555. }
  556. else if (pMsg->IsType(CDVDMsg::PLAYER_SETSPEED))
  557. {
  558. m_speed = static_cast<CDVDMsgInt*>(pMsg)->m_value;
  559. }
  560. else if (pMsg->IsType(CDVDMsg::GENERAL_FLUSH)
  561. || pMsg->IsType(CDVDMsg::GENERAL_RESET))
  562. {
  563. ResetTeletextCache();
  564. }
  565. pMsg->Release();
  566. }
  567. }
  568. void CDVDTeletextData::OnExit()
  569. {
  570. CLog::Log(LOGNOTICE, "thread end: data_thread");
  571. }
  572. void CDVDTeletextData::Flush()
  573. {
  574. if(!m_messageQueue.IsInited())
  575. return;
  576. /* flush using message as this get's called from dvdplayer thread */
  577. /* and any demux packet that has been taken out of queue need to */
  578. /* be disposed of before we flush */
  579. m_messageQueue.Flush();
  580. m_messageQueue.Put(new CDVDMsg(CDVDMsg::GENERAL_FLUSH));
  581. }
  582. void CDVDTeletextData::Decode_p2829(unsigned char *vtxt_row, TextExtData_t **ptExtData)
  583. {
  584. int bitsleft, colorindex;
  585. unsigned char *p;
  586. int t1 = CDVDTeletextTools::deh24(&vtxt_row[7-4]);
  587. int t2 = CDVDTeletextTools::deh24(&vtxt_row[10-4]);
  588. if (t1 < 0 || t2 < 0)
  589. return;
  590. if (!(*ptExtData))
  591. (*ptExtData) = (TextExtData_t*) calloc(1, sizeof(TextExtData_t));
  592. if (!(*ptExtData))
  593. return;
  594. (*ptExtData)->p28Received = 1;
  595. (*ptExtData)->DefaultCharset = (t1>>7) & 0x7f;
  596. (*ptExtData)->SecondCharset = ((t1>>14) & 0x0f) | ((t2<<4) & 0x70);
  597. (*ptExtData)->LSP = !!(t2 & 0x08);
  598. (*ptExtData)->RSP = !!(t2 & 0x10);
  599. (*ptExtData)->SPL25 = !!(t2 & 0x20);
  600. (*ptExtData)->LSPColumns = (t2>>6) & 0x0f;
  601. bitsleft = 8; /* # of bits not evaluated in val */
  602. t2 >>= 10; /* current data */
  603. p = &vtxt_row[13-4]; /* pointer to next data triplet */
  604. for (colorindex = 0; colorindex < 16; colorindex++)
  605. {
  606. if (bitsleft < 12)
  607. {
  608. t2 |= CDVDTeletextTools::deh24(p) << bitsleft;
  609. if (t2 < 0) /* hamming error */
  610. break;
  611. p += 3;
  612. bitsleft += 18;
  613. }
  614. (*ptExtData)->bgr[colorindex] = t2 & 0x0fff;
  615. bitsleft -= 12;
  616. t2 >>= 12;
  617. }
  618. if (t2 < 0 || bitsleft != 14)
  619. {
  620. (*ptExtData)->p28Received = 0;
  621. return;
  622. }
  623. (*ptExtData)->DefScreenColor = t2 & 0x1f;
  624. t2 >>= 5;
  625. (*ptExtData)->DefRowColor = t2 & 0x1f;
  626. (*ptExtData)->BlackBgSubst = !!(t2 & 0x20);
  627. t2 >>= 6;
  628. (*ptExtData)->ColorTableRemapping = t2 & 0x07;
  629. }
  630. void CDVDTeletextData::SavePage(int p, int sp, unsigned char* buffer)
  631. {
  632. CSingleLock lock(m_critSection);
  633. TextCachedPage_t* pg = m_TXTCache.astCachetable[p][sp];
  634. if (!pg)
  635. {
  636. CLog::Log(LOGERROR, "CDVDTeletextData: trying to save a not allocated page!!");
  637. return;
  638. }
  639. memcpy(pg->data, buffer, 23*40);
  640. }
  641. void CDVDTeletextData::LoadPage(int p, int sp, unsigned char* buffer)
  642. {
  643. CSingleLock lock(m_critSection);
  644. TextCachedPage_t* pg = m_TXTCache.astCachetable[p][sp];
  645. if (!pg)
  646. {
  647. CLog::Log(LOGERROR, "CDVDTeletextData: trying to load a not allocated page!!");
  648. return;
  649. }
  650. memcpy(buffer, pg->data, 23*40);
  651. }
  652. void CDVDTeletextData::ErasePage(int magazine)
  653. {
  654. CSingleLock lock(m_critSection);
  655. TextCachedPage_t* pg = m_TXTCache.astCachetable[m_TXTCache.CurrentPage[magazine]][m_TXTCache.CurrentSubPage[magazine]];
  656. if (pg)
  657. {
  658. memset(&(pg->pageinfo), 0, sizeof(TextPageinfo_t)); /* struct pageinfo */
  659. memset(pg->p0, ' ', 24);
  660. memset(pg->data, ' ', 23*40);
  661. }
  662. }
  663. void CDVDTeletextData::AllocateCache(int magazine)
  664. {
  665. /* check cachetable and allocate memory if needed */
  666. if (m_TXTCache.astCachetable[m_TXTCache.CurrentPage[magazine]][m_TXTCache.CurrentSubPage[magazine]] == 0)
  667. {
  668. m_TXTCache.astCachetable[m_TXTCache.CurrentPage[magazine]][m_TXTCache.CurrentSubPage[magazine]] = new TextCachedPage_t;
  669. if (m_TXTCache.astCachetable[m_TXTCache.CurrentPage[magazine]][m_TXTCache.CurrentSubPage[magazine]] )
  670. {
  671. ErasePage(magazine);
  672. m_TXTCache.CachedPages++;
  673. }
  674. }
  675. }