MythTV  0.26-pre
mythccextractorplayer.cpp
Go to the documentation of this file.
00001 // -*- Mode: c++ -*-
00002 
00003 /*
00004  *  Class MythCCExtractorPlayer
00005  *
00006  *  Copyright (C) Digital Nirvana, Inc. 2010
00007  *
00008  *   This program is free software; you can redistribute it and/or modify
00009  *   it under the terms of the GNU General Public License as published by
00010  *   the Free Software Foundation; either version 2 of the License, or
00011  *   (at your option) any later version.
00012  *
00013  *   This program is distributed in the hope that it will be useful,
00014  *   but WITHOUT ANY WARRANTY; without even the implied warranty of
00015  *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00016  *   GNU General Public License for more details.
00017  *
00018  *   You should have received a copy of the GNU General Public License
00019  *   along with this program; if not, write to the Free Software
00020  *   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
00021  */
00022 
00023 #include <iostream>
00024 using namespace std;
00025 
00026 #include <QPainter>
00027 
00028 #include "teletextextractorreader.h"
00029 #include "mythccextractorplayer.h"
00030 #include "avformatdecoder.h"
00031 #include "subtitlescreen.h"
00032 #include "srtwriter.h"
00033 
00034 
00035 const int OneSubtitle::kDefaultLength = 750; /* ms */
00036 
00037 SRTStuff::~SRTStuff()
00038 {
00039     while (!srtwriters.empty())
00040     {
00041         delete *srtwriters.begin();
00042         srtwriters.erase(srtwriters.begin());
00043     }
00044 }
00045 CC608Stuff::~CC608Stuff() { delete reader; }
00046 CC708Stuff::~CC708Stuff() { delete reader; }
00047 TeletextStuff::~TeletextStuff() { delete reader; }
00048 DVBSubStuff::~DVBSubStuff() { delete reader; }
00049 
00050 MythCCExtractorPlayer::MythCCExtractorPlayer(
00051     PlayerFlags flags, bool showProgress, const QString &fileName) :
00052     MythPlayer(flags),
00053     m_curTime(0),
00054     m_myFramesPlayed(0),
00055     m_showProgress(showProgress),
00056     m_fileName(fileName)
00057 {
00058     // Determine where we will put extracted info.
00059     QStringList comps = QFileInfo(m_fileName).fileName().split(".");
00060     if (!comps.empty())
00061         comps.removeLast();
00062     m_workingDir = QDir(QFileInfo(m_fileName).path());
00063     m_baseName = comps.join(".");
00064 }
00065 
00070 void MythCCExtractorPlayer::OnGotNewFrame(void)
00071 {
00072     m_myFramesPlayed = decoder->GetFramesRead();
00073     videoOutput->StartDisplayingFrame();
00074     {
00075         VideoFrame *frame = videoOutput->GetLastShownFrame();
00076         double fps = frame->frame_rate;
00077         if (fps <= 0)
00078             fps = GetDecoder()->GetFPS();
00079         double duration = 1 / fps + frame->repeat_pict * 0.5 / fps;
00080         m_curTime += duration * 1000;
00081         videoOutput->DoneDisplayingFrame(frame);
00082     }
00083 
00084     Ingest608Captions();  Process608Captions(kProcessNormal);
00085     Ingest708Captions();  Process708Captions(kProcessNormal);
00086     IngestTeletext();     ProcessTeletext();
00087     IngestDVBSubtitles(); ProcessDVBSubtitles(kProcessNormal);
00088 }
00089 
00090 static QString progress_string(
00091     MythTimer &flagTime, uint64_t m_myFramesPlayed, uint64_t totalFrames)
00092 {
00093     if (totalFrames == 0ULL)
00094     {
00095         return QString("%1 frames processed    \r")
00096             .arg(m_myFramesPlayed,7);
00097     }
00098 
00099     double elapsed = flagTime.elapsed() * 0.001;
00100     double flagFPS = (elapsed > 0.0) ? (m_myFramesPlayed / elapsed) : 0;
00101 
00102     double percentage = m_myFramesPlayed * 100.0 / totalFrames;
00103     percentage = (percentage > 100.0 && percentage < 101.0) ?
00104         100.0 : percentage;
00105 
00106     if (flagFPS < 10.0)
00107     {
00108         return QString("%1 fps %2%     \r")
00109             .arg(flagFPS,4,'f',1).arg(percentage,4,'f',1);
00110     }
00111     else
00112     {
00113         return QString("%1 fps %2%     \r")
00114             .arg(flagFPS,4,'f',0).arg(percentage,4,'f',1);
00115     }
00116 }
00117 
00118 bool MythCCExtractorPlayer::run(void)
00119 {
00120     m_myFramesPlayed = 0;
00121 
00122     killdecoder = false;
00123     framesPlayed = 0;
00124 
00125     decoder->SetDecodeAllSubtitles(true);
00126 
00127     SetPlaying(true);
00128 
00129     if (!InitVideo())
00130     {
00131         LOG(VB_GENERAL, LOG_ERR, "Unable to initialize video");
00132         SetPlaying(false);
00133         return false;
00134     }
00135 
00136     ClearAfterSeek();
00137 
00138     MythTimer flagTime, ui_timer, inuse_timer, save_timer;
00139     flagTime.start();
00140     ui_timer.start();
00141     inuse_timer.start();
00142     save_timer.start();
00143 
00144     m_curTime = 0;
00145 
00146     QString currDir = QFileInfo(m_fileName).path();
00147 
00148     if (DecoderGetFrame(kDecodeVideo))
00149         OnGotNewFrame();
00150 
00151     if (m_showProgress)
00152         cout << "\r                                      \r" << flush;
00153 
00154     while (!killdecoder && !IsErrored())
00155     {
00156         if (inuse_timer.elapsed() > 2534)
00157         {
00158             inuse_timer.restart();
00159             player_ctx->LockPlayingInfo(__FILE__, __LINE__);
00160             if (player_ctx->playingInfo)
00161                 player_ctx->playingInfo->UpdateInUseMark();
00162             player_ctx->UnlockPlayingInfo(__FILE__, __LINE__);
00163         }
00164 
00165         if (m_showProgress && (ui_timer.elapsed() > 98 * 4))
00166         {
00167             ui_timer.restart();
00168             QString str = progress_string(
00169                 flagTime, m_myFramesPlayed, totalFrames);
00170             cout << qPrintable(str) << '\r' << flush;
00171         }
00172 
00173         if (!DecoderGetFrame(kDecodeVideo))
00174             break;
00175 
00176         OnGotNewFrame();
00177     }
00178 
00179     if (m_showProgress)
00180     {
00181         if ((m_myFramesPlayed < totalFrames) &&
00182             ((m_myFramesPlayed + 30) > totalFrames))
00183         {
00184             m_myFramesPlayed = totalFrames;
00185         }
00186         QString str = progress_string(flagTime, m_myFramesPlayed, totalFrames);
00187         cout << qPrintable(str) << endl;
00188     }
00189 
00190     Process608Captions(kProcessFinalize);
00191     Process708Captions(kProcessFinalize);
00192     ProcessDVBSubtitles(kProcessFinalize);
00193 
00194     SetPlaying(false);
00195     killdecoder = true;
00196 
00197     return true;
00198 }
00199 
00200 
00207 void MythCCExtractorPlayer::IngestSubtitle(
00208     QList<OneSubtitle> &list, const QStringList &content)
00209 {
00210     bool update_last =
00211         !list.isEmpty() &&
00212         (int64_t)m_curTime == list.back().start_time &&
00213         !content.isEmpty();
00214 
00215     if (update_last)
00216     {
00217         //update text only (need for cc608)
00218         list.back().text = content;
00219         return;
00220     }
00221 
00222     OneSubtitle last_one = list.isEmpty() ? OneSubtitle() : list.back();
00223     if (content != last_one.text || last_one.length >= 0)
00224     {
00225         // Finish previous subtitle.
00226         if (!last_one.text.isEmpty() && last_one.length < 0)
00227         {
00228             list.back().length = (int64_t)m_curTime - last_one.start_time;
00229         }
00230 
00231         // Put new one if it isn't empty.
00232         if (!content.isEmpty())
00233         {
00234             OneSubtitle new_one;
00235             new_one.start_time = (int64_t)m_curTime;
00236             new_one.text = content;
00237 
00238             list.push_back(new_one);
00239         }
00240     }
00241 }
00242 
00249 void MythCCExtractorPlayer::IngestSubtitle(
00250     QList<OneSubtitle> &list, const OneSubtitle &content)
00251 {
00252     bool update_last =
00253         !list.isEmpty() &&
00254         content.start_time == list.back().start_time &&
00255         !content.img.isNull();
00256 
00257     if (update_last)
00258     {
00259         list.back().img = content.img; // update image only
00260         return;
00261     }
00262 
00263     OneSubtitle last_one = list.isEmpty() ? OneSubtitle() : list.back();
00264     if (content.img != last_one.img || last_one.length >= 0)
00265     {
00266         // Finish previous subtitle.
00267         if (!last_one.img.isNull() && last_one.length < 0)
00268         {
00269             list.back().length = content.start_time - last_one.start_time;
00270         }
00271 
00272         // Put new one if it isn't empty.
00273         if (!content.img.isNull())
00274         {
00275             OneSubtitle new_one;
00276             new_one.start_time = content.start_time;
00277             new_one.img = content.img;
00278 
00279             list.push_back(new_one);
00280         }
00281     }
00282 }
00283 
00284 void MythCCExtractorPlayer::Ingest608Captions(void)
00285 {
00286     static const int ccIndexTbl[7] =
00287     {
00288         0, // CC_CC1
00289         1, // CC_CC2
00290         9, // sentinel
00291         9, // sentinel
00292         2, // CC_CC3
00293         3, // CC_CC4
00294         9, // sentinel
00295     };
00296 
00297     // for each CC of each video...
00298     CC608Info::iterator it = m_cc608_info.begin();
00299     for (; it != m_cc608_info.end(); ++it)
00300     {
00301         while (true)
00302         {
00303             bool changed = false;
00304             int streamRawIdx = -1;
00305             CC608Buffer *textlist = (*it).reader->GetOutputText(
00306                 changed, streamRawIdx);
00307 
00308             if (!changed || !textlist)
00309                 break;
00310 
00311             if (streamRawIdx < 0)
00312                 continue;
00313 
00314             textlist->lock.lock();
00315 
00316             const int ccIdx = ccIndexTbl[min(streamRawIdx,6)];
00317 
00318             if (ccIdx >= 4)
00319             {
00320                 textlist->lock.unlock();
00321                 continue;
00322             }
00323 
00324             FormattedTextSubtitle fsub;
00325             fsub.InitFromCC608(textlist->buffers);
00326             QStringList content = fsub.ToSRT();
00327 
00328             textlist->lock.unlock();
00329 
00330             IngestSubtitle((*it).subs[ccIdx], content);
00331         }
00332     }
00333 }
00334 
00335 // Note: GetCaptionLanguage() will not return valid if there are multiple videos
00336 void MythCCExtractorPlayer::Process608Captions(uint flags)
00337 {
00338     int i = 0;
00339     CC608Info::iterator cc608it = m_cc608_info.begin();
00340     for (; cc608it != m_cc608_info.end(); ++cc608it)
00341     {
00342         QString stream_id_str = (m_cc608_info.size() <= 1) ?
00343             QString("") : QString("%1.").arg(i,2,QChar('0'));
00344 
00345         CC608StreamType &subs = (*cc608it).subs;
00346         CC608StreamType::iterator it = subs.begin();
00347         for (; it != subs.end(); ++it)
00348         {
00349             if ((*it).empty())
00350                 continue; // Skip empty subtitle streams.
00351             if (((kProcessFinalize & flags) == 0) && ((*it).size() <= 1))
00352                 continue; // Leave one caption behind so it can be amended
00353 
00354             int idx = it.key();
00355 
00356             if (!(*cc608it).srtwriters[idx])
00357             {
00358                 int langCode = 0;
00359                 AvFormatDecoder *avd = dynamic_cast<AvFormatDecoder *>(decoder);
00360                 if (avd)
00361                     langCode = avd->GetCaptionLanguage(
00362                         kTrackTypeCC608, idx + 1);
00363 
00364                 QString lang = iso639_key_to_str3(langCode);
00365                 lang = iso639_is_key_undefined(langCode) ? "und" : lang;
00366                 
00367                 QString service_key = QString("cc%1").arg(idx + 1);
00368                 QString filename = QString("%1.%2%3-%4.%5.srt")
00369                     .arg(m_baseName).arg(stream_id_str).arg("608")
00370                     .arg(service_key).arg(lang);
00371 
00372                 (*cc608it).srtwriters[idx] = new SRTWriter(
00373                     m_workingDir.filePath(filename));
00374             }
00375 
00376             if (!(*cc608it).srtwriters[idx]->IsOpen())
00377             {
00378                 (*it).clear();
00379                 continue;
00380             }
00381 
00382             while ((*it).size() > ((kProcessFinalize & flags) ? 0 : 1))
00383             {
00384                 if ((*it).front().length <= 0)
00385                     (*it).front().length = OneSubtitle::kDefaultLength;
00386 
00387                 (*cc608it).srtwriters[idx]->AddSubtitle(
00388                     (*it).front(), ++(*cc608it).subs_num[idx]);
00389                 (*it).pop_front();
00390             }
00391 
00392             (*cc608it).srtwriters[idx]->Flush();
00393         }
00394     }
00395 }
00396 
00397 void MythCCExtractorPlayer::Ingest708Captions(void)
00398 {
00399     // For each window of each service of each video...
00400     CC708Info::const_iterator it = m_cc708_info.begin();
00401     for (; it != m_cc708_info.end(); ++it)
00402     {
00403         for (uint serviceIdx = 1; serviceIdx < 64; ++serviceIdx)
00404         {
00405             CC708Service *service = (*it).reader->GetService(serviceIdx);
00406             for (uint windowIdx = 0; windowIdx < 8; ++windowIdx)
00407             {
00408                 CC708Window &win = service->windows[windowIdx];
00409                 if (win.changed)
00410                 {
00411                     vector<CC708String*> strings;
00412                     if (win.visible)
00413                         strings = win.GetStrings();
00414                     Ingest708Caption(it.key(), serviceIdx, windowIdx,
00415                                      win.pen.row, win.pen.column, win, strings);
00416                     while (!strings.empty())
00417                     {
00418                         delete strings.back();
00419                         strings.pop_back();
00420                     }
00421                     service->windows[windowIdx].changed = false;
00422                 }
00423             }
00424         }
00425     }
00426 }
00427 
00428 void MythCCExtractorPlayer::Ingest708Caption(
00429     uint streamId, uint serviceIdx,
00430     uint windowIdx, uint start_row, uint start_column,
00431     const CC708Window &win,
00432     const vector<CC708String*> &content)
00433 {
00434     FormattedTextSubtitle fsub;
00435     fsub.InitFromCC708(win, windowIdx, content);
00436     QStringList winContent = fsub.ToSRT();
00437 
00438     QMap<int, Window> &cc708win = m_cc708_windows[streamId][serviceIdx];
00439     cc708win[windowIdx].row = start_row;
00440     cc708win[windowIdx].column = start_column;
00441     cc708win[windowIdx].text = winContent;
00442 
00443     QMap<uint, QStringList> orderedContent;
00444     QMap<int, Window>::const_iterator ccIt = cc708win.begin();
00445     for (; ccIt != cc708win.end() ; ++ccIt)
00446     {
00447         uint idx = (*ccIt).row * 1000 + (*ccIt).column;
00448         for (QStringList::const_iterator sit = (*ccIt).text.begin();
00449              sit != (*ccIt).text.end(); ++sit)
00450         {
00451             orderedContent[idx] += (*sit);
00452         }
00453     }
00454 
00455     QStringList screenContent;
00456     for (QMap<uint, QStringList>::const_iterator oit = orderedContent.begin();
00457          oit != orderedContent.end(); ++oit)
00458     {
00459         screenContent += *oit;
00460     }
00461     IngestSubtitle(m_cc708_info[streamId].subs[serviceIdx], screenContent);
00462 }
00463 
00464 // Note: GetCaptionLanguage() will not return valid if there are multiple videos
00465 void MythCCExtractorPlayer::Process708Captions(uint flags)
00466 {
00467     int i = 0;
00468     CC708Info::iterator cc708it = m_cc708_info.begin();
00469     for (; cc708it != m_cc708_info.end(); ++cc708it)
00470     {
00471         QString stream_id_str = (m_cc708_info.size() <= 1) ?
00472             QString("") : QString("%1.").arg(i,2,QChar('0'));
00473 
00474         CC708StreamType &subs = (*cc708it).subs;
00475         CC708StreamType::iterator it = subs.begin();
00476         for (; it != subs.end(); ++it)
00477         {
00478             if ((*it).empty())
00479                 continue; // Skip empty subtitle streams.
00480             if (((kProcessFinalize & flags) == 0) && ((*it).size() <= 1))
00481                 continue; // Leave one caption behind so it can be amended
00482 
00483             int idx = it.key();
00484 
00485             if (!(*cc708it).srtwriters[idx])
00486             {
00487                 int langCode = 0;
00488                 AvFormatDecoder *avd = dynamic_cast<AvFormatDecoder*>(decoder);
00489                 if (avd)
00490                     langCode = avd->GetCaptionLanguage(kTrackTypeCC708, idx);
00491 
00492                 QString lang = iso639_key_to_str3(langCode);
00493 
00494                 QString service_key = QString("service-%1")
00495                     .arg(idx, 2, 10, QChar('0'));
00496                 QString id = iso639_is_key_undefined(langCode) ?
00497                     service_key : lang;
00498                 QString filename = QString("%1.%2%3-%4.%5.srt")
00499                     .arg(m_baseName).arg(stream_id_str).arg("708")
00500                     .arg(service_key).arg(lang);
00501 
00502                 (*cc708it).srtwriters[idx] = new SRTWriter(
00503                     m_workingDir.filePath(filename));
00504             }
00505 
00506             if (!(*cc708it).srtwriters[idx]->IsOpen())
00507             {
00508                 (*it).clear();
00509                 continue;
00510             }
00511 
00512             while ((*it).size() > ((kProcessFinalize & flags) ? 0 : 1))
00513             {
00514                 if ((*it).front().length <= 0)
00515                     (*it).front().length = OneSubtitle::kDefaultLength;
00516 
00517                 (*cc708it).srtwriters[idx]->AddSubtitle(
00518                     (*it).front(), ++(*cc708it).subs_num[idx]);
00519                 (*it).pop_front();
00520             }
00521 
00522             (*cc708it).srtwriters[idx]->Flush();
00523         }
00524     }
00525 }
00526 
00527 static QStringList to_string_list(const TeletextSubPage &subPage)
00528 {
00529     QStringList content;
00530     for (int i = 0; i < 25; ++i)
00531     {
00532         QString str = decode_teletext(subPage.lang, subPage.data[i]).trimmed();
00533         if (!str.isEmpty())
00534             content += str;
00535     }
00536     return content;
00537 }
00538 
00539 void MythCCExtractorPlayer::IngestTeletext(void)
00540 {
00541     TeletextInfo::iterator ttxit = m_ttx_info.begin();
00542     for (; ttxit != m_ttx_info.end(); ++ttxit)
00543     {
00544         typedef QPair<int, int> qpii;
00545         QSet<qpii> updatedPages = (*ttxit).reader->GetUpdatedPages();
00546         if (updatedPages.isEmpty())
00547             continue;
00548 
00549         QSet<qpii>::const_iterator it = updatedPages.constBegin();
00550         for (; it != updatedPages.constEnd(); ++it)
00551         {
00552             (*ttxit).reader->SetPage((*it).first, (*it).second);
00553             TeletextSubPage *subpage = (*ttxit).reader->FindSubPage();
00554             if (subpage && subpage->subtitle)
00555             {
00556                 IngestSubtitle((*ttxit).subs[(*it).first],
00557                                to_string_list(*subpage));
00558             }
00559         }
00560         
00561         (*ttxit).reader->ClearUpdatedPages();
00562     }
00563 }
00564 
00565 void MythCCExtractorPlayer::ProcessTeletext(void)
00566 {
00567     int i = 0;
00568     TeletextInfo::iterator ttxit = m_ttx_info.begin();
00569     for (; ttxit != m_ttx_info.end(); ++ttxit)
00570     {
00571         QString stream_id_str = (m_cc608_info.size() <= 1) ?
00572             QString("") : QString("%1.").arg(i,2,QChar('0'));
00573 
00574         TeletextStreamType &subs = (*ttxit).subs;
00575         TeletextStreamType::iterator it = subs.begin();
00576         for (; it != subs.end(); ++it)
00577         {
00578             if ((*it).empty())
00579                 continue; // Skip empty subtitle streams.
00580 
00581             int page = it.key();
00582 
00583             if (!(*ttxit).srtwriters[page])
00584             {
00585                 QString filename = QString("%1.%2ttx-0x%3.srt")
00586                     .arg(m_baseName)
00587                     .arg(stream_id_str)
00588                     .arg(page, 3, 16, QChar('0'));
00589 
00590                 (*ttxit).srtwriters[page] = new SRTWriter(
00591                     m_workingDir.filePath(filename));
00592             }
00593 
00594             if (!(*ttxit).srtwriters[page]->IsOpen())
00595             {
00596                 (*it).clear();
00597                 continue;
00598             }
00599 
00600             while (!(*it).empty())
00601             {
00602                 if ((*it).front().length <= 0)
00603                     (*it).front().length = OneSubtitle::kDefaultLength;
00604 
00605                 (*ttxit).srtwriters[page]->AddSubtitle(
00606                     (*it).front(), ++(*ttxit).subs_num[page]);
00607                 (*it).pop_front();
00608             }
00609 
00610             (*ttxit).srtwriters[page]->Flush();
00611         }
00612     }
00613 }
00614 
00615 void MythCCExtractorPlayer::IngestDVBSubtitles(void)
00616 {
00617     DVBSubInfo::iterator subit = m_dvbsub_info.begin();
00618     for (; subit != m_dvbsub_info.end(); ++subit)
00619     {
00621         if ((*subit).reader->HasTextSubtitles())
00622         {
00623             LOG(VB_VBI, LOG_DEBUG,
00624                 "There are unhandled text dvb subtitles");
00625         }
00626 
00627         uint64_t duration;
00628         const QStringList rawSubs =
00629             (*subit).reader->GetRawTextSubtitles(duration);
00630         if (!rawSubs.isEmpty())
00631         {
00632             LOG(VB_VBI, LOG_DEBUG,
00633                 QString("There are also %1 raw text subtitles with duration %2")
00634                 .arg(rawSubs.size()).arg(duration));
00635         }
00637 
00638         AVSubtitles *subtitles = (*subit).reader->GetAVSubtitles();
00639 
00640         QMutexLocker locker(&(subtitles->lock));
00641 
00642         while (!subtitles->buffers.empty())
00643         {
00644             const AVSubtitle subtitle = subtitles->buffers.front();
00645             subtitles->buffers.pop_front();
00646 
00647             const QSize v_size =
00648                 QSize(GetVideoSize().width()*4, GetVideoSize().height()*4); 
00649             QImage sub_pict(v_size, QImage::Format_ARGB32);
00650             sub_pict.fill(0);
00651 
00652             int min_x = v_size.width();
00653             int min_y = v_size.height();
00654             int max_x = 0;
00655             int max_y = 0;
00656 
00657             QPainter painter(&sub_pict);
00658             for (int i = 0; i < (int) subtitle.num_rects; ++i)
00659             {
00660                 AVSubtitleRect *rect = subtitle.rects[i];
00661 
00662                 if (subtitle.rects[i]->type == SUBTITLE_BITMAP)
00663                 {
00664                     const int x = rect->x;
00665                     const int y = rect->y;
00666                     const int w = rect->w;
00667                     const int h = rect->h;
00668                     const int cc = rect->nb_colors;
00669                     const uchar *data = rect->pict.data[0];
00670                     const QRgb *palette = (QRgb *) rect->pict.data[1];
00671 
00672                     QImage img(data, w, h, QImage::Format_Indexed8);
00673                     img.setColorCount(cc);
00674                     for (int i = 0; i < cc; ++i)
00675                         img.setColor(i, palette[i]);
00676 
00677                     painter.drawImage(x, y, img);
00678 
00679                     min_x = min(min_x, x);
00680                     min_y = min(min_y, y);
00681                     max_x = max(max_x, x + w);
00682                     max_y = max(max_y, y + h);
00683                 }
00684             }
00685             painter.end();
00686             (*subit).reader->FreeAVSubtitle(subtitle);
00687 
00688             OneSubtitle sub;
00689             sub.start_time = subtitle.start_display_time;
00690             sub.length =
00691                 subtitle.end_display_time - subtitle.start_display_time;
00692 
00693             if (min_x < max_x && min_y < max_y)
00694             {
00695                 sub.img_shift = QPoint(min_x, min_y);
00696                 sub.img = sub_pict.copy(
00697                     min_x, min_y, max_x - min_x, max_y - min_y);
00698             }
00699             else
00700             {
00701                 // Empty subtitle, do nothing.
00702             }
00703 
00704             IngestSubtitle((*subit).subs, sub);
00705         }
00706 
00707         locker.unlock();
00708 
00709         (*subit).reader->ClearRawTextSubtitles();
00710     }
00711 }
00712 
00713 void MythCCExtractorPlayer::ProcessDVBSubtitles(uint flags)
00714 {
00715     // Process (DVB) subtitle streams.
00716     DVBSubInfo::iterator subit = m_dvbsub_info.begin();
00717     for (; subit != m_dvbsub_info.end(); ++subit)
00718     {
00719         QString dir_name = QString(m_baseName + ".dvb-%1").arg(subit.key());
00720         if (!m_workingDir.exists(dir_name) && !m_workingDir.mkdir(dir_name))
00721         {
00722             LOG(VB_GENERAL, LOG_ERR, QString("Can't create directory '%1'")
00723                 .arg(dir_name));
00724             (*subit).subs.clear();
00725             continue;
00726         }
00727 
00728         DVBStreamType &subs = (*subit).subs;
00729         if (subs.empty())
00730             continue; // Skip empty subtitle streams.
00731         if (((kProcessFinalize & flags) == 0) && (subs.size() <= 1))
00732             continue; // Leave one caption behind so it can be amended
00733 
00734         QDir stream_dir(m_workingDir.filePath(dir_name));
00735         while (subs.size() > ((kProcessFinalize & flags) ? 0 : 1))
00736         {
00737             if (subs.front().length <= 0)
00738                 subs.front().length = OneSubtitle::kDefaultLength;
00739 
00740             const OneSubtitle &sub = subs.front();
00741             int64_t end_time = sub.start_time + sub.length;
00742             const QString file_name =
00743                 stream_dir.filePath(
00744                     QString("%1_%2-to-%3.png")
00745                     .arg((*subit).subs_num)
00746                     .arg(sub.start_time).arg(end_time));
00747 
00748             if (end_time > sub.start_time)
00749             {
00750                 //check is there exist file with same start_time
00751                 QStringList filter;
00752                 filter << QString("*_%1*.png").arg(sub.start_time);
00753                 QFileInfoList found = stream_dir.entryInfoList(filter);
00754                 if (found.isEmpty())
00755                 {
00756                     //no same start_time founded
00757                     if (!sub.img.save(file_name))
00758                     {
00759                         LOG(VB_GENERAL, LOG_ERR,
00760                             QString("Can't write file '%1'")
00761                             .arg(file_name));
00762                     }
00763                     (*subit).subs_num++;
00764                 }
00765             }
00766             subs.pop_front();
00767         }
00768     }
00769 }
00770 
00771 
00772 CC708Reader *MythCCExtractorPlayer::GetCC708Reader(uint id)
00773 {
00774     if (!m_cc708_info[id].reader)
00775     {
00776         m_cc708_info[id].reader = new CC708Reader(this);
00777         m_cc708_info[id].reader->SetEnabled(true);
00778         LOG(VB_GENERAL, LOG_INFO, "Created CC708Reader");
00779     }
00780     return m_cc708_info[id].reader;
00781 }
00782 
00783 CC608Reader *MythCCExtractorPlayer::GetCC608Reader(uint id)
00784 {
00785     if (!m_cc608_info[id].reader)
00786     {
00787         m_cc608_info[id].reader = new CC608Reader(this);
00788         m_cc608_info[id].reader->SetEnabled(true);
00789     }
00790     return m_cc608_info[id].reader;
00791 }
00792 
00793 TeletextReader *MythCCExtractorPlayer::GetTeletextReader(uint id)
00794 {
00795     if (!m_ttx_info[id].reader)
00796         m_ttx_info[id].reader = new TeletextExtractorReader();
00797     return m_ttx_info[id].reader;
00798 }
00799 
00800 SubtitleReader *MythCCExtractorPlayer::GetSubReader(uint id)
00801 {
00802     if (!m_dvbsub_info[id].reader)
00803     {
00804         m_dvbsub_info[id].reader = new SubtitleReader();
00805         m_dvbsub_info[id].reader->EnableAVSubtitles(true);
00806         m_dvbsub_info[id].reader->EnableTextSubtitles(true);
00807         m_dvbsub_info[id].reader->EnableRawTextSubtitles(true);
00808     }
00809     return m_dvbsub_info[id].reader;
00810 }
00811 
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Properties Friends