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