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 {
64 m_workingDir = QDir(QFileInfo(m_fileName).path());
65 }
66 else
67 {
68 m_workingDir = QDir(destdir);
69 if (!m_workingDir.exists())
70 m_workingDir = QDir(QFileInfo(m_fileName).path());
71 }
72 m_baseName = comps.join(".");
73}
74
80{
83 {
85 double fps = frame->m_frameRate;
86 if (fps <= 0)
87 fps = GetDecoder()->GetFPS();
88 double duration = (1 / fps) + (static_cast<double>(frame->m_repeatPic) * 0.5 / fps);
89 m_curTime += secondsFromFloat(duration);
91 }
92
97}
98
99static QString progress_string(
100 MythTimer &flagTime, uint64_t m_myFramesPlayed, uint64_t totalFrames)
101{
102 if (totalFrames == 0ULL)
103 {
104 return QString("%1 frames processed \r")
105 .arg(m_myFramesPlayed,7);
106 }
107
108 static const std::string kSpinChars { R"(/-\|)" };
109 static uint s_spinCnt = 0;
110
111 double elapsed = flagTime.elapsed().count() * 0.001;
112 double flagFPS = (elapsed > 0.0) ? (m_myFramesPlayed / elapsed) : 0;
113
114 double percentage = m_myFramesPlayed * 100.0 / totalFrames;
115 percentage = (percentage > 100.0 && percentage < 101.0) ?
116 100.0 : percentage;
117
118 if (m_myFramesPlayed < totalFrames)
119 return QString("%1 fps %2% \r")
120 .arg(flagFPS,4,'f', (flagFPS < 10.0 ? 1 : 0)).arg(percentage,4,'f',1);
121 return QString("%1 fps %2 \r")
122 .arg(flagFPS,4,'f', (flagFPS < 10.0 ? 1 : 0))
123 .arg(kSpinChars[++s_spinCnt % 4]);
124}
125
127{
129
130 m_killDecoder = false;
131 m_framesPlayed = 0;
132
134
135 SetPlaying(true);
136
137 if (!InitVideo())
138 {
139 LOG(VB_GENERAL, LOG_ERR, "Unable to initialize video");
140 SetPlaying(false);
141 return false;
142 }
143
145
146 MythTimer flagTime;
147 MythTimer ui_timer;
148 MythTimer inuse_timer;
149 MythTimer save_timer;
150 flagTime.start();
151 ui_timer.start();
152 inuse_timer.start();
153 save_timer.start();
154
155 m_curTime = 0ms;
156
159
160 if (m_showProgress)
161 std::cout << "\r \r" << std::flush;
162
163 while (!m_killDecoder && !IsErrored())
164 {
165 if (inuse_timer.elapsed() > 2534ms)
166 {
167 inuse_timer.restart();
168 m_playerCtx->LockPlayingInfo(__FILE__, __LINE__);
171 m_playerCtx->UnlockPlayingInfo(__FILE__, __LINE__);
172 }
173
174 if (m_showProgress && (ui_timer.elapsed() > 98ms * 4))
175 {
176 ui_timer.restart();
177 QString str = progress_string(
179 std::cout << qPrintable(str) << '\r' << std::flush;
180 }
181
183 break;
184
186 }
187
188 if (m_showProgress)
189 {
192 {
194 }
195 QString str = progress_string(flagTime, m_myFramesPlayed, m_totalFrames);
196 std::cout << qPrintable(str) << '\n';
197 }
198
203
204 SetPlaying(false);
205 m_killDecoder = true;
206
207 return true;
208}
209
210
218 QList<OneSubtitle> &list, const QStringList &content) const
219{
220 bool update_last =
221 !list.isEmpty() &&
222 m_curTime == list.back().m_startTime &&
223 !content.isEmpty();
224
225 if (update_last)
226 {
227 //update text only (need for cc608)
228 list.back().m_text = content;
229 return;
230 }
231
232 OneSubtitle last_one = list.isEmpty() ? OneSubtitle() : list.back();
233 if (content != last_one.m_text || last_one.m_length >= 0ms)
234 {
235 // Finish previous subtitle.
236 if (!last_one.m_text.isEmpty() && last_one.m_length < 0ms)
237 {
238 list.back().m_length = m_curTime - last_one.m_startTime;
239 }
240
241 // Put new one if it isn't empty.
242 if (!content.isEmpty())
243 {
244 OneSubtitle new_one;
245 new_one.m_startTime = m_curTime;
246 new_one.m_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.m_startTime == list.back().m_startTime &&
266 !content.m_img.isNull();
267
268 if (update_last)
269 {
270 list.back().m_img = content.m_img; // update image only
271 return;
272 }
273
274 OneSubtitle last_one = list.isEmpty() ? OneSubtitle() : list.back();
275 if (content.m_img != last_one.m_img || last_one.m_length >= 0ms)
276 {
277 // Finish previous subtitle.
278 if (!last_one.m_img.isNull() && last_one.m_length < 0ms)
279 {
280 list.back().m_length = content.m_startTime - last_one.m_startTime;
281 }
282
283 // Put new one if it isn't empty.
284 if (!content.m_img.isNull())
285 {
286 OneSubtitle new_one;
287 new_one.m_startTime = content.m_startTime;
288 new_one.m_img = content.m_img;
289
290 list.push_back(new_one);
291 }
292 }
293}
294
296{
297 static constexpr std::array<int,7> kCcIndexTbl
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 // NOLINTNEXTLINE(modernize-loop-convert)
310 for (auto it = m_cc608Info.begin(); it != m_cc608Info.end(); ++it)
311 {
312 while (true)
313 {
314 bool changed = false;
315 int streamRawIdx = -1;
316 CC608Buffer *textlist = (*it).m_reader->GetOutputText(
317 changed, streamRawIdx);
318
319 if (!changed || !textlist)
320 break;
321
322 if (streamRawIdx < 0)
323 continue;
324
325 textlist->m_lock.lock();
326
327 const int ccIdx = kCcIndexTbl[std::min(streamRawIdx,6)];
328
329 if (ccIdx >= 4)
330 {
331 textlist->m_lock.unlock();
332 continue;
333 }
334
335 FormattedTextSubtitle608 fsub(textlist->m_buffers);
336 QStringList content = fsub.ToSRT();
337
338 textlist->m_lock.unlock();
339
340 IngestSubtitle((*it).m_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 // NOLINTNEXTLINE(modernize-loop-convert)
350 for (auto cc608it = m_cc608Info.begin(); cc608it != m_cc608Info.end(); ++cc608it)
351 {
352 QString stream_id_str = (m_cc608Info.size() <= 1) ?
353 QString("") : QString("%1.").arg(i,2,10,QChar('0'));
354
355 CC608StreamType &subs = (*cc608it).m_subs;
356 for (auto it = subs.begin(); it != subs.end(); ++it)
357 {
358 if ((*it).empty())
359 continue; // Skip empty subtitle streams.
360 if (((kProcessFinalize & flags) == 0) && ((*it).size() <= 1))
361 continue; // Leave one caption behind so it can be amended
362
363 int idx = it.key();
364
365 if (!(*cc608it).m_srtWriters[idx])
366 {
367 int langCode = 0;
368 auto *avd = dynamic_cast<AvFormatDecoder *>(m_decoder);
369 if (avd)
370 langCode = avd->GetCaptionLanguage(
371 kTrackTypeCC608, idx + 1);
372
373 QString lang = iso639_key_to_str3(langCode);
374 lang = iso639_is_key_undefined(langCode) ? "und" : lang;
375
376 QString service_key = QString("cc%1").arg(idx + 1);
377 QString filename = QString("%1.%2%3-%4.%5.srt")
378 .arg(m_baseName, stream_id_str, "608",
379 service_key, lang);
380
381 (*cc608it).m_srtWriters[idx] = new SRTWriter(
382 m_workingDir.filePath(filename));
383 }
384
385 if (!(*cc608it).m_srtWriters[idx]->IsOpen())
386 {
387 (*it).clear();
388 continue;
389 }
390
391 while ((*it).size() > ((kProcessFinalize & flags) ? 0 : 1))
392 {
393 if ((*it).front().m_length <= 0ms)
394 (*it).front().m_length = OneSubtitle::kDefaultLength;
395
396 (*cc608it).m_srtWriters[idx]->AddSubtitle(
397 (*it).front(), ++(*cc608it).m_subsNum[idx]);
398 (*it).pop_front();
399 }
400
401 (*cc608it).m_srtWriters[idx]->Flush();
402 }
403 }
404}
405
407{
408 // For each window of each service of each video...
409 for (auto it = m_cc708Info.cbegin(); it != m_cc708Info.cend(); ++it)
410 {
411 for (uint serviceIdx = 1; serviceIdx < k708MaxServices; ++serviceIdx)
412 {
413 CC708Service *service = (*it).m_reader->GetService(serviceIdx);
414 for (uint windowIdx = 0; windowIdx < 8; ++windowIdx)
415 {
416 CC708Window &win = service->m_windows[windowIdx];
417 if (win.GetChanged())
418 {
419 std::vector<CC708String*> strings;
420 if (win.GetVisible())
421 {
422 strings = win.GetStrings();
423 Ingest708Caption(it.key(), serviceIdx, windowIdx,
424 win.m_pen.m_row, win.m_pen.m_column,
425 win, strings);
427 }
428 service->m_windows[windowIdx].ResetChanged();
429 }
430 }
431 }
432 }
433}
434
436 uint streamId, uint serviceIdx,
437 uint windowIdx, uint start_row, uint start_column,
438 const CC708Window &win,
439 const std::vector<CC708String*> &content)
440{
441 FormattedTextSubtitle708 fsub(win, windowIdx, content);
442 QStringList winContent = fsub.ToSRT();
443
444 QMap<int, Window> &cc708win = m_cc708Windows[streamId][serviceIdx];
445 cc708win[windowIdx].row = start_row;
446 cc708win[windowIdx].column = start_column;
447 cc708win[windowIdx].text = winContent;
448
449 QMap<uint, QStringList> orderedContent;
450 for (const auto& ccIt : std::as_const(cc708win))
451 {
452 uint idx = (ccIt.row * 1000) + ccIt.column;
453 for (const auto& str : std::as_const(ccIt.text))
454 {
455 orderedContent[idx] += str;
456 }
457 }
458
459 QStringList screenContent;
460 for (const auto & ordered : std::as_const(orderedContent))
461 screenContent += ordered;
462 IngestSubtitle(m_cc708Info[streamId].m_subs[serviceIdx], screenContent);
463}
464
465// Note: GetCaptionLanguage() will not return valid if there are multiple videos
467{
468 int i = 0;
469 // NOLINTNEXTLINE(modernize-loop-convert)
470 for (auto cc708it = m_cc708Info.begin(); cc708it != m_cc708Info.end(); ++cc708it)
471 {
472 QString stream_id_str = (m_cc708Info.size() <= 1) ?
473 QString("") : QString("%1.").arg(i,2,10,QChar('0'));
474
475 CC708StreamType &subs = (*cc708it).m_subs;
476 for (auto it = subs.begin(); it != subs.end(); ++it)
477 {
478 if ((*it).empty())
479 continue; // Skip empty subtitle streams.
480 if (((kProcessFinalize & flags) == 0) && ((*it).size() <= 1))
481 continue; // Leave one caption behind so it can be amended
482
483 int idx = it.key();
484
485 if (!(*cc708it).m_srtWriters[idx])
486 {
487 int langCode = 0;
488 auto *avd = dynamic_cast<AvFormatDecoder*>(m_decoder);
489 if (avd)
490 langCode = avd->GetCaptionLanguage(kTrackTypeCC708, idx);
491
492 QString lang = iso639_key_to_str3(langCode);
493
494 QString service_key = QString("service-%1")
495 .arg(idx, 2, 10, QChar('0'));
496 QString filename = QString("%1.%2%3-%4.%5.srt")
497 .arg(m_baseName, stream_id_str, "708",
498 service_key, lang);
499
500 (*cc708it).m_srtWriters[idx] = new SRTWriter(
501 m_workingDir.filePath(filename));
502 }
503
504 if (!(*cc708it).m_srtWriters[idx]->IsOpen())
505 {
506 (*it).clear();
507 continue;
508 }
509
510 while ((*it).size() > ((kProcessFinalize & flags) ? 0 : 1))
511 {
512 if ((*it).front().m_length <= 0ms)
513 (*it).front().m_length = OneSubtitle::kDefaultLength;
514
515 (*cc708it).m_srtWriters[idx]->AddSubtitle(
516 (*it).front(), ++(*cc708it).m_subsNum[idx]);
517 (*it).pop_front();
518 }
519
520 (*cc708it).m_srtWriters[idx]->Flush();
521 }
522 }
523}
524
525static QStringList to_string_list(const TeletextSubPage &subPage)
526{
527 QStringList content;
528 // Skip the page header (line 0)
529 for (size_t i = 1; i < subPage.data.size(); ++i)
530 {
531 QString str = decode_teletext(subPage.lang, subPage.data[i]).trimmed();
532 if (!str.isEmpty())
533 content += str;
534 }
535 return content;
536}
537
539{
540 // NOLINTNEXTLINE(modernize-loop-convert)
541 for (auto ttxit = m_ttxInfo.begin(); ttxit != m_ttxInfo.end(); ++ttxit)
542 {
543 using qpii = QPair<int, int>;
544 QSet<qpii> updatedPages = (*ttxit).m_reader->GetUpdatedPages();
545 if (updatedPages.isEmpty())
546 continue;
547
548 for (auto it = updatedPages.constBegin(); it != updatedPages.constEnd(); ++it)
549 {
550 (*ttxit).m_reader->SetPage((*it).first, (*it).second);
551 TeletextSubPage *subpage = (*ttxit).m_reader->FindSubPage();
552 if (subpage && subpage->subtitle)
553 {
554 IngestSubtitle((*ttxit).m_subs[(*it).first],
555 to_string_list(*subpage));
556 }
557 }
558
559 (*ttxit).m_reader->ClearUpdatedPages();
560 }
561}
562
564{
565 int i = 0;
566 // NOLINTNEXTLINE(modernize-loop-convert)
567 for (auto ttxit = m_ttxInfo.begin(); ttxit != m_ttxInfo.end(); ++ttxit)
568 {
569 QString stream_id_str = (m_cc608Info.size() <= 1) ?
570 QString("") : QString("%1.").arg(i,2,10,QChar('0'));
571
572 TeletextStreamType &subs = (*ttxit).m_subs;
573 for (auto it = subs.begin(); it != subs.end(); ++it)
574 {
575 if ((*it).empty())
576 continue; // Skip empty subtitle streams.
577 if (((kProcessFinalize & flags) == 0) && ((*it).size() <= 1))
578 continue; // Leave one caption behind so it can be amended
579
580 uint page = it.key();
581
582 if (!(*ttxit).m_srtWriters[page])
583 {
584 int langCode = 0;
585 auto *avd = dynamic_cast<AvFormatDecoder *>(m_decoder);
586
587 if (avd)
588 langCode = avd->GetTeletextLanguage(page);
589
590 QString lang = iso639_key_to_str3(langCode);
591 lang = iso639_is_key_undefined(langCode) ? "und" : lang;
592 QString filename = QString("%1-%2.%3ttx-0x%4.srt")
593 .arg(m_baseName, lang, stream_id_str)
594 .arg(page, 3, 16, QChar('0'));
595
596 (*ttxit).m_srtWriters[page] = new SRTWriter(
597 m_workingDir.filePath(filename));
598 }
599
600 if (!(*ttxit).m_srtWriters[page]->IsOpen())
601 {
602 (*it).clear();
603 continue;
604 }
605
606 while ((*it).size() > ((kProcessFinalize & flags) ? 0 : 1))
607 {
608 if ((*it).front().m_length <= 0ms)
609 (*it).front().m_length = OneSubtitle::kDefaultLength;
610
611 (*ttxit).m_srtWriters[page]->AddSubtitle(
612 (*it).front(), ++(*ttxit).m_subsNum[page]);
613 (*it).pop_front();
614 }
615
616 (*ttxit).m_srtWriters[page]->Flush();
617 }
618 }
619}
620
622{
623 // NOLINTNEXTLINE(modernize-loop-convert)
624 for (auto subit = m_dvbsubInfo.begin(); subit != m_dvbsubInfo.end(); ++subit)
625 {
627 if ((*subit).m_reader->HasTextSubtitles())
628 {
629 LOG(VB_VBI, LOG_DEBUG,
630 "There are unhandled text dvb subtitles");
631 }
632
633 std::chrono::milliseconds duration = 0ms;
634 const QStringList rawSubs =
635 (*subit).m_reader->GetRawTextSubtitles(duration);
636 if (!rawSubs.isEmpty())
637 {
638 LOG(VB_VBI, LOG_DEBUG,
639 QString("There are also %1 raw text subtitles with duration %2")
640 .arg(rawSubs.size()).arg(duration.count()));
641 }
643
644 AVSubtitles *avsubtitles = (*subit).m_reader->GetAVSubtitles();
645
646 QMutexLocker locker(&(avsubtitles->m_lock));
647
648 while (!avsubtitles->m_buffers.empty())
649 {
650 AVSubtitle subtitle = avsubtitles->m_buffers.front();
651 avsubtitles->m_buffers.pop_front();
652
653 const QSize v_size =
654 QSize(GetVideoSize().width()*4, GetVideoSize().height()*4);
655 QImage sub_pict(v_size, QImage::Format_ARGB32);
656 sub_pict.fill(0);
657
658 int min_x = v_size.width();
659 int min_y = v_size.height();
660 int max_x = 0;
661 int max_y = 0;
662
663 QPainter painter(&sub_pict);
664 for (int i = 0; i < (int) subtitle.num_rects; ++i)
665 {
666 AVSubtitleRect *rect = subtitle.rects[i];
667
668 if (subtitle.rects[i]->type == SUBTITLE_BITMAP)
669 {
670 const int x = rect->x;
671 const int y = rect->y;
672 const int w = rect->w;
673 const int h = rect->h;
674 const int cc = rect->nb_colors;
675 const uchar *data = rect->data[0];
676 const QRgb *palette = (QRgb *) rect->data[1];
677
678 QImage img(data, w, h, QImage::Format_Indexed8);
679 img.setColorCount(cc);
680 for (int j = 0; j < cc; ++j)
681 img.setColor(j, palette[j]);
682
683 painter.drawImage(x, y, img);
684
685 min_x = std::min(min_x, x);
686 min_y = std::min(min_y, y);
687 max_x = std::max(max_x, x + w);
688 max_y = std::max(max_y, y + h);
689 }
690 }
691 painter.end();
692
693 OneSubtitle sub;
694 sub.m_startTime =
695 std::chrono::milliseconds(subtitle.start_display_time);
696 sub.m_length =
697 std::chrono::milliseconds(subtitle.end_display_time -
698 subtitle.start_display_time);
699
701
702 if (min_x < max_x && min_y < max_y)
703 {
704 sub.m_imgShift = QPoint(min_x, min_y);
705 sub.m_img = sub_pict.copy(
706 min_x, min_y, max_x - min_x, max_y - min_y);
707 }
708 else
709 {
710 // Empty subtitle, do nothing.
711 }
712
713 IngestSubtitle((*subit).m_subs, sub);
714 }
715
716 locker.unlock();
717
718 (*subit).m_reader->ClearRawTextSubtitles();
719 }
720}
721
723{
724 // Process (DVB) subtitle streams.
725 int subtitleStreamCount = 0;
726 for (auto subit = m_dvbsubInfo.begin(); subit != m_dvbsubInfo.end(); ++subit)
727 {
728 int langCode = 0;
729 auto *avd = dynamic_cast<AvFormatDecoder *>(m_decoder);
730 int idx = subit.key();
731 if (avd)
732 langCode = avd->GetSubtitleLanguage(subtitleStreamCount, idx);
733 subtitleStreamCount++;
734
735 QString lang = iso639_key_to_str3(langCode);
736 lang = iso639_is_key_undefined(langCode) ? "und" : lang;
737 QString dir_name = m_baseName + QString("-%1.dvb-%2").arg(lang).arg(subit.key());
738 if (!m_workingDir.exists(dir_name) && !m_workingDir.mkdir(dir_name))
739 {
740 LOG(VB_GENERAL, LOG_ERR, QString("Can't create directory '%1'")
741 .arg(dir_name));
742 (*subit).m_subs.clear();
743 continue;
744 }
745
746 DVBStreamType &subs = (*subit).m_subs;
747 if (subs.empty())
748 continue; // Skip empty subtitle streams.
749 if (((kProcessFinalize & flags) == 0) && (subs.size() <= 1))
750 continue; // Leave one caption behind so it can be amended
751
752 QDir stream_dir(m_workingDir.filePath(dir_name));
753 while (subs.size() > ((kProcessFinalize & flags) ? 0 : 1))
754 {
755 if (subs.front().m_length <= 0ms)
756 subs.front().m_length = OneSubtitle::kDefaultLength;
757
758 const OneSubtitle &sub = subs.front();
759 std::chrono::milliseconds end_time = sub.m_startTime + sub.m_length;
760 const QString file_name =
761 stream_dir.filePath(
762 QString("%1_%2-to-%3.png")
763 .arg((*subit).m_subsNum)
764 .arg(sub.m_startTime.count()).arg(end_time.count()));
765
766 if (end_time > sub.m_startTime)
767 {
768 //check is there exist file with same m_startTime
769 QStringList filter;
770 filter << QString("*_%1*.png").arg(sub.m_startTime.count());
771 QFileInfoList found = stream_dir.entryInfoList(filter);
772 if (found.isEmpty())
773 {
774 //no same m_startTime founded
775 if (!sub.m_img.save(file_name))
776 {
777 LOG(VB_GENERAL, LOG_ERR,
778 QString("Can't write file '%1'")
779 .arg(file_name));
780 }
781 (*subit).m_subsNum++;
782 }
783 }
784 subs.pop_front();
785 }
786 }
787}
788
789
791{
792 if (!m_cc708Info[id].m_reader)
793 {
794 m_cc708Info[id].m_reader = new CC708Reader();
795 m_cc708Info[id].m_reader->SetEnabled(true);
796 LOG(VB_GENERAL, LOG_INFO, "Created CC708Reader");
797 }
798 return m_cc708Info[id].m_reader;
799}
800
802{
803 if (!m_cc608Info[id].m_reader)
804 {
805 m_cc608Info[id].m_reader = new CC608Reader(this);
806 m_cc608Info[id].m_reader->SetEnabled(true);
807 }
808 return m_cc608Info[id].m_reader;
809}
810
812{
813 if (!m_ttxInfo[id].m_reader)
814 m_ttxInfo[id].m_reader = new TeletextExtractorReader();
815 return m_ttxInfo[id].m_reader;
816}
817
819{
820 if (!m_dvbsubInfo[id].m_reader)
821 {
822 m_dvbsubInfo[id].m_reader = new SubtitleReader();
823 m_dvbsubInfo[id].m_reader->EnableAVSubtitles(true);
824 m_dvbsubInfo[id].m_reader->EnableTextSubtitles(true);
825 m_dvbsubInfo[id].m_reader->EnableRawTextSubtitles(true);
826 }
827 return m_dvbsubInfo[id].m_reader;
828}
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:183
QSize GetVideoSize(void) const
Definition: mythplayer.h:130
DecoderBase * m_decoder
Definition: mythplayer.h:361
uint64_t m_framesPlayed
Definition: mythplayer.h:423
uint64_t m_totalFrames
Definition: mythplayer.h:424
friend class CC608Reader
Definition: mythplayer.h:89
bool IsErrored(void) const
bool DecoderGetFrame(DecodeType decodetype, bool unsafe=false)
friend class CC708Reader
Definition: mythplayer.h:88
bool volatile m_killDecoder
Definition: mythplayer.h:387
void ClearAfterSeek(bool clearvideobuffers=true)
This is to support seeking...
void SetPlaying(bool is_playing)
Definition: mythplayer.cpp:239
PlayerContext * m_playerCtx
Definition: mythplayer.h:365
MythVideoOutput * m_videoOutput
Definition: mythplayer.h:363
virtual bool InitVideo(void)
Definition: mythplayer.cpp:267
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
unsigned int uint
Definition: compat.h:60
@ kTrackTypeCC608
Definition: decoderbase.h:32
@ kTrackTypeCC708
Definition: decoderbase.h:33
@ kDecodeVideo
Definition: decoderbase.h:50
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::chrono::seconds secondsFromFloat(T value)
Helper function for convert a floating point number to a duration.
Definition: mythchrono.h:68
#define LOG(_MASK_, _LEVEL_, _QSTRING_)
Definition: mythlogging.h:39
PlayerFlags
Definition: mythplayer.h:64
static const std::array< std::array< QString, 3 >, 95 > comps
QString decode_teletext(int codePage, const tt_line_array &data)
Get decoded ttx as a string.