MythTV  0.26-pre
textsubtitleparser.cpp
Go to the documentation of this file.
00001 // -*- Mode: c++ -*-
00007 // ANSI C
00008 #include <cstdio>
00009 #include <cstring>
00010 #include <climits>
00011 
00012 // C++
00013 #include <algorithm>
00014 using std::lower_bound;
00015 
00016 // Qt
00017 #include <QTextCodec>
00018 
00019 // MythTV
00020 #include "mythcorecontext.h"
00021 #include "ringbuffer.h"
00022 #include "textsubtitleparser.h"
00023 #include "xine_demux_sputext.h"
00024 
00025 static bool operator<(const text_subtitle_t& left,
00026                       const text_subtitle_t& right)
00027 {
00028     return left.start < right.start;
00029 }
00030 
00041 bool TextSubtitles::HasSubtitleChanged(uint64_t timecode) const
00042 {
00043     return (timecode < m_lastReturnedSubtitle.start ||
00044             timecode > m_lastReturnedSubtitle.end);
00045 }
00046 
00054 QStringList TextSubtitles::GetSubtitles(uint64_t timecode) const
00055 {
00056     QStringList list;
00057     if (m_subtitles.empty())
00058         return list;
00059 
00060     text_subtitle_t searchTarget(timecode, timecode);
00061 
00062     TextSubtitleList::const_iterator nextSubPos =
00063         lower_bound(m_subtitles.begin(), m_subtitles.end(), searchTarget);
00064 
00065     uint64_t startCode = 0, endCode = 0;
00066     if (nextSubPos != m_subtitles.begin())
00067     {
00068         TextSubtitleList::const_iterator currentSubPos = nextSubPos;
00069         --currentSubPos;
00070 
00071         const text_subtitle_t &sub = *currentSubPos;
00072         if (sub.start <= timecode && sub.end >= timecode)
00073         {
00074             // found a sub to display
00075             m_lastReturnedSubtitle = sub;
00076             QStringList tmp = m_lastReturnedSubtitle.textLines;
00077             tmp.detach();
00078             return tmp;
00079         }
00080 
00081         // the subtitle time span has ended, let's display a blank sub
00082         startCode = sub.end + 1;
00083     }
00084 
00085     if (nextSubPos == m_subtitles.end())
00086     {
00087         // at the end of video, the blank subtitle should last until
00088         // forever
00089         endCode = startCode + INT_MAX;
00090     }
00091     else
00092     {
00093         endCode = (*nextSubPos).start - 1;
00094     }
00095 
00096     // we are in a position in which there are no subtitles to display,
00097     // return an empty subtitle and create a dummy empty subtitle for this
00098     // time span so SubtitleChanged() functions also in this case
00099     text_subtitle_t blankSub(startCode, endCode);
00100     m_lastReturnedSubtitle = blankSub;
00101 
00102     return list;
00103 }
00104 
00105 void TextSubtitles::AddSubtitle(const text_subtitle_t &newSub)
00106 {
00107     m_lock.lock();
00108     m_subtitles.push_back(newSub);
00109     m_lock.unlock();
00110 }
00111 
00112 void TextSubtitles::Clear(void)
00113 {
00114     m_lock.lock();
00115     m_subtitles.clear();
00116     m_lock.unlock();
00117 }
00118 
00119 bool TextSubtitleParser::LoadSubtitles(QString fileName, TextSubtitles &target)
00120 {
00121     demux_sputext_t sub_data;
00122     sub_data.rbuffer = RingBuffer::Create(fileName, 0, false);
00123 
00124     if (!sub_data.rbuffer)
00125         return false;
00126 
00127     sub_data.errs = 0;
00128     subtitle_t *loaded_subs = sub_read_file(&sub_data);
00129     if (!loaded_subs)
00130     {
00131         delete sub_data.rbuffer;
00132         return false;
00133     }
00134 
00135     target.SetFrameBasedTiming(!sub_data.uses_time);
00136 
00137     QTextCodec *textCodec = NULL;
00138     QString codec = gCoreContext->GetSetting("SubtitleCodec", "");
00139     if (!codec.isEmpty())
00140         textCodec = QTextCodec::codecForName(codec.toLatin1());
00141     if (!textCodec)
00142         textCodec = QTextCodec::codecForName("utf-8");
00143     if (!textCodec)
00144     {
00145         delete sub_data.rbuffer;
00146         return false;
00147     }
00148 
00149     QTextDecoder *dec = textCodec->makeDecoder();
00150 
00151     // convert the subtitles to our own format and free the original structures
00152     for (int sub_i = 0; sub_i < sub_data.num; ++sub_i)
00153     {
00154         const subtitle_t *sub = &loaded_subs[sub_i];
00155         text_subtitle_t newsub(sub->start, sub->end);
00156 
00157         if (!target.IsFrameBasedTiming())
00158         {
00159             newsub.start *= 10; // convert from csec to msec
00160             newsub.end *= 10;
00161         }
00162 
00163         for (int line = 0; line < sub->lines; ++line)
00164         {
00165             const char *subLine = sub->text[line];
00166             QString str = dec->toUnicode(subLine, strlen(subLine));
00167             newsub.textLines.push_back(str);
00168 
00169             free(sub->text[line]);
00170         }
00171         target.AddSubtitle(newsub);
00172     }
00173 
00174     delete dec;
00175     // textCodec object is managed by Qt, do not delete...
00176 
00177     free(loaded_subs);
00178     delete sub_data.rbuffer;
00179 
00180     return true;
00181 }
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Properties Friends