18 #include <QDataStream>
19 #if QT_VERSION < QT_VERSION_CHECK(6,0,0)
21 #elif QT_VERSION < QT_VERSION_CHECK(6,3,0)
22 #include <QStringConverter>
36 #define IO_BUFFER_SIZE 32768
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);
175 : m_parent(parent), m_target(target), m_fileName(
std::move(fileName))
177 m_pkt = av_packet_alloc();
184 av_packet_free(&
m_pkt);
195 off_t remaining = bd->rbuffer_len - bd->rbuffer_cur;
198 buf_size = FFMIN(buf_size, remaining);
199 memcpy(buf, bd->rbuffer_text + bd->rbuffer_cur, buf_size);
200 bd->rbuffer_cur += buf_size;
213 offset = bd->rbuffer_cur + offset;
217 offset = bd->rbuffer_len - offset;
227 if ((offset < 0) || (offset > bd->rbuffer_len))
229 bd->rbuffer_cur = offset;
249 ret = avcodec_decode_subtitle2(
m_decCtx, &sub, &got_sub_ptr,
m_pkt);
255 sub.start_display_time = av_q2d(
m_stream->time_base) *
m_pkt->dts * 1000;
256 sub.end_display_time = av_q2d(
m_stream->time_base) * (
m_pkt->dts +
m_pkt->duration) * 1000;
285 LOG(VB_VBI, LOG_INFO,
286 QString(
"Preparing to load subtitle file %1").arg(
m_fileName));
289 LOG(VB_VBI, LOG_INFO,
290 QString(
"Failed to load subtitle file %1").arg(
m_fileName));
301 LOG(VB_VBI, LOG_INFO,
302 QString(
"Failed to get file size for %1").arg(
m_fileName));
308 LOG(VB_VBI, LOG_INFO,
309 QString(
"Filesize unchanged (%1), not reloading subs (%2)")
314 LOG(VB_VBI, LOG_INFO,
315 QString(
"Preparing to read %1 subtitle bytes from %2")
318 sub_data.rbuffer_len = new_len;
319 sub_data.rbuffer_text =
new char[sub_data.rbuffer_len + 1];
320 sub_data.rbuffer_cur = 0;
323 int numread = rfile.
Read(sub_data.rbuffer_text, sub_data.rbuffer_len);
324 LOG(VB_VBI, LOG_INFO,
325 QString(
"Finished reading %1 subtitle bytes (requested %2)")
326 .arg(numread).arg(new_len));
328 auto qba = QByteArray::fromRawData(sub_data.rbuffer_text,
329 sub_data.rbuffer_len);
330 #if QT_VERSION < QT_VERSION_CHECK(6,0,0)
331 QTextCodec *textCodec = QTextCodec::codecForUtfText(qba,
nullptr);
332 isUtf8 = (textCodec !=
nullptr);
333 #elif QT_VERSION < QT_VERSION_CHECK(6,3,0)
334 auto qba_encoding = QStringConverter::encodingForData(qba);
335 isUtf8 = qba_encoding.has_value()
336 && (qba_encoding.value() == QStringConverter::Utf8);
338 isUtf8 = qba.isValidUtf8();
342 m_fmtCtx = avformat_alloc_context();
344 LOG(VB_VBI, LOG_INFO,
"Couldn't allocate format context");
348 if (avio_ctx_buffer ==
nullptr)
350 LOG(VB_VBI, LOG_INFO,
"Couldn't allocate memory for avio context");
357 if (
int ret = avformat_open_input(&
m_fmtCtx,
nullptr,
nullptr,
nullptr); ret < 0) {
358 LOG(VB_VBI, LOG_INFO, QString(
"Couldn't open input context %1")
365 QString encoding {
"utf-8"};
368 const AVCodec *codec {
nullptr};
369 int stream_num = av_find_best_stream(
m_fmtCtx, AVMEDIA_TYPE_SUBTITLE, -1, -1, &codec, 0);
370 if (stream_num < 0) {
371 LOG(VB_VBI, LOG_INFO, QString(
"Couldn't find subtitle stream. %1")
378 LOG(VB_VBI, LOG_INFO, QString(
"Stream %1 is null").arg(stream_num));
384 m_decCtx = avcodec_alloc_context3(codec);
386 LOG(VB_VBI, LOG_INFO, QString(
"Couldn't allocate decoder context"));
392 AVDictionary *
dict =
nullptr;
396 if (encoding !=
"utf-8")
398 LOG(VB_VBI, LOG_INFO,
399 QString(
"Converting from %1 to utf-8.").arg(encoding));
400 av_dict_set(&
dict,
"sub_charenc", qPrintable(encoding), 0);
404 LOG(VB_VBI, LOG_INFO,
405 QString(
"Couldn't open decoder context for encoding %1").arg(encoding));
412 LOG(VB_GENERAL, LOG_INFO, QString(
"Loaded %2 '%3' subtitles from %4")
421 return {
reinterpret_cast<char*
>(
m_decCtx->subtitle_header),
427 if (av_seek_frame(
m_fmtCtx, -1, ts, flags) < 0)
429 LOG(VB_PLAYBACK, LOG_INFO,
430 QString(
"TextSubtitleParser av_seek_frame(fmtCtx, -1, %1, %2) -- error")
431 .arg(ts).arg(flags));