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