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  return QString("%1 fps %2 \r")
123  .arg(flagFPS,4,'f', (flagFPS < 10.0 ? 1 : 0))
124  .arg(spin_chars[++spin_cnt % 4]);
125 }
126 
128 {
129  m_myFramesPlayed = 0;
130 
131  killdecoder = false;
132  framesPlayed = 0;
133 
135 
136  SetPlaying(true);
137 
138  if (!InitVideo())
139  {
140  LOG(VB_GENERAL, LOG_ERR, "Unable to initialize video");
141  SetPlaying(false);
142  return false;
143  }
144 
145  ClearAfterSeek();
146 
147  MythTimer flagTime, ui_timer, inuse_timer, save_timer;
148  flagTime.start();
149  ui_timer.start();
150  inuse_timer.start();
151  save_timer.start();
152 
153  m_curTime = 0;
154 
155  QString currDir = QFileInfo(m_fileName).path();
156 
158  OnGotNewFrame();
159 
160  if (m_showProgress)
161  cout << "\r \r" << flush;
162 
163  while (!killdecoder && !IsErrored())
164  {
165  if (inuse_timer.elapsed() > 2534)
166  {
167  inuse_timer.restart();
168  player_ctx->LockPlayingInfo(__FILE__, __LINE__);
171  player_ctx->UnlockPlayingInfo(__FILE__, __LINE__);
172  }
173 
174  if (m_showProgress && (ui_timer.elapsed() > 98 * 4))
175  {
176  ui_timer.restart();
177  QString str = progress_string(
178  flagTime, m_myFramesPlayed, totalFrames);
179  cout << qPrintable(str) << '\r' << flush;
180  }
181 
183  break;
184 
185  OnGotNewFrame();
186  }
187 
188  if (m_showProgress)
189  {
190  if ((m_myFramesPlayed < totalFrames) &&
191  ((m_myFramesPlayed + 30) > totalFrames))
192  {
194  }
195  QString str = progress_string(flagTime, m_myFramesPlayed, totalFrames);
196  cout << qPrintable(str) << endl;
197  }
198 
203 
204  SetPlaying(false);
205  killdecoder = true;
206 
207  return true;
208 }
209 
210 
218  QList<OneSubtitle> &list, const QStringList &content)
219 {
220  bool update_last =
221  !list.isEmpty() &&
222  (int64_t)m_curTime == list.back().start_time &&
223  !content.isEmpty();
224 
225  if (update_last)
226  {
227  //update text only (need for cc608)
228  list.back().text = content;
229  return;
230  }
231 
232  OneSubtitle last_one = list.isEmpty() ? OneSubtitle() : list.back();
233  if (content != last_one.text || last_one.length >= 0)
234  {
235  // Finish previous subtitle.
236  if (!last_one.text.isEmpty() && last_one.length < 0)
237  {
238  list.back().length = (int64_t)m_curTime - last_one.start_time;
239  }
240 
241  // Put new one if it isn't empty.
242  if (!content.isEmpty())
243  {
244  OneSubtitle new_one;
245  new_one.start_time = (int64_t)m_curTime;
246  new_one.text = content;
247 
248  list.push_back(new_one);
249  }
250  }
251 }
252 
261  QList<OneSubtitle> &list, const OneSubtitle &content)
262 {
263  bool update_last =
264  !list.isEmpty() &&
265  content.start_time == list.back().start_time &&
266  !content.img.isNull();
267 
268  if (update_last)
269  {
270  list.back().img = content.img; // update image only
271  return;
272  }
273 
274  OneSubtitle last_one = list.isEmpty() ? OneSubtitle() : list.back();
275  if (content.img != last_one.img || last_one.length >= 0)
276  {
277  // Finish previous subtitle.
278  if (!last_one.img.isNull() && last_one.length < 0)
279  {
280  list.back().length = content.start_time - last_one.start_time;
281  }
282 
283  // Put new one if it isn't empty.
284  if (!content.img.isNull())
285  {
286  OneSubtitle new_one;
287  new_one.start_time = content.start_time;
288  new_one.img = content.img;
289 
290  list.push_back(new_one);
291  }
292  }
293 }
294 
296 {
297  static const int ccIndexTbl[7] =
298  {
299  0, // CC_CC1
300  1, // CC_CC2
301  9, // sentinel
302  9, // sentinel
303  2, // CC_CC3
304  3, // CC_CC4
305  9, // sentinel
306  };
307 
308  // for each CC of each video...
309  CC608Info::iterator it = m_cc608_info.begin();
310  for (; it != m_cc608_info.end(); ++it)
311  {
312  while (true)
313  {
314  bool changed = false;
315  int streamRawIdx = -1;
316  CC608Buffer *textlist = (*it).reader->GetOutputText(
317  changed, streamRawIdx);
318 
319  if (!changed || !textlist)
320  break;
321 
322  if (streamRawIdx < 0)
323  continue;
324 
325  textlist->lock.lock();
326 
327  const int ccIdx = ccIndexTbl[min(streamRawIdx,6)];
328 
329  if (ccIdx >= 4)
330  {
331  textlist->lock.unlock();
332  continue;
333  }
334 
335  FormattedTextSubtitle608 fsub(textlist->buffers);
336  QStringList content = fsub.ToSRT();
337 
338  textlist->lock.unlock();
339 
340  IngestSubtitle((*it).subs[ccIdx], content);
341  }
342  }
343 }
344 
345 // Note: GetCaptionLanguage() will not return valid if there are multiple videos
347 {
348  int i = 0;
349  CC608Info::iterator cc608it = m_cc608_info.begin();
350  for (; cc608it != m_cc608_info.end(); ++cc608it)
351  {
352  QString stream_id_str = (m_cc608_info.size() <= 1) ?
353  QString("") : QString("%1.").arg(i,2,10,QChar('0'));
354 
355  CC608StreamType &subs = (*cc608it).subs;
356  CC608StreamType::iterator it = subs.begin();
357  for (; it != subs.end(); ++it)
358  {
359  if ((*it).empty())
360  continue; // Skip empty subtitle streams.
361  if (((kProcessFinalize & flags) == 0) && ((*it).size() <= 1))
362  continue; // Leave one caption behind so it can be amended
363 
364  int idx = it.key();
365 
366  if (!(*cc608it).srtwriters[idx])
367  {
368  int langCode = 0;
369  AvFormatDecoder *avd = dynamic_cast<AvFormatDecoder *>(decoder);
370  if (avd)
371  langCode = avd->GetCaptionLanguage(
372  kTrackTypeCC608, idx + 1);
373 
374  QString lang = iso639_key_to_str3(langCode);
375  lang = iso639_is_key_undefined(langCode) ? "und" : lang;
376 
377  QString service_key = QString("cc%1").arg(idx + 1);
378  QString filename = QString("%1.%2%3-%4.%5.srt")
379  .arg(m_baseName).arg(stream_id_str).arg("608")
380  .arg(service_key).arg(lang);
381 
382  (*cc608it).srtwriters[idx] = new SRTWriter(
383  m_workingDir.filePath(filename));
384  }
385 
386  if (!(*cc608it).srtwriters[idx]->IsOpen())
387  {
388  (*it).clear();
389  continue;
390  }
391 
392  while ((*it).size() > ((kProcessFinalize & flags) ? 0 : 1))
393  {
394  if ((*it).front().length <= 0)
395  (*it).front().length = OneSubtitle::kDefaultLength;
396 
397  (*cc608it).srtwriters[idx]->AddSubtitle(
398  (*it).front(), ++(*cc608it).subs_num[idx]);
399  (*it).pop_front();
400  }
401 
402  (*cc608it).srtwriters[idx]->Flush();
403  }
404  }
405 }
406 
408 {
409  // For each window of each service of each video...
410  CC708Info::const_iterator it = m_cc708_info.begin();
411  for (; it != m_cc708_info.end(); ++it)
412  {
413  for (uint serviceIdx = 1; serviceIdx < k708MaxServices; ++serviceIdx)
414  {
415  CC708Service *service = (*it).reader->GetService(serviceIdx);
416  for (uint windowIdx = 0; windowIdx < 8; ++windowIdx)
417  {
418  CC708Window &win = service->m_windows[windowIdx];
419  if (win.GetChanged())
420  {
421  vector<CC708String*> strings;
422  if (win.GetVisible())
423  {
424  strings = win.GetStrings();
425  Ingest708Caption(it.key(), serviceIdx, windowIdx,
426  win.m_pen.m_row, win.m_pen.m_column,
427  win, strings);
428  win.DisposeStrings(strings);
429  }
430  service->m_windows[windowIdx].ResetChanged();
431  }
432  }
433  }
434  }
435 }
436 
438  uint streamId, uint serviceIdx,
439  uint windowIdx, uint start_row, uint start_column,
440  const CC708Window &win,
441  const vector<CC708String*> &content)
442 {
443  FormattedTextSubtitle708 fsub(win, windowIdx, content);
444  QStringList winContent = fsub.ToSRT();
445 
446  QMap<int, Window> &cc708win = m_cc708_windows[streamId][serviceIdx];
447  cc708win[windowIdx].row = start_row;
448  cc708win[windowIdx].column = start_column;
449  cc708win[windowIdx].text = winContent;
450 
451  QMap<uint, QStringList> orderedContent;
452  QMap<int, Window>::const_iterator ccIt = cc708win.begin();
453  for (; ccIt != cc708win.end() ; ++ccIt)
454  {
455  uint idx = (*ccIt).row * 1000 + (*ccIt).column;
456  for (QStringList::const_iterator sit = (*ccIt).text.begin();
457  sit != (*ccIt).text.end(); ++sit)
458  {
459  orderedContent[idx] += (*sit);
460  }
461  }
462 
463  QStringList screenContent;
464  for (QMap<uint, QStringList>::const_iterator oit = orderedContent.begin();
465  oit != orderedContent.end(); ++oit)
466  {
467  screenContent += *oit;
468  }
469  IngestSubtitle(m_cc708_info[streamId].subs[serviceIdx], screenContent);
470 }
471 
472 // Note: GetCaptionLanguage() will not return valid if there are multiple videos
474 {
475  int i = 0;
476  CC708Info::iterator cc708it = m_cc708_info.begin();
477  for (; cc708it != m_cc708_info.end(); ++cc708it)
478  {
479  QString stream_id_str = (m_cc708_info.size() <= 1) ?
480  QString("") : QString("%1.").arg(i,2,10,QChar('0'));
481 
482  CC708StreamType &subs = (*cc708it).subs;
483  CC708StreamType::iterator it = subs.begin();
484  for (; it != subs.end(); ++it)
485  {
486  if ((*it).empty())
487  continue; // Skip empty subtitle streams.
488  if (((kProcessFinalize & flags) == 0) && ((*it).size() <= 1))
489  continue; // Leave one caption behind so it can be amended
490 
491  int idx = it.key();
492 
493  if (!(*cc708it).srtwriters[idx])
494  {
495  int langCode = 0;
496  AvFormatDecoder *avd = dynamic_cast<AvFormatDecoder*>(decoder);
497  if (avd)
498  langCode = avd->GetCaptionLanguage(kTrackTypeCC708, idx);
499 
500  QString lang = iso639_key_to_str3(langCode);
501 
502  QString service_key = QString("service-%1")
503  .arg(idx, 2, 10, QChar('0'));
504  QString id = iso639_is_key_undefined(langCode) ?
505  service_key : lang;
506  QString filename = QString("%1.%2%3-%4.%5.srt")
507  .arg(m_baseName).arg(stream_id_str).arg("708")
508  .arg(service_key).arg(lang);
509 
510  (*cc708it).srtwriters[idx] = new SRTWriter(
511  m_workingDir.filePath(filename));
512  }
513 
514  if (!(*cc708it).srtwriters[idx]->IsOpen())
515  {
516  (*it).clear();
517  continue;
518  }
519 
520  while ((*it).size() > ((kProcessFinalize & flags) ? 0 : 1))
521  {
522  if ((*it).front().length <= 0)
523  (*it).front().length = OneSubtitle::kDefaultLength;
524 
525  (*cc708it).srtwriters[idx]->AddSubtitle(
526  (*it).front(), ++(*cc708it).subs_num[idx]);
527  (*it).pop_front();
528  }
529 
530  (*cc708it).srtwriters[idx]->Flush();
531  }
532  }
533 }
534 
535 static QStringList to_string_list(const TeletextSubPage &subPage)
536 {
537  QStringList content;
538  // Skip the page header (line 0)
539  for (int i = 1; i < 25; ++i)
540  {
541  QString str = decode_teletext(subPage.lang, subPage.data[i]).trimmed();
542  if (!str.isEmpty())
543  content += str;
544  }
545  return content;
546 }
547 
549 {
550  TeletextInfo::iterator ttxit = m_ttx_info.begin();
551  for (; ttxit != m_ttx_info.end(); ++ttxit)
552  {
553  typedef QPair<int, int> qpii;
554  QSet<qpii> updatedPages = (*ttxit).reader->GetUpdatedPages();
555  if (updatedPages.isEmpty())
556  continue;
557 
558  QSet<qpii>::const_iterator it = updatedPages.constBegin();
559  for (; it != updatedPages.constEnd(); ++it)
560  {
561  (*ttxit).reader->SetPage((*it).first, (*it).second);
562  TeletextSubPage *subpage = (*ttxit).reader->FindSubPage();
563  if (subpage && subpage->subtitle)
564  {
565  IngestSubtitle((*ttxit).subs[(*it).first],
566  to_string_list(*subpage));
567  }
568  }
569 
570  (*ttxit).reader->ClearUpdatedPages();
571  }
572 }
573 
575 {
576  int i = 0;
577  TeletextInfo::iterator ttxit = m_ttx_info.begin();
578  for (; ttxit != m_ttx_info.end(); ++ttxit)
579  {
580  QString stream_id_str = (m_cc608_info.size() <= 1) ?
581  QString("") : QString("%1.").arg(i,2,10,QChar('0'));
582 
583  TeletextStreamType &subs = (*ttxit).subs;
584  TeletextStreamType::iterator it = subs.begin();
585  for (; it != subs.end(); ++it)
586  {
587  if ((*it).empty())
588  continue; // Skip empty subtitle streams.
589  if (((kProcessFinalize & flags) == 0) && ((*it).size() <= 1))
590  continue; // Leave one caption behind so it can be amended
591 
592  uint page = it.key();
593 
594  if (!(*ttxit).srtwriters[page])
595  {
596  int langCode = 0;
597  AvFormatDecoder *avd = dynamic_cast<AvFormatDecoder *>(decoder);
598 
599  if (avd)
600  langCode = avd->GetTeletextLanguage(page);
601 
602  QString lang = iso639_key_to_str3(langCode);
603  lang = iso639_is_key_undefined(langCode) ? "und" : lang;
604  QString filename = QString("%1-%2.%3ttx-0x%4.srt")
605  .arg(m_baseName)
606  .arg(lang)
607  .arg(stream_id_str)
608  .arg(page, 3, 16, QChar('0'));
609 
610  (*ttxit).srtwriters[page] = new SRTWriter(
611  m_workingDir.filePath(filename));
612  }
613 
614  if (!(*ttxit).srtwriters[page]->IsOpen())
615  {
616  (*it).clear();
617  continue;
618  }
619 
620  while ((*it).size() > ((kProcessFinalize & flags) ? 0 : 1))
621  {
622  if ((*it).front().length <= 0)
623  (*it).front().length = OneSubtitle::kDefaultLength;
624 
625  (*ttxit).srtwriters[page]->AddSubtitle(
626  (*it).front(), ++(*ttxit).subs_num[page]);
627  (*it).pop_front();
628  }
629 
630  (*ttxit).srtwriters[page]->Flush();
631  }
632  }
633 }
634 
636 {
637  DVBSubInfo::iterator subit = m_dvbsub_info.begin();
638  for (; subit != m_dvbsub_info.end(); ++subit)
639  {
641  if ((*subit).reader->HasTextSubtitles())
642  {
643  LOG(VB_VBI, LOG_DEBUG,
644  "There are unhandled text dvb subtitles");
645  }
646 
647  uint64_t duration;
648  const QStringList rawSubs =
649  (*subit).reader->GetRawTextSubtitles(duration);
650  if (!rawSubs.isEmpty())
651  {
652  LOG(VB_VBI, LOG_DEBUG,
653  QString("There are also %1 raw text subtitles with duration %2")
654  .arg(rawSubs.size()).arg(duration));
655  }
657 
658  AVSubtitles *avsubtitles = (*subit).reader->GetAVSubtitles();
659 
660  QMutexLocker locker(&(avsubtitles->m_lock));
661 
662  while (!avsubtitles->m_buffers.empty())
663  {
664  const AVSubtitle subtitle = avsubtitles->m_buffers.front();
665  avsubtitles->m_buffers.pop_front();
666 
667  const QSize v_size =
668  QSize(GetVideoSize().width()*4, GetVideoSize().height()*4);
669  QImage sub_pict(v_size, QImage::Format_ARGB32);
670  sub_pict.fill(0);
671 
672  int min_x = v_size.width();
673  int min_y = v_size.height();
674  int max_x = 0;
675  int max_y = 0;
676 
677  QPainter painter(&sub_pict);
678  for (int i = 0; i < (int) subtitle.num_rects; ++i)
679  {
680  AVSubtitleRect *rect = subtitle.rects[i];
681 
682  if (subtitle.rects[i]->type == SUBTITLE_BITMAP)
683  {
684  const int x = rect->x;
685  const int y = rect->y;
686  const int w = rect->w;
687  const int h = rect->h;
688  const int cc = rect->nb_colors;
689  const uchar *data = rect->data[0];
690  const QRgb *palette = (QRgb *) rect->data[1];
691 
692  QImage img(data, w, h, QImage::Format_Indexed8);
693  img.setColorCount(cc);
694  for (int j = 0; j < cc; ++j)
695  img.setColor(j, palette[j]);
696 
697  painter.drawImage(x, y, img);
698 
699  min_x = min(min_x, x);
700  min_y = min(min_y, y);
701  max_x = max(max_x, x + w);
702  max_y = max(max_y, y + h);
703  }
704  }
705  painter.end();
706 
707  OneSubtitle sub;
708  sub.start_time = subtitle.start_display_time;
709  sub.length =
710  subtitle.end_display_time - subtitle.start_display_time;
711 
712  (*subit).reader->FreeAVSubtitle(subtitle);
713 
714  if (min_x < max_x && min_y < max_y)
715  {
716  sub.img_shift = QPoint(min_x, min_y);
717  sub.img = sub_pict.copy(
718  min_x, min_y, max_x - min_x, max_y - min_y);
719  }
720  else
721  {
722  // Empty subtitle, do nothing.
723  }
724 
725  IngestSubtitle((*subit).subs, sub);
726  }
727 
728  locker.unlock();
729 
730  (*subit).reader->ClearRawTextSubtitles();
731  }
732 }
733 
735 {
736  // Process (DVB) subtitle streams.
737  DVBSubInfo::iterator subit = m_dvbsub_info.begin();
738  int subtitleStreamCount = 0;
739  for (; subit != m_dvbsub_info.end(); ++subit)
740  {
741  int langCode = 0;
742  AvFormatDecoder *avd = dynamic_cast<AvFormatDecoder *>(decoder);
743  int idx = subit.key();
744  if (avd)
745  langCode = avd->GetSubtitleLanguage(subtitleStreamCount, idx);
746  subtitleStreamCount++;
747 
748  QString lang = iso639_key_to_str3(langCode);
749  lang = iso639_is_key_undefined(langCode) ? "und" : lang;
750  QString dir_name = m_baseName + QString("-%1.dvb-%2").arg(lang).arg(subit.key());
751  if (!m_workingDir.exists(dir_name) && !m_workingDir.mkdir(dir_name))
752  {
753  LOG(VB_GENERAL, LOG_ERR, QString("Can't create directory '%1'")
754  .arg(dir_name));
755  (*subit).subs.clear();
756  continue;
757  }
758 
759  DVBStreamType &subs = (*subit).subs;
760  if (subs.empty())
761  continue; // Skip empty subtitle streams.
762  if (((kProcessFinalize & flags) == 0) && (subs.size() <= 1))
763  continue; // Leave one caption behind so it can be amended
764 
765  QDir stream_dir(m_workingDir.filePath(dir_name));
766  while (subs.size() > ((kProcessFinalize & flags) ? 0 : 1))
767  {
768  if (subs.front().length <= 0)
769  subs.front().length = OneSubtitle::kDefaultLength;
770 
771  const OneSubtitle &sub = subs.front();
772  int64_t end_time = sub.start_time + sub.length;
773  const QString file_name =
774  stream_dir.filePath(
775  QString("%1_%2-to-%3.png")
776  .arg((*subit).subs_num)
777  .arg(sub.start_time).arg(end_time));
778 
779  if (end_time > sub.start_time)
780  {
781  //check is there exist file with same start_time
782  QStringList filter;
783  filter << QString("*_%1*.png").arg(sub.start_time);
784  QFileInfoList found = stream_dir.entryInfoList(filter);
785  if (found.isEmpty())
786  {
787  //no same start_time founded
788  if (!sub.img.save(file_name))
789  {
790  LOG(VB_GENERAL, LOG_ERR,
791  QString("Can't write file '%1'")
792  .arg(file_name));
793  }
794  (*subit).subs_num++;
795  }
796  }
797  subs.pop_front();
798  }
799  }
800 }
801 
802 
804 {
805  if (!m_cc708_info[id].reader)
806  {
807  m_cc708_info[id].reader = new CC708Reader(this);
808  m_cc708_info[id].reader->SetEnabled(true);
809  LOG(VB_GENERAL, LOG_INFO, "Created CC708Reader");
810  }
811  return m_cc708_info[id].reader;
812 }
813 
815 {
816  if (!m_cc608_info[id].reader)
817  {
818  m_cc608_info[id].reader = new CC608Reader(this);
819  m_cc608_info[id].reader->SetEnabled(true);
820  }
821  return m_cc608_info[id].reader;
822 }
823 
825 {
826  if (!m_ttx_info[id].reader)
827  m_ttx_info[id].reader = new TeletextExtractorReader();
828  return m_ttx_info[id].reader;
829 }
830 
832 {
833  if (!m_dvbsub_info[id].reader)
834  {
835  m_dvbsub_info[id].reader = new SubtitleReader();
836  m_dvbsub_info[id].reader->EnableAVSubtitles(true);
837  m_dvbsub_info[id].reader->EnableTextSubtitles(true);
838  m_dvbsub_info[id].reader->EnableRawTextSubtitles(true);
839  }
840  return m_dvbsub_info[id].reader;
841 }
uint64_t totalFrames
Definition: mythplayer.h:710
CC708Window m_windows[k708MaxWindows]
Definition: cc708window.h:309
void SetPlaying(bool is_playing)
Definition: mythplayer.cpp:365
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.
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:663
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:706
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.
ProgramInfo * m_playingInfo
Currently playing info.
Class to write SubRip files.
Definition: srtwriter.h:26
virtual double GetFPS(void) const
Definition: decoderbase.h:200
QSize GetVideoSize(void) const
Definition: mythplayer.h:174
bool DecoderGetFrame(DecodeType, bool unsafe=false)
uint m_column
Definition: cc708window.h:161
QList< OneSubtitle > DVBStreamType
Subtitles in chrono order.
void Process608Captions(uint flags)
bool GetVisible(void) const
Definition: cc708window.h:277
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.
bool IsErrored(void) const
uint m_row
Definition: cc708window.h:160
QPoint img_shift
Shift of image on the screen.
static QStringList to_string_list(const TeletextSubPage &subPage)
bool GetChanged(void) const
Definition: cc708window.h:278
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
MythDeque< AVSubtitle > m_buffers
CC608Reader * GetCC608Reader(uint id=0) override
void SetDecodeAllSubtitles(bool val)
Definition: decoderbase.h:237
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:393
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
VideoOutput * videoOutput
Definition: mythplayer.h:639
QHash< uint, WindowsOnService > m_cc708_windows
PlayerContext * player_ctx
Definition: mythplayer.h:640
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:205
void start(void)
starts measuring elapsed time.
Definition: mythtimer.cpp:47
QStringList text
Lines of text of subtitles.
void ResetChanged(void)
Definition: cc708window.h:295
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:637
CC708Pen m_pen
Definition: cc708window.h:268
void IngestSubtitle(QList< OneSubtitle > &, const QStringList &)
Adds new subtitle, finishes last if needed.