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
71#if QT_VERSION < QT_VERSION_CHECK(6,0,0)
74#include <QStringDecoder>
118using namespace std::string_view_literals;
120#define LOC QString("AFD: ")
130#if QT_VERSION < QT_VERSION_CHECK(6,0,0)
138 return {ctx.width >> ctx.lowres, ctx.height >> ctx.lowres};
142 float aspect_ratio = 0.0F;
144 if (ctx.sample_aspect_ratio.num && ctx.height)
146 aspect_ratio = av_q2d(ctx.sample_aspect_ratio) *
147 static_cast<double>(ctx.width);
148 aspect_ratio /= (float) ctx.height;
151 if (aspect_ratio <= 0.0F || aspect_ratio > 6.0F)
154 aspect_ratio = (float)ctx.width / (
float)ctx.height;
156 aspect_ratio = 4.0F / 3.0F;
163 static constexpr float kDefaultAspect = 4.0F / 3.0F;
164 int asp =
p.aspectRatio();
167 case 0:
return kDefaultAspect;
168 case 2:
return 4.0F / 3.0F;
169 case 3:
return 16.0F / 9.0F;
170 case 4:
return 2.21F;
174 float aspect_ratio = asp * 0.000001F;
175 if (aspect_ratio <= 0.0F || aspect_ratio > 6.0F)
177 if (
p.pictureHeight() &&
p.pictureWidth())
180 (float)
p.pictureWidth() /(float)
p.pictureHeight();
184 aspect_ratio = kDefaultAspect;
205#define FAIL(errmsg) do { \
206 LOG(VB_PLAYBACK, LOG_INFO, LOC + (errmsg)); \
217 switch (Stream->codecpar->codec_type)
221 case AVMEDIA_TYPE_VIDEO:
223 FAIL(
"No codec for video stream");
224 if (!Stream->codecpar->width || !Stream->codecpar->height)
225 FAIL(
"Unspecified video size");
226 if (Stream->codecpar->format == AV_PIX_FMT_NONE)
227 FAIL(
"Unspecified video pixel format");
234 case AVMEDIA_TYPE_AUDIO:
236 FAIL(
"No codec for audio stream");
254 case AVMEDIA_TYPE_SUBTITLE:
255 if (Stream->codecpar->codec_id == AV_CODEC_ID_HDMV_PGS_SUBTITLE && !Stream->codecpar->width)
256 FAIL(
"Unspecified subtitle size");
258 case AVMEDIA_TYPE_DATA:
259 if (Stream->codecpar->codec_id == AV_CODEC_ID_NONE)
266 if (Stream->codecpar->codec_id == AV_CODEC_ID_NONE)
267 FAIL(
"Unknown codec");
271static void myth_av_log(
void *ptr,
int level,
const char* fmt, va_list vl)
276 static QString s_fullLine(
"");
277 static QMutex s_stringLock;
278 uint64_t verbose_mask = VB_LIBAV;
279 LogLevel_t verbose_level = LOG_EMERG;
285 verbose_level = LOG_EMERG;
286 verbose_mask |= VB_GENERAL;
289 verbose_level = LOG_CRIT;
290 verbose_mask |= VB_GENERAL;
293 verbose_level = LOG_ERR;
296 verbose_level = LOG_WARNING;
299 verbose_level = LOG_INFO;
303 verbose_level = LOG_DEBUG;
306 verbose_level = LOG_TRACE;
316 if (s_fullLine.isEmpty() && ptr) {
317 AVClass* avc = *(AVClass**)ptr;
318 s_fullLine = QString(
"[%1 @ %2] ")
319 .arg(avc->item_name(ptr))
320 .arg((quintptr)avc, QT_POINTER_SIZE * 2, 16, QChar(
'0'));
323 s_fullLine += QString::vasprintf(fmt, vl);
324 if (s_fullLine.endsWith(
"\n"))
326 LOG(verbose_mask, verbose_level, s_fullLine.trimmed());
327 s_fullLine.truncate(0);
329 s_stringLock.unlock();
334 if (lang_cstr[0] ==
'\0' || lang_cstr[1] ==
'\0')
338 if (lang_cstr[2] ==
'\0')
340 QString tmp2 = lang_cstr;
358 case AVMEDIA_TYPE_UNKNOWN:
return "Unknown";
359 case AVMEDIA_TYPE_VIDEO:
return "Video";
360 case AVMEDIA_TYPE_AUDIO:
return "Audio";
361 case AVMEDIA_TYPE_DATA:
return "Data";
362 case AVMEDIA_TYPE_SUBTITLE:
return "Subtitle";
363 case AVMEDIA_TYPE_ATTACHMENT:
return "Attachment";
364 default:
return "Invalid Codec Type";
374 m_playerFlags(flags),
379 m_itv(parent->GetInteractiveTV()),
380 m_audioSamples((uint8_t *)av_mallocz(
AudioOutput::kMaxSizeBuffer))
394 LOG(VB_PLAYBACK, LOG_INFO,
LOC + QString(
"PlayerFlags: 0x%1, AudioReadAhead: %2 msec")
403 av_packet_free(&pkt);
421 lcd->setAudioFormatLEDs(
AUDIO_AC3,
false);
422 lcd->setVideoFormatLEDs(
VIDEO_MPG,
false);
439 for (
uint i = 0; i <
m_ic->nb_streams; i++)
441 AVStream *st =
m_ic->streams[i];
457 avformat_close_input(&
m_ic);
463static int64_t
lsb3full(int64_t lsb, int64_t base_ts,
int lsb_bits)
465 int64_t mask = (lsb_bits < 64) ? (1LL<<lsb_bits)-1 : -1LL;
466 return ((lsb - base_ts)&mask);
471 int64_t start_pts = 0;
473 AVStream *st =
nullptr;
474 for (
uint i = 0; i <
m_ic->nb_streams; i++)
476 AVStream *st1 =
m_ic->streams[i];
477 if (st1 && st1->codecpar->codec_type == AVMEDIA_TYPE_VIDEO)
486 if (
m_ic->start_time != AV_NOPTS_VALUE)
488 start_pts = av_rescale(
m_ic->start_time,
490 AV_TIME_BASE * (int64_t)st->time_base.num);
493 int64_t
pts = av_rescale(timecode.count() / 1000.0,
504 std::chrono::milliseconds timecode)
506 int64_t start_pts = 0;
508 if (
m_ic->start_time != AV_NOPTS_VALUE)
510 start_pts = av_rescale(
m_ic->start_time,
512 AV_TIME_BASE * (int64_t)st->time_base.num);
515 int64_t
pts = av_rescale(timecode.count() / 1000.0,
528 return m_ic->nb_chapters;
538 for (
int i = 0; i < total; i++)
540 int num =
m_ic->chapters[i]->time_base.num;
541 int den =
m_ic->chapters[i]->time_base.den;
542 int64_t start =
m_ic->chapters[i]->start;
543 long double total_secs = (
long double)start * (
long double)num /
545 times.push_back(std::chrono::seconds((
long long)total_secs));
554 for (
int i = (
m_ic->nb_chapters - 1); i > -1 ; i--)
556 int num =
m_ic->chapters[i]->time_base.num;
557 int den =
m_ic->chapters[i]->time_base.den;
558 int64_t start =
m_ic->chapters[i]->start;
559 long double total_secs = (
long double)start * (
long double)num /
561 auto framenum = (
long long)(total_secs *
m_fps);
562 if (framesPlayed >= framenum)
564 LOG(VB_PLAYBACK, LOG_INFO,
LOC +
565 QString(
"GetCurrentChapter(selected chapter %1 framenum %2)")
566 .arg(i + 1).arg(framenum));
578 int num =
m_ic->chapters[chapter - 1]->time_base.num;
579 int den =
m_ic->chapters[chapter - 1]->time_base.den;
580 int64_t start =
m_ic->chapters[chapter - 1]->start;
581 long double total_secs = (
long double)start * (
long double)num /
583 auto framenum = (
long long)(total_secs *
m_fps);
584 LOG(VB_PLAYBACK, LOG_INFO,
LOC + QString(
"GetChapter %1: framenum %2")
585 .arg(chapter).arg(framenum));
591 LOG(VB_PLAYBACK, LOG_INFO,
LOC + QString(
"DoRewind(%1, %2 discard frames)")
592 .arg(desiredFrame).arg( discardFrames ?
"do" :
"don't" ));
598 return do_av_seek(desiredFrame, discardFrames, AVSEEK_FLAG_BACKWARD);
603 LOG(VB_PLAYBACK, LOG_INFO,
LOC +
604 QString(
"DoFastForward(%1 (%2), %3 discard frames)")
606 .arg((discardFrames) ?
"do" :
"don't"));
614 if (seekDelta >= 0 && seekDelta < 2 && m_parent->GetPlaySpeed() == 0.0F)
620 return do_av_seek(desiredFrame, discardFrames, 0);
626 if (
m_ic->start_time != AV_NOPTS_VALUE)
627 ts =
m_ic->start_time;
630 long double seekts = desiredFrame * AV_TIME_BASE /
m_fps;
631 ts += (
long long)seekts;
638 flags |= AVSEEK_FLAG_BACKWARD;
641 int ret = av_seek_frame(
m_ic, -1, ts, flags);
644 LOG(VB_GENERAL, LOG_ERR,
LOC +
645 QString(
"av_seek_frame(m_ic, -1, %1, 0b%2) error: %3").arg(
647 QString::number(flags, 2),
654 reader->SeekFrame(ts, flags);
656 int normalframes = 0;
674 bool doflush,
bool discardFrames)
679 LOG(VB_PLAYBACK, LOG_INFO,
LOC +
680 QString(
"SeekReset(%1, %2, %3 flush, %4 discard)")
681 .arg(newKey).arg(skipFrames)
682 .arg((doflush) ?
"do" :
"don't",
683 (discardFrames) ?
"do" :
"don't"));
703 avformat_flush(
m_ic);
710 m_ic->pb->buf_ptr =
m_ic->pb->buffer;
711 m_ic->pb->buf_end =
m_ic->pb->buffer;
712 m_ic->pb->eof_reached = 0;
716 LOG(VB_PLAYBACK, LOG_INFO,
LOC +
"SeekReset() flushing");
717 for (
uint i = 0; i <
m_ic->nb_streams; i++)
723 if (codecContext && codecContext->internal)
724 avcodec_flush_buffers(codecContext);
731 av_packet_free(&pkt);
753 static constexpr std::chrono::milliseconds maxSeekTimeMs { 200ms };
754 int profileFrames = 0;
756 for (; (skipFrames > 0 && !
m_atEof &&
757 (exactSeeks || begin.
elapsed() < maxSeekTimeMs));
758 --skipFrames, ++profileFrames)
762 QElapsedTimer getframetimer;
763 getframetimer.start();
765 while (retry && !getframetimer.hasExpired(100))
770 std::this_thread::sleep_for(1ms);
778 if (!exactSeeks && profileFrames >= 5 && profileFrames < 10)
780 const int giveUpPredictionMs = 400;
781 int remainingTimeMs =
782 skipFrames * (float)begin.
elapsed().count() / profileFrames;
783 if (remainingTimeMs > giveUpPredictionMs)
785 LOG(VB_PLAYBACK, LOG_DEBUG,
786 QString(
"Frame-by-frame seeking would take "
787 "%1 ms to finish, skipping.").arg(remainingTimeMs));
804 LOG(VB_GENERAL, LOG_NOTICE,
LOC +
805 QString(
"Resetting byte context eof (livetv %1 was eof %2)")
807 m_ic->pb->eof_reached = 0;
815 LOG(VB_PLAYBACK, LOG_INFO,
LOC +
816 QString(
"Reset: Video %1, Seek %2, File %3")
817 .arg(reset_video_data).arg(seek_reset).arg(reset_file));
824 if (reset_video_data)
834 memset(&probe, 0,
sizeof(AVProbeData));
836 QByteArray fname =
filename.toLatin1();
837 probe.filename = fname.constData();
838 probe.buf = (
unsigned char *)testbuf.data();
839 probe.buf_size = testbuf.size();
841 int score = AVPROBE_SCORE_MAX/4;
853 memset(probe.buf + probe.buf_size, 0, AVPROBE_PADDING_SIZE);
855 return av_probe_input_format2(&probe,
static_cast<int>(
true), &score) !=
nullptr;
862 int cnt = decoder->
m_ic->nb_streams;
864 LOG(VB_PLAYBACK, LOG_INFO,
LOC +
865 QString(
"streams_changed 0x%1 -- program_number %2 stream count %3")
866 .arg((uint64_t)data,0,16).arg(QString::number(avprogram_id), QString::number(cnt)));
868 auto* program = decoder->get_current_AVProgram();
869 if (program !=
nullptr && program->id != avprogram_id)
873 decoder->m_streamsChanged =
true;
910 const AVInputFormat *fmt =
nullptr;
912 QByteArray fnamea = fnames.toLatin1();
913 const char *
filename = fnamea.constData();
916 memset(&probe, 0,
sizeof(AVProbeData));
918 probe.buf =
reinterpret_cast<unsigned char *
>(testbuf.data());
920 probe.buf_size = testbuf.size();
923 memset(probe.buf + probe.buf_size, 0, AVPROBE_PADDING_SIZE);
925 fmt = av_probe_input_format(&probe,
static_cast<int>(
true));
928 LOG(VB_GENERAL, LOG_ERR,
LOC + QString(
"Probe failed for '%1'").arg(
filename));
933 bool scancomplete =
false;
934 int remainingscans = 5;
936 while (!scancomplete && remainingscans--)
950 while (!found && --retries)
952 m_ic = avformat_alloc_context();
955 LOG(VB_GENERAL, LOG_ERR,
LOC +
"Could not allocate format context.");
962 LOG(VB_PLAYBACK, LOG_INFO,
LOC +
963 QString(
"Buffer size: %1 Streamed %2 Seekable %3 Available %4")
966 .arg(
m_ic->pb->seekable)
970 err = avformat_open_input(&
m_ic,
filename, fmt,
nullptr);
974 LOG(VB_PLAYBACK, LOG_INFO,
LOC + QString(
"Failed to open input ('%1')")
982 std::this_thread::sleep_for(100ms);
993 LOG(VB_GENERAL, LOG_ERR,
LOC +
"Fatal error opening input. Aborting");
1005 m_ic->max_analyze_duration = 60LL * AV_TIME_BASE;
1009 err = avformat_find_stream_info(
m_ic,
nullptr);
1013 LOG(VB_GENERAL, LOG_ERR,
LOC + QString(
"Could not find codec parameters for '%1'").arg(
filename));
1020 scancomplete =
true;
1025 scancomplete =
false;
1029 LOG(VB_PLAYBACK, LOG_INFO,
LOC +
"Stream scan incomplete - retrying");
1030 std::this_thread::sleep_for(250ms);
1038 LOG(VB_GENERAL, LOG_WARNING,
LOC +
"Scan incomplete - playback may not work");
1041 m_ic->stream_change_data =
this;
1053 QString extension = QFileInfo(fnames).suffix();
1054 if (strcmp(fmt->name,
"mp3") == 0 || strcmp(fmt->name,
"flac") == 0 ||
1055 strcmp(fmt->name,
"ogg") == 0 ||
1056 (extension.compare(
"m4a", Qt::CaseInsensitive) == 0))
1071 int initialAudio = -1;
1072 int initialVideo = -1;
1073 if (
m_itv ==
nullptr)
1075 if (
m_itv !=
nullptr)
1076 m_itv->GetInitialStreams(initialAudio, initialVideo);
1077 if (initialAudio >= 0)
1079 if (initialVideo >= 0)
1100 std::chrono::seconds dur = 0s;
1109 dur = duration_cast<std::chrono::seconds>(av_duration(
m_ic->duration));
1120 LOG(VB_PLAYBACK, LOG_INFO,
LOC +
1121 "Recording has no position -- using libavformat seeking.");
1130 float bytespersec = (float)
m_bitrate / 8 / 2;
1133 (int)(secs *
static_cast<float>(
m_fps)));
1142 if (strcmp(fmt->name,
"avi") == 0)
1155 LOG(VB_PLAYBACK, LOG_INFO,
LOC +
"Position map found");
1157 LOG(VB_PLAYBACK, LOG_INFO,
LOC +
"Partial position map found");
1158 LOG(VB_PLAYBACK, LOG_INFO,
LOC +
1159 QString(
"Successfully opened decoder for file: \"%1\". novideo(%2)")
1163 for (
unsigned int i=0; i <
m_ic->nb_chapters; i++)
1165 int num =
m_ic->chapters[i]->time_base.num;
1166 int den =
m_ic->chapters[i]->time_base.den;
1167 int64_t start =
m_ic->chapters[i]->start;
1168 auto total_secs =
static_cast<long double>(start) *
static_cast<long double>(num) /
1169 static_cast<long double>(den);
1171 auto framenum =
static_cast<long long>(total_secs *
static_cast<long double>(
m_fps));
1172 LOG(VB_PLAYBACK, LOG_INFO,
LOC +
1173 QString(
"Chapter %1 found @ [%2]->%3")
1176 QString::number(framenum)));
1189 Reset(
true,
true,
true);
1203 double avg_fps = (Stream->avg_frame_rate.den == 0) ? 0.0 : av_q2d(Stream->avg_frame_rate);
1204 double codec_fps = av_q2d(Context->framerate);
1205 double container_fps = (Stream->time_base.num == 0) ? 0.0 : av_q2d(av_inv_q(Stream->time_base));
1207 double estimated_fps = (Stream->r_frame_rate.den == 0) ? 0.0 : av_q2d(Stream->r_frame_rate);
1211 static const std::vector<double> k_standard_rates =
1231 std::vector<double> rates;
1236 if (QString(
m_ic->iformat->name).contains(
"matroska") ||
1237 QString(
m_ic->iformat->name).contains(
"mov"))
1239 rates.emplace_back(avg_fps);
1243 if (QString(
m_ic->iformat->name).contains(
"avi"))
1245 rates.emplace_back(container_fps);
1248 rates.emplace_back(codec_fps);
1249 rates.emplace_back(container_fps);
1250 rates.emplace_back(avg_fps);
1252 rates.emplace_back(estimated_fps);
1254 rates.emplace_back(30000.0 / 1001.0);
1256 auto invalid_fps = [](
double rate) {
return rate < 3.0 || rate > 121.0; };
1257 auto [first, last] = std::ranges::remove_if(rates, invalid_fps);
1258 rates.erase(first, last);
1260 auto FuzzyEquals = [](
double First,
double Second) {
return std::abs(First - Second) < 0.03; };
1263 if (!FuzzyEquals(rates.front(),
m_fps))
1265 LOG(VB_PLAYBACK, LOG_INFO,
LOC +
1266 QString(
"Selected FPS: %1 (Avg:%2 Mult:%3 Codec:%4 Container:%5 Estimated:%6)")
1267 .arg(
static_cast<double>(rates.front())).arg(avg_fps)
1268 .arg(
m_fpsMultiplier).arg(codec_fps).arg(container_fps).arg(estimated_fps));
1270 LOG(VB_GENERAL, LOG_INFO,
LOC +
1271 QString(
"Sanitise:%1").arg(Sanitise) +
1272 QString(
" avg_fps:%1").arg(avg_fps) +
1273 QString(
" codec_fps:%1").arg(codec_fps) +
1274 QString(
" container_fps:%1").arg(container_fps) +
1275 QString(
" estimated_fps:%1").arg(estimated_fps) +
1276 QString(
" m_fps:%1").arg(
m_fps));
1279 for (
auto rate : rates)
1280 rs.append(QString::number(rate));
1281 LOG(VB_GENERAL, LOG_INFO,
LOC +
1282 QString(
"Frame rates:%1").arg(rs.join(
' ')));
1285 auto IsStandard = [&FuzzyEquals](
double Rate)
1287 if (Rate > 23.0 && Rate < 121.0)
1289 for (
auto standard_rate : k_standard_rates)
1290 if (FuzzyEquals(Rate, standard_rate))
1298 auto NearestStandardFrameRate = [](
double rate,
double epsilon)
1300 double result = rate;
1301 double lowest_delta = rate;
1302 for (
auto standard_rate : k_standard_rates)
1304 double delta = std::abs(rate - standard_rate);
1305 if ((delta < lowest_delta) && (delta <
epsilon))
1307 lowest_delta = delta;
1308 result = standard_rate;
1315 double detected = rates.front();
1320 double nearest = NearestStandardFrameRate(detected, 3.0);
1321 LOG(VB_GENERAL, LOG_INFO,
LOC +
1322 QString(
"Frame rate %1 rounded to nearest standard rate %2")
1323 .arg(detected, 0,
'f', 2).arg(nearest, 0,
'f', 2));
1327 if (Sanitise && !IsStandard(detected))
1329 for (
auto rate : rates)
1331 if (IsStandard(rate))
1333 LOG(VB_GENERAL, LOG_INFO,
LOC + QString(
"%1 is non-standard - using %2 instead.")
1334 .arg(rates.front()).arg(rate));
1342 if (rate > 33.0 && detected < 33.0)
1344 double half = rate / 2.0;
1345 if (std::abs(half - detected) < (half * 0.1))
1347 LOG(VB_GENERAL, LOG_INFO,
LOC +
1348 QString(
"Assuming %1 is a better choice than %2")
1349 .arg(half).arg(rate));
1350 return static_cast<float>(half);
1353 return static_cast<float>(rate);
1358 return static_cast<float>(detected);
1363 switch (Context->codec_id)
1365 case AV_CODEC_ID_H264:
1368 if (Context->extradata && (Context->extradata_size >= 7))
1371 if (Context->extradata[0] == 1)
1382 parser.parse_SPS(Context->extradata + offset,
1383 static_cast<uint>(Context->extradata_size - offset), dummy, result);
1388 case AV_CODEC_ID_H265:
return 16;
1389 case AV_CODEC_ID_VP9:
return 8;
1390 case AV_CODEC_ID_VP8:
return 3;
1396 bool selectedStream)
1398 LOG(VB_PLAYBACK, LOG_INFO,
LOC +
1399 QString(
"InitVideoCodec ID:%1 Type:%2 Size:%3x%4")
1400 .arg(avcodec_get_name(codecContext->codec_id),
1402 .arg(codecContext->width).arg(codecContext->height));
1407 codecContext->opaque =
static_cast<void*
>(
this);
1409 codecContext->slice_flags = 0;
1411 codecContext->err_recognition = AV_EF_COMPLIANT;
1412 codecContext->workaround_bugs = FF_BUG_AUTODETECT;
1413 codecContext->error_concealment = FF_EC_GUESS_MVS | FF_EC_DEBLOCK;
1414 codecContext->idct_algo = FF_IDCT_AUTO;
1415 codecContext->debug = 0;
1418 const AVCodec *codec1 = codecContext->codec;
1424 const AVPacketSideData *sd = av_packet_side_data_get(stream->codecpar->coded_side_data,
1425 stream->codecpar->nb_coded_side_data, AV_PKT_DATA_DISPLAYMATRIX);
1427 m_videoRotation =
static_cast<int>(-av_display_rotation_get(
reinterpret_cast<int32_t*
>(sd->data)));
1432 sd = av_packet_side_data_get(stream->codecpar->coded_side_data,
1433 stream->codecpar->nb_coded_side_data, AV_PKT_DATA_STEREO3D);
1436 auto * avstereo =
reinterpret_cast<AVStereo3D*
>(sd->data);
1461 bool doublerate =
true;
1465 if (codec1 && ((AV_CODEC_ID_MPEG2VIDEO == codec1->id) ||
1466 (AV_CODEC_ID_MPEG1VIDEO == codec1->id)))
1470 int total_blocks = (codecContext->height + 15) / 16;
1471 codecContext->skip_top = (total_blocks + 3) / 4;
1472 codecContext->skip_bottom = (total_blocks + 3) / 4;
1476 codecContext->lowres = 2;
1480 codecContext->flags &= ~AV_CODEC_FLAG_LOOP_FILTER;
1481 codecContext->skip_loop_filter = AVDISCARD_ALL;
1485 codecContext->skip_idct = AVDISCARD_ALL;
1497 if (!width || !height)
1499 LOG(VB_PLAYBACK, LOG_INFO,
LOC +
1500 "InitVideoCodec invalid dimensions, resetting decoder.");
1508 const AVCodec *codec2 = codecContext->codec;
1511 codecName = codec2->name;
1519 switch (codecContext->codec_id)
1521 case AV_CODEC_ID_H263:
1522 case AV_CODEC_ID_MPEG4:
1523 case AV_CODEC_ID_MSMPEG4V1:
1524 case AV_CODEC_ID_MSMPEG4V2:
1525 case AV_CODEC_ID_MSMPEG4V3:
1526 case AV_CODEC_ID_H263P:
1527 case AV_CODEC_ID_H263I:
1530 case AV_CODEC_ID_WMV1:
1531 case AV_CODEC_ID_WMV2:
1535 case AV_CODEC_ID_XVID:
1544 lcd->setVideoFormatLEDs(video_format,
true);
1556 static constexpr std::array<uint8_t, 256> odd_parity_LUT
1558 0, 1, 1, 0, 1, 0, 0, 1, 1, 0, 0, 1, 0, 1, 1, 0,
1559 1, 0, 0, 1, 0, 1, 1, 0, 0, 1, 1, 0, 1, 0, 0, 1,
1560 1, 0, 0, 1, 0, 1, 1, 0, 0, 1, 1, 0, 1, 0, 0, 1,
1561 0, 1, 1, 0, 1, 0, 0, 1, 1, 0, 0, 1, 0, 1, 1, 0,
1562 1, 0, 0, 1, 0, 1, 1, 0, 0, 1, 1, 0, 1, 0, 0, 1,
1563 0, 1, 1, 0, 1, 0, 0, 1, 1, 0, 0, 1, 0, 1, 1, 0,
1564 0, 1, 1, 0, 1, 0, 0, 1, 1, 0, 0, 1, 0, 1, 1, 0,
1565 1, 0, 0, 1, 0, 1, 1, 0, 0, 1, 1, 0, 1, 0, 0, 1,
1566 1, 0, 0, 1, 0, 1, 1, 0, 0, 1, 1, 0, 1, 0, 0, 1,
1567 0, 1, 1, 0, 1, 0, 0, 1, 1, 0, 0, 1, 0, 1, 1, 0,
1568 0, 1, 1, 0, 1, 0, 0, 1, 1, 0, 0, 1, 0, 1, 1, 0,
1569 1, 0, 0, 1, 0, 1, 1, 0, 0, 1, 1, 0, 1, 0, 0, 1,
1570 0, 1, 1, 0, 1, 0, 0, 1, 1, 0, 0, 1, 0, 1, 1, 0,
1571 1, 0, 0, 1, 0, 1, 1, 0, 0, 1, 1, 0, 1, 0, 0, 1,
1572 1, 0, 0, 1, 0, 1, 1, 0, 0, 1, 1, 0, 1, 0, 0, 1,
1573 0, 1, 1, 0, 1, 0, 0, 1, 1, 0, 0, 1, 0, 1, 1, 0,
1575 bool ret = (odd_parity_LUT[data & 0xff] == 1) &&
1576 (odd_parity_LUT[(data & 0xff00) >> 8] == 1);
1579 LOG(VB_VBI, LOG_ERR,
LOC +
1580 QString(
"VBI: Bad parity in EIA-608 data (%1)") .arg(data,0,16));
1587 if (program ==
nullptr)
1591 return program->pmt_section;
1596 AVProgram* program = av_find_program_from_stream(context,
nullptr, stream_index);
1610 if (!pmt_buffer.has_buffer())
1612 LOG(VB_GENERAL, LOG_DEBUG,
LOC +
1613 "ScanATSCCaptionStreams() called with no PMT");
1618 bool video_found =
false;
1642 desc_list.insert(desc_list.end(), desc_list2.begin(), desc_list2.end());
1644 for (
auto & desc : desc_list)
1686 std::array<std::map<int,uint>,2> lang_cc_cnt;
1703 else if (!pofr && sofr)
1729 LOG(VB_GENERAL, LOG_ERR,
LOC +
"in_tracks key too small");
1735 LOG(VB_PLAYBACK, LOG_INFO,
LOC +
1736 QString(
"%1 caption service #%2 is in the %3 language.")
1737 .arg((
type) ?
"EIA-708" :
"EIA-608")
1753 AVStream* st =
m_ic->streams[av_index];
1754 const AVDictionaryEntry* language_dictionary_entry =
1755 av_dict_get(st->metadata,
"language",
nullptr, 0);
1757 if (language_dictionary_entry ==
nullptr ||
1758 language_dictionary_entry->value ==
nullptr ||
1759 st->codecpar->extradata ==
nullptr
1765 std::vector<std::string_view> languages {
StringUtil::split_sv(language_dictionary_entry->value,
","sv)};
1767 if (st->codecpar->extradata_size !=
static_cast<int>(languages.size() * 2))
1771 for (
size_t i = 0; i < languages.size(); i++)
1773 if (languages[i].size() != 3)
1779 uint8_t teletext_type = st->codecpar->extradata[i * 2] >> 3;
1780 uint8_t teletext_magazine_number = st->codecpar->extradata[i * 2] & 0x7;
1781 if (teletext_magazine_number == 0)
1782 teletext_magazine_number = 8;
1783 uint8_t teletext_page_number = st->codecpar->extradata[(i * 2) + 1];
1784 if (teletext_type == 2 || teletext_type == 1)
1786 TrackType track = (teletext_type == 2) ?
1789 m_tracks[track].emplace_back(av_index, 0, language,
1790 (
static_cast<unsigned>(teletext_magazine_number) << 8) | teletext_page_number);
1791 LOG(VB_PLAYBACK, LOG_INFO,
LOC +
1792 QString(
"Teletext stream #%1 (%2) is in the %3 language on page %4 %5.")
1793 .arg(QString::number(i),
1794 (teletext_type == 2) ?
"Caption" :
"Menu",
1796 QString::number(teletext_magazine_number),
1797 QString::number(teletext_page_number)));
1806 AVDictionaryEntry *metatag =
1807 av_dict_get(
m_ic->streams[av_stream_index]->metadata,
"language",
nullptr,
1809 bool forced = (
m_ic->streams[av_stream_index]->disposition & AV_DISPOSITION_FORCED) != 0;
1812 LOG(VB_PLAYBACK, LOG_INFO,
LOC +
1813 QString(
"Text Subtitle track #%1 is A/V stream #%2 "
1814 "and is in the %3 language(%4), forced=%5.")
1817 StreamInfo si {av_stream_index, 0, lang, 0, forced};
1827 if (
m_itv ==
nullptr)
1829 if (
m_itv ==
nullptr)
1833 if (!pmt_buffer.has_buffer())
1844 LOG(VB_DSMCC, LOG_NOTICE, QString(
"ScanDSMCCStreams Found Object Carousel in Stream %1").arg(QString::number(i)));
1850 for (
const auto *desc : desc_list)
1853 uint length = *desc++;
1854 const unsigned char *endDesc = desc+length;
1855 uint dataBroadcastId = desc[0]<<8 | desc[1];
1856 LOG(VB_DSMCC, LOG_NOTICE, QString(
"ScanDSMCCStreams dataBroadcastId %1").arg(QString::number(dataBroadcastId)));
1857 if (dataBroadcastId != 0x0106)
1860 while (desc != endDesc)
1862 [[maybe_unused]]
uint appTypeCode = desc[0]<<8 | desc[1];
1864 uint appSpecDataLen = *desc++;
1866 LOG(VB_DSMCC, LOG_NOTICE, QString(
"ScanDSMCCStreams AppTypeCode %1").arg(QString::number(appTypeCode)));
1867 if (appTypeCode == 0x101)
1869 const unsigned char *subDescEnd = desc + appSpecDataLen;
1870 while (desc < subDescEnd)
1872 uint sub_desc_tag = *desc++;
1873 uint sub_desc_len = *desc++;
1875 if (sub_desc_tag == 1)
1876 m_itv->SetNetBootInfo(desc, sub_desc_len);
1877 desc += sub_desc_len;
1883 desc += appSpecDataLen;
1897 const AVCodec *codec =
nullptr;
1898 LOG(VB_PLAYBACK, LOG_INFO,
LOC +
"Trying to select best video track");
1912 int stream_index = av_find_best_stream(
m_ic, AVMEDIA_TYPE_VIDEO, -1, -1, &codec, 0);
1914 if (stream_index < 0)
1916 LOG(VB_PLAYBACK, LOG_INFO,
LOC +
"No video track found/selected.");
1917 return stream_index;
1920 AVStream *stream =
m_ic->streams[stream_index];
1931 if (codecContext->codec_type == AVMEDIA_TYPE_VIDEO)
1932 codectype += QString(
"(%1x%2)").arg(codecContext->width).arg(codecContext->height);
1933 LOG(VB_PLAYBACK, LOG_INFO,
LOC +
1934 QString(
"Selected track #%1: ID: 0x%2 Codec ID: %3 Profile: %4 Type: %5 Bitrate: %6")
1935 .arg(stream_index).arg(
static_cast<uint64_t
>(stream->id), 0, 16)
1936 .arg(avcodec_get_name(codecContext->codec_id),
1937 avcodec_profile_name(codecContext->codec_id, codecContext->profile),
1939 QString::number(codecContext->bit_rate)));
1946 if ((codecContext->width != stream->codecpar->width) || (codecContext->height != stream->codecpar->height))
1948 LOG(VB_GENERAL, LOG_INFO,
LOC + QString(
1949 "Video resolution mismatch: Context: %1x%2 Stream: %3x%4 Codec: %5 Stream change: %6")
1950 .arg(codecContext->width).arg(codecContext->height)
1951 .arg(stream->codecpar->width).arg(stream->codecpar->height)
1958 int width = std::max(dim.width(), 16);
1959 int height = std::max(dim.height(), 16);
1960 QString dec =
"ffmpeg";
1961 uint thread_count = 1;
1963 if (codecContext->codec)
1964 codecName = codecContext->codec->name;
1969 if (codecContext->framerate.den && codecContext->framerate.num)
1970 m_fps = float(codecContext->framerate.num) / float(codecContext->framerate.den);
1974 bool foundgpudecoder =
false;
1975 QStringList unavailabledecoders;
1985 LOG(VB_GENERAL, LOG_WARNING,
LOC + QString(
1986 "GPU/hardware decoder '%1' failed - forcing software decode")
1993 while (unavailabledecoders.size() < 10)
1997 if (!unavailabledecoders.isEmpty())
1999 LOG(VB_PLAYBACK, LOG_INFO,
LOC + QString(
"Unavailable decoders: %1")
2000 .arg(unavailabledecoders.join(
",")));
2006 if (!skip_loop_filter)
2007 codecContext->skip_loop_filter = AVDISCARD_NONKEY;
2015 if (
version && allowgpu && dec !=
"ffmpeg")
2019 codecContext->opaque =
static_cast<void*
>(
this);
2024 codecContext->opaque =
static_cast<void*
>(
this);
2026 foundgpudecoder =
true;
2031 unavailabledecoders.append(dec);
2039 LOG(VB_GENERAL, LOG_ERR,
LOC +
"Unknown video codec - defaulting to MPEG2");
2054 if (!foundgpudecoder)
2056 LOG(VB_PLAYBACK, LOG_INFO,
LOC + QString(
"Using %1 CPUs for decoding")
2057 .arg(thread_count));
2058 codecContext->thread_count =
static_cast<int>(thread_count);
2072 return stream_index;
2077 AVProgram* program = av_find_program_from_stream(
m_ic,
nullptr, stream_index);
2078 if (program ==
nullptr)
2083 LOG(VB_PLAYBACK, LOG_INFO,
2084 QString(
"Removing streams not in Program %1 from track selection.")
2085 .arg(QString::number(program->id)));
2087 const auto *
const begin = program->stream_index;
2088 const auto *
const end = program->stream_index + program->nb_stream_indexes;
2092 LOG(VB_PLAYBACK, LOG_DEBUG,
2093 QString(
"Size before: %1").arg(QString::number(track_list.size())));
2094 auto [first, last] = std::ranges::remove_if(track_list,
2099 track_list.erase(first, last);
2100 LOG(VB_PLAYBACK, LOG_DEBUG,
2101 QString(
"Size after: %1").arg(QString::number(track_list.size())));
2107 return (ch_layout.order == AV_CHANNEL_ORDER_CUSTOM) &&
2108 (ch_layout.nb_channels == 2) &&
2109 (ch_layout.u.map[0].id == AV_CHAN_FRONT_CENTER) &&
2110 (ch_layout.u.map[1].id == AV_CHAN_FRONT_CENTER);
2118 bool unknownbitrate =
false;
2122 constexpr std::array<TrackType, 6>
types {
2136 std::map<int,uint> lang_sub_cnt;
2137 uint subtitleStreamCount = 0;
2138 std::map<int,uint> lang_aud_cnt;
2139 uint audioStreamCount = 0;
2148 if (
m_ic ==
nullptr)
2151 for (
uint strm = 0; strm <
m_ic->nb_streams; strm++)
2153 AVCodecParameters *par =
m_ic->streams[strm]->codecpar;
2156 if (par->codec_type == AVMEDIA_TYPE_VIDEO)
2157 codectype += QString(
"(%1x%2)").arg(par->width).arg(par->height);
2158 QString program_id =
"null";
2159 if (av_find_program_from_stream(
m_ic,
nullptr, strm) !=
nullptr)
2161 program_id = QString::number(av_find_program_from_stream(
m_ic,
nullptr, strm)->
id);
2163 LOG(VB_PLAYBACK, LOG_INFO,
LOC +
2164 QString(
"Stream #%1: ID: 0x%2 Program ID: %3 Codec ID: %4 Type: %5 Bitrate: %6").arg(
2165 QString::number(strm),
2166 QString::number(
static_cast<uint64_t
>(
m_ic->streams[strm]->id), 16),
2168 avcodec_get_name(par->codec_id),
2170 QString::number(par->bit_rate))
2173 switch (par->codec_type)
2175 case AVMEDIA_TYPE_VIDEO:
2183 if (ctx && (ctx->hw_frames_ctx || ctx->hw_device_ctx))
2190 LOG(VB_GENERAL, LOG_ERR,
LOC +
2191 QString(
"Stream #%1 has an unknown video "
2192 "codec id, skipping.").arg(strm));
2204 if (par->bit_rate == 0)
2206 static constexpr int64_t s_baseBitrate { 1000000LL };
2208 if (par->width && par->height)
2210 static const int s_baseSize = 1920 * 1080;
2211 multiplier = ((par->width * par->height) + s_baseSize - 1) / s_baseSize;
2212 multiplier = std::max(multiplier, 1);
2214 par->bit_rate = s_baseBitrate * multiplier;
2215 unknownbitrate =
true;
2221 case AVMEDIA_TYPE_AUDIO:
2223 LOG(VB_GENERAL, LOG_INFO,
LOC +
2224 QString(
"codec %1 has %2 channels")
2225 .arg(avcodec_get_name(par->codec_id))
2226 .arg(par->ch_layout.nb_channels));
2231 case AVMEDIA_TYPE_SUBTITLE:
2233 if (par->codec_id == AV_CODEC_ID_DVB_TELETEXT)
2235 if (par->codec_id == AV_CODEC_ID_TEXT)
2239 LOG(VB_PLAYBACK, LOG_INFO,
LOC + QString(
"subtitle codec (%1)")
2243 case AVMEDIA_TYPE_DATA:
2245 if (par->codec_id == AV_CODEC_ID_DVB_VBI)
2248 LOG(VB_PLAYBACK, LOG_INFO,
LOC + QString(
"data codec (%1)")
2252 case AVMEDIA_TYPE_ATTACHMENT:
2254 if (par->codec_id == AV_CODEC_ID_TTF)
2257 LOG(VB_PLAYBACK, LOG_INFO,
LOC +
2258 QString(
"Attachment codec (%1)")
2265 LOG(VB_PLAYBACK, LOG_ERR,
LOC +
2266 QString(
"Unknown codec type (%1)")
2272 if (par->codec_type != AVMEDIA_TYPE_AUDIO &&
2273 par->codec_type != AVMEDIA_TYPE_SUBTITLE)
2277 if (par->codec_type == AVMEDIA_TYPE_SUBTITLE &&
2278 (par->codec_id == AV_CODEC_ID_DVB_TELETEXT ||
2279 par->codec_id == AV_CODEC_ID_TEXT))
2282 LOG(VB_PLAYBACK, LOG_INFO,
LOC + QString(
"Looking for decoder for %1")
2283 .arg(avcodec_get_name(par->codec_id)));
2285 if (par->codec_id == AV_CODEC_ID_PROBE)
2287 LOG(VB_GENERAL, LOG_ERR,
LOC +
2288 QString(
"Probing of stream #%1 unsuccesful, ignoring.").arg(strm));
2294 if (codecContext ==
nullptr)
2296 LOG(VB_GENERAL, LOG_WARNING,
LOC +
2297 QString(
"Could not find decoder for codec (%1), ignoring.")
2298 .arg(avcodec_get_name(par->codec_id)));
2299 LOG(VB_LIBAV, LOG_INFO,
"For a list of all codecs, run `mythffmpeg -codecs`.");
2303 if (codecContext->codec && par->codec_id != codecContext->codec_id)
2305 LOG(VB_PLAYBACK, LOG_INFO,
LOC +
2306 QString(
"Already opened codec not matching (%1 vs %2). Reopening")
2307 .arg(avcodec_get_name(codecContext->codec_id),
2308 avcodec_get_name(codecContext->codec->id)));
2312 if (!
OpenAVCodec(codecContext, codecContext->codec))
2324 LOG(VB_PLAYBACK, LOG_INFO,
LOC +
2325 QString(
"Stream 0x%1 is not valid in this context - skipping")
2326 .arg(
m_ic->streams[strm]->id, 4, 16));
2330 if (par->codec_type == AVMEDIA_TYPE_SUBTITLE)
2332 bool forced = (
m_ic->streams[strm]->disposition & AV_DISPOSITION_FORCED) != 0;
2334 uint lang_indx = lang_sub_cnt[lang]++;
2335 subtitleStreamCount++;
2338 static_cast<int>(strm),
m_ic->streams[strm]->id, lang, lang_indx, forced);
2340 LOG(VB_PLAYBACK, LOG_INFO,
LOC +
2341 QString(
"Subtitle track #%1 is A/V stream #%2 "
2342 "and is in the %3 language(%4).")
2347 if (par->codec_type == AVMEDIA_TYPE_AUDIO)
2351 uint lang_indx = lang_aud_cnt[lang]++;
2354 int stream_id =
m_ic->streams[strm]->id;
2358 if (stream_id == -1)
2366 static_cast<int>(strm), stream_id, lang, lang_indx,
type);
2370 lang_indx = lang_aud_cnt[lang]++;
2372 static_cast<int>(strm), stream_id, lang, lang_indx,
type);
2375 LOG(VB_AUDIO, LOG_INFO,
LOC +
2376 QString(
"Audio Track #%1, of type (%2) is A/V stream #%3 (id=0x%4) "
2377 "and has %5 channels in the %6 language(%7).")
2379 .arg(strm).arg(
m_ic->streams[strm]->id,0,16).arg(codecContext->ch_layout.nb_channels)
2405 QString(
m_ic->iformat->name).contains(
"matroska"));
2447 for (
unsigned i = 0; i <
m_ic->nb_programs; i++)
2459#if CONFIG_MEDIACODEC
2460 if (QString(
"mediacodec") == codec->wrapper_name)
2461 av_jni_set_java_vm(QAndroidJniEnvironment::javaVM(),
nullptr);
2463 int ret = avcodec_open2(avctx, codec,
nullptr);
2468 LOG(VB_GENERAL, LOG_ERR,
LOC +
2469 QString(
"Could not open codec 0x%1, id(%2) type(%3) "
2470 "ignoring. reason %4").arg((uint64_t)avctx,0,16)
2471 .arg(avcodec_get_name(avctx->codec_id),
2477 LOG(VB_GENERAL, LOG_INFO,
LOC +
2478 QString(
"Opened codec 0x%1, id(%2) type(%3)")
2479 .arg((uint64_t)avctx,0,16)
2480 .arg(avcodec_get_name(avctx->codec_id),
2505 if (si.m_language_index == Index)
2506 return si.m_language;
2513 AVDictionaryEntry *metatag = av_dict_get(
m_ic->streams[StreamIndex]->metadata,
"language",
nullptr, 0);
2556 AVStream *stream =
m_ic->streams[StreamIndex];
2560 if (stream->disposition & AV_DISPOSITION_VISUAL_IMPAIRED)
2562 else if (stream->disposition & AV_DISPOSITION_COMMENT)
2564 else if (stream->disposition & AV_DISPOSITION_HEARING_IMPAIRED)
2566 else if (stream->disposition & AV_DISPOSITION_CLEAN_EFFECTS)
2593 if (
current->m_av_stream_index == streamIndex)
2599 LOG(VB_GENERAL, LOG_WARNING,
LOC +
2600 QString(
"Invalid stream index passed to "
2601 "SetupAudioStreamSubIndexes: %1").arg(streamIndex));
2608 if (
current->m_av_substream_index == -1)
2621 (next->m_av_stream_index != streamIndex))
2623 QString msg = QString(
2624 "Expected substream 1 (Language I) of stream %1\n\t\t\t"
2625 "following substream 0, found end of list or another stream.")
2628 LOG(VB_GENERAL, LOG_WARNING,
LOC + msg);
2650 bool do_flush =
false;
2651 for (
uint i = 0; i <
m_ic->nb_streams; i++)
2653 AVStream *st =
m_ic->streams[i];
2656 if (avctx && avctx->codec_type == AVMEDIA_TYPE_AUDIO)
2659 LOG(VB_LIBAV, LOG_DEBUG, QString(
"removing audio stream (id: 0x%1, index: %2, nb_streams: %3)")
2660 .arg(QString::number(st->id, 16),
2662 QString::number(
m_ic->nb_streams)
2666 if ((
m_ic->nb_streams - i) > 0) {
2667 std::memmove(
reinterpret_cast<void*
>(&
m_ic->streams[i]),
2668 reinterpret_cast<const void*
>(&
m_ic->streams[i + 1]),
2669 (
m_ic->nb_streams - i) *
sizeof(AVFormatContext*));
2673 m_ic->streams[i] =
nullptr;
2681 avformat_flush(
m_ic);
2690#ifdef __cpp_lib_ranges_contains
2691 if (!std::ranges::contains(*decoder->m_renderFormats,
type))
2693 if (!std::ranges::any_of(*decoder->m_renderFormats,
2694 [&
type](
auto Format) { return type == Format; }))
2697 decoder->m_directRendering =
false;
2698 return avcodec_default_get_buffer2(c, pic, flags);
2701 decoder->m_directRendering =
true;
2702 MythVideoFrame *frame = decoder->GetPlayer()->GetNextVideoFrame();
2712 if ((frame->
m_type !=
type) || (pic->width > width) || (pic->height > height))
2729 for (
uint i = 0; i < 3; i++)
2735 pic->opaque = frame;
2738 AVBufferRef *buffer = av_buffer_create(
reinterpret_cast<uint8_t*
>(frame), 0,
2739 [](
void* Opaque, uint8_t* Data)
2743 if (avfd && avfd->GetPlayer())
2744 avfd->GetPlayer()->DeLimboFrame(vf);
2747 pic->buf[0] = buffer;
2753int get_avf_buffer_dxva2(
struct AVCodecContext *c,
AVFrame *pic,
int )
2758 for (
int i = 0; i < 4; i++)
2760 pic->data[i] =
nullptr;
2761 pic->linesize[i] = 0;
2763 pic->opaque = frame;
2765 pic->data[0] = (uint8_t*)frame->
m_buffer;
2766 pic->data[3] = (uint8_t*)frame->
m_buffer;
2769 AVBufferRef *buffer =
2770 av_buffer_create((uint8_t*)frame, 0,
2771 [](
void* Opaque, uint8_t* Data)
2779 pic->buf[0] = buffer;
2790 bool had_608 =
false;
2791 bool had_708 =
false;
2792 for (
uint cur = 0; cur + 2 < buf_size; cur += 3)
2794 uint cc_code = buf[cur];
2795 bool cc_valid = (cc_code & 0x04) != 0U;
2797 uint data1 = buf[cur+1];
2798 uint data2 = buf[cur+2];
2799 uint data = (data2 << 8) | data1;
2800 uint cc_type = cc_code & 0x03;
2825 bool check_608,
bool check_708)
2827 bool need_change_608 =
false;
2832 for (
uint i = 0; i < 4; i++)
2839 bool need_change_708 =
false;
2841 if (check_708 || need_change_608)
2844 for (
uint i = 1; i < 64 && !need_change_608 && !need_change_708; i++)
2849 if (need_change_708 && !check_608)
2853 if (!need_change_608 && !need_change_708)
2864 for (
int i = 1; i < 64; i++)
2873 for (
int i = 0; i < 4; i++)
2894 AVPacket *pkt,
bool can_reliably_parse_keyframes)
2899 bool reset_kfd =
false;
2903 LOG(VB_PLAYBACK, LOG_INFO,
LOC +
2904 "gopset not set, syncing positionMap");
2906 if (tempKeyFrameDist > 0 && !
m_livetv)
2908 LOG(VB_PLAYBACK, LOG_INFO,
LOC +
2909 QString(
"Initial key frame distance: %1.")
2915 else if (
m_keyframeDist != tempKeyFrameDist && tempKeyFrameDist > 0)
2917 LOG(VB_PLAYBACK, LOG_INFO,
LOC +
2918 QString(
"Key frame distance changed from %1 to %2.")
2946 if (can_reliably_parse_keyframes &&
2949 long long last_frame = 0;
2957 LOG(VB_PLAYBACK, LOG_DEBUG,
LOC +
2958 QString(
"framesRead: %1 last_frame: %2 keyframedist: %3")
2965 long long startpos = pkt->pos;
2967 LOG(VB_PLAYBACK | VB_TIMESTAMP, LOG_INFO,
LOC +
2968 QString(
"positionMap[ %1 ] == %2.")
3000 float bytespersec = (float)
m_bitrate / 8;
3017 const uint8_t *bufptr = pkt->data;
3018 const uint8_t *bufend = pkt->data + pkt->size;
3020 while (bufptr < bufend)
3024 float aspect_override = -1.0F;
3033 if (bufptr + 11 >= pkt->data + pkt->size)
3035 const auto *seq =
reinterpret_cast<const SequenceHeader*
>(bufptr);
3037 int width =
static_cast<int>(seq->width()) >> context->lowres;
3038 int height =
static_cast<int>(seq->height()) >> context->lowres;
3039 float aspect = seq->
aspect(context->codec_id == AV_CODEC_ID_MPEG1VIDEO);
3040 if (stream->sample_aspect_ratio.num)
3041 aspect =
static_cast<float>(av_q2d(stream->sample_aspect_ratio) * width / height);
3042 if (aspect_override > 0.0F)
3043 aspect = aspect_override;
3044 float seqFPS = seq->fps();
3048 changed |= (seqFPS >
static_cast<float>(
m_fps)+0.01F) ||
3049 (seqFPS < static_cast<float>(
m_fps)-0.01F);
3053 bool forceaspectchange = !qFuzzyCompare(
m_currentAspect + 10.0F, aspect + 10.0F) &&
3057 if (changed || forceaspectchange)
3062 bool doublerate =
false;
3065 forceaspectchange, 2,
3068 if (context->hw_frames_ctx)
3069 if (context->internal)
3070 avcodec_flush_buffers(context);
3084 if ((seqFPS > avFPS+0.01F) || (seqFPS < avFPS-0.01F))
3086 LOG(VB_PLAYBACK, LOG_INFO,
LOC + QString(
"avFPS(%1) != seqFPS(%2)")
3087 .arg(
static_cast<double>(avFPS)).arg(
static_cast<double>(seqFPS)));
3096 pkt->flags |= AV_PKT_FLAG_KEY;
3103 pkt->flags |= AV_PKT_FLAG_KEY;
3111 const uint8_t *buf = pkt->data;
3112 const uint8_t *buf_end = pkt->data + pkt->size;
3117 if (context->extradata && (context->extradata_size >= 7) && (context->extradata[0] == 0x01))
3119 if (pkt->flags & AV_PKT_FLAG_KEY)
3124 while (buf < buf_end)
3155 bool fps_changed = (seqFPS > 0.0) && ((seqFPS >
m_fps + 0.01) ||
3156 (seqFPS <
m_fps - 0.01));
3161 if (fps_changed || res_changed || forcechange)
3166 bool doublerate =
false;
3179 if (context->hw_frames_ctx && (forcechange || res_changed))
3180 if (context->internal)
3181 avcodec_flush_buffers(context);
3187 m_fps =
static_cast<float>(seqFPS);
3197 if ((seqFPS > avFPS + 0.01) || (seqFPS < avFPS - 0.01))
3199 LOG(VB_PLAYBACK, LOG_INFO,
LOC +
3200 QString(
"avFPS(%1) != seqFPS(%2)").arg(avFPS).arg(seqFPS));
3205 pkt->flags |= AV_PKT_FLAG_KEY;
3225 if (pkt->flags & AV_PKT_FLAG_KEY)
3241 !(pkt->flags & AV_PKT_FLAG_KEY))
3243 av_packet_unref(pkt);
3277 bool sentPacket =
false;
3297 if (ret == AVERROR(EAGAIN))
3301 if (ret==0 && !gotpicture)
3303 ret2 = avcodec_send_packet(context, pkt);
3304 if (ret2 == AVERROR(EAGAIN))
3316 if (ret < 0 || ret2 < 0)
3321 LOG(VB_GENERAL, LOG_ERR,
LOC +
3322 QString(
"video avcodec_receive_frame error: %1 (%2) gotpicture:%3")
3324 .arg(ret).arg(gotpicture));
3329 LOG(VB_GENERAL, LOG_ERR,
LOC +
3330 QString(
"video avcodec_send_packet error: %1 (%2) gotpicture:%3")
3332 .arg(ret2).arg(gotpicture));
3346 LOG(VB_GENERAL, LOG_INFO,
LOC +
"Decoder needs reset");
3350 if (ret == AVERROR_EXTERNAL || ret2 == AVERROR_EXTERNAL)
3352 LOG(VB_PLAYBACK, LOG_INFO,
LOC +
"FFmpeg external library error - assuming streams changed");
3364 LOG(VB_PLAYBACK | VB_TIMESTAMP, LOG_INFO,
LOC +
3365 QString(
"video timecodes packet-pts:%1 frame-pts:%2 packet-dts: %3 frame-dts:%4")
3366 .arg(pkt->pts).arg(mpa_pic->pts).arg(pkt->dts)
3367 .arg(mpa_pic->pkt_dts));
3376 auto *newPkt = av_packet_clone(pkt);
3386 auto * side_data = av_frame_get_side_data(AvFrame, AV_FRAME_DATA_A53_CC);
3387 if (side_data && (side_data->size > 0))
3400 frame->m_directRendering =
false;
3411 av_image_fill_arrays(tmppicture.data, tmppicture.linesize,
3412 frame->m_buffer, AV_PIX_FMT_YUV420P, AvFrame->width,
3413 AvFrame->height, IMAGE_ALIGN);
3414 tmppicture.data[0] = frame->m_buffer + frame->m_offsets[0];
3415 tmppicture.data[1] = frame->m_buffer + frame->m_offsets[1];
3416 tmppicture.data[2] = frame->m_buffer + frame->m_offsets[2];
3417 tmppicture.linesize[0] = frame->m_pitches[0];
3418 tmppicture.linesize[1] = frame->m_pitches[1];
3419 tmppicture.linesize[2] = frame->m_pitches[2];
3423 AvFrame->height,
static_cast<AVPixelFormat
>(AvFrame->format),
3424 AvFrame->width, AvFrame->height,
3425 AV_PIX_FMT_YUV420P, SWS_FAST_BILINEAR,
3426 nullptr,
nullptr,
nullptr);
3429 LOG(VB_GENERAL, LOG_ERR,
LOC +
"Failed to allocate sws context");
3432 sws_scale(
m_swsCtx, AvFrame->data, AvFrame->linesize, 0, dim.height(),
3433 tmppicture.data, tmppicture.linesize);
3441 oldframe->
m_interlaced = (AvFrame->flags & AV_FRAME_FLAG_INTERLACED) != 0;
3442 oldframe->
m_topFieldFirst = (AvFrame->flags & AV_FRAME_FLAG_TOP_FIELD_FIRST) != 0;
3468 LOG(VB_GENERAL, LOG_ERR,
LOC +
"NULL videoframe - direct rendering not "
3469 "correctly initialized.");
3474 if (AvFrame->best_effort_timestamp == AV_NOPTS_VALUE)
3476 LOG(VB_GENERAL, LOG_ERR,
LOC +
"No PTS found - unable to process video.");
3480 AvFrame->best_effort_timestamp * 1000);
3481 std::chrono::milliseconds temppts =
pts;
3498 double calcfps = 1000.0 /
ptsdiff.count();
3499 if (calcfps < 121.0 && calcfps > 3.0)
3503 double fpschange = calcfps /
m_fps;
3505 if (fpschange > 1.9 && fpschange < 2.1)
3507 if (fpschange > 0.9 && fpschange < 1.1)
3513 LOG(VB_PLAYBACK | VB_TIMESTAMP, LOG_INFO,
LOC +
3514 QString(
"video timecode %1 %2 %3 %4%5")
3515 .arg(AvFrame->best_effort_timestamp)
3516 .arg(
pts.count()).arg(temppts.count()).arg(
m_lastVPts.count())
3517 .arg((
pts != temppts) ?
" fixup" :
""));
3519 frame->m_interlaced = (AvFrame->flags & AV_FRAME_FLAG_INTERLACED) != 0;
3520 frame->m_topFieldFirst = (AvFrame->flags & AV_FRAME_FLAG_TOP_FIELD_FIRST) != 0;
3522 frame->m_repeatPic = AvFrame->repeat_pict != 0;
3527 frame->m_colorspace = AvFrame->colorspace;
3528 frame->m_colorrange = AvFrame->color_range;
3529 frame->m_colorprimaries = AvFrame->color_primaries;
3530 frame->m_colortransfer = AvFrame->color_trc;
3531 frame->m_chromalocation = AvFrame->chroma_location;
3532 frame->m_pixFmt = AvFrame->format;
3537 frame->m_dummy =
false;
3538 frame->m_pauseFrame =
false;
3539 frame->m_deinterlaceInuse2x =
false;
3540 frame->m_alreadyDeinterlaced =
false;
3541 frame->m_interlacedReverse =
false;
3571 [[maybe_unused]]
const AVStream *stream,
const AVPacket *pkt)
3573 const uint8_t *buf = pkt->data;
3574 uint64_t linemask = 0;
3579 if ((buf[0]==
't') && (buf[1]==
'v') && (buf[2] ==
'0'))
3582 memcpy(&linemask, buf + 3, 8);
3585 else if ((buf[0]==
'T') && (buf[1]==
'V') && (buf[2] ==
'0'))
3587 linemask = 0xffffffffffffffffLL;
3592 LOG(VB_VBI, LOG_ERR,
LOC + QString(
"Unknown VBI data stream '%1%2%3'")
3593 .arg(QChar(buf[0])).arg(QChar(buf[1])).arg(QChar(buf[2])));
3597 static constexpr uint kMinBlank = 6;
3598 for (
uint i = 0; i < 36; i++)
3600 if (!((linemask >> i) & 0x1))
3603 const uint line = ((i < 18) ? i : i-18) + kMinBlank;
3604 const uint field = (i<18) ? 0 : 1;
3605 const uint id2 = *buf & 0xf;
3629 int data = (buf[2] << 8) | buf[1];
3656 const AVStream* ,
const AVPacket *pkt)
3665 const uint8_t *buf = pkt->data;
3666 const uint8_t *buf_end = pkt->data + pkt->size;
3668 if (*buf >= 0x10 && *buf <= 0x1F)
3674 LOG(VB_VBI, LOG_WARNING,
LOC +
3675 QString(
"VBI: Unknown data_identier: %1 discarded").arg(*buf));
3680 while (buf < buf_end)
3685 if ((buf_end - buf) >= 42)
3689 else if (*buf == 0x03)
3692 if ((buf_end - buf) >= 42)
3696 else if (*buf == 0xff)
3702 LOG(VB_VBI, LOG_WARNING,
LOC +
3703 QString(
"VBI: Unsupported data_unit_id: %1 discarded").arg(*buf));
3713 [[maybe_unused]]
const AVPacket *pkt)
3716 if (
m_itv ==
nullptr)
3718 if (
m_itv ==
nullptr)
3722 uint8_t *data = pkt->data;
3723 int length = pkt->size;
3724 int componentTag = 0;
3725 int dataBroadcastId = 0;
3726 unsigned carouselId = 0;
3729 componentTag = str->component_tag;
3730 dataBroadcastId = str->data_id;
3731 carouselId = (unsigned) str->carousel_id;
3736 uint16_t sectionLen = (((data[1] & 0xF) << 8) | data[2]) + 3;
3738 if (sectionLen > length)
3741 m_itv->ProcessDSMCCSection(data, sectionLen,
3742 componentTag, carouselId,
3744 length -= sectionLen;
3755 long long pts = pkt->pts;
3756 if (
pts == AV_NOPTS_VALUE)
3758 if (
pts == AV_NOPTS_VALUE)
3760 LOG(VB_GENERAL, LOG_ERR,
LOC +
"No PTS found - unable to process subtitle.");
3763 pts =
static_cast<long long>(av_q2d(curstream->time_base) *
pts * 1000);
3769 bool isForcedTrack =
false;
3772 int gotSubtitles = 0;
3773 AVSubtitle subtitle;
3774 memset(&subtitle, 0,
sizeof(AVSubtitle));
3781 curstream->id,
pts);
3785 if (pkt->stream_index == subIdx)
3789 pkt->data, pkt->size,
pts);
3795 || pkt->stream_index == forcedSubIdx)
3798 avcodec_decode_subtitle2(codecContext, &subtitle, &gotSubtitles, pkt);
3801 subtitle.start_display_time +=
pts;
3802 subtitle.end_display_time +=
pts;
3804 if (pkt->stream_index != subIdx)
3805 isForcedTrack =
true;
3812 for (
unsigned i = 0; i < subtitle.num_rects; i++)
3814 subtitle.rects[i]->flags |= AV_SUBTITLE_FLAG_FORCED;
3817 LOG(VB_PLAYBACK | VB_TIMESTAMP, LOG_INFO,
LOC +
3818 QString(
"subtl timecode %1 %2 %3 %4")
3819 .arg(pkt->pts).arg(pkt->dts)
3820 .arg(subtitle.start_display_time)
3821 .arg(subtitle.end_display_time));
3824 subtitle, curstream->codecpar->codec_id == AV_CODEC_ID_XSUB,
3838 auto id =
static_cast<uint>(Packet->stream_index + 0x2000);
3842#if QT_VERSION < QT_VERSION_CHECK(6,0,0)
3843 const auto * codec = QTextCodec::codecForName(
"utf-8");
3844 auto text = codec->toUnicode(
reinterpret_cast<const char *
>(Packet->data), Packet->size - 1);
3846 auto toUtf16 = QStringDecoder(QStringDecoder::Utf8);
3847 QString text = toUtf16.decode(Packet->data);
3849 auto list = text.split(
'\n', Qt::SkipEmptyParts);
3857 enum AVCodecID codec_id = curstream->codecpar->codec_id;
3861 case AV_CODEC_ID_DVB_VBI:
3864 case AV_CODEC_ID_DSMCC_B:
3889 LOG(VB_AUDIO, LOG_INFO,
LOC +
"Audio stream type " + msg +
"changed.");
3903 QString forcedString = forced ? QObject::tr(
" (forced)") :
"";
3905 int av_index =
m_tracks[
type][TrackNo].m_av_stream_index;
3906 AVStream *stream {
nullptr };
3907 if (av_index >= 0 && av_index < (
int)
m_ic->nb_streams)
3908 stream =
m_ic->streams[av_index];
3909 AVDictionaryEntry *entry =
3910 stream ? av_dict_get(stream->metadata,
"title",
nullptr, 0) :
nullptr;
3911 QString user_title = entry ? QString(R
"( "%1")").arg(entry->value) : "";
3923 AVCodecParameters *par = stream->codecpar;
3925 if (par->codec_id == AV_CODEC_ID_MP3)
3926 msg += QString(
" MP3");
3927 else if (ctx && ctx->codec)
3928 msg += QString(
" %1").arg(ctx->codec->name).toUpper();
3929 if (!user_title.isEmpty())
3932 int channels = par->ch_layout.nb_channels;
3935 msg += QString(
" ?ch");
3936 else if((channels > 4) && !(channels & 1))
3937 msg += QString(
" %1.1ch").arg(channels - 1);
3939 msg += QString(
" %1ch").arg(channels);
3949 if (!user_title.isEmpty())
3952 msg += QString(
" (%1)")
3956 return QString(
"%1: %2").arg(TrackNo + 1).arg(msg);
3960 return QObject::tr(
"Subtitle") + QString(
" %1: %2%3%4")
3961 .arg(QString::number(TrackNo + 1),
3989 return ctx ? QByteArray(
reinterpret_cast<char*
>(ctx->subtitle_header), ctx->subtitle_header_size) :
4000 AVDictionaryEntry *tag = av_dict_get(
m_ic->streams[index]->metadata,
"filename",
nullptr, 0);
4002 Filename = QByteArray(tag->value);
4003 AVCodecParameters *par =
m_ic->streams[index]->codecpar;
4004 Data = QByteArray(
reinterpret_cast<char*
>(par->extradata), par->extradata_size);
4014 if ((stream->component_tag == Tag) || ((Tag <= 0) && stream->component_tag <= 0))
4023 for (
uint i = 0; i <
m_ic->nb_streams; i++)
4025 AVStream *stream =
m_ic->streams[i];
4028 if (stream->component_tag == Tag)
4052 const std::vector<int> &ftype)
4054 std::vector<int> ret;
4056 for (
int index : ftype)
4058 if ((lang_key < 0) || tracks[index].m_language == lang_key)
4059 ret.push_back(index);
4067 std::vector<int> ret;
4069 for (
size_t i = 0; i < tracks.size(); i++)
4071 if (tracks[i].m_audio_type ==
type)
4080 const std::vector<int>&fs,
4081 enum AVCodecID codecId,
4084 int selectedTrack = -1;
4089 const int stream_index = tracks[f].m_av_stream_index;
4090 AVCodecParameters *par = ic->streams[stream_index]->codecpar;
4091 if ((codecId == AV_CODEC_ID_NONE || codecId == par->codec_id) &&
4092 (max_seen < par->ch_layout.nb_channels))
4094 if (codecId == AV_CODEC_ID_DTS &&
profile > 0)
4101 max_seen = par->ch_layout.nb_channels;
4105 return selectedTrack;
4113 std::vector<int> flang =
filter_lang(atracks, lang_key, ftype);
4118 AV_PROFILE_DTS_HD_MA);
4129 AV_PROFILE_DTS_HD_HRA);
4205 uint numStreams = atracks.size();
4209 if ((ctrack >= 0) && (ctrack < (
int)numStreams))
4212 LOG(VB_AUDIO, LOG_DEBUG, QString(
"%1 available audio streams").arg(numStreams));
4213 for (
const auto & track : atracks)
4215 AVCodecParameters *codecpar =
m_ic->streams[track.m_av_stream_index]->codecpar;
4216 LOG(VB_AUDIO, LOG_DEBUG, QString(
"%1: %2 bps, %3 Hz, %4 channels, passthrough(%5)")
4217 .arg(avcodec_get_name(codecpar->codec_id), QString::number(codecpar->bit_rate),
4218 QString::number(codecpar->sample_rate), QString::number(codecpar->ch_layout.nb_channels),
4223 if (1 == numStreams)
4233 LOG(VB_AUDIO, LOG_INFO,
LOC +
"Trying to reselect audio sub-stream");
4239 for (
uint i = 0; i < numStreams; i++)
4241 if (atracks[i].m_av_substream_index == substream_index)
4249 if ((selTrack < 0) && wlang >= -1)
4251 LOG(VB_AUDIO, LOG_INFO,
LOC +
"Trying to reselect audio track");
4256 for (
uint i = 0; i < numStreams; i++)
4258 if (wlang == atracks[i].m_language)
4262 if (windx == atracks[i].m_language_index)
4270 LOG(VB_AUDIO, LOG_INFO,
LOC +
"Trying to select audio track (w/lang)");
4277 LOG(VB_AUDIO, LOG_WARNING,
"No audio tracks matched the type filter, "
4278 "so trying all tracks.");
4279 for (
int i = 0; i < static_cast<int>(atracks.size()); i++)
4305 LOG(VB_AUDIO, LOG_INFO,
LOC +
"Trying to select default track");
4306 for (
size_t i = 0; i < atracks.size(); i++) {
4307 int idx = atracks[i].m_av_stream_index;
4308 if (
m_ic->streams[idx]->disposition & AV_DISPOSITION_DEFAULT)
4319 LOG(VB_AUDIO, LOG_INFO,
LOC +
4320 "Trying to select audio track (wo/lang)");
4330 if (ctrack != selTrack)
4332 LOG(VB_AUDIO, LOG_INFO,
LOC +
"No suitable audio track exists.");
4339 strack = atracks[selTrack];
4344 LOG(VB_AUDIO, LOG_INFO,
LOC + QString(
"Selected track %1 (A/V Stream #%2)")
4353 char *buffer,
int bufsize)
4364 const uint halfsample = samplesize >> 1;
4366 const char *from = (channel == 1) ? buffer + halfsample : buffer;
4367 char *to = (channel == 0) ? buffer + halfsample : buffer;
4370 (sample++), (from += samplesize), (to += samplesize))
4372 memmove(to, from, halfsample);
4381 bool firstloop =
true;
4382 int decoded_size = -1;
4389 AVPacket *tmp_pkt = av_packet_alloc();
4390 tmp_pkt->data = pkt->data;
4391 tmp_pkt->size = pkt->size;
4392 while (tmp_pkt->size > 0)
4394 bool reselectAudioTrack =
false;
4399 LOG(VB_AUDIO, LOG_INFO,
LOC +
4400 "Audio is disabled - trying to restart it");
4401 reselectAudioTrack =
true;
4406 bool wasDual = audSubIdx != -1;
4408 if ((wasDual && !isDual) || (!wasDual && isDual))
4411 reselectAudioTrack =
true;
4416 bool already_decoded =
false;
4417 if (!context->ch_layout.nb_channels)
4429 AVChannelLayout channel_layout;
4431 av_opt_set_chlayout(context->priv_data,
"downmix", &channel_layout, 0);
4433 if (context->codec_id == AV_CODEC_ID_AC3)
4438 decoded_size = data_size;
4439 already_decoded =
true;
4440 reselectAudioTrack |= context->ch_layout.nb_channels;
4444 if (reselectAudioTrack)
4454 if (!(decodetype &
kDecodeAudio) || (pkt->stream_index != audIdx)
4458 if (firstloop && pkt->pts != AV_NOPTS_VALUE)
4471 LOG(VB_GENERAL, LOG_INFO,
LOC +
"Audio stream changed");
4474 LOG(VB_GENERAL, LOG_INFO,
LOC + QString(
"Number of audio channels changed from %1 to %2")
4486 if (!already_decoded)
4491 decoded_size = data_size;
4499 data_size = tmp_pkt->size;
4505 if (!already_decoded)
4509 AVChannelLayout channel_layout;
4511 av_opt_set_chlayout(context->priv_data,
"downmix", &channel_layout, 0);
4515 decoded_size = data_size;
4522 LOG(VB_GENERAL, LOG_ERR,
LOC +
"Unknown audio decoding error");
4523 av_packet_free(&tmp_pkt);
4529 tmp_pkt->data += ret;
4530 tmp_pkt->size -= ret;
4534 std::chrono::milliseconds temppts =
m_lastAPts;
4541 int frames = (context->ch_layout.nb_channels <= 0 || decoded_size < 0 || !samplesize) ? -1 :
4542 decoded_size / (context->ch_layout.nb_channels * samplesize);
4551 ((
double)(frames * 1000) / context->sample_rate);
4554 LOG(VB_TIMESTAMP, LOG_INFO,
LOC + QString(
"audio timecode %1 %2 %3 %4")
4555 .arg(pkt->pts).arg(pkt->dts).arg(temppts.count()).arg(
m_lastAPts.count()));
4560 tmp_pkt->data += ret;
4561 tmp_pkt->size -= ret;
4565 av_packet_free(&tmp_pkt);
4572 AVPacket *pkt =
nullptr;
4573 bool have_err =
false;
4575 const DecodeType origDecodetype = decodetype;
4583 bool storevideoframes =
false;
4600 decodetype = (
DecodeType)((
int)decodetype & ~kDecodeVideo);
4616 decodetype = (
DecodeType)((
int)decodetype & ~kDecodeAudio);
4650 storevideoframes =
true;
4656 LOG(VB_GENERAL, LOG_WARNING,
LOC +
4657 QString(
"Audio %1 ms behind video but already %2 "
4658 "video frames queued. AV-Sync might be broken.")
4669 av_packet_free(&pkt);
4675 pkt = av_packet_alloc();
4678 if (
m_ic !=
nullptr)
4680 if ((
m_ic ==
nullptr) || (retval < 0))
4682 if (retval == -EAGAIN)
4686 av_packet_free(&pkt);
4688 if (retval == AVERROR_EOF)
4691 LOG(VB_GENERAL, LOG_INFO, QString(
"decoding reached end of file"));
4695 LOG(VB_GENERAL, LOG_ERR, QString(
"decoding error %1 (%2)")
4697 QString::number(retval)));
4711 LOG(VB_GENERAL, LOG_ERR,
LOC +
"No context");
4712 av_packet_unref(pkt);
4716 if (pkt->stream_index >= (
int)
m_ic->nb_streams)
4718 LOG(VB_GENERAL, LOG_ERR,
LOC +
"Bad stream");
4719 av_packet_unref(pkt);
4723 AVStream *curstream =
m_ic->streams[pkt->stream_index];
4727 LOG(VB_GENERAL, LOG_ERR,
LOC +
"Bad stream (NULL)");
4728 av_packet_unref(pkt);
4732 enum AVMediaType codec_type = curstream->codecpar->codec_type;
4733 const AVCodecID codec_id = curstream->codecpar->codec_id;
4739 case AVMEDIA_TYPE_VIDEO:
4740 if (storevideoframes)
4747 case AVMEDIA_TYPE_AUDIO:
4749 if (codec_id == AV_CODEC_ID_AC4)
4751 av_packet_unref(pkt);
4755 case AVMEDIA_TYPE_SUBTITLE:
4758 case AV_CODEC_ID_TEXT:
4760 av_packet_unref(pkt);
4762 case AV_CODEC_ID_DVB_TELETEXT:
4764 av_packet_unref(pkt);
4766 case AV_CODEC_ID_IVTV_VBI:
4768 av_packet_unref(pkt);
4774 case AVMEDIA_TYPE_DATA:
4776 av_packet_unref(pkt);
4784 if (context ==
nullptr)
4786 if (codec_type != AVMEDIA_TYPE_VIDEO)
4788 LOG(VB_PLAYBACK, LOG_ERR,
LOC +
4789 QString(
"No codec for stream index %1, type(%2) id(%3:%4)")
4790 .arg(QString::number(pkt->stream_index),
4792 avcodec_get_name(codec_id),
4793 QString::number(codec_id)
4800 av_packet_unref(pkt);
4808 case AVMEDIA_TYPE_AUDIO:
4817 case AVMEDIA_TYPE_VIDEO:
4831 av_packet_free(&pkt);
4835 if (pkt->pts != AV_NOPTS_VALUE)
4838 (av_q2d(curstream->time_base)*pkt->pts*1000000);
4853 case AVMEDIA_TYPE_SUBTITLE:
4862 LOG(VB_GENERAL, LOG_ERR,
LOC +
4863 QString(
"Decoding - id(%1) type(%2)")
4864 .arg(avcodec_get_name(codec_id),
4871 if (!have_err && !Retry)
4873 av_packet_unref(pkt);
4878 av_packet_free(&pkt);
4886 LOG(VB_PLAYBACK, LOG_INFO,
LOC + QString(
"StreamChangeCheck skip SeekReset"));
4896 int result = av_read_frame(ctx, pkt);
4904 if (pmt_buffer.has_buffer())
4961 if (stream < 0 || !
m_ic)
4963 return avcodec_get_name(
m_ic->streams[stream]->codecpar->codec_id);
4977 QString msg = (disable) ?
"Disabling" :
"Allowing";
4978 LOG(VB_AUDIO, LOG_INFO,
LOC + msg +
" pass through");
5001 switch (ctx->codec_id)
5003 case AV_CODEC_ID_AC3:
5004 case AV_CODEC_ID_TRUEHD:
5005 case AV_CODEC_ID_EAC3:
5006 case AV_CODEC_ID_MLP:
5007 case AV_CODEC_ID_DTS:
5016 bool passthru =
false;
5020 if (!withProfile && par->codec_id == AV_CODEC_ID_DTS && !
m_audio->
CanDTSHD())
5023 par->codec_id, AV_PROFILE_DTS);
5028 par->codec_id, par->profile);
5044 AVStream *curstream =
nullptr;
5045 AVCodecContext *ctx =
nullptr;
5047 int requested_channels = 0;
5051 (
int)
m_ic->nb_streams))
5054 .m_av_stream_index];
5055 if (curstream !=
nullptr)
5062 LOG(VB_PLAYBACK, LOG_INFO,
LOC +
"No codec context. Returning false");
5068 ctx->bits_per_raw_sample);
5070 if (av_sample_fmt_is_planar(ctx->sample_fmt))
5072 LOG(VB_AUDIO, LOG_INFO,
LOC + QString(
"Audio data is planar"));
5077 int bps = av_get_bytes_per_sample(ctx->sample_fmt) << 3;
5078 if (ctx->sample_fmt == AV_SAMPLE_FMT_S32 &&
5079 ctx->bits_per_raw_sample)
5080 bps = ctx->bits_per_raw_sample;
5081 LOG(VB_GENERAL, LOG_ERR,
LOC +
5082 QString(
"Unsupported sample format with %1 bits").arg(bps));
5086 bool using_passthru =
DoPassThrough(curstream->codecpar,
false);
5088 requested_channels = ctx->ch_layout.nb_channels;
5090 if (!using_passthru &&
5096 AVChannelLayout channel_layout;
5097 av_channel_layout_default(&channel_layout, requested_channels);
5098 av_opt_set_chlayout(ctx->priv_data,
"downmix", &channel_layout, 0);
5102 requested_channels, using_passthru, ctx->ch_layout.nb_channels,
5103 ctx->codec_id == AV_CODEC_ID_DTS ? ctx->profile : 0);
5107 LOG(VB_AUDIO, LOG_INFO,
LOC +
"Initializing audio parms from " +
5112 LOG(VB_AUDIO, LOG_INFO,
LOC +
"Audio format changed " +
5113 QString(
"\n\t\t\tfrom %1 to %2")
5129 switch (ctx->codec_id)
5131 case AV_CODEC_ID_MP2:
5134 case AV_CODEC_ID_MP3:
5137 case AV_CODEC_ID_AC3:
5140 case AV_CODEC_ID_DTS:
5143 case AV_CODEC_ID_VORBIS:
5146 case AV_CODEC_ID_WMAV1:
5149 case AV_CODEC_ID_WMAV2:
5157 lcd->setAudioFormatLEDs(audio_format,
true);
5192 int64_t start_time = INT64_MAX;
5193 int64_t end_time = INT64_MIN;
5194 AVStream *st =
nullptr;
5196 for (
uint i = 0; i < ic->nb_streams; i++)
5198 AVStream *st1 = ic->streams[i];
5199 if (st1 && st1->codecpar->codec_type == AVMEDIA_TYPE_VIDEO)
5208 int64_t duration = INT64_MIN;
5209 if (st->start_time != AV_NOPTS_VALUE && st->time_base.den) {
5210 int64_t start_time1= av_rescale_q(st->start_time, st->time_base, AV_TIME_BASE_Q);
5211 start_time = std::min(start_time1, start_time);
5212 if (st->duration != AV_NOPTS_VALUE) {
5213 int64_t end_time1 = start_time1 +
5214 av_rescale_q(st->duration, st->time_base, AV_TIME_BASE_Q);
5215 end_time = std::max(end_time1, end_time);
5218 if (st->duration != AV_NOPTS_VALUE) {
5219 int64_t duration1 = av_rescale_q(st->duration, st->time_base, AV_TIME_BASE_Q);
5220 duration = std::max(duration1, duration);
5222 if (start_time != INT64_MAX) {
5223 ic->start_time = start_time;
5224 if (end_time != INT64_MIN) {
5225 duration = std::max(end_time - start_time, duration);
5228 if (duration != INT64_MIN) {
5229 ic->duration = duration;
5232 int64_t filesize = avio_size(ic->pb);
5235 ic->bit_rate = (double)filesize * 8.0 * AV_TIME_BASE /
5236 (
double)ic->duration;
5252 if (
m_ic ==
nullptr)
5257 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