20#if QT_VERSION < QT_VERSION_CHECK(6,0,0)
22#elif QT_VERSION < QT_VERSION_CHECK(6,3,0)
23#include <QStringConverter>
25#include <QWaitCondition>
49 QMutexLocker locker(&
s_lock);
53 void run(
void)
override
57 QMutexLocker locker(&
s_lock);
65 QMutexLocker locker(&
s_lock);
71 QMutexLocker locker(&
s_lock);
140 int Read(
void *data,
int size) {
146 return stream.readRawData(
static_cast<char*
>(data), size);
164 QMutexLocker locker(&
m_lock);
178 m_fileName(
std::move(fileName)),
179 m_pkt(av_packet_alloc())
187 av_packet_free(&
m_pkt);
198 off_t remaining = bd->rbuffer_len - bd->rbuffer_cur;
201 buf_size = FFMIN(buf_size, remaining);
202 memcpy(buf, bd->rbuffer_text + bd->rbuffer_cur, buf_size);
203 bd->rbuffer_cur += buf_size;
216 offset = bd->rbuffer_cur + offset;
220 offset = bd->rbuffer_len - offset;
230 if ((offset < 0) || (offset > bd->rbuffer_len))
232 bd->rbuffer_cur = offset;
252 ret = avcodec_decode_subtitle2(
m_decCtx, &sub, &got_sub_ptr,
m_pkt);
258 sub.start_display_time = av_q2d(
m_stream->time_base) *
m_pkt->dts * 1000;
259 sub.end_display_time = av_q2d(
m_stream->time_base) * (
m_pkt->dts +
m_pkt->duration) * 1000;
288 LOG(VB_VBI, LOG_INFO,
289 QString(
"Preparing to load subtitle file %1").arg(
m_fileName));
292 LOG(VB_VBI, LOG_INFO,
293 QString(
"Failed to load subtitle file %1").arg(
m_fileName));
304 LOG(VB_VBI, LOG_INFO,
305 QString(
"Failed to get file size for %1").arg(
m_fileName));
311 LOG(VB_VBI, LOG_INFO,
312 QString(
"Filesize unchanged (%1), not reloading subs (%2)")
317 LOG(VB_VBI, LOG_INFO,
318 QString(
"Preparing to read %1 subtitle bytes from %2")
321 sub_data.rbuffer_len = new_len;
322 sub_data.rbuffer_text =
new char[sub_data.rbuffer_len + 1];
323 sub_data.rbuffer_cur = 0;
326 int numread = rfile.
Read(sub_data.rbuffer_text, sub_data.rbuffer_len);
327 LOG(VB_VBI, LOG_INFO,
328 QString(
"Finished reading %1 subtitle bytes (requested %2)")
329 .arg(numread).arg(new_len));
331 auto qba = QByteArray::fromRawData(sub_data.rbuffer_text,
332 sub_data.rbuffer_len);
333#if QT_VERSION < QT_VERSION_CHECK(6,0,0)
334 QTextCodec *textCodec = QTextCodec::codecForUtfText(qba,
nullptr);
335 isUtf8 = (textCodec !=
nullptr);
336#elif QT_VERSION < QT_VERSION_CHECK(6,3,0)
337 auto qba_encoding = QStringConverter::encodingForData(qba);
338 isUtf8 = qba_encoding.has_value()
339 && (qba_encoding.value() == QStringConverter::Utf8);
341 isUtf8 = qba.isValidUtf8();
345 m_fmtCtx = avformat_alloc_context();
347 LOG(VB_VBI, LOG_INFO,
"Couldn't allocate format context");
351 if (avio_ctx_buffer ==
nullptr)
353 LOG(VB_VBI, LOG_INFO,
"Couldn't allocate memory for avio context");
360 if (
int ret = avformat_open_input(&
m_fmtCtx,
nullptr,
nullptr,
nullptr); ret < 0) {
361 LOG(VB_VBI, LOG_INFO, QString(
"Couldn't open input context %1")
368 QString encoding {
"utf-8"};
371 const AVCodec *codec {
nullptr};
372 int stream_num = av_find_best_stream(
m_fmtCtx, AVMEDIA_TYPE_SUBTITLE, -1, -1, &codec, 0);
373 if (stream_num < 0) {
374 LOG(VB_VBI, LOG_INFO, QString(
"Couldn't find subtitle stream. %1")
381 LOG(VB_VBI, LOG_INFO, QString(
"Stream %1 is null").arg(stream_num));
387 m_decCtx = avcodec_alloc_context3(codec);
389 LOG(VB_VBI, LOG_INFO, QString(
"Couldn't allocate decoder context"));
395 AVDictionary *
dict =
nullptr;
399 if (encoding !=
"utf-8")
401 LOG(VB_VBI, LOG_INFO,
402 QString(
"Converting from %1 to utf-8.").arg(encoding));
403 av_dict_set(&
dict,
"sub_charenc", qPrintable(encoding), 0);
407 LOG(VB_VBI, LOG_INFO,
408 QString(
"Couldn't open decoder context for encoding %1").arg(encoding));
415 LOG(VB_GENERAL, LOG_INFO, QString(
"Loaded %2 '%3' subtitles from %4")
424 return {
reinterpret_cast<char*
>(
m_decCtx->subtitle_header),
430 if (av_seek_frame(
m_fmtCtx, -1, ts, flags) < 0)
432 LOG(VB_PLAYBACK, LOG_INFO,
433 QString(
"TextSubtitleParser av_seek_frame(fmtCtx, -1, %1, %2) -- error")
434 .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...