14#include "libavutil/avutil.h"
15#include "libavutil/error.h"
16#include "libavutil/log.h"
17#include "libavutil/opt.h"
18#include "libavcodec/avcodec.h"
19#include "libavcodec/defs.h"
20#include "libavformat/avformat.h"
21#include "libavformat/avio.h"
22#include "libswscale/swscale.h"
23#include "libavutil/stereo3d.h"
24#include "libavutil/imgutils.h"
25#include "libavutil/display.h"
28#include "libmythbase/mythconfig.h"
30#if QT_VERSION >= QT_VERSION_CHECK(6,5,0)
31#include <QtSystemDetection>
32#include <QtVersionChecks>
37#include "libavcodec/jni.h"
39#if QT_VERSION < QT_VERSION_CHECK(6,0,0)
40#include <QtAndroidExtras>
42#include <QJniEnvironment>
43#define QAndroidJniEnvironment QJniEnvironment
75#if QT_VERSION < QT_VERSION_CHECK(6,0,0)
78#include <QStringDecoder>
122using namespace std::string_view_literals;
124#define LOC QString("AFD: ")
134#if QT_VERSION < QT_VERSION_CHECK(6,0,0)
142 return {ctx.width >> ctx.lowres, ctx.height >> ctx.lowres};
146 float aspect_ratio = 0.0F;
148 if (ctx.sample_aspect_ratio.num && ctx.height)
150 aspect_ratio = av_q2d(ctx.sample_aspect_ratio) *
151 static_cast<double>(ctx.width);
152 aspect_ratio /= (float) ctx.height;
155 if (aspect_ratio <= 0.0F || aspect_ratio > 6.0F)
158 aspect_ratio = (float)ctx.width / (
float)ctx.height;
160 aspect_ratio = 4.0F / 3.0F;
167 static constexpr float kDefaultAspect = 4.0F / 3.0F;
168 int asp =
p.aspectRatio();
171 case 0:
return kDefaultAspect;
172 case 2:
return 4.0F / 3.0F;
173 case 3:
return 16.0F / 9.0F;
174 case 4:
return 2.21F;
178 float aspect_ratio = asp * 0.000001F;
179 if (aspect_ratio <= 0.0F || aspect_ratio > 6.0F)
181 if (
p.pictureHeight() &&
p.pictureWidth())
184 (float)
p.pictureWidth() /(float)
p.pictureHeight();
188 aspect_ratio = kDefaultAspect;
209#define FAIL(errmsg) do { \
210 LOG(VB_PLAYBACK, LOG_INFO, LOC + (errmsg)); \
221 switch (Stream->codecpar->codec_type)
225 case AVMEDIA_TYPE_VIDEO:
227 FAIL(
"No codec for video stream");
228 if (!Stream->codecpar->width || !Stream->codecpar->height)
229 FAIL(
"Unspecified video size");
230 if (Stream->codecpar->format == AV_PIX_FMT_NONE)
231 FAIL(
"Unspecified video pixel format");
238 case AVMEDIA_TYPE_AUDIO:
240 FAIL(
"No codec for audio stream");
258 case AVMEDIA_TYPE_SUBTITLE:
259 if (Stream->codecpar->codec_id == AV_CODEC_ID_HDMV_PGS_SUBTITLE && !Stream->codecpar->width)
260 FAIL(
"Unspecified subtitle size");
262 case AVMEDIA_TYPE_DATA:
263 if (Stream->codecpar->codec_id == AV_CODEC_ID_NONE)
270 if (Stream->codecpar->codec_id == AV_CODEC_ID_NONE)
271 FAIL(
"Unknown codec");
275static void myth_av_log(
void *ptr,
int level,
const char* fmt, va_list vl)
280 static QString s_fullLine(
"");
281 static QMutex s_stringLock;
282 uint64_t verbose_mask = VB_LIBAV;
283 LogLevel_t verbose_level = LOG_EMERG;
289 verbose_level = LOG_EMERG;
290 verbose_mask |= VB_GENERAL;
293 verbose_level = LOG_CRIT;
294 verbose_mask |= VB_GENERAL;
297 verbose_level = LOG_ERR;
300 verbose_level = LOG_WARNING;
303 verbose_level = LOG_INFO;
307 verbose_level = LOG_DEBUG;
310 verbose_level = LOG_TRACE;
320 if (s_fullLine.isEmpty() && ptr) {
321 AVClass* avc = *(AVClass**)ptr;
322 s_fullLine = QString(
"[%1 @ %2] ")
323 .arg(avc->item_name(ptr))
324 .arg((quintptr)avc, QT_POINTER_SIZE * 2, 16, QChar(
'0'));
327 s_fullLine += QString::vasprintf(fmt, vl);
328 if (s_fullLine.endsWith(
"\n"))
330 LOG(verbose_mask, verbose_level, s_fullLine.trimmed());
331 s_fullLine.truncate(0);
333 s_stringLock.unlock();
338 if (lang_cstr[0] ==
'\0' || lang_cstr[1] ==
'\0')
342 if (lang_cstr[2] ==
'\0')
344 QString tmp2 = lang_cstr;
362 case AVMEDIA_TYPE_UNKNOWN:
return "Unknown";
363 case AVMEDIA_TYPE_VIDEO:
return "Video";
364 case AVMEDIA_TYPE_AUDIO:
return "Audio";
365 case AVMEDIA_TYPE_DATA:
return "Data";
366 case AVMEDIA_TYPE_SUBTITLE:
return "Subtitle";
367 case AVMEDIA_TYPE_ATTACHMENT:
return "Attachment";
368 default:
return "Invalid Codec Type";
378 m_playerFlags(flags),
383 m_itv(parent->GetInteractiveTV()),
384 m_audioSamples((uint8_t *)av_mallocz(
AudioOutput::kMaxSizeBuffer))
398 LOG(VB_PLAYBACK, LOG_INFO,
LOC + QString(
"PlayerFlags: 0x%1, AudioReadAhead: %2 msec")
407 av_packet_free(&pkt);
425 lcd->setAudioFormatLEDs(
AUDIO_AC3,
false);
426 lcd->setVideoFormatLEDs(
VIDEO_MPG,
false);
443 for (
uint i = 0; i <
m_ic->nb_streams; i++)
445 AVStream *st =
m_ic->streams[i];
461 avformat_close_input(&
m_ic);
467static int64_t
lsb3full(int64_t lsb, int64_t base_ts,
int lsb_bits)
469 int64_t mask = (lsb_bits < 64) ? (1LL<<lsb_bits)-1 : -1LL;
470 return ((lsb - base_ts)&mask);
475 int64_t start_pts = 0;
477 AVStream *st =
nullptr;
478 for (
uint i = 0; i <
m_ic->nb_streams; i++)
480 AVStream *st1 =
m_ic->streams[i];
481 if (st1 && st1->codecpar->codec_type == AVMEDIA_TYPE_VIDEO)
490 if (
m_ic->start_time != AV_NOPTS_VALUE)
492 start_pts = av_rescale(
m_ic->start_time,
494 AV_TIME_BASE * (int64_t)st->time_base.num);
497 int64_t
pts = av_rescale(timecode.count() / 1000.0,
508 std::chrono::milliseconds timecode)
510 int64_t start_pts = 0;
512 if (
m_ic->start_time != AV_NOPTS_VALUE)
514 start_pts = av_rescale(
m_ic->start_time,
516 AV_TIME_BASE * (int64_t)st->time_base.num);
519 int64_t
pts = av_rescale(timecode.count() / 1000.0,
532 return m_ic->nb_chapters;
542 for (
int i = 0; i < total; i++)
544 int num =
m_ic->chapters[i]->time_base.num;
545 int den =
m_ic->chapters[i]->time_base.den;
546 int64_t start =
m_ic->chapters[i]->start;
547 long double total_secs = (
long double)start * (
long double)num /
549 times.push_back(std::chrono::seconds((
long long)total_secs));
558 for (
int i = (
m_ic->nb_chapters - 1); i > -1 ; i--)
560 int num =
m_ic->chapters[i]->time_base.num;
561 int den =
m_ic->chapters[i]->time_base.den;
562 int64_t start =
m_ic->chapters[i]->start;
563 long double total_secs = (
long double)start * (
long double)num /
565 auto framenum = (
long long)(total_secs *
m_fps);
566 if (framesPlayed >= framenum)
568 LOG(VB_PLAYBACK, LOG_INFO,
LOC +
569 QString(
"GetCurrentChapter(selected chapter %1 framenum %2)")
570 .arg(i + 1).arg(framenum));
582 int num =
m_ic->chapters[chapter - 1]->time_base.num;
583 int den =
m_ic->chapters[chapter - 1]->time_base.den;
584 int64_t start =
m_ic->chapters[chapter - 1]->start;
585 long double total_secs = (
long double)start * (
long double)num /
587 auto framenum = (
long long)(total_secs *
m_fps);
588 LOG(VB_PLAYBACK, LOG_INFO,
LOC + QString(
"GetChapter %1: framenum %2")
589 .arg(chapter).arg(framenum));
595 LOG(VB_PLAYBACK, LOG_INFO,
LOC + QString(
"DoRewind(%1, %2 discard frames)")
596 .arg(desiredFrame).arg( discardFrames ?
"do" :
"don't" ));
602 return do_av_seek(desiredFrame, discardFrames, AVSEEK_FLAG_BACKWARD);
607 LOG(VB_PLAYBACK, LOG_INFO,
LOC +
608 QString(
"DoFastForward(%1 (%2), %3 discard frames)")
610 .arg((discardFrames) ?
"do" :
"don't"));
618 if (seekDelta >= 0 && seekDelta < 2 && m_parent->GetPlaySpeed() == 0.0F)
624 return do_av_seek(desiredFrame, discardFrames, 0);
630 if (
m_ic->start_time != AV_NOPTS_VALUE)
631 ts =
m_ic->start_time;
634 long double seekts = desiredFrame * AV_TIME_BASE /
m_fps;
635 ts += (
long long)seekts;
642 flags |= AVSEEK_FLAG_BACKWARD;
645 int ret = av_seek_frame(
m_ic, -1, ts, flags);
648 LOG(VB_GENERAL, LOG_ERR,
LOC +
649 QString(
"av_seek_frame(m_ic, -1, %1, 0b%2) error: %3").arg(
651 QString::number(flags, 2),
658 reader->SeekFrame(ts, flags);
660 int normalframes = 0;
678 bool doflush,
bool discardFrames)
683 LOG(VB_PLAYBACK, LOG_INFO,
LOC +
684 QString(
"SeekReset(%1, %2, %3 flush, %4 discard)")
685 .arg(newKey).arg(skipFrames)
686 .arg((doflush) ?
"do" :
"don't",
687 (discardFrames) ?
"do" :
"don't"));
707 avformat_flush(
m_ic);
714 m_ic->pb->buf_ptr =
m_ic->pb->buffer;
715 m_ic->pb->buf_end =
m_ic->pb->buffer;
716 m_ic->pb->eof_reached = 0;
720 LOG(VB_PLAYBACK, LOG_INFO,
LOC +
"SeekReset() flushing");
721 for (
uint i = 0; i <
m_ic->nb_streams; i++)
727 if (codecContext && codecContext->internal)
728 avcodec_flush_buffers(codecContext);
735 av_packet_free(&pkt);
757 static constexpr std::chrono::milliseconds maxSeekTimeMs { 200ms };
758 int profileFrames = 0;
760 for (; (skipFrames > 0 && !
m_atEof &&
761 (exactSeeks || begin.
elapsed() < maxSeekTimeMs));
762 --skipFrames, ++profileFrames)
766 QElapsedTimer getframetimer;
767 getframetimer.start();
769 while (retry && !getframetimer.hasExpired(100))
774 std::this_thread::sleep_for(1ms);
782 if (!exactSeeks && profileFrames >= 5 && profileFrames < 10)
784 const int giveUpPredictionMs = 400;
785 int remainingTimeMs =
786 skipFrames * (float)begin.
elapsed().count() / profileFrames;
787 if (remainingTimeMs > giveUpPredictionMs)
789 LOG(VB_PLAYBACK, LOG_DEBUG,
790 QString(
"Frame-by-frame seeking would take "
791 "%1 ms to finish, skipping.").arg(remainingTimeMs));
808 LOG(VB_GENERAL, LOG_NOTICE,
LOC +
809 QString(
"Resetting byte context eof (livetv %1 was eof %2)")
811 m_ic->pb->eof_reached = 0;
819 LOG(VB_PLAYBACK, LOG_INFO,
LOC +
820 QString(
"Reset: Video %1, Seek %2, File %3")
821 .arg(reset_video_data).arg(seek_reset).arg(reset_file));
828 if (reset_video_data)
838 memset(&probe, 0,
sizeof(AVProbeData));
840 QByteArray fname =
filename.toLatin1();
841 probe.filename = fname.constData();
842 probe.buf = (
unsigned char *)testbuf.data();
843 probe.buf_size = testbuf.size();
845 int score = AVPROBE_SCORE_MAX/4;
857 memset(probe.buf + probe.buf_size, 0, AVPROBE_PADDING_SIZE);
859 return av_probe_input_format2(&probe,
static_cast<int>(
true), &score) !=
nullptr;
866 int cnt = decoder->
m_ic->nb_streams;
868 LOG(VB_PLAYBACK, LOG_INFO,
LOC +
869 QString(
"streams_changed 0x%1 -- program_number %2 stream count %3")
870 .arg((uint64_t)data,0,16).arg(QString::number(avprogram_id), QString::number(cnt)));
872 auto* program = decoder->get_current_AVProgram();
873 if (program !=
nullptr && program->id != avprogram_id)
877 decoder->m_streamsChanged =
true;
914 const AVInputFormat *fmt =
nullptr;
916 QByteArray fnamea = fnames.toLatin1();
917 const char *
filename = fnamea.constData();
920 memset(&probe, 0,
sizeof(AVProbeData));
922 probe.buf =
reinterpret_cast<unsigned char *
>(testbuf.data());
924 probe.buf_size = testbuf.size();
927 memset(probe.buf + probe.buf_size, 0, AVPROBE_PADDING_SIZE);
929 fmt = av_probe_input_format(&probe,
static_cast<int>(
true));
932 LOG(VB_GENERAL, LOG_ERR,
LOC + QString(
"Probe failed for '%1'").arg(
filename));
937 bool scancomplete =
false;
938 int remainingscans = 5;
940 while (!scancomplete && remainingscans--)
954 while (!found && --retries)
956 m_ic = avformat_alloc_context();
959 LOG(VB_GENERAL, LOG_ERR,
LOC +
"Could not allocate format context.");
966 LOG(VB_PLAYBACK, LOG_INFO,
LOC +
967 QString(
"Buffer size: %1 Streamed %2 Seekable %3 Available %4")
970 .arg(
m_ic->pb->seekable)
974 err = avformat_open_input(&
m_ic,
filename, fmt,
nullptr);
978 LOG(VB_PLAYBACK, LOG_INFO,
LOC + QString(
"Failed to open input ('%1')")
986 std::this_thread::sleep_for(100ms);
997 LOG(VB_GENERAL, LOG_ERR,
LOC +
"Fatal error opening input. Aborting");
1009 m_ic->max_analyze_duration = 60LL * AV_TIME_BASE;
1013 err = avformat_find_stream_info(
m_ic,
nullptr);
1017 LOG(VB_GENERAL, LOG_ERR,
LOC + QString(
"Could not find codec parameters for '%1'").arg(
filename));
1024 scancomplete =
true;
1029 scancomplete =
false;
1033 LOG(VB_PLAYBACK, LOG_INFO,
LOC +
"Stream scan incomplete - retrying");
1034 std::this_thread::sleep_for(250ms);
1042 LOG(VB_GENERAL, LOG_WARNING,
LOC +
"Scan incomplete - playback may not work");
1045 m_ic->stream_change_data =
this;
1057 QString extension = QFileInfo(fnames).suffix();
1058 if (strcmp(fmt->name,
"mp3") == 0 || strcmp(fmt->name,
"flac") == 0 ||
1059 strcmp(fmt->name,
"ogg") == 0 ||
1060 (extension.compare(
"m4a", Qt::CaseInsensitive) == 0))
1075 int initialAudio = -1;
1076 int initialVideo = -1;
1077 if (
m_itv ==
nullptr)
1079 if (
m_itv !=
nullptr)
1080 m_itv->GetInitialStreams(initialAudio, initialVideo);
1081 if (initialAudio >= 0)
1083 if (initialVideo >= 0)
1104 std::chrono::seconds dur = 0s;
1113 dur = duration_cast<std::chrono::seconds>(av_duration(
m_ic->duration));
1124 LOG(VB_PLAYBACK, LOG_INFO,
LOC +
1125 "Recording has no position -- using libavformat seeking.");
1134 float bytespersec = (float)
m_bitrate / 8 / 2;
1137 (int)(secs *
static_cast<float>(
m_fps)));
1146 if (strcmp(fmt->name,
"avi") == 0)
1159 LOG(VB_PLAYBACK, LOG_INFO,
LOC +
"Position map found");
1161 LOG(VB_PLAYBACK, LOG_INFO,
LOC +
"Partial position map found");
1162 LOG(VB_PLAYBACK, LOG_INFO,
LOC +
1163 QString(
"Successfully opened decoder for file: \"%1\". novideo(%2)")
1167 for (
unsigned int i=0; i <
m_ic->nb_chapters; i++)
1169 int num =
m_ic->chapters[i]->time_base.num;
1170 int den =
m_ic->chapters[i]->time_base.den;
1171 int64_t start =
m_ic->chapters[i]->start;
1172 auto total_secs =
static_cast<long double>(start) *
static_cast<long double>(num) /
1173 static_cast<long double>(den);
1175 auto framenum =
static_cast<long long>(total_secs *
static_cast<long double>(
m_fps));
1176 LOG(VB_PLAYBACK, LOG_INFO,
LOC +
1177 QString(
"Chapter %1 found @ [%2]->%3")
1180 QString::number(framenum)));
1193 Reset(
true,
true,
true);
1207 double avg_fps = (Stream->avg_frame_rate.den == 0) ? 0.0 : av_q2d(Stream->avg_frame_rate);
1208 double codec_fps = av_q2d(Context->framerate);
1209 double container_fps = (Stream->time_base.num == 0) ? 0.0 : av_q2d(av_inv_q(Stream->time_base));
1211 double estimated_fps = (Stream->r_frame_rate.den == 0) ? 0.0 : av_q2d(Stream->r_frame_rate);
1215 static const std::vector<double> k_standard_rates =
1235 std::vector<double> rates;
1240 if (QString(
m_ic->iformat->name).contains(
"matroska") ||
1241 QString(
m_ic->iformat->name).contains(
"mov"))
1243 rates.emplace_back(avg_fps);
1247 if (QString(
m_ic->iformat->name).contains(
"avi"))
1249 rates.emplace_back(container_fps);
1252 rates.emplace_back(codec_fps);
1253 rates.emplace_back(container_fps);
1254 rates.emplace_back(avg_fps);
1256 rates.emplace_back(estimated_fps);
1258 rates.emplace_back(30000.0 / 1001.0);
1260 auto invalid_fps = [](
double rate) {
return rate < 3.0 || rate > 121.0; };
1261 auto [first, last] = std::ranges::remove_if(rates, invalid_fps);
1262 rates.erase(first, last);
1264 auto FuzzyEquals = [](
double First,
double Second) {
return std::abs(First - Second) < 0.03; };
1267 if (!FuzzyEquals(rates.front(),
m_fps))
1269 LOG(VB_PLAYBACK, LOG_INFO,
LOC +
1270 QString(
"Selected FPS: %1 (Avg:%2 Mult:%3 Codec:%4 Container:%5 Estimated:%6)")
1271 .arg(
static_cast<double>(rates.front())).arg(avg_fps)
1272 .arg(
m_fpsMultiplier).arg(codec_fps).arg(container_fps).arg(estimated_fps));
1274 LOG(VB_GENERAL, LOG_INFO,
LOC +
1275 QString(
"Sanitise:%1").arg(Sanitise) +
1276 QString(
" avg_fps:%1").arg(avg_fps) +
1277 QString(
" codec_fps:%1").arg(codec_fps) +
1278 QString(
" container_fps:%1").arg(container_fps) +
1279 QString(
" estimated_fps:%1").arg(estimated_fps) +
1280 QString(
" m_fps:%1").arg(
m_fps));
1283 rs.reserve(rates.size());
1284 for (
auto rate : rates)
1285 rs.append(QString::number(rate));
1286 LOG(VB_GENERAL, LOG_INFO,
LOC +
1287 QString(
"Frame rates:%1").arg(rs.join(
' ')));
1290 auto IsStandard = [&FuzzyEquals](
double Rate)
1292 if (Rate > 23.0 && Rate < 121.0)
1294 for (
auto standard_rate : k_standard_rates)
1295 if (FuzzyEquals(Rate, standard_rate))
1303 auto NearestStandardFrameRate = [](
double rate,
double epsilon)
1305 double result = rate;
1306 double lowest_delta = rate;
1307 for (
auto standard_rate : k_standard_rates)
1309 double delta = std::abs(rate - standard_rate);
1310 if ((delta < lowest_delta) && (delta <
epsilon))
1312 lowest_delta = delta;
1313 result = standard_rate;
1320 double detected = rates.front();
1325 double nearest = NearestStandardFrameRate(detected, 3.0);
1326 LOG(VB_GENERAL, LOG_INFO,
LOC +
1327 QString(
"Frame rate %1 rounded to nearest standard rate %2")
1328 .arg(detected, 0,
'f', 2).arg(nearest, 0,
'f', 2));
1332 if (Sanitise && !IsStandard(detected))
1334 for (
auto rate : rates)
1336 if (IsStandard(rate))
1338 LOG(VB_GENERAL, LOG_INFO,
LOC + QString(
"%1 is non-standard - using %2 instead.")
1339 .arg(rates.front()).arg(rate));
1347 if (rate > 33.0 && detected < 33.0)
1349 double half = rate / 2.0;
1350 if (std::abs(half - detected) < (half * 0.1))
1352 LOG(VB_GENERAL, LOG_INFO,
LOC +
1353 QString(
"Assuming %1 is a better choice than %2")
1354 .arg(half).arg(rate));
1355 return static_cast<float>(half);
1358 return static_cast<float>(rate);
1363 return static_cast<float>(detected);
1368 switch (Context->codec_id)
1370 case AV_CODEC_ID_H264:
1373 if (Context->extradata && (Context->extradata_size >= 7))
1376 if (Context->extradata[0] == 1)
1387 parser.parse_SPS(Context->extradata + offset,
1388 static_cast<uint>(Context->extradata_size - offset), dummy, result);
1393 case AV_CODEC_ID_H265:
return 16;
1394 case AV_CODEC_ID_VP9:
return 8;
1395 case AV_CODEC_ID_VP8:
return 3;
1401 bool selectedStream)
1403 LOG(VB_PLAYBACK, LOG_INFO,
LOC +
1404 QString(
"InitVideoCodec ID:%1 Type:%2 Size:%3x%4")
1405 .arg(avcodec_get_name(codecContext->codec_id),
1407 .arg(codecContext->width).arg(codecContext->height));
1412 codecContext->opaque =
static_cast<void*
>(
this);
1414 codecContext->slice_flags = 0;
1416 codecContext->err_recognition = AV_EF_COMPLIANT;
1417 codecContext->workaround_bugs = FF_BUG_AUTODETECT;
1418 codecContext->error_concealment = FF_EC_GUESS_MVS | FF_EC_DEBLOCK;
1419 codecContext->idct_algo = FF_IDCT_AUTO;
1420 codecContext->debug = 0;
1423 const AVCodec *codec1 = codecContext->codec;
1429 const AVPacketSideData *sd = av_packet_side_data_get(stream->codecpar->coded_side_data,
1430 stream->codecpar->nb_coded_side_data, AV_PKT_DATA_DISPLAYMATRIX);
1432 m_videoRotation =
static_cast<int>(-av_display_rotation_get(
reinterpret_cast<int32_t*
>(sd->data)));
1437 sd = av_packet_side_data_get(stream->codecpar->coded_side_data,
1438 stream->codecpar->nb_coded_side_data, AV_PKT_DATA_STEREO3D);
1441 auto * avstereo =
reinterpret_cast<AVStereo3D*
>(sd->data);
1466 bool doublerate =
true;
1470 if (codec1 && ((AV_CODEC_ID_MPEG2VIDEO == codec1->id) ||
1471 (AV_CODEC_ID_MPEG1VIDEO == codec1->id)))
1475 int total_blocks = (codecContext->height + 15) / 16;
1476 codecContext->skip_top = (total_blocks + 3) / 4;
1477 codecContext->skip_bottom = (total_blocks + 3) / 4;
1481 codecContext->lowres = 2;
1485 codecContext->flags &= ~AV_CODEC_FLAG_LOOP_FILTER;
1486 codecContext->skip_loop_filter = AVDISCARD_ALL;
1490 codecContext->skip_idct = AVDISCARD_ALL;
1502 if (!width || !height)
1504 LOG(VB_PLAYBACK, LOG_INFO,
LOC +
1505 "InitVideoCodec invalid dimensions, resetting decoder.");
1513 const AVCodec *codec2 = codecContext->codec;
1516 codecName = codec2->name;
1524 switch (codecContext->codec_id)
1526 case AV_CODEC_ID_H263:
1527 case AV_CODEC_ID_MPEG4:
1528 case AV_CODEC_ID_MSMPEG4V1:
1529 case AV_CODEC_ID_MSMPEG4V2:
1530 case AV_CODEC_ID_MSMPEG4V3:
1531 case AV_CODEC_ID_H263P:
1532 case AV_CODEC_ID_H263I:
1535 case AV_CODEC_ID_WMV1:
1536 case AV_CODEC_ID_WMV2:
1540 case AV_CODEC_ID_XVID:
1549 lcd->setVideoFormatLEDs(video_format,
true);
1561 static constexpr std::array<uint8_t, 256> odd_parity_LUT
1563 0, 1, 1, 0, 1, 0, 0, 1, 1, 0, 0, 1, 0, 1, 1, 0,
1564 1, 0, 0, 1, 0, 1, 1, 0, 0, 1, 1, 0, 1, 0, 0, 1,
1565 1, 0, 0, 1, 0, 1, 1, 0, 0, 1, 1, 0, 1, 0, 0, 1,
1566 0, 1, 1, 0, 1, 0, 0, 1, 1, 0, 0, 1, 0, 1, 1, 0,
1567 1, 0, 0, 1, 0, 1, 1, 0, 0, 1, 1, 0, 1, 0, 0, 1,
1568 0, 1, 1, 0, 1, 0, 0, 1, 1, 0, 0, 1, 0, 1, 1, 0,
1569 0, 1, 1, 0, 1, 0, 0, 1, 1, 0, 0, 1, 0, 1, 1, 0,
1570 1, 0, 0, 1, 0, 1, 1, 0, 0, 1, 1, 0, 1, 0, 0, 1,
1571 1, 0, 0, 1, 0, 1, 1, 0, 0, 1, 1, 0, 1, 0, 0, 1,
1572 0, 1, 1, 0, 1, 0, 0, 1, 1, 0, 0, 1, 0, 1, 1, 0,
1573 0, 1, 1, 0, 1, 0, 0, 1, 1, 0, 0, 1, 0, 1, 1, 0,
1574 1, 0, 0, 1, 0, 1, 1, 0, 0, 1, 1, 0, 1, 0, 0, 1,
1575 0, 1, 1, 0, 1, 0, 0, 1, 1, 0, 0, 1, 0, 1, 1, 0,
1576 1, 0, 0, 1, 0, 1, 1, 0, 0, 1, 1, 0, 1, 0, 0, 1,
1577 1, 0, 0, 1, 0, 1, 1, 0, 0, 1, 1, 0, 1, 0, 0, 1,
1578 0, 1, 1, 0, 1, 0, 0, 1, 1, 0, 0, 1, 0, 1, 1, 0,
1580 bool ret = (odd_parity_LUT[data & 0xff] == 1) &&
1581 (odd_parity_LUT[(data & 0xff00) >> 8] == 1);
1584 LOG(VB_VBI, LOG_ERR,
LOC +
1585 QString(
"VBI: Bad parity in EIA-608 data (%1)") .arg(data,0,16));
1592 if (program ==
nullptr)
1596 return program->pmt_section;
1601 AVProgram* program = av_find_program_from_stream(context,
nullptr, stream_index);
1615 if (!pmt_buffer.has_buffer())
1617 LOG(VB_GENERAL, LOG_DEBUG,
LOC +
1618 "ScanATSCCaptionStreams() called with no PMT");
1623 bool video_found =
false;
1647 desc_list.insert(desc_list.end(), desc_list2.begin(), desc_list2.end());
1649 for (
auto & desc : desc_list)
1691 std::array<std::map<int,uint>,2> lang_cc_cnt;
1708 else if (!pofr && sofr)
1734 LOG(VB_GENERAL, LOG_ERR,
LOC +
"in_tracks key too small");
1740 LOG(VB_PLAYBACK, LOG_INFO,
LOC +
1741 QString(
"%1 caption service #%2 is in the %3 language.")
1742 .arg((
type) ?
"EIA-708" :
"EIA-608")
1758 AVStream* st =
m_ic->streams[av_index];
1759 const AVDictionaryEntry* language_dictionary_entry =
1760 av_dict_get(st->metadata,
"language",
nullptr, 0);
1762 if (language_dictionary_entry ==
nullptr ||
1763 language_dictionary_entry->value ==
nullptr ||
1764 st->codecpar->extradata ==
nullptr
1770 std::vector<std::string_view> languages {
StringUtil::split_sv(language_dictionary_entry->value,
","sv)};
1772 if (st->codecpar->extradata_size !=
static_cast<int>(languages.size() * 2))
1776 for (
size_t i = 0; i < languages.size(); i++)
1778 if (languages[i].size() != 3)
1784 uint8_t teletext_type = st->codecpar->extradata[i * 2] >> 3;
1785 uint8_t teletext_magazine_number = st->codecpar->extradata[i * 2] & 0x7;
1786 if (teletext_magazine_number == 0)
1787 teletext_magazine_number = 8;
1788 uint8_t teletext_page_number = st->codecpar->extradata[(i * 2) + 1];
1789 if (teletext_type == 2 || teletext_type == 1)
1791 TrackType track = (teletext_type == 2) ?
1794 m_tracks[track].emplace_back(av_index, 0, language,
1795 (
static_cast<unsigned>(teletext_magazine_number) << 8) | teletext_page_number);
1796 LOG(VB_PLAYBACK, LOG_INFO,
LOC +
1797 QString(
"Teletext stream #%1 (%2) is in the %3 language on page %4 %5.")
1798 .arg(QString::number(i),
1799 (teletext_type == 2) ?
"Caption" :
"Menu",
1801 QString::number(teletext_magazine_number),
1802 QString::number(teletext_page_number)));
1811 AVDictionaryEntry *metatag =
1812 av_dict_get(
m_ic->streams[av_stream_index]->metadata,
"language",
nullptr,
1814 bool forced = (
m_ic->streams[av_stream_index]->disposition & AV_DISPOSITION_FORCED) != 0;
1817 LOG(VB_PLAYBACK, LOG_INFO,
LOC +
1818 QString(
"Text Subtitle track #%1 is A/V stream #%2 "
1819 "and is in the %3 language(%4), forced=%5.")
1822 StreamInfo si {av_stream_index, 0, lang, 0, forced};
1832 if (
m_itv ==
nullptr)
1834 if (
m_itv ==
nullptr)
1838 if (!pmt_buffer.has_buffer())
1849 LOG(VB_DSMCC, LOG_NOTICE, QString(
"ScanDSMCCStreams Found Object Carousel in Stream %1").arg(QString::number(i)));
1855 for (
const auto *desc : desc_list)
1858 uint length = *desc++;
1859 const unsigned char *endDesc = desc+length;
1860 uint dataBroadcastId = desc[0]<<8 | desc[1];
1861 LOG(VB_DSMCC, LOG_NOTICE, QString(
"ScanDSMCCStreams dataBroadcastId %1").arg(QString::number(dataBroadcastId)));
1862 if (dataBroadcastId != 0x0106)
1865 while (desc != endDesc)
1867 [[maybe_unused]]
uint appTypeCode = desc[0]<<8 | desc[1];
1869 uint appSpecDataLen = *desc++;
1871 LOG(VB_DSMCC, LOG_NOTICE, QString(
"ScanDSMCCStreams AppTypeCode %1").arg(QString::number(appTypeCode)));
1872 if (appTypeCode == 0x101)
1874 const unsigned char *subDescEnd = desc + appSpecDataLen;
1875 while (desc < subDescEnd)
1877 uint sub_desc_tag = *desc++;
1878 uint sub_desc_len = *desc++;
1880 if (sub_desc_tag == 1)
1881 m_itv->SetNetBootInfo(desc, sub_desc_len);
1882 desc += sub_desc_len;
1888 desc += appSpecDataLen;
1902 const AVCodec *codec =
nullptr;
1903 LOG(VB_PLAYBACK, LOG_INFO,
LOC +
"Trying to select best video track");
1917 int stream_index = av_find_best_stream(
m_ic, AVMEDIA_TYPE_VIDEO, -1, -1, &codec, 0);
1919 if (stream_index < 0)
1921 LOG(VB_PLAYBACK, LOG_INFO,
LOC +
"No video track found/selected.");
1922 return stream_index;
1925 AVStream *stream =
m_ic->streams[stream_index];
1936 if (codecContext->codec_type == AVMEDIA_TYPE_VIDEO)
1937 codectype += QString(
"(%1x%2)").arg(codecContext->width).arg(codecContext->height);
1938 LOG(VB_PLAYBACK, LOG_INFO,
LOC +
1939 QString(
"Selected track #%1: ID: 0x%2 Codec ID: %3 Profile: %4 Type: %5 Bitrate: %6")
1940 .arg(stream_index).arg(
static_cast<uint64_t
>(stream->id), 0, 16)
1941 .arg(avcodec_get_name(codecContext->codec_id),
1942 avcodec_profile_name(codecContext->codec_id, codecContext->profile),
1944 QString::number(codecContext->bit_rate)));
1951 if ((codecContext->width != stream->codecpar->width) || (codecContext->height != stream->codecpar->height))
1953 LOG(VB_GENERAL, LOG_INFO,
LOC + QString(
1954 "Video resolution mismatch: Context: %1x%2 Stream: %3x%4 Codec: %5 Stream change: %6")
1955 .arg(codecContext->width).arg(codecContext->height)
1956 .arg(stream->codecpar->width).arg(stream->codecpar->height)
1963 int width = std::max(dim.width(), 16);
1964 int height = std::max(dim.height(), 16);
1965 QString dec =
"ffmpeg";
1966 uint thread_count = 1;
1968 if (codecContext->codec)
1969 codecName = codecContext->codec->name;
1974 if (codecContext->framerate.den && codecContext->framerate.num)
1975 m_fps = float(codecContext->framerate.num) / float(codecContext->framerate.den);
1979 bool foundgpudecoder =
false;
1980 QStringList unavailabledecoders;
1990 LOG(VB_GENERAL, LOG_WARNING,
LOC + QString(
1991 "GPU/hardware decoder '%1' failed - forcing software decode")
1998 while (unavailabledecoders.size() < 10)
2002 if (!unavailabledecoders.isEmpty())
2004 LOG(VB_PLAYBACK, LOG_INFO,
LOC + QString(
"Unavailable decoders: %1")
2005 .arg(unavailabledecoders.join(
",")));
2011 if (!skip_loop_filter)
2012 codecContext->skip_loop_filter = AVDISCARD_NONKEY;
2020 if (
version && allowgpu && dec !=
"ffmpeg")
2024 codecContext->opaque =
static_cast<void*
>(
this);
2029 codecContext->opaque =
static_cast<void*
>(
this);
2031 foundgpudecoder =
true;
2036 unavailabledecoders.append(dec);
2044 LOG(VB_GENERAL, LOG_ERR,
LOC +
"Unknown video codec - defaulting to MPEG2");
2059 if (!foundgpudecoder)
2061 LOG(VB_PLAYBACK, LOG_INFO,
LOC + QString(
"Using %1 CPUs for decoding")
2062 .arg(thread_count));
2063 codecContext->thread_count =
static_cast<int>(thread_count);
2077 return stream_index;
2082 AVProgram* program = av_find_program_from_stream(
m_ic,
nullptr, stream_index);
2083 if (program ==
nullptr)
2088 LOG(VB_PLAYBACK, LOG_INFO,
2089 QString(
"Removing streams not in Program %1 from track selection.")
2090 .arg(QString::number(program->id)));
2092 const auto *
const begin = program->stream_index;
2093 const auto *
const end = program->stream_index + program->nb_stream_indexes;
2097 LOG(VB_PLAYBACK, LOG_DEBUG,
2098 QString(
"Size before: %1").arg(QString::number(track_list.size())));
2099 auto [first, last] = std::ranges::remove_if(track_list,
2104 track_list.erase(first, last);
2105 LOG(VB_PLAYBACK, LOG_DEBUG,
2106 QString(
"Size after: %1").arg(QString::number(track_list.size())));
2112 return (ch_layout.order == AV_CHANNEL_ORDER_CUSTOM) &&
2113 (ch_layout.nb_channels == 2) &&
2114 (ch_layout.u.map[0].id == AV_CHAN_FRONT_CENTER) &&
2115 (ch_layout.u.map[1].id == AV_CHAN_FRONT_CENTER);
2123 bool unknownbitrate =
false;
2127 constexpr std::array<TrackType, 6>
types {
2141 std::map<int,uint> lang_sub_cnt;
2142 uint subtitleStreamCount = 0;
2143 std::map<int,uint> lang_aud_cnt;
2144 uint audioStreamCount = 0;
2153 if (
m_ic ==
nullptr)
2156 for (
uint strm = 0; strm <
m_ic->nb_streams; strm++)
2158 AVCodecParameters *par =
m_ic->streams[strm]->codecpar;
2161 if (par->codec_type == AVMEDIA_TYPE_VIDEO)
2162 codectype += QString(
"(%1x%2)").arg(par->width).arg(par->height);
2163 QString program_id =
"null";
2164 if (av_find_program_from_stream(
m_ic,
nullptr, strm) !=
nullptr)
2166 program_id = QString::number(av_find_program_from_stream(
m_ic,
nullptr, strm)->
id);
2168 LOG(VB_PLAYBACK, LOG_INFO,
LOC +
2169 QString(
"Stream #%1: ID: 0x%2 Program ID: %3 Codec ID: %4 Type: %5 Bitrate: %6").arg(
2170 QString::number(strm),
2171 QString::number(
static_cast<uint64_t
>(
m_ic->streams[strm]->id), 16),
2173 avcodec_get_name(par->codec_id),
2175 QString::number(par->bit_rate))
2178 switch (par->codec_type)
2180 case AVMEDIA_TYPE_VIDEO:
2188 if (ctx && (ctx->hw_frames_ctx || ctx->hw_device_ctx))
2195 LOG(VB_GENERAL, LOG_ERR,
LOC +
2196 QString(
"Stream #%1 has an unknown video "
2197 "codec id, skipping.").arg(strm));
2209 if (par->bit_rate == 0)
2211 static constexpr int64_t s_baseBitrate { 1000000LL };
2213 if (par->width && par->height)
2215 static const int s_baseSize = 1920 * 1080;
2216 multiplier = ((par->width * par->height) + s_baseSize - 1) / s_baseSize;
2217 multiplier = std::max(multiplier, 1);
2219 par->bit_rate = s_baseBitrate * multiplier;
2220 unknownbitrate =
true;
2226 case AVMEDIA_TYPE_AUDIO:
2228 LOG(VB_GENERAL, LOG_INFO,
LOC +
2229 QString(
"codec %1 has %2 channels")
2230 .arg(avcodec_get_name(par->codec_id))
2231 .arg(par->ch_layout.nb_channels));
2236 case AVMEDIA_TYPE_SUBTITLE:
2238 if (par->codec_id == AV_CODEC_ID_DVB_TELETEXT)
2240 if (par->codec_id == AV_CODEC_ID_TEXT)
2244 LOG(VB_PLAYBACK, LOG_INFO,
LOC + QString(
"subtitle codec (%1)")
2248 case AVMEDIA_TYPE_DATA:
2250 if (par->codec_id == AV_CODEC_ID_DVB_VBI)
2253 LOG(VB_PLAYBACK, LOG_INFO,
LOC + QString(
"data codec (%1)")
2257 case AVMEDIA_TYPE_ATTACHMENT:
2259 if (par->codec_id == AV_CODEC_ID_TTF)
2262 LOG(VB_PLAYBACK, LOG_INFO,
LOC +
2263 QString(
"Attachment codec (%1)")
2270 LOG(VB_PLAYBACK, LOG_ERR,
LOC +
2271 QString(
"Unknown codec type (%1)")
2277 if (par->codec_type != AVMEDIA_TYPE_AUDIO &&
2278 par->codec_type != AVMEDIA_TYPE_SUBTITLE)
2282 if (par->codec_type == AVMEDIA_TYPE_SUBTITLE &&
2283 (par->codec_id == AV_CODEC_ID_DVB_TELETEXT ||
2284 par->codec_id == AV_CODEC_ID_TEXT))
2287 LOG(VB_PLAYBACK, LOG_INFO,
LOC + QString(
"Looking for decoder for %1")
2288 .arg(avcodec_get_name(par->codec_id)));
2290 if (par->codec_id == AV_CODEC_ID_PROBE)
2292 LOG(VB_GENERAL, LOG_ERR,
LOC +
2293 QString(
"Probing of stream #%1 unsuccesful, ignoring.").arg(strm));
2299 if (codecContext ==
nullptr)
2301 LOG(VB_GENERAL, LOG_WARNING,
LOC +
2302 QString(
"Could not find decoder for codec (%1), ignoring.")
2303 .arg(avcodec_get_name(par->codec_id)));
2304 LOG(VB_LIBAV, LOG_INFO,
"For a list of all codecs, run `mythffmpeg -codecs`.");
2308 if (codecContext->codec && par->codec_id != codecContext->codec_id)
2310 LOG(VB_PLAYBACK, LOG_INFO,
LOC +
2311 QString(
"Already opened codec not matching (%1 vs %2). Reopening")
2312 .arg(avcodec_get_name(codecContext->codec_id),
2313 avcodec_get_name(codecContext->codec->id)));
2317 if (!
OpenAVCodec(codecContext, codecContext->codec))
2329 LOG(VB_PLAYBACK, LOG_INFO,
LOC +
2330 QString(
"Stream 0x%1 is not valid in this context - skipping")
2331 .arg(
m_ic->streams[strm]->id, 4, 16));
2335 if (par->codec_type == AVMEDIA_TYPE_SUBTITLE)
2337 bool forced = (
m_ic->streams[strm]->disposition & AV_DISPOSITION_FORCED) != 0;
2339 uint lang_indx = lang_sub_cnt[lang]++;
2340 subtitleStreamCount++;
2343 static_cast<int>(strm),
m_ic->streams[strm]->id, lang, lang_indx, forced);
2345 LOG(VB_PLAYBACK, LOG_INFO,
LOC +
2346 QString(
"Subtitle track #%1 is A/V stream #%2 "
2347 "and is in the %3 language(%4).")
2352 if (par->codec_type == AVMEDIA_TYPE_AUDIO)
2356 uint lang_indx = lang_aud_cnt[lang]++;
2359 int stream_id =
m_ic->streams[strm]->id;
2363 if (stream_id == -1)
2371 static_cast<int>(strm), stream_id, lang, lang_indx,
type);
2375 lang_indx = lang_aud_cnt[lang]++;
2377 static_cast<int>(strm), stream_id, lang, lang_indx,
type);
2380 LOG(VB_AUDIO, LOG_INFO,
LOC +
2381 QString(
"Audio Track #%1, of type (%2) is A/V stream #%3 (id=0x%4) "
2382 "and has %5 channels in the %6 language(%7).")
2384 .arg(strm).arg(
m_ic->streams[strm]->id,0,16).arg(codecContext->ch_layout.nb_channels)
2410 QString(
m_ic->iformat->name).contains(
"matroska"));
2452 for (
unsigned i = 0; i <
m_ic->nb_programs; i++)
2464#if CONFIG_MEDIACODEC
2465 if (QString(
"mediacodec") == codec->wrapper_name)
2466 av_jni_set_java_vm(QAndroidJniEnvironment::javaVM(),
nullptr);
2468 int ret = avcodec_open2(avctx, codec,
nullptr);
2473 LOG(VB_GENERAL, LOG_ERR,
LOC +
2474 QString(
"Could not open codec 0x%1, id(%2) type(%3) "
2475 "ignoring. reason %4").arg((uint64_t)avctx,0,16)
2476 .arg(avcodec_get_name(avctx->codec_id),
2482 LOG(VB_GENERAL, LOG_INFO,
LOC +
2483 QString(
"Opened codec 0x%1, id(%2) type(%3)")
2484 .arg((uint64_t)avctx,0,16)
2485 .arg(avcodec_get_name(avctx->codec_id),
2510 if (si.m_language_index == Index)
2511 return si.m_language;
2518 AVDictionaryEntry *metatag = av_dict_get(
m_ic->streams[StreamIndex]->metadata,
"language",
nullptr, 0);
2561 AVStream *stream =
m_ic->streams[StreamIndex];
2565 if (stream->disposition & AV_DISPOSITION_VISUAL_IMPAIRED)
2567 else if (stream->disposition & AV_DISPOSITION_COMMENT)
2569 else if (stream->disposition & AV_DISPOSITION_HEARING_IMPAIRED)
2571 else if (stream->disposition & AV_DISPOSITION_CLEAN_EFFECTS)
2598 if (
current->m_av_stream_index == streamIndex)
2604 LOG(VB_GENERAL, LOG_WARNING,
LOC +
2605 QString(
"Invalid stream index passed to "
2606 "SetupAudioStreamSubIndexes: %1").arg(streamIndex));
2613 if (
current->m_av_substream_index == -1)
2626 (next->m_av_stream_index != streamIndex))
2628 QString msg = QString(
2629 "Expected substream 1 (Language I) of stream %1\n\t\t\t"
2630 "following substream 0, found end of list or another stream.")
2633 LOG(VB_GENERAL, LOG_WARNING,
LOC + msg);
2655 bool do_flush =
false;
2656 for (
uint i = 0; i <
m_ic->nb_streams; i++)
2658 AVStream *st =
m_ic->streams[i];
2661 if (avctx && avctx->codec_type == AVMEDIA_TYPE_AUDIO)
2664 LOG(VB_LIBAV, LOG_DEBUG, QString(
"removing audio stream (id: 0x%1, index: %2, nb_streams: %3)")
2665 .arg(QString::number(st->id, 16),
2667 QString::number(
m_ic->nb_streams)
2671 if ((
m_ic->nb_streams - i) > 0) {
2672 std::memmove(
reinterpret_cast<void*
>(&
m_ic->streams[i]),
2673 reinterpret_cast<const void*
>(&
m_ic->streams[i + 1]),
2674 (
m_ic->nb_streams - i) *
sizeof(AVFormatContext*));
2678 m_ic->streams[i] =
nullptr;
2686 avformat_flush(
m_ic);
2695#ifdef __cpp_lib_ranges_contains
2696 if (!std::ranges::contains(*decoder->m_renderFormats,
type))
2698 if (!std::ranges::any_of(*decoder->m_renderFormats,
2699 [&
type](
auto Format) { return type == Format; }))
2702 decoder->m_directRendering =
false;
2703 return avcodec_default_get_buffer2(c, pic, flags);
2706 decoder->m_directRendering =
true;
2707 MythVideoFrame *frame = decoder->GetPlayer()->GetNextVideoFrame();
2717 if ((frame->
m_type !=
type) || (pic->width > width) || (pic->height > height))
2734 for (
uint i = 0; i < 3; i++)
2740 pic->opaque = frame;
2743 AVBufferRef *buffer = av_buffer_create(
reinterpret_cast<uint8_t*
>(frame), 0,
2744 [](
void* Opaque, uint8_t* Data)
2748 if (avfd && avfd->GetPlayer())
2749 avfd->GetPlayer()->DeLimboFrame(vf);
2752 pic->buf[0] = buffer;
2758int get_avf_buffer_dxva2(
struct AVCodecContext *c,
AVFrame *pic,
int )
2763 for (
int i = 0; i < 4; i++)
2765 pic->data[i] =
nullptr;
2766 pic->linesize[i] = 0;
2768 pic->opaque = frame;
2770 pic->data[0] = (uint8_t*)frame->
m_buffer;
2771 pic->data[3] = (uint8_t*)frame->
m_buffer;
2774 AVBufferRef *buffer =
2775 av_buffer_create((uint8_t*)frame, 0,
2776 [](
void* Opaque, uint8_t* Data)
2784 pic->buf[0] = buffer;
2795 bool had_608 =
false;
2796 bool had_708 =
false;
2797 for (
uint cur = 0; cur + 2 < buf_size; cur += 3)
2799 uint cc_code = buf[cur];
2800 bool cc_valid = (cc_code & 0x04) != 0U;
2802 uint data1 = buf[cur+1];
2803 uint data2 = buf[cur+2];
2804 uint data = (data2 << 8) | data1;
2805 uint cc_type = cc_code & 0x03;
2830 bool check_608,
bool check_708)
2832 bool need_change_608 =
false;
2837 for (
uint i = 0; i < 4; i++)
2844 bool need_change_708 =
false;
2846 if (check_708 || need_change_608)
2849 for (
uint i = 1; i < 64 && !need_change_608 && !need_change_708; i++)
2854 if (need_change_708 && !check_608)
2858 if (!need_change_608 && !need_change_708)
2869 for (
int i = 1; i < 64; i++)
2878 for (
int i = 0; i < 4; i++)
2899 AVPacket *pkt,
bool can_reliably_parse_keyframes)
2904 bool reset_kfd =
false;
2908 LOG(VB_PLAYBACK, LOG_INFO,
LOC +
2909 "gopset not set, syncing positionMap");
2911 if (tempKeyFrameDist > 0 && !
m_livetv)
2913 LOG(VB_PLAYBACK, LOG_INFO,
LOC +
2914 QString(
"Initial key frame distance: %1.")
2920 else if (
m_keyframeDist != tempKeyFrameDist && tempKeyFrameDist > 0)
2922 LOG(VB_PLAYBACK, LOG_INFO,
LOC +
2923 QString(
"Key frame distance changed from %1 to %2.")
2951 if (can_reliably_parse_keyframes &&
2954 long long last_frame = 0;
2962 LOG(VB_PLAYBACK, LOG_DEBUG,
LOC +
2963 QString(
"framesRead: %1 last_frame: %2 keyframedist: %3")
2970 long long startpos = pkt->pos;
2972 LOG(VB_PLAYBACK | VB_TIMESTAMP, LOG_INFO,
LOC +
2973 QString(
"positionMap[ %1 ] == %2.")
3005 float bytespersec = (float)
m_bitrate / 8;
3022 const uint8_t *bufptr = pkt->data;
3023 const uint8_t *bufend = pkt->data + pkt->size;
3025 while (bufptr < bufend)
3029 float aspect_override = -1.0F;
3038 if (bufptr + 11 >= pkt->data + pkt->size)
3040 const auto *seq =
reinterpret_cast<const SequenceHeader*
>(bufptr);
3042 int width =
static_cast<int>(seq->width()) >> context->lowres;
3043 int height =
static_cast<int>(seq->height()) >> context->lowres;
3044 float aspect = seq->
aspect(context->codec_id == AV_CODEC_ID_MPEG1VIDEO);
3045 if (stream->sample_aspect_ratio.num)
3046 aspect =
static_cast<float>(av_q2d(stream->sample_aspect_ratio) * width / height);
3047 if (aspect_override > 0.0F)
3048 aspect = aspect_override;
3049 float seqFPS = seq->fps();
3053 changed |= (seqFPS >
static_cast<float>(
m_fps)+0.01F) ||
3054 (seqFPS < static_cast<float>(
m_fps)-0.01F);
3058 bool forceaspectchange = !qFuzzyCompare(
m_currentAspect + 10.0F, aspect + 10.0F) &&
3062 if (changed || forceaspectchange)
3067 bool doublerate =
false;
3070 forceaspectchange, 2,
3073 if (context->hw_frames_ctx)
3074 if (context->internal)
3075 avcodec_flush_buffers(context);
3089 if ((seqFPS > avFPS+0.01F) || (seqFPS < avFPS-0.01F))
3091 LOG(VB_PLAYBACK, LOG_INFO,
LOC + QString(
"avFPS(%1) != seqFPS(%2)")
3092 .arg(
static_cast<double>(avFPS)).arg(
static_cast<double>(seqFPS)));
3101 pkt->flags |= AV_PKT_FLAG_KEY;
3108 pkt->flags |= AV_PKT_FLAG_KEY;
3116 const uint8_t *buf = pkt->data;
3117 const uint8_t *buf_end = pkt->data + pkt->size;
3122 if (context->extradata && (context->extradata_size >= 7) && (context->extradata[0] == 0x01))
3124 if (pkt->flags & AV_PKT_FLAG_KEY)
3129 while (buf < buf_end)
3160 bool fps_changed = (seqFPS > 0.0) && ((seqFPS >
m_fps + 0.01) ||
3161 (seqFPS <
m_fps - 0.01));
3166 if (fps_changed || res_changed || forcechange)
3171 bool doublerate =
false;
3184 if (context->hw_frames_ctx && (forcechange || res_changed))
3185 if (context->internal)
3186 avcodec_flush_buffers(context);
3192 m_fps =
static_cast<float>(seqFPS);
3202 if ((seqFPS > avFPS + 0.01) || (seqFPS < avFPS - 0.01))
3204 LOG(VB_PLAYBACK, LOG_INFO,
LOC +
3205 QString(
"avFPS(%1) != seqFPS(%2)").arg(avFPS).arg(seqFPS));
3210 pkt->flags |= AV_PKT_FLAG_KEY;
3230 if (pkt->flags & AV_PKT_FLAG_KEY)
3246 !(pkt->flags & AV_PKT_FLAG_KEY))
3248 av_packet_unref(pkt);
3282 bool sentPacket =
false;
3302 if (ret == AVERROR(EAGAIN))
3306 if (ret==0 && !gotpicture)
3308 ret2 = avcodec_send_packet(context, pkt);
3309 if (ret2 == AVERROR(EAGAIN))
3321 if (ret < 0 || ret2 < 0)
3326 LOG(VB_GENERAL, LOG_ERR,
LOC +
3327 QString(
"video avcodec_receive_frame error: %1 (%2) gotpicture:%3")
3329 .arg(ret).arg(gotpicture));
3334 LOG(VB_GENERAL, LOG_ERR,
LOC +
3335 QString(
"video avcodec_send_packet error: %1 (%2) gotpicture:%3")
3337 .arg(ret2).arg(gotpicture));
3351 LOG(VB_GENERAL, LOG_INFO,
LOC +
"Decoder needs reset");
3355 if (ret == AVERROR_EXTERNAL || ret2 == AVERROR_EXTERNAL)
3357 LOG(VB_PLAYBACK, LOG_INFO,
LOC +
"FFmpeg external library error - assuming streams changed");
3369 LOG(VB_PLAYBACK | VB_TIMESTAMP, LOG_INFO,
LOC +
3370 QString(
"video timecodes packet-pts:%1 frame-pts:%2 packet-dts: %3 frame-dts:%4")
3371 .arg(pkt->pts).arg(mpa_pic->pts).arg(pkt->dts)
3372 .arg(mpa_pic->pkt_dts));
3381 auto *newPkt = av_packet_clone(pkt);
3391 auto * side_data = av_frame_get_side_data(AvFrame, AV_FRAME_DATA_A53_CC);
3392 if (side_data && (side_data->size > 0))
3405 frame->m_directRendering =
false;
3416 av_image_fill_arrays(tmppicture.data, tmppicture.linesize,
3417 frame->m_buffer, AV_PIX_FMT_YUV420P, AvFrame->width,
3418 AvFrame->height, IMAGE_ALIGN);
3419 tmppicture.data[0] = frame->m_buffer + frame->m_offsets[0];
3420 tmppicture.data[1] = frame->m_buffer + frame->m_offsets[1];
3421 tmppicture.data[2] = frame->m_buffer + frame->m_offsets[2];
3422 tmppicture.linesize[0] = frame->m_pitches[0];
3423 tmppicture.linesize[1] = frame->m_pitches[1];
3424 tmppicture.linesize[2] = frame->m_pitches[2];
3428 AvFrame->height,
static_cast<AVPixelFormat
>(AvFrame->format),
3429 AvFrame->width, AvFrame->height,
3430 AV_PIX_FMT_YUV420P, SWS_FAST_BILINEAR,
3431 nullptr,
nullptr,
nullptr);
3434 LOG(VB_GENERAL, LOG_ERR,
LOC +
"Failed to allocate sws context");
3437 sws_scale(
m_swsCtx, AvFrame->data, AvFrame->linesize, 0, dim.height(),
3438 tmppicture.data, tmppicture.linesize);
3446 oldframe->
m_interlaced = (AvFrame->flags & AV_FRAME_FLAG_INTERLACED) != 0;
3447 oldframe->
m_topFieldFirst = (AvFrame->flags & AV_FRAME_FLAG_TOP_FIELD_FIRST) != 0;
3473 LOG(VB_GENERAL, LOG_ERR,
LOC +
"NULL videoframe - direct rendering not "
3474 "correctly initialized.");
3479 if (AvFrame->best_effort_timestamp == AV_NOPTS_VALUE)
3481 LOG(VB_GENERAL, LOG_ERR,
LOC +
"No PTS found - unable to process video.");
3485 AvFrame->best_effort_timestamp * 1000);
3486 std::chrono::milliseconds temppts =
pts;
3503 double calcfps = 1000.0 /
ptsdiff.count();
3504 if (calcfps < 121.0 && calcfps > 3.0)
3508 double fpschange = calcfps /
m_fps;
3510 if (fpschange > 1.9 && fpschange < 2.1)
3512 if (fpschange > 0.9 && fpschange < 1.1)
3518 LOG(VB_PLAYBACK | VB_TIMESTAMP, LOG_INFO,
LOC +
3519 QString(
"video timecode %1 %2 %3 %4%5")
3520 .arg(AvFrame->best_effort_timestamp)
3521 .arg(
pts.count()).arg(temppts.count()).arg(
m_lastVPts.count())
3522 .arg((
pts != temppts) ?
" fixup" :
""));
3524 frame->m_interlaced = (AvFrame->flags & AV_FRAME_FLAG_INTERLACED) != 0;
3525 frame->m_topFieldFirst = (AvFrame->flags & AV_FRAME_FLAG_TOP_FIELD_FIRST) != 0;
3527 frame->m_repeatPic = AvFrame->repeat_pict != 0;
3532 frame->m_colorspace = AvFrame->colorspace;
3533 frame->m_colorrange = AvFrame->color_range;
3534 frame->m_colorprimaries = AvFrame->color_primaries;
3535 frame->m_colortransfer = AvFrame->color_trc;
3536 frame->m_chromalocation = AvFrame->chroma_location;
3537 frame->m_pixFmt = AvFrame->format;
3542 frame->m_dummy =
false;
3543 frame->m_pauseFrame =
false;
3544 frame->m_deinterlaceInuse2x =
false;
3545 frame->m_alreadyDeinterlaced =
false;
3546 frame->m_interlacedReverse =
false;
3576 [[maybe_unused]]
const AVStream *stream,
const AVPacket *pkt)
3578 const uint8_t *buf = pkt->data;
3579 uint64_t linemask = 0;
3584 if ((buf[0]==
't') && (buf[1]==
'v') && (buf[2] ==
'0'))
3587 memcpy(&linemask, buf + 3, 8);
3590 else if ((buf[0]==
'T') && (buf[1]==
'V') && (buf[2] ==
'0'))
3592 linemask = 0xffffffffffffffffLL;
3597 LOG(VB_VBI, LOG_ERR,
LOC + QString(
"Unknown VBI data stream '%1%2%3'")
3598 .arg(QChar(buf[0])).arg(QChar(buf[1])).arg(QChar(buf[2])));
3602 static constexpr uint kMinBlank = 6;
3603 for (
uint i = 0; i < 36; i++)
3605 if (!((linemask >> i) & 0x1))
3608 const uint line = ((i < 18) ? i : i-18) + kMinBlank;
3609 const uint field = (i<18) ? 0 : 1;
3610 const uint id2 = *buf & 0xf;
3634 int data = (buf[2] << 8) | buf[1];
3661 const AVStream* ,
const AVPacket *pkt)
3670 const uint8_t *buf = pkt->data;
3671 const uint8_t *buf_end = pkt->data + pkt->size;
3673 if (*buf >= 0x10 && *buf <= 0x1F)
3679 LOG(VB_VBI, LOG_WARNING,
LOC +
3680 QString(
"VBI: Unknown data_identier: %1 discarded").arg(*buf));
3685 while (buf < buf_end)
3690 if ((buf_end - buf) >= 42)
3694 else if (*buf == 0x03)
3697 if ((buf_end - buf) >= 42)
3701 else if (*buf == 0xff)
3707 LOG(VB_VBI, LOG_WARNING,
LOC +
3708 QString(
"VBI: Unsupported data_unit_id: %1 discarded").arg(*buf));
3718 [[maybe_unused]]
const AVPacket *pkt)
3721 if (
m_itv ==
nullptr)
3723 if (
m_itv ==
nullptr)
3727 uint8_t *data = pkt->data;
3728 int length = pkt->size;
3729 int componentTag = 0;
3730 int dataBroadcastId = 0;
3731 unsigned carouselId = 0;
3734 componentTag = str->component_tag;
3735 dataBroadcastId = str->data_id;
3736 carouselId = (unsigned) str->carousel_id;
3741 uint16_t sectionLen = (((data[1] & 0xF) << 8) | data[2]) + 3;
3743 if (sectionLen > length)
3746 m_itv->ProcessDSMCCSection(data, sectionLen,
3747 componentTag, carouselId,
3749 length -= sectionLen;
3760 long long pts = pkt->pts;
3761 if (
pts == AV_NOPTS_VALUE)
3763 if (
pts == AV_NOPTS_VALUE)
3765 LOG(VB_GENERAL, LOG_ERR,
LOC +
"No PTS found - unable to process subtitle.");
3768 pts =
static_cast<long long>(av_q2d(curstream->time_base) *
pts * 1000);
3774 bool isForcedTrack =
false;
3777 int gotSubtitles = 0;
3778 AVSubtitle subtitle;
3779 memset(&subtitle, 0,
sizeof(AVSubtitle));
3786 curstream->id,
pts);
3790 if (pkt->stream_index == subIdx)
3794 pkt->data, pkt->size,
pts);
3800 || pkt->stream_index == forcedSubIdx)
3803 avcodec_decode_subtitle2(codecContext, &subtitle, &gotSubtitles, pkt);
3806 subtitle.start_display_time +=
pts;
3807 subtitle.end_display_time +=
pts;
3809 if (pkt->stream_index != subIdx)
3810 isForcedTrack =
true;
3817 for (
unsigned i = 0; i < subtitle.num_rects; i++)
3819 subtitle.rects[i]->flags |= AV_SUBTITLE_FLAG_FORCED;
3822 LOG(VB_PLAYBACK | VB_TIMESTAMP, LOG_INFO,
LOC +
3823 QString(
"subtl timecode %1 %2 %3 %4")
3824 .arg(pkt->pts).arg(pkt->dts)
3825 .arg(subtitle.start_display_time)
3826 .arg(subtitle.end_display_time));
3829 subtitle, curstream->codecpar->codec_id == AV_CODEC_ID_XSUB,
3843 auto id =
static_cast<uint>(Packet->stream_index + 0x2000);
3847#if QT_VERSION < QT_VERSION_CHECK(6,0,0)
3848 const auto * codec = QTextCodec::codecForName(
"utf-8");
3849 auto text = codec->toUnicode(
reinterpret_cast<const char *
>(Packet->data), Packet->size - 1);
3851 auto toUtf16 = QStringDecoder(QStringDecoder::Utf8);
3852 QString text = toUtf16.decode(Packet->data);
3854 auto list = text.split(
'\n', Qt::SkipEmptyParts);
3862 enum AVCodecID codec_id = curstream->codecpar->codec_id;
3866 case AV_CODEC_ID_DVB_VBI:
3869 case AV_CODEC_ID_DSMCC_B:
3894 LOG(VB_AUDIO, LOG_INFO,
LOC +
"Audio stream type " + msg +
"changed.");
3908 QString forcedString = forced ? QObject::tr(
" (forced)") :
"";
3910 int av_index =
m_tracks[
type][TrackNo].m_av_stream_index;
3911 AVStream *stream {
nullptr };
3912 if (av_index >= 0 && av_index < (
int)
m_ic->nb_streams)
3913 stream =
m_ic->streams[av_index];
3914 AVDictionaryEntry *entry =
3915 stream ? av_dict_get(stream->metadata,
"title",
nullptr, 0) :
nullptr;
3916 QString user_title = entry ? QString(R
"( "%1")").arg(entry->value) : "";
3928 AVCodecParameters *par = stream->codecpar;
3930 if (par->codec_id == AV_CODEC_ID_MP3)
3931 msg += QString(
" MP3");
3932 else if (ctx && ctx->codec)
3933 msg += QString(
" %1").arg(ctx->codec->name).toUpper();
3934 if (!user_title.isEmpty())
3937 int channels = par->ch_layout.nb_channels;
3940 msg += QString(
" ?ch");
3941 else if((channels > 4) && !(channels & 1))
3942 msg += QString(
" %1.1ch").arg(channels - 1);
3944 msg += QString(
" %1ch").arg(channels);
3954 if (!user_title.isEmpty())
3957 msg += QString(
" (%1)")
3961 return QString(
"%1: %2").arg(TrackNo + 1).arg(msg);
3965 return QObject::tr(
"Subtitle") + QString(
" %1: %2%3%4")
3966 .arg(QString::number(TrackNo + 1),
3994 return ctx ? QByteArray(
reinterpret_cast<char*
>(ctx->subtitle_header), ctx->subtitle_header_size) :
4005 AVDictionaryEntry *tag = av_dict_get(
m_ic->streams[index]->metadata,
"filename",
nullptr, 0);
4007 Filename = QByteArray(tag->value);
4008 AVCodecParameters *par =
m_ic->streams[index]->codecpar;
4009 Data = QByteArray(
reinterpret_cast<char*
>(par->extradata), par->extradata_size);
4019 if ((stream->component_tag == Tag) || ((Tag <= 0) && stream->component_tag <= 0))
4028 for (
uint i = 0; i <
m_ic->nb_streams; i++)
4030 AVStream *stream =
m_ic->streams[i];
4033 if (stream->component_tag == Tag)
4057 const std::vector<int> &ftype)
4059 std::vector<int> ret;
4061 for (
int index : ftype)
4063 if ((lang_key < 0) || tracks[index].m_language == lang_key)
4064 ret.push_back(index);
4072 std::vector<int> ret;
4074 for (
size_t i = 0; i < tracks.size(); i++)
4076 if (tracks[i].m_audio_type ==
type)
4085 const std::vector<int>&fs,
4086 enum AVCodecID codecId,
4089 int selectedTrack = -1;
4094 const int stream_index = tracks[f].m_av_stream_index;
4095 AVCodecParameters *par = ic->streams[stream_index]->codecpar;
4096 if ((codecId == AV_CODEC_ID_NONE || codecId == par->codec_id) &&
4097 (max_seen < par->ch_layout.nb_channels))
4099 if (codecId == AV_CODEC_ID_DTS &&
profile > 0)
4106 max_seen = par->ch_layout.nb_channels;
4110 return selectedTrack;
4118 std::vector<int> flang =
filter_lang(atracks, lang_key, ftype);
4123 AV_PROFILE_DTS_HD_MA);
4134 AV_PROFILE_DTS_HD_HRA);
4210 uint numStreams = atracks.size();
4214 if ((ctrack >= 0) && (ctrack < (
int)numStreams))
4217 LOG(VB_AUDIO, LOG_DEBUG, QString(
"%1 available audio streams").arg(numStreams));
4218 for (
const auto & track : atracks)
4220 AVCodecParameters *codecpar =
m_ic->streams[track.m_av_stream_index]->codecpar;
4221 LOG(VB_AUDIO, LOG_DEBUG, QString(
"%1: %2 bps, %3 Hz, %4 channels, passthrough(%5)")
4222 .arg(avcodec_get_name(codecpar->codec_id), QString::number(codecpar->bit_rate),
4223 QString::number(codecpar->sample_rate), QString::number(codecpar->ch_layout.nb_channels),
4228 if (1 == numStreams)
4238 LOG(VB_AUDIO, LOG_INFO,
LOC +
"Trying to reselect audio sub-stream");
4244 for (
uint i = 0; i < numStreams; i++)
4246 if (atracks[i].m_av_substream_index == substream_index)
4254 if ((selTrack < 0) && wlang >= -1)
4256 LOG(VB_AUDIO, LOG_INFO,
LOC +
"Trying to reselect audio track");
4261 for (
uint i = 0; i < numStreams; i++)
4263 if (wlang == atracks[i].m_language)
4267 if (windx == atracks[i].m_language_index)
4275 LOG(VB_AUDIO, LOG_INFO,
LOC +
"Trying to select audio track (w/lang)");
4282 LOG(VB_AUDIO, LOG_WARNING,
"No audio tracks matched the type filter, "
4283 "so trying all tracks.");
4284 ftype.reserve(atracks.size());
4285 for (
int i = 0; i < static_cast<int>(atracks.size()); i++)
4311 LOG(VB_AUDIO, LOG_INFO,
LOC +
"Trying to select default track");
4312 for (
size_t i = 0; i < atracks.size(); i++) {
4313 int idx = atracks[i].m_av_stream_index;
4314 if (
m_ic->streams[idx]->disposition & AV_DISPOSITION_DEFAULT)
4325 LOG(VB_AUDIO, LOG_INFO,
LOC +
4326 "Trying to select audio track (wo/lang)");
4336 if (ctrack != selTrack)
4338 LOG(VB_AUDIO, LOG_INFO,
LOC +
"No suitable audio track exists.");
4345 strack = atracks[selTrack];
4350 LOG(VB_AUDIO, LOG_INFO,
LOC + QString(
"Selected track %1 (A/V Stream #%2)")
4359 char *buffer,
int bufsize)
4370 const uint halfsample = samplesize >> 1;
4372 const char *from = (channel == 1) ? buffer + halfsample : buffer;
4373 char *to = (channel == 0) ? buffer + halfsample : buffer;
4376 (sample++), (from += samplesize), (to += samplesize))
4378 memmove(to, from, halfsample);
4387 bool firstloop =
true;
4388 int decoded_size = -1;
4395 AVPacket *tmp_pkt = av_packet_alloc();
4396 tmp_pkt->data = pkt->data;
4397 tmp_pkt->size = pkt->size;
4398 while (tmp_pkt->size > 0)
4400 bool reselectAudioTrack =
false;
4405 LOG(VB_AUDIO, LOG_INFO,
LOC +
4406 "Audio is disabled - trying to restart it");
4407 reselectAudioTrack =
true;
4412 bool wasDual = audSubIdx != -1;
4414 if ((wasDual && !isDual) || (!wasDual && isDual))
4417 reselectAudioTrack =
true;
4422 bool already_decoded =
false;
4423 if (!context->ch_layout.nb_channels)
4435 AVChannelLayout channel_layout;
4437 av_opt_set_chlayout(context->priv_data,
"downmix", &channel_layout, 0);
4439 if (context->codec_id == AV_CODEC_ID_AC3)
4444 decoded_size = data_size;
4445 already_decoded =
true;
4446 reselectAudioTrack |= context->ch_layout.nb_channels;
4450 if (reselectAudioTrack)
4460 if (!(decodetype &
kDecodeAudio) || (pkt->stream_index != audIdx)
4464 if (firstloop && pkt->pts != AV_NOPTS_VALUE)
4477 LOG(VB_GENERAL, LOG_INFO,
LOC +
"Audio stream changed");
4480 LOG(VB_GENERAL, LOG_INFO,
LOC + QString(
"Number of audio channels changed from %1 to %2")
4492 if (!already_decoded)
4497 decoded_size = data_size;
4505 data_size = tmp_pkt->size;
4511 if (!already_decoded)
4515 AVChannelLayout channel_layout;
4517 av_opt_set_chlayout(context->priv_data,
"downmix", &channel_layout, 0);
4521 decoded_size = data_size;
4528 LOG(VB_GENERAL, LOG_ERR,
LOC +
"Unknown audio decoding error");
4529 av_packet_free(&tmp_pkt);
4535 tmp_pkt->data += ret;
4536 tmp_pkt->size -= ret;
4540 std::chrono::milliseconds temppts =
m_lastAPts;
4547 int frames = (context->ch_layout.nb_channels <= 0 || decoded_size < 0 || !samplesize) ? -1 :
4548 decoded_size / (context->ch_layout.nb_channels * samplesize);
4557 ((
double)(frames * 1000) / context->sample_rate);
4560 LOG(VB_TIMESTAMP, LOG_INFO,
LOC + QString(
"audio timecode %1 %2 %3 %4")
4561 .arg(pkt->pts).arg(pkt->dts).arg(temppts.count()).arg(
m_lastAPts.count()));
4566 tmp_pkt->data += ret;
4567 tmp_pkt->size -= ret;
4571 av_packet_free(&tmp_pkt);
4578 AVPacket *pkt =
nullptr;
4579 bool have_err =
false;
4581 const DecodeType origDecodetype = decodetype;
4589 bool storevideoframes =
false;
4606 decodetype = (
DecodeType)((
int)decodetype & ~kDecodeVideo);
4622 decodetype = (
DecodeType)((
int)decodetype & ~kDecodeAudio);
4656 storevideoframes =
true;
4662 LOG(VB_GENERAL, LOG_WARNING,
LOC +
4663 QString(
"Audio %1 ms behind video but already %2 "
4664 "video frames queued. AV-Sync might be broken.")
4675 av_packet_free(&pkt);
4681 pkt = av_packet_alloc();
4684 if (
m_ic !=
nullptr)
4686 if ((
m_ic ==
nullptr) || (retval < 0))
4688 if (retval == -EAGAIN)
4692 av_packet_free(&pkt);
4694 if (retval == AVERROR_EOF)
4697 LOG(VB_GENERAL, LOG_INFO, QString(
"decoding reached end of file"));
4701 LOG(VB_GENERAL, LOG_ERR, QString(
"decoding error %1 (%2)")
4703 QString::number(retval)));
4717 LOG(VB_GENERAL, LOG_ERR,
LOC +
"No context");
4718 av_packet_unref(pkt);
4722 if (pkt->stream_index >= (
int)
m_ic->nb_streams)
4724 LOG(VB_GENERAL, LOG_ERR,
LOC +
"Bad stream");
4725 av_packet_unref(pkt);
4729 AVStream *curstream =
m_ic->streams[pkt->stream_index];
4733 LOG(VB_GENERAL, LOG_ERR,
LOC +
"Bad stream (NULL)");
4734 av_packet_unref(pkt);
4738 enum AVMediaType codec_type = curstream->codecpar->codec_type;
4739 const AVCodecID codec_id = curstream->codecpar->codec_id;
4745 case AVMEDIA_TYPE_VIDEO:
4746 if (storevideoframes)
4753 case AVMEDIA_TYPE_AUDIO:
4755 if (codec_id == AV_CODEC_ID_AC4)
4757 av_packet_unref(pkt);
4761 case AVMEDIA_TYPE_SUBTITLE:
4764 case AV_CODEC_ID_TEXT:
4766 av_packet_unref(pkt);
4768 case AV_CODEC_ID_DVB_TELETEXT:
4770 av_packet_unref(pkt);
4772 case AV_CODEC_ID_IVTV_VBI:
4774 av_packet_unref(pkt);
4780 case AVMEDIA_TYPE_DATA:
4782 av_packet_unref(pkt);
4790 if (context ==
nullptr)
4792 if (codec_type != AVMEDIA_TYPE_VIDEO)
4794 LOG(VB_PLAYBACK, LOG_ERR,
LOC +
4795 QString(
"No codec for stream index %1, type(%2) id(%3:%4)")
4796 .arg(QString::number(pkt->stream_index),
4798 avcodec_get_name(codec_id),
4799 QString::number(codec_id)
4806 av_packet_unref(pkt);
4814 case AVMEDIA_TYPE_AUDIO:
4823 case AVMEDIA_TYPE_VIDEO:
4837 av_packet_free(&pkt);
4841 if (pkt->pts != AV_NOPTS_VALUE)
4844 (av_q2d(curstream->time_base)*pkt->pts*1000000);
4859 case AVMEDIA_TYPE_SUBTITLE:
4868 LOG(VB_GENERAL, LOG_ERR,
LOC +
4869 QString(
"Decoding - id(%1) type(%2)")
4870 .arg(avcodec_get_name(codec_id),
4877 if (!have_err && !Retry)
4879 av_packet_unref(pkt);
4884 av_packet_free(&pkt);
4892 LOG(VB_PLAYBACK, LOG_INFO,
LOC + QString(
"StreamChangeCheck skip SeekReset"));
4902 int result = av_read_frame(ctx, pkt);
4910 if (pmt_buffer.has_buffer())
4967 if (stream < 0 || !
m_ic)
4969 return avcodec_get_name(
m_ic->streams[stream]->codecpar->codec_id);
4983 QString msg = disable ?
"Disabling" :
"Allowing";
4984 LOG(VB_AUDIO, LOG_INFO,
LOC + msg +
" pass through");
5007 switch (ctx->codec_id)
5009 case AV_CODEC_ID_AC3:
5010 case AV_CODEC_ID_TRUEHD:
5011 case AV_CODEC_ID_EAC3:
5012 case AV_CODEC_ID_MLP:
5013 case AV_CODEC_ID_DTS:
5022 bool passthru =
false;
5026 if (!withProfile && par->codec_id == AV_CODEC_ID_DTS && !
m_audio->
CanDTSHD())
5029 par->codec_id, AV_PROFILE_DTS);
5034 par->codec_id, par->profile);
5050 AVStream *curstream =
nullptr;
5051 AVCodecContext *ctx =
nullptr;
5053 int requested_channels = 0;
5057 (
int)
m_ic->nb_streams))
5060 .m_av_stream_index];
5061 if (curstream !=
nullptr)
5068 LOG(VB_PLAYBACK, LOG_INFO,
LOC +
"No codec context. Returning false");
5074 ctx->bits_per_raw_sample);
5076 if (av_sample_fmt_is_planar(ctx->sample_fmt))
5078 LOG(VB_AUDIO, LOG_INFO,
LOC + QString(
"Audio data is planar"));
5083 int bps = av_get_bytes_per_sample(ctx->sample_fmt) << 3;
5084 if (ctx->sample_fmt == AV_SAMPLE_FMT_S32 &&
5085 ctx->bits_per_raw_sample)
5086 bps = ctx->bits_per_raw_sample;
5087 LOG(VB_GENERAL, LOG_ERR,
LOC +
5088 QString(
"Unsupported sample format with %1 bits").arg(bps));
5092 bool using_passthru =
DoPassThrough(curstream->codecpar,
false);
5094 requested_channels = ctx->ch_layout.nb_channels;
5096 if (!using_passthru &&
5102 AVChannelLayout channel_layout;
5103 av_channel_layout_default(&channel_layout, requested_channels);
5104 av_opt_set_chlayout(ctx->priv_data,
"downmix", &channel_layout, 0);
5108 requested_channels, using_passthru, ctx->ch_layout.nb_channels,
5109 ctx->codec_id == AV_CODEC_ID_DTS ? ctx->profile : 0);
5113 LOG(VB_AUDIO, LOG_INFO,
LOC +
"Initializing audio parms from " +
5118 LOG(VB_AUDIO, LOG_INFO,
LOC +
"Audio format changed " +
5119 QString(
"\n\t\t\tfrom %1 to %2")
5135 switch (ctx->codec_id)
5137 case AV_CODEC_ID_MP2:
5140 case AV_CODEC_ID_MP3:
5143 case AV_CODEC_ID_AC3:
5146 case AV_CODEC_ID_DTS:
5149 case AV_CODEC_ID_VORBIS:
5152 case AV_CODEC_ID_WMAV1:
5155 case AV_CODEC_ID_WMAV2:
5163 lcd->setAudioFormatLEDs(audio_format,
true);
5198 int64_t start_time = INT64_MAX;
5199 int64_t end_time = INT64_MIN;
5200 AVStream *st =
nullptr;
5202 for (
uint i = 0; i < ic->nb_streams; i++)
5204 AVStream *st1 = ic->streams[i];
5205 if (st1 && st1->codecpar->codec_type == AVMEDIA_TYPE_VIDEO)
5214 int64_t duration = INT64_MIN;
5215 if (st->start_time != AV_NOPTS_VALUE && st->time_base.den) {
5216 int64_t start_time1= av_rescale_q(st->start_time, st->time_base, AV_TIME_BASE_Q);
5217 start_time = std::min(start_time1, start_time);
5218 if (st->duration != AV_NOPTS_VALUE) {
5219 int64_t end_time1 = start_time1 +
5220 av_rescale_q(st->duration, st->time_base, AV_TIME_BASE_Q);
5221 end_time = std::max(end_time1, end_time);
5224 if (st->duration != AV_NOPTS_VALUE) {
5225 int64_t duration1 = av_rescale_q(st->duration, st->time_base, AV_TIME_BASE_Q);
5226 duration = std::max(duration1, duration);
5228 if (start_time != INT64_MAX) {
5229 ic->start_time = start_time;
5230 if (end_time != INT64_MIN) {
5231 duration = std::max(end_time - start_time, duration);
5234 if (duration != INT64_MIN) {
5235 ic->duration = duration;
5238 int64_t filesize = avio_size(ic->pb);
5241 ic->bit_rate = (double)filesize * 8.0 * AV_TIME_BASE /
5242 (
double)ic->duration;
5258 if (
m_ic ==
nullptr)
5263 if (program ==
nullptr)
This is in libmythtv because that is where the parsers, which are its main users, are.
std::array< bool, 4 > CC608Seen
std::array< bool, 64 > cc708_seen_flags
uint pictureWidthCropped(void) const override
uint32_t addBytes(const uint8_t *bytes, uint32_t byte_count, uint64_t stream_offset) override
uint pictureHeightCropped(void) const override
field_type getFieldType(void) const override
double frameRate(void) const
void Reset(void) override
uint getRefFrames(void) const
static int SampleSize(AudioFormat format)
static AudioFormat AVSampleFormatToFormat(AVSampleFormat format, int bits=0)
Return AVSampleFormat closest equivalent to AudioFormat.
virtual bool has_optimized_SIMD()
virtual void SetSourceBitrate(int)
AudioOutput * GetAudioOutput(void) const
Return internal AudioOutput object.
QString ReinitAudio(void)
bool CanPassthrough(int samplerate, int channels, AVCodecID codec, int profile)
uint GetMaxChannels(void)
int DecodeAudio(AVCodecContext *ctx, uint8_t *buffer, int &data_size, const AVPacket *pkt)
DecodeAudio Utility routine.
void AddAudioData(char *buffer, int len, std::chrono::milliseconds timecode, int frames)
AudioFormat GetFormat(void) const
std::chrono::milliseconds LengthLastData(void)
bool NeedDecodingBeforePassthrough(void)
void SetAudioParams(AudioFormat format, int orig_channels, int channels, AVCodecID codec, int samplerate, bool passthru, int codec_profile=-1)
Set audio output parameters.
bool HasAudioOut(void) const
bool HasAudioIn(void) const
bool IsBufferAlmostFull(void)
QString GetXDS(const QString &key) const
void DecodeWSS(const unsigned char *buf)
void DecodeVPS(const unsigned char *buf)
void GetServices(std::chrono::seconds seconds, CC608Seen &seen) const
void SetIgnoreTimecode(bool val)
void FormatCCField(std::chrono::milliseconds tc, size_t field, int data)
void decode_cc_data(uint cc_type, uint data1, uint data2)
void services(std::chrono::seconds seconds, cc708_seen_flags &seen) const
QString toString() const override
bool Line21Field(int i) const
int CanonicalLanguageKey(int i) const
uint ServicesCount() const
int CaptionServiceNumber(int i) const
MythAVRational m_totalDuration
QRecursiveMutex m_positionMapLock
virtual uint GetTrackCount(uint Type)
MarkTypes m_positionMapType
frm_pos_map_t m_frameToDurMap
virtual void DoFastForwardSeek(long long desiredFrame, bool &needflush)
Seeks to the keyframe just before the desiredFrame if exact seeks is enabled, or the frame just after...
virtual void SetEof(bool eof)
bool m_dontSyncPositionMap
virtual QString GetTrackDesc(uint Type, uint TrackNo)
virtual int SetTrack(uint Type, int TrackNo)
uint64_t GetSeekSnap(void) const
virtual void UpdateFramesPlayed(void)
MythMediaBuffer * m_ringBuffer
QRecursiveMutex m_trackLock
bool m_nextDecodedFrameIsKeyFrame
bool m_decodeAllSubtitles
std::vector< int > m_languagePreference
language preferences for auto-selection of streams
virtual void Reset(bool reset_video_data, bool seek_reset, bool reset_file)
std::array< StreamInfo, kTrackTypeCount > m_wantedTrack
bool m_hasFullPositionMap
MythVideoProfile m_videoDisplayProfile
bool m_trackTotalDuration
frm_pos_map_t m_durToFrameMap
virtual bool DoFastForward(long long desiredFrame, bool discardFrames=true)
Skips ahead or rewinds to desiredFrame.
virtual void SeekReset(long long newkey, uint skipFrames, bool doFlush, bool discardFrames)
std::array< sinfo_vec_t, kTrackTypeCount > m_tracks
virtual bool SyncPositionMap(void)
Updates the position map used for skipping frames.
virtual int AutoSelectTrack(uint Type)
Select best track.
MythCodecContext * m_mythCodecCtx
std::array< StreamInfo, kTrackTypeCount > m_selectedForcedTrack
std::vector< PosMapEntry > m_positionMap
std::array< int, kTrackTypeCount > m_currentTrack
virtual bool DoRewindSeek(long long desiredFrame)
bool m_recordingHasPositionMap
virtual bool DoRewind(long long desiredFrame, bool discardFrames=true)
ProgramInfo * m_playbackInfo
std::array< StreamInfo, kTrackTypeCount > m_selectedTrack
bool stateChanged(void) const
bool onFrameStart(void) const
bool onKeyFrameStart(void) const
static desc_list_t ParseOnlyInclude(const unsigned char *data, uint len, int excluded_descid)
C++ wrapper for AVBufferRef.
MythAVFrame little utility class that act as a safe way to allocate an AVFrame which can then be allo...
C++ wrapper for FFmpeg libavutil AVRational.
long long toFixed(long long base) const
Convert the rational number to fixed point.
static VideoFrameType PixelFormatToFrameType(AVPixelFormat Fmt)
static MythCodecID FindDecoder(const QString &Decoder, AVStream *Stream, AVCodecContext **Context, const AVCodec **Codec)
virtual void SetDeinterlacing(AVCodecContext *, MythVideoProfile *, bool)
virtual void PostProcessFrame(AVCodecContext *, MythVideoFrame *)
virtual int HwDecoderInit(AVCodecContext *)
virtual bool IsDeinterlacing(bool &, bool=false)
virtual bool DecoderNeedsReset(AVCodecContext *)
virtual bool RetrieveFrame(AVCodecContext *, MythVideoFrame *, AVFrame *)
virtual void InitVideoCodec(AVCodecContext *Context, bool SelectedStream, bool &DirectRendering)
static MythCodecContext * CreateContext(DecoderBase *Parent, MythCodecID Codec)
virtual void SetDecoderOptions(AVCodecContext *, const AVCodec *)
virtual bool DecoderWillResetOnAspect(void)
virtual int FilteredReceiveFrame(AVCodecContext *Context, AVFrame *Frame)
Retrieve and process/filter AVFrame.
virtual bool DecoderWillResetOnFlush(void)
AVCodecContext * FindCodecContext(const AVStream *Stream)
AVCodecContext * GetCodecContext(const AVStream *Stream, const AVCodec *Codec=nullptr, bool NullCodec=false)
void FreeCodecContext(const AVStream *Stream)
QString GetAudioLanguage(void)
Returns two character ISO-639 language descriptor for audio language.
T GetDurSetting(const QString &key, T defaultval=T::zero())
int NumMenuButtons(void) const
void GetMenuSPUPkt(uint8_t *Buffer, int Size, int StreamID, uint32_t StartTime)
Get SPU pkt from dvd menu subtitle stream.
int GetAudioTrackNum(uint StreamId)
get the logical track index (into PGC_AST_CTL) of the element that maps the given physical stream id.
bool AudioStreamsChanged(void) const
bool DecodeSubtitles(AVSubtitle *Subtitle, int *GotSubtitles, const uint8_t *SpuPkt, int BufSize, uint32_t StartTime)
generate dvd subtitle bitmap or dvd menu bitmap.
float GetAspectOverride(void) const
void SetDuration(std::chrono::seconds duration)
virtual void ReleaseNextVideoFrame(MythVideoFrame *buffer, std::chrono::milliseconds timecode, bool wrap=true)
Places frame on the queue of frames ready for display.
virtual void SetVideoParams(int w, int h, double fps, float aspect, bool ForceUpdate, int ReferenceFrames, FrameScanType=kScan_Ignore, const QString &codecName=QString())
void SetFramesPlayed(uint64_t played)
virtual InteractiveTV * GetInteractiveTV()
void DiscardVideoFrames(bool KeyFrame, bool Flushed)
Places frames in the available frames queue.
void SetErrored(const QString &reason)
void SetFrameRate(double fps)
void DeLimboFrame(MythVideoFrame *frame)
bool IsErrored(void) const
void EnableForcedSubtitles(bool enable)
void SetKeyframeDistance(int keyframedistance)
void SetFileLength(std::chrono::seconds total, int frames)
virtual SubtitleReader * GetSubReader(uint=0)
bool GetAllowForcedSubtitles(void) const
MythVideoFrame * GetNextVideoFrame(void)
Removes a frame from the available queue for decoding onto.
int GetFreeVideoFrames(void) const
Returns the number of frames available for decoding onto.
void DiscardVideoFrame(MythVideoFrame *buffer)
Places frame in the available frames queue.
A QElapsedTimer based timer to replace use of QTime as a timer.
std::chrono::milliseconds elapsed(void)
Returns milliseconds elapsed since last start() or restart()
static uint GetNumPlanes(VideoFrameType Type)
bool m_deinterlaceInuse2x
bool m_alreadyDeinterlaced
MythDeintType m_deinterlaceInuse
void ClearBufferToBlank()
void SetInput(QSize Size, float Framerate=0, const QString &CodecName=QString(), const QStringList &DisallowedDecoders=QStringList())
QString GetDecoder() const
bool IsSkipLoopEnabled() const
A PSIP table is a variant of a PES packet containing an MPEG, ATSC or DVB table.
Holds information on recordings and videos.
std::chrono::milliseconds QueryTotalDuration(void) const
If present this loads the total duration in milliseconds of the main video stream from recordedmarkup...
A PMT table maps a program described in the ProgramAssociationTable to various PID's which describe t...
uint StreamCount(void) const
uint StreamType(uint i) const
const unsigned char * ProgramInfo(void) const
const unsigned char * StreamInfo(uint i) const
uint ProgramInfoLength(void) const
bool IsVideo(uint i, const QString &sistandard) const
Returns true iff the stream at index i is a video stream.
uint StreamInfoLength(uint i) const
@ PrivData
ISO 13818-1 PES private data & ITU H.222.0.
static bool IsObjectCarousel(uint type)
Returns true iff stream contains DSMCC Object Carousel.
uint m_language_index
Audio, Subtitle, Teletext.
int m_language
ISO639 canonical language key; Audio, Subtitle, CC, Teletext, RawText.
int m_av_substream_index
Audio only; -1 for no substream, 0 for first dual audio stream, 1 for second dual.
bool AddAVSubtitle(AVSubtitle &subtitle, bool fix_position, bool is_selected_forced_track, bool allow_forced, bool isExternal)
void AddRawTextSubtitle(const QStringList &list, std::chrono::milliseconds duration)
void Decode(const unsigned char *buf, int vbimode)
Decodes teletext data.
int GetDecoderType(void) const
static bool ReinitBuffer(MythVideoFrame *Frame, VideoFrameType Type, MythCodecID CodecID, int Width, int Height)
@ kAudioTypeAudioDescription
@ kAudioTypeHearingImpaired
std::vector< char > TestBufferVec
std::vector< StreamInfo > sinfo_vec_t
const int kDecoderProbeBufferSize
@ kTrackTypeTeletextCaptions
static pid_list_t::iterator find(const PIDInfoMap &map, pid_list_t &list, pid_list_t::iterator begin, pid_list_t::iterator end, bool find_open)
static const std::array< const uint64_t, 4 > samples
static const float epsilon
static const struct wl_interface * types[]
QString iso639_key_toName(int iso639_2)
Converts a canonical key to language name in English.
int iso639_key_to_canonical_key(int iso639_2)
QString iso639_str2_to_str3(const QString &str2)
ISO 639-1 and ISO 639-2 support functions.
static int iso639_str3_to_key(const unsigned char *iso639_2)
static bool iso639_is_key_undefined(int code)
Returns true if the key is 0, 0xFFFFFF, or 'und'.
std::vector< const unsigned char * > desc_list_t
char * av_make_error_stdstring(std::string &errbuf, int errnum)
A C++ equivalent to av_make_error_string.
MTV_PUBLIC std::string av_make_error_stdstring_unknown(int errnum)
std::chrono::microseconds microsecondsFromFloat(T value)
Helper function for convert a floating point number to a duration.
std::chrono::seconds secondsFromFloat(T value)
Helper function for convert a floating point number to a duration.
std::chrono::milliseconds millisecondsFromFloat(T value)
Helper function for convert a floating point number to a duration.
QString get_decoder_name(MythCodecID codec_id)
uint mpeg_version(AVCodecID codec_id)
static bool codec_is_std(MythCodecID id)
static bool CODEC_IS_H264(AVCodecID id)
static bool CODEC_IS_MPEG(AVCodecID id)
MythCoreContext * gCoreContext
This global variable contains the MythCoreContext instance for the app.
static constexpr uint8_t MYTH_WIDTH_ALIGNMENT
static constexpr uint8_t MYTH_HEIGHT_ALIGNMENT
static bool VERBOSE_LEVEL_CHECK(uint64_t mask, LogLevel_t level)
static bool VERBOSE_LEVEL_NONE()
#define LOG(_MASK_, _LEVEL_, _QSTRING_)
uint32_t readBigEndianU32(const uint8_t *x)
uint32_t readBigEndianU24(const uint8_t *x)
MTV_PUBLIC const uint8_t * find_start_code_truncated(const uint8_t *p, const uint8_t *end, uint32_t *start_code)
By preserving the start_code value between subsequent calls, the caller can detect start codes across...
QString formatTime(std::chrono::milliseconds msecs, QString fmt)
Format a milliseconds time value.
QString toString(const QDateTime &raw_dt, uint format)
Returns formatted string representing the time.
QDateTime current(bool stripped)
Returns current Date and Time in UTC.
std::vector< std::string_view > split_sv(const std::string_view s, const std::string_view delimiter)
Split a std::string_view into a std::vector of std::string_views.
QString intToPaddedString(int n, int width=2)
Creates a zero padded string representation of an integer.
std::chrono::duration< CHRONO_TYPE, std::ratio< 1, 90000 > > pts
int64_t ptsdiff(uint64_t pts1, uint64_t pts2)
@ VBI_DVB_SUBTITLE
< DVB packet