PageRenderTime 76ms CodeModel.GetById 12ms app.highlight 57ms RepoModel.GetById 1ms app.codeStats 0ms

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