19#if QT_VERSION < QT_VERSION_CHECK(6,0,0)
21#elif QT_VERSION < QT_VERSION_CHECK(6,3,0)
22#include <QStringConverter>
48 QMutexLocker locker(&
s_lock);
52 void run(
void)
override
56 QMutexLocker locker(&
s_lock);
64 QMutexLocker locker(&
s_lock);
70 QMutexLocker locker(&
s_lock);
139 int Read(
void *data,
int size) {
145 return stream.readRawData(
static_cast<char*
>(data), size);
163 QMutexLocker locker(&
m_lock);
177 m_fileName(
std::move(fileName)),
178 m_pkt(av_packet_alloc())
186 av_packet_free(&
m_pkt);
197 off_t remaining = bd->rbuffer_len - bd->rbuffer_cur;
200 buf_size = FFMIN(buf_size, remaining);
201 memcpy(buf, bd->rbuffer_text + bd->rbuffer_cur, buf_size);
202 bd->rbuffer_cur += buf_size;
215 offset = bd->rbuffer_cur + offset;
219 offset = bd->rbuffer_len - offset;
229 if ((offset < 0) || (offset > bd->rbuffer_len))
231 bd->rbuffer_cur = offset;
251 ret = avcodec_decode_subtitle2(
m_decCtx, &sub, &got_sub_ptr,
m_pkt);
257 sub.start_display_time = av_q2d(
m_stream->time_base) *
m_pkt->dts * 1000;
258 sub.end_display_time = av_q2d(
m_stream->time_base) * (
m_pkt->dts +
m_pkt->duration) * 1000;
287 LOG(VB_VBI, LOG_INFO,
288 QString(
"Preparing to load subtitle file %1").arg(
m_fileName));
291 LOG(VB_VBI, LOG_INFO,
292 QString(
"Failed to load subtitle file %1").arg(
m_fileName));
303 LOG(VB_VBI, LOG_INFO,
304 QString(
"Failed to get file size for %1").arg(
m_fileName));
310 LOG(VB_VBI, LOG_INFO,
311 QString(
"Filesize unchanged (%1), not reloading subs (%2)")
316 LOG(VB_VBI, LOG_INFO,
317 QString(
"Preparing to read %1 subtitle bytes from %2")
320 sub_data.rbuffer_len = new_len;
321 sub_data.rbuffer_text =
new char[sub_data.rbuffer_len + 1];
322 sub_data.rbuffer_cur = 0;
325 int numread = rfile.
Read(sub_data.rbuffer_text, sub_data.rbuffer_len);
326 LOG(VB_VBI, LOG_INFO,
327 QString(
"Finished reading %1 subtitle bytes (requested %2)")
328 .arg(numread).arg(new_len));
330 auto qba = QByteArray::fromRawData(sub_data.rbuffer_text,
331 sub_data.rbuffer_len);
332#if QT_VERSION < QT_VERSION_CHECK(6,0,0)
333 QTextCodec *textCodec = QTextCodec::codecForUtfText(qba,
nullptr);
334 isUtf8 = (textCodec !=
nullptr);
335#elif QT_VERSION < QT_VERSION_CHECK(6,3,0)
336 auto qba_encoding = QStringConverter::encodingForData(qba);
337 isUtf8 = qba_encoding.has_value()
338 && (qba_encoding.value() == QStringConverter::Utf8);
340 isUtf8 = qba.isValidUtf8();
344 m_fmtCtx = avformat_alloc_context();
346 LOG(VB_VBI, LOG_INFO,
"Couldn't allocate format context");
350 if (avio_ctx_buffer ==
nullptr)
352 LOG(VB_VBI, LOG_INFO,
"Couldn't allocate memory for avio context");
359 if (
int ret = avformat_open_input(&
m_fmtCtx,
nullptr,
nullptr,
nullptr); ret < 0) {
360 LOG(VB_VBI, LOG_INFO, QString(
"Couldn't open input context %1")
367 QString encoding {
"utf-8"};
370 const AVCodec *codec {
nullptr};
371 int stream_num = av_find_best_stream(
m_fmtCtx, AVMEDIA_TYPE_SUBTITLE, -1, -1, &codec, 0);
372 if (stream_num < 0) {
373 LOG(VB_VBI, LOG_INFO, QString(
"Couldn't find subtitle stream. %1")
380 LOG(VB_VBI, LOG_INFO, QString(
"Stream %1 is null").arg(stream_num));
386 m_decCtx = avcodec_alloc_context3(codec);
388 LOG(VB_VBI, LOG_INFO, QString(
"Couldn't allocate decoder context"));
394 AVDictionary *
dict =
nullptr;
398 if (encoding !=
"utf-8")
400 LOG(VB_VBI, LOG_INFO,
401 QString(
"Converting from %1 to utf-8.").arg(encoding));
402 av_dict_set(&
dict,
"sub_charenc", qPrintable(encoding), 0);
406 LOG(VB_VBI, LOG_INFO,
407 QString(
"Couldn't open decoder context for encoding %1").arg(encoding));
414 LOG(VB_GENERAL, LOG_INFO, QString(
"Loaded %2 '%3' subtitles from %4")
423 return {
reinterpret_cast<char*
>(
m_decCtx->subtitle_header),
429 if (av_seek_frame(
m_fmtCtx, -1, ts, flags) < 0)
431 LOG(VB_PLAYBACK, LOG_INFO,
432 QString(
"TextSubtitleParser av_seek_frame(fmtCtx, -1, %1, %2) -- error")
433 .arg(ts).arg(flags));
static MThreadPool * globalInstance(void)
QString GetSetting(const QString &key, const QString &defaultval="")
long long GetFileSize(void) const
RemoteFileWrapper & operator=(const RemoteFileWrapper &)=delete
RemoteFileWrapper(const QString &filename)
RemoteFile * m_remoteFile
int Read(void *data, int size)
RemoteFileWrapper(const RemoteFileWrapper &)=delete
int Read(void *data, int size)
long long GetFileSize(void) const
GetFileSize: returns the remote file's size at the time it was first opened Will query the server in ...
static bool IsLoading(TextSubtitles *target)
static void Wait(TextSubtitles *target)
static QWaitCondition s_wait
TextSubtitleParser * m_parent
static QHash< TextSubtitles *, uint > s_loading
SubtitleLoadHelper(TextSubtitleParser *parent, TextSubtitles *target)
void EnableRawTextSubtitles(bool enable)
bool AddAVSubtitle(AVSubtitle &subtitle, bool fix_position, bool is_selected_forced_track, bool allow_forced, bool isExternal)
void EnableAVSubtitles(bool enable)
void EnableTextSubtitles(bool enable)
static int64_t seek_packet(void *opaque, int64_t offset, int whence)
Seek in the file buffer.
QByteArray GetSubHeader()
SubtitleReader * m_parent
TextSubtitleParser(SubtitleReader *parent, QString fileName, TextSubtitles *target)
AVFormatContext * m_fmtCtx
static int read_packet(void *opaque, uint8_t *buf, int buf_size)
Read data from the file buffer into the avio context buffer.
void LoadSubtitles(bool inBackground)
void SeekFrame(int64_t ts, int flags)
AVCodecContext * m_decCtx
int ReadNextSubtitle(void)
Read the next subtitle in the AV stream.
SubtitleLoadHelper * m_loadHelper
void SetHasSubtitles(bool hasSubs)
off_t GetByteCount(void) const
void SetByteCount(off_t count)
void TextSubtitlesUpdated()
void SetFilename(const QString &fileName)
~TextSubtitles() override
char * av_make_error_stdstring(std::string &errbuf, int errnum)
A C++ equivalent to av_make_error_string.
MythCoreContext * gCoreContext
This global variable contains the MythCoreContext instance for the app.
#define LOG(_MASK_, _LEVEL_, _QSTRING_)
A local buffer that the entire file is slurped into.
static constexpr uint32_t IO_BUFFER_SIZE
TextSubtitles Copyright (c) 2006 by Pekka Jääskeläinen Distributed as part of MythTV under GPL v2 and...