MythTV  master
mythccextractorplayer.cpp
Go to the documentation of this file.
1 // -*- Mode: c++ -*-
2 
3 /*
4  * Class MythCCExtractorPlayer
5  *
6  * Copyright (C) Digital Nirvana, Inc. 2010
7  *
8  * This program is free software; you can redistribute it and/or modify
9  * it under the terms of the GNU General Public License as published by
10  * the Free Software Foundation; either version 2 of the License, or
11  * (at your option) any later version.
12  *
13  * This program is distributed in the hope that it will be useful,
14  * but WITHOUT ANY WARRANTY; without even the implied warranty of
15  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16  * GNU General Public License for more details.
17  *
18  * You should have received a copy of the GNU General Public License
19  * along with this program; if not, write to the Free Software
20  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
21  */
22 
23 #include <iostream>
24 using namespace std;
25 
26 #include <QFileInfo>
27 #include <QPainter>
28 
30 #include "mythccextractorplayer.h"
31 #include "avformatdecoder.h"
32 #include "subtitlescreen.h"
33 #include "srtwriter.h"
34 #include "iso639.h"
35 
36 
37 const int OneSubtitle::kDefaultLength = 750; /* ms */
38 
40 {
41  while (!srtwriters.empty())
42  {
43  delete *srtwriters.begin();
44  srtwriters.erase(srtwriters.begin());
45  }
46 }
47 CC608Stuff::~CC608Stuff() { delete reader; }
48 CC708Stuff::~CC708Stuff() { delete reader; }
49 TeletextStuff::~TeletextStuff() { delete reader; }
50 DVBSubStuff::~DVBSubStuff() { delete reader; }
51 
53  const QString &fileName,
54  const QString &destdir) :
55  MythPlayer(flags),
56  m_curTime(0),
57  m_myFramesPlayed(0),
58  m_showProgress(showProgress),
59  m_fileName(fileName)
60 {
61  // Determine where we will put extracted info.
62  QStringList comps = QFileInfo(m_fileName).fileName().split(".");
63  if (!comps.empty())
64  comps.removeLast();
65  if (destdir.isEmpty())
66  m_workingDir = QDir(QFileInfo(m_fileName).path());
67  else
68  {
69  m_workingDir = QDir(destdir);
70  if (!m_workingDir.exists())
71  m_workingDir = QDir(QFileInfo(m_fileName).path());
72  }
73  m_baseName = comps.join(".");
74 }
75 
81 {
84  {
86  double fps = frame->frame_rate;
87  if (fps <= 0)
88  fps = GetDecoder()->GetFPS();
89  double duration = 1 / fps + frame->repeat_pict * 0.5 / fps;
90  m_curTime += duration * 1000;
92  }
93 
98 }
99 
100 static QString progress_string(
101  MythTimer &flagTime, uint64_t m_myFramesPlayed, uint64_t totalFrames)
102 {
103  if (totalFrames == 0ULL)
104  {
105  return QString("%1 frames processed \r")
106  .arg(m_myFramesPlayed,7);
107  }
108 
109  static char const spin_chars[] = "/-\\|";
110  static uint spin_cnt = 0;
111 
112  double elapsed = flagTime.elapsed() * 0.001;
113  double flagFPS = (elapsed > 0.0) ? (m_myFramesPlayed / elapsed) : 0;
114 
115  double percentage = m_myFramesPlayed * 100.0 / totalFrames;
116  percentage = (percentage > 100.0 && percentage < 101.0) ?
117  100.0 : percentage;
118 
119  if (m_myFramesPlayed < totalFrames)
120  return QString("%1 fps %2% \r")
121  .arg(flagFPS,4,'f', (flagFPS < 10.0 ? 1 : 0)).arg(percentage,4,'f',1);
122  else
123  return QString("%1 fps %2 \r")
124  .arg(flagFPS,4,'f', (flagFPS < 10.0 ? 1 : 0))
125  .arg(spin_chars[++spin_cnt % 4]);
126 }
127 
129 {
130  m_myFramesPlayed = 0;
131 
132  killdecoder = false;
133  framesPlayed = 0;
134 
136 
137  SetPlaying(true);
138 
139  if (!InitVideo())
140  {
141  LOG(VB_GENERAL, LOG_ERR, "Unable to initialize video");
142  SetPlaying(false);
143  return false;
144  }
145 
146  ClearAfterSeek();
147 
148  MythTimer flagTime, ui_timer, inuse_timer, save_timer;
149  flagTime.start();
150  ui_timer.start();
151  inuse_timer.start();
152  save_timer.start();
153 
154  m_curTime = 0;
155 
156  QString currDir = QFileInfo(m_fileName).path();
157 
159  OnGotNewFrame();
160 
161  if (m_showProgress)
162  cout << "\r \r" << flush;
163 
164  while (!killdecoder && !IsErrored())
165  {
166  if (inuse_timer.elapsed() > 2534)
167  {
168  inuse_timer.restart();
169  player_ctx->LockPlayingInfo(__FILE__, __LINE__);
170  if (player_ctx->playingInfo)
172  player_ctx->UnlockPlayingInfo(__FILE__, __LINE__);
173  }
174 
175  if (m_showProgress && (ui_timer.elapsed() > 98 * 4))
176  {
177  ui_timer.restart();
178  QString str = progress_string(
179  flagTime, m_myFramesPlayed, totalFrames);
180  cout << qPrintable(str) << '\r' << flush;
181  }
182 
184  break;
185 
186  OnGotNewFrame();
187  }
188 
189  if (m_showProgress)
190  {
191  if ((m_myFramesPlayed < totalFrames) &&
192  ((m_myFramesPlayed + 30) > totalFrames))
193  {
195  }
196  QString str = progress_string(flagTime, m_myFramesPlayed, totalFrames);
197  cout << qPrintable(str) << endl;
198  }
199 
204 
205  SetPlaying(false);
206  killdecoder = true;
207 
208  return true;
209 }
210 
211 
219  QList<OneSubtitle> &list, const QStringList &content)
220 {
221  bool update_last =
222  !list.isEmpty() &&
223  (int64_t)m_curTime == list.back().start_time &&
224  !content.isEmpty();
225 
226  if (update_last)
227  {
228  //update text only (need for cc608)
229  list.back().text = content;
230  return;
231  }
232 
233  OneSubtitle last_one = list.isEmpty() ? OneSubtitle() : list.back();
234  if (content != last_one.text || last_one.length >= 0)
235  {
236  // Finish previous subtitle.
237  if (!last_one.text.isEmpty() && last_one.length < 0)
238  {
239  list.back().length = (int64_t)m_curTime - last_one.start_time;
240  }
241 
242  // Put new one if it isn't empty.
243  if (!content.isEmpty())
244  {
245  OneSubtitle new_one;
246  new_one.start_time = (int64_t)m_curTime;
247  new_one.text = content;
248 
249  list.push_back(new_one);
250  }
251  }
252 }
253 
262  QList<OneSubtitle> &list, const OneSubtitle &content)
263 {
264  bool update_last =
265  !list.isEmpty() &&
266  content.start_time == list.back().start_time &&
267  !content.img.isNull();
268 
269  if (update_last)
270  {
271  list.back().img = content.img; // update image only
272  return;
273  }
274 
275  OneSubtitle last_one = list.isEmpty() ? OneSubtitle() : list.back();
276  if (content.img != last_one.img || last_one.length >= 0)
277  {
278  // Finish previous subtitle.
279  if (!last_one.img.isNull() && last_one.length < 0)
280  {
281  list.back().length = content.start_time - last_one.start_time;
282  }
283 
284  // Put new one if it isn't empty.
285  if (!content.img.isNull())
286  {
287  OneSubtitle new_one;
288  new_one.start_time = content.start_time;
289  new_one.img = content.img;
290 
291  list.push_back(new_one);
292  }
293  }
294 }
295 
297 {
298  static const int ccIndexTbl[7] =
299  {
300  0, // CC_CC1
301  1, // CC_CC2
302  9, // sentinel
303  9, // sentinel
304  2, // CC_CC3
305  3, // CC_CC4
306  9, // sentinel
307  };
308 
309  // for each CC of each video...
310  CC608Info::iterator it = m_cc608_info.begin();
311  for (; it != m_cc608_info.end(); ++it)
312  {
313  while (true)
314  {
315  bool changed = false;
316  int streamRawIdx = -1;
317  CC608Buffer *textlist = (*it).reader->GetOutputText(
318  changed, streamRawIdx);
319 
320  if (!changed || !textlist)
321  break;
322 
323  if (streamRawIdx < 0)
324  continue;
325 
326  textlist->lock.lock();
327 
328  const int ccIdx = ccIndexTbl[min(streamRawIdx,6)];
329 
330  if (ccIdx >= 4)
331  {
332  textlist->lock.unlock();
333  continue;
334  }
335 
336  FormattedTextSubtitle608 fsub(textlist->buffers);
337  QStringList content = fsub.ToSRT();
338 
339  textlist->lock.unlock();
340 
341  IngestSubtitle((*it).subs[ccIdx], content);
342  }
343  }
344 }
345 
346 // Note: GetCaptionLanguage() will not return valid if there are multiple videos
348 {
349  int i = 0;
350  CC608Info::iterator cc608it = m_cc608_info.begin();
351  for (; cc608it != m_cc608_info.end(); ++cc608it)
352  {
353  QString stream_id_str = (m_cc608_info.size() <= 1) ?
354  QString("") : QString("%1.").arg(i,2,QChar('0'));
355 
356  CC608StreamType &subs = (*cc608it).subs;
357  CC608StreamType::iterator it = subs.begin();
358  for (; it != subs.end(); ++it)
359  {
360  if ((*it).empty())
361  continue; // Skip empty subtitle streams.
362  if (((kProcessFinalize & flags) == 0) && ((*it).size() <= 1))
363  continue; // Leave one caption behind so it can be amended
364 
365  int idx = it.key();
366 
367  if (!(*cc608it).srtwriters[idx])
368  {
369  int langCode = 0;
370  AvFormatDecoder *avd = dynamic_cast<AvFormatDecoder *>(decoder);
371  if (avd)
372  langCode = avd->GetCaptionLanguage(
373  kTrackTypeCC608, idx + 1);
374 
375  QString lang = iso639_key_to_str3(langCode);
376  lang = iso639_is_key_undefined(langCode) ? "und" : lang;
377 
378  QString service_key = QString("cc%1").arg(idx + 1);
379  QString filename = QString("%1.%2%3-%4.%5.srt")
380  .arg(m_baseName).arg(stream_id_str).arg("608")
381  .arg(service_key).arg(lang);
382 
383  (*cc608it).srtwriters[idx] = new SRTWriter(
384  m_workingDir.filePath(filename));
385  }
386 
387  if (!(*cc608it).srtwriters[idx]->IsOpen())
388  {
389  (*it).clear();
390  continue;
391  }
392 
393  while ((*it).size() > ((kProcessFinalize & flags) ? 0 : 1))
394  {
395  if ((*it).front().length <= 0)
396  (*it).front().length = OneSubtitle::kDefaultLength;
397 
398  (*cc608it).srtwriters[idx]->AddSubtitle(
399  (*it).front(), ++(*cc608it).subs_num[idx]);
400  (*it).pop_front();
401  }
402 
403  (*cc608it).srtwriters[idx]->Flush();
404  }
405  }
406 }
407 
409 {
410  // For each window of each service of each video...
411  CC708Info::const_iterator it = m_cc708_info.begin();
412  for (; it != m_cc708_info.end(); ++it)
413  {
414  for (uint serviceIdx = 1; serviceIdx < k708MaxServices; ++serviceIdx)
415  {
416  CC708Service *service = (*it).reader->GetService(serviceIdx);
417  for (uint windowIdx = 0; windowIdx < 8; ++windowIdx)
418  {
419  CC708Window &win = service->windows[windowIdx];
420  if (win.GetChanged())
421  {
422  vector<CC708String*> strings;
423  if (win.GetVisible())
424  {
425  strings = win.GetStrings();
426  Ingest708Caption(it.key(), serviceIdx, windowIdx,
427  win.pen.row, win.pen.column,
428  win, strings);
429  win.DisposeStrings(strings);
430  }
431  service->windows[windowIdx].ResetChanged();
432  }
433  }
434  }
435  }
436 }
437 
439  uint streamId, uint serviceIdx,
440  uint windowIdx, uint start_row, uint start_column,
441  const CC708Window &win,
442  const vector<CC708String*> &content)
443 {
444  FormattedTextSubtitle708 fsub(win, windowIdx, content);
445  QStringList winContent = fsub.ToSRT();
446 
447  QMap<int, Window> &cc708win = m_cc708_windows[streamId][serviceIdx];
448  cc708win[windowIdx].row = start_row;
449  cc708win[windowIdx].column = start_column;
450  cc708win[windowIdx].text = winContent;
451 
452  QMap<uint, QStringList> orderedContent;
453  QMap<int, Window>::const_iterator ccIt = cc708win.begin();
454  for (; ccIt != cc708win.end() ; ++ccIt)
455  {
456  uint idx = (*ccIt).row * 1000 + (*ccIt).column;
457  for (QStringList::const_iterator sit = (*ccIt).text.begin();
458  sit != (*ccIt).text.end(); ++sit)
459  {
460  orderedContent[idx] += (*sit);
461  }
462  }
463 
464  QStringList screenContent;
465  for (QMap<uint, QStringList>::const_iterator oit = orderedContent.begin();
466  oit != orderedContent.end(); ++oit)
467  {
468  screenContent += *oit;
469  }
470  IngestSubtitle(m_cc708_info[streamId].subs[serviceIdx], screenContent);
471 }
472 
473 // Note: GetCaptionLanguage() will not return valid if there are multiple videos
475 {
476  int i = 0;
477  CC708Info::iterator cc708it = m_cc708_info.begin();
478  for (; cc708it != m_cc708_info.end(); ++cc708it)
479  {
480  QString stream_id_str = (m_cc708_info.size() <= 1) ?
481  QString("") : QString("%1.").arg(i,2,QChar('0'));
482 
483  CC708StreamType &subs = (*cc708it).subs;
484  CC708StreamType::iterator it = subs.begin();
485  for (; it != subs.end(); ++it)
486  {
487  if ((*it).empty())
488  continue; // Skip empty subtitle streams.
489  if (((kProcessFinalize & flags) == 0) && ((*it).size() <= 1))
490  continue; // Leave one caption behind so it can be amended
491 
492  int idx = it.key();
493 
494  if (!(*cc708it).srtwriters[idx])
495  {
496  int langCode = 0;
497  AvFormatDecoder *avd = dynamic_cast<AvFormatDecoder*>(decoder);
498  if (avd)
499  langCode = avd->GetCaptionLanguage(kTrackTypeCC708, idx);
500 
501  QString lang = iso639_key_to_str3(langCode);
502 
503  QString service_key = QString("service-%1")
504  .arg(idx, 2, 10, QChar('0'));
505  QString id = iso639_is_key_undefined(langCode) ?
506  service_key : lang;
507  QString filename = QString("%1.%2%3-%4.%5.srt")
508  .arg(m_baseName).arg(stream_id_str).arg("708")
509  .arg(service_key).arg(lang);
510 
511  (*cc708it).srtwriters[idx] = new SRTWriter(
512  m_workingDir.filePath(filename));
513  }
514 
515  if (!(*cc708it).srtwriters[idx]->IsOpen())
516  {
517  (*it).clear();
518  continue;
519  }
520 
521  while ((*it).size() > ((kProcessFinalize & flags) ? 0 : 1))
522  {
523  if ((*it).front().length <= 0)
524  (*it).front().length = OneSubtitle::kDefaultLength;
525 
526  (*cc708it).srtwriters[idx]->AddSubtitle(
527  (*it).front(), ++(*cc708it).subs_num[idx]);
528  (*it).pop_front();
529  }
530 
531  (*cc708it).srtwriters[idx]->Flush();
532  }
533  }
534 }
535 
536 static QStringList to_string_list(const TeletextSubPage &subPage)
537 {
538  QStringList content;
539  // Skip the page header (line 0)
540  for (int i = 1; i < 25; ++i)
541  {
542  QString str = decode_teletext(subPage.lang, subPage.data[i]).trimmed();
543  if (!str.isEmpty())
544  content += str;
545  }
546  return content;
547 }
548 
550 {
551  TeletextInfo::iterator ttxit = m_ttx_info.begin();
552  for (; ttxit != m_ttx_info.end(); ++ttxit)
553  {
554  typedef QPair<int, int> qpii;
555  QSet<qpii> updatedPages = (*ttxit).reader->GetUpdatedPages();
556  if (updatedPages.isEmpty())
557  continue;
558 
559  QSet<qpii>::const_iterator it = updatedPages.constBegin();
560  for (; it != updatedPages.constEnd(); ++it)
561  {
562  (*ttxit).reader->SetPage((*it).first, (*it).second);
563  TeletextSubPage *subpage = (*ttxit).reader->FindSubPage();
564  if (subpage && subpage->subtitle)
565  {
566  IngestSubtitle((*ttxit).subs[(*it).first],
567  to_string_list(*subpage));
568  }
569  }
570 
571  (*ttxit).reader->ClearUpdatedPages();
572  }
573 }
574 
576 {
577  int i = 0;
578  TeletextInfo::iterator ttxit = m_ttx_info.begin();
579  for (; ttxit != m_ttx_info.end(); ++ttxit)
580  {
581  QString stream_id_str = (m_cc608_info.size() <= 1) ?
582  QString("") : QString("%1.").arg(i,2,QChar('0'));
583 
584  TeletextStreamType &subs = (*ttxit).subs;
585  TeletextStreamType::iterator it = subs.begin();
586  for (; it != subs.end(); ++it)
587  {
588  if ((*it).empty())
589  continue; // Skip empty subtitle streams.
590  if (((kProcessFinalize & flags) == 0) && ((*it).size() <= 1))
591  continue; // Leave one caption behind so it can be amended
592 
593  uint page = it.key();
594 
595  if (!(*ttxit).srtwriters[page])
596  {
597  int langCode = 0;
598  AvFormatDecoder *avd = dynamic_cast<AvFormatDecoder *>(decoder);
599 
600  if (avd)
601  langCode = avd->GetTeletextLanguage(page);
602 
603  QString lang = iso639_key_to_str3(langCode);
604  lang = iso639_is_key_undefined(langCode) ? "und" : lang;
605  QString filename = QString("%1-%2.%3ttx-0x%4.srt")
606  .arg(m_baseName)
607  .arg(lang)
608  .arg(stream_id_str)
609  .arg(page, 3, 16, QChar('0'));
610 
611  (*ttxit).srtwriters[page] = new SRTWriter(
612  m_workingDir.filePath(filename));
613  }
614 
615  if (!(*ttxit).srtwriters[page]->IsOpen())
616  {
617  (*it).clear();
618  continue;
619  }
620 
621  while ((*it).size() > ((kProcessFinalize & flags) ? 0 : 1))
622  {
623  if ((*it).front().length <= 0)
624  (*it).front().length = OneSubtitle::kDefaultLength;
625 
626  (*ttxit).srtwriters[page]->AddSubtitle(
627  (*it).front(), ++(*ttxit).subs_num[page]);
628  (*it).pop_front();
629  }
630 
631  (*ttxit).srtwriters[page]->Flush();
632  }
633  }
634 }
635 
637 {
638  DVBSubInfo::iterator subit = m_dvbsub_info.begin();
639  for (; subit != m_dvbsub_info.end(); ++subit)
640  {
642  if ((*subit).reader->HasTextSubtitles())
643  {
644  LOG(VB_VBI, LOG_DEBUG,
645  "There are unhandled text dvb subtitles");
646  }
647 
648  uint64_t duration;
649  const QStringList rawSubs =
650  (*subit).reader->GetRawTextSubtitles(duration);
651  if (!rawSubs.isEmpty())
652  {
653  LOG(VB_VBI, LOG_DEBUG,
654  QString("There are also %1 raw text subtitles with duration %2")
655  .arg(rawSubs.size()).arg(duration));
656  }
658 
659  AVSubtitles *avsubtitles = (*subit).reader->GetAVSubtitles();
660 
661  QMutexLocker locker(&(avsubtitles->lock));
662 
663  while (!avsubtitles->buffers.empty())
664  {
665  const AVSubtitle subtitle = avsubtitles->buffers.front();
666  avsubtitles->buffers.pop_front();
667 
668  const QSize v_size =
669  QSize(GetVideoSize().width()*4, GetVideoSize().height()*4);
670  QImage sub_pict(v_size, QImage::Format_ARGB32);
671  sub_pict.fill(0);
672 
673  int min_x = v_size.width();
674  int min_y = v_size.height();
675  int max_x = 0;
676  int max_y = 0;
677 
678  QPainter painter(&sub_pict);
679  for (int i = 0; i < (int) subtitle.num_rects; ++i)
680  {
681  AVSubtitleRect *rect = subtitle.rects[i];
682 
683  if (subtitle.rects[i]->type == SUBTITLE_BITMAP)
684  {
685  const int x = rect->x;
686  const int y = rect->y;
687  const int w = rect->w;
688  const int h = rect->h;
689  const int cc = rect->nb_colors;
690  const uchar *data = rect->data[0];
691  const QRgb *palette = (QRgb *) rect->data[1];
692 
693  QImage img(data, w, h, QImage::Format_Indexed8);
694  img.setColorCount(cc);
695  for (int j = 0; j < cc; ++j)
696  img.setColor(j, palette[j]);
697 
698  painter.drawImage(x, y, img);
699 
700  min_x = min(min_x, x);
701  min_y = min(min_y, y);
702  max_x = max(max_x, x + w);
703  max_y = max(max_y, y + h);
704  }
705  }
706  painter.end();
707 
708  OneSubtitle sub;
709  sub.start_time = subtitle.start_display_time;
710  sub.length =
711  subtitle.end_display_time - subtitle.start_display_time;
712 
713  (*subit).reader->FreeAVSubtitle(subtitle);
714 
715  if (min_x < max_x && min_y < max_y)
716  {
717  sub.img_shift = QPoint(min_x, min_y);
718  sub.img = sub_pict.copy(
719  min_x, min_y, max_x - min_x, max_y - min_y);
720  }
721  else
722  {
723  // Empty subtitle, do nothing.
724  }
725 
726  IngestSubtitle((*subit).subs, sub);
727  }
728 
729  locker.unlock();
730 
731  (*subit).reader->ClearRawTextSubtitles();
732  }
733 }
734 
736 {
737  // Process (DVB) subtitle streams.
738  DVBSubInfo::iterator subit = m_dvbsub_info.begin();
739  int subtitleStreamCount = 0;
740  for (; subit != m_dvbsub_info.end(); ++subit)
741  {
742  int langCode = 0;
743  AvFormatDecoder *avd = dynamic_cast<AvFormatDecoder *>(decoder);
744  int idx = subit.key();
745  if (avd)
746  langCode = avd->GetSubtitleLanguage(subtitleStreamCount, idx);
747  subtitleStreamCount++;
748 
749  QString lang = iso639_key_to_str3(langCode);
750  lang = iso639_is_key_undefined(langCode) ? "und" : lang;
751  QString dir_name = m_baseName + QString("-%1.dvb-%2").arg(lang).arg(subit.key());
752  if (!m_workingDir.exists(dir_name) && !m_workingDir.mkdir(dir_name))
753  {
754  LOG(VB_GENERAL, LOG_ERR, QString("Can't create directory '%1'")
755  .arg(dir_name));
756  (*subit).subs.clear();
757  continue;
758  }
759 
760  DVBStreamType &subs = (*subit).subs;
761  if (subs.empty())
762  continue; // Skip empty subtitle streams.
763  if (((kProcessFinalize & flags) == 0) && (subs.size() <= 1))
764  continue; // Leave one caption behind so it can be amended
765 
766  QDir stream_dir(m_workingDir.filePath(dir_name));
767  while (subs.size() > ((kProcessFinalize & flags) ? 0 : 1))
768  {
769  if (subs.front().length <= 0)
770  subs.front().length = OneSubtitle::kDefaultLength;
771 
772  const OneSubtitle &sub = subs.front();
773  int64_t end_time = sub.start_time + sub.length;
774  const QString file_name =
775  stream_dir.filePath(
776  QString("%1_%2-to-%3.png")
777  .arg((*subit).subs_num)
778  .arg(sub.start_time).arg(end_time));
779 
780  if (end_time > sub.start_time)
781  {
782  //check is there exist file with same start_time
783  QStringList filter;
784  filter << QString("*_%1*.png").arg(sub.start_time);
785  QFileInfoList found = stream_dir.entryInfoList(filter);
786  if (found.isEmpty())
787  {
788  //no same start_time founded
789  if (!sub.img.save(file_name))
790  {
791  LOG(VB_GENERAL, LOG_ERR,
792  QString("Can't write file '%1'")
793  .arg(file_name));
794  }
795  (*subit).subs_num++;
796  }
797  }
798  subs.pop_front();
799  }
800  }
801 }
802 
803 
805 {
806  if (!m_cc708_info[id].reader)
807  {
808  m_cc708_info[id].reader = new CC708Reader(this);
809  m_cc708_info[id].reader->SetEnabled(true);
810  LOG(VB_GENERAL, LOG_INFO, "Created CC708Reader");
811  }
812  return m_cc708_info[id].reader;
813 }
814 
816 {
817  if (!m_cc608_info[id].reader)
818  {
819  m_cc608_info[id].reader = new CC608Reader(this);
820  m_cc608_info[id].reader->SetEnabled(true);
821  }
822  return m_cc608_info[id].reader;
823 }
824 
826 {
827  if (!m_ttx_info[id].reader)
828  m_ttx_info[id].reader = new TeletextExtractorReader();
829  return m_ttx_info[id].reader;
830 }
831 
833 {
834  if (!m_dvbsub_info[id].reader)
835  {
836  m_dvbsub_info[id].reader = new SubtitleReader();
837  m_dvbsub_info[id].reader->EnableAVSubtitles(true);
838  m_dvbsub_info[id].reader->EnableTextSubtitles(true);
839  m_dvbsub_info[id].reader->EnableRawTextSubtitles(true);
840  }
841  return m_dvbsub_info[id].reader;
842 }
uint64_t totalFrames
Definition: mythplayer.h:709
void SetPlaying(bool is_playing)
Definition: mythplayer.cpp:467
int restart(void)
Returns milliseconds elapsed since last start() or restart() and resets the count.
Definition: mythtimer.cpp:62
ISO 639-1 and ISO 639-2 support functions.
Definition: cc.h:13
A QElapsedTimer based timer to replace use of QTime as a timer.
Definition: mythtimer.h:13
SubtitleReader * GetSubReader(uint id=0) override
QHash< int, QList< OneSubtitle > > CC608StreamType
Key is a CC number (1-4), values are the subtitles in chrono order.
uint row
Definition: cc708window.h:170
PlayerFlags
Definition: mythplayer.h:88
void ClearAfterSeek(bool clearvideobuffers=true)
This is to support seeking...
int repeat_pict
Definition: mythframe.h:59
QHash< int, QList< OneSubtitle > > CC708StreamType
Key is a CC service (1-63), values are the subtitles in chrono order.
virtual int GetCaptionLanguage(TrackTypes trackType, int service_num)
Return ATSC Closed Caption Language.
bool volatile killdecoder
Definition: mythplayer.h:662
void UnlockPlayingInfo(const char *file, int line) const
CC708Reader * GetCC708Reader(uint id=0) override
vector< CC608Text * > buffers
Definition: cc608reader.h:54
void Process708Captions(uint flags)
void DisposeStrings(vector< CC708String * > &strings) const
unsigned int uint
Definition: compat.h:140
uint8_t data[25][40]
page data
void UpdateInUseMark(bool force=false)
virtual int GetTeletextLanguage(uint lang_idx) const
Returns TeleText language.
virtual int GetSubtitleLanguage(uint subtitle_index, uint stream_index)
Returns DVD Subtitle language.
MythCCExtractorPlayer(PlayerFlags flags, bool showProgress, const QString &fileName, const QString &destdir)
uint64_t framesPlayed
Definition: mythplayer.h:705
QMutex lock
Definition: cc608reader.h:53
virtual void StartDisplayingFrame(void)
Tell GetLastShownFrame() to return the next frame from the head of the queue of frames to display.
Definition: videooutbase.h:217
QImage img
Image of subtitle.
Class to write SubRip files.
Definition: srtwriter.h:26
virtual double GetFPS(void) const
Definition: decoderbase.h:204
QSize GetVideoSize(void) const
Definition: mythplayer.h:174
bool DecoderGetFrame(DecodeType, bool unsafe=false)
QList< OneSubtitle > DVBStreamType
Subtitles in chrono order.
CC708Pen pen
Definition: cc708window.h:278
void Process608Captions(uint flags)
bool GetVisible(void) const
Definition: cc708window.h:287
void LockPlayingInfo(const char *file, int line) const
A decoder for video files.
bool subtitle
page is subtitle page
static bool iso639_is_key_undefined(int code)
Returns true if the key is 0, 0xFFFFFF, or 'und'.
Definition: iso639.h:57
QString decode_teletext(int codePage, const uint8_t data[40])
Get decoded ttx as a string.
MythDeque< AVSubtitle > buffers
CC708Window windows[k708MaxWindows]
Definition: cc708window.h:319
bool IsErrored(void) const
QPoint img_shift
Shift of image on the screen.
static QStringList to_string_list(const TeletextSubPage &subPage)
bool GetChanged(void) const
Definition: cc708window.h:288
ProgramInfo * playingInfo
Currently playing info.
void OnGotNewFrame(void)
Call it when you got new video frame to process subtitles if any.
friend class CC708Reader
Definition: mythplayer.h:128
int elapsed(void) const
Returns milliseconds elapsed since last start() or restart()
Definition: mythtimer.cpp:90
virtual void DoneDisplayingFrame(VideoFrame *frame)
Releases frame returned from GetLastShownFrame() onto the queue of frames ready for decoding onto.
Definition: videooutbase.h:220
int length
Time we have to show subtitle, msec.
friend class CC608Reader
Definition: mythplayer.h:129
#define LOG(_MASK_, _LEVEL_, _STRING_)
Definition: mythlogging.h:41
vector< CC708String * > GetStrings(void) const
Represents one subtitle record.
void Ingest708Caption(uint streamId, uint serviceIdx, uint windowIdx, uint start_row, uint start_column, const CC708Window &win, const vector< CC708String * > &content)
virtual VideoFrame * GetLastShownFrame(void)
Returns frame from the head of the ready to be displayed queue, if StartDisplayingFrame has been call...
Definition: videooutbase.h:239
CC608Reader * GetCC608Reader(uint id=0) override
void SetDecodeAllSubtitles(bool val)
Definition: decoderbase.h:241
static QString progress_string(MythTimer &flagTime, uint64_t m_myFramesPlayed, uint64_t totalFrames)
const uint k708MaxServices
Definition: cc708reader.h:14
static QString iso639_key_to_str3(int code)
Definition: iso639.h:46
bool InitVideo(void)
Definition: mythplayer.cpp:495
static const QString comps[numcomps][3]
TeletextReader * GetTeletextReader(uint id=0) override
double m_curTime
Keeps track for decoding time to make timestamps for subtitles.
QStringList ToSRT(void) const
uint column
Definition: cc708window.h:171
VideoOutput * videoOutput
Definition: mythplayer.h:638
QHash< uint, WindowsOnService > m_cc708_windows
PlayerContext * player_ctx
Definition: mythplayer.h:639
QHash< int, QList< OneSubtitle > > TeletextStreamType
Key is a page number, values are the subtitles in chrono order.
long long GetFramesRead(void) const
Definition: decoderbase.h:209
void start(void)
starts measuring elapsed time.
Definition: mythtimer.cpp:47
QStringList text
Lines of text of subtitles.
void ResetChanged(void)
Definition: cc708window.h:305
static const int kDefaultLength
DecoderBase * GetDecoder(void)
Returns the stream decoder currently in use.
Definition: mythplayer.h:278
int64_t start_time
Time we have to start showing subtitle, msec.
int lang
language code
void ProcessDVBSubtitles(uint flags)
double frame_rate
Definition: mythframe.h:44
DecoderBase * decoder
Definition: mythplayer.h:636
void IngestSubtitle(QList< OneSubtitle > &, const QStringList &)
Adds new subtitle, finishes last if needed.