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