15#include "libavutil/avutil.h"
16#include "libavutil/error.h"
17#include "libavutil/intreadwrite.h"
18#include "libavutil/log.h"
19#include "libavutil/opt.h"
20#include "libavcodec/avcodec.h"
21#include "libavformat/avformat.h"
22#include "libavformat/avio.h"
23#include "libswscale/swscale.h"
24#include "libavutil/stereo3d.h"
25#include "libavutil/imgutils.h"
26#include "libavutil/display.h"
31#include "libavcodec/jni.h"
33#if QT_VERSION < QT_VERSION_CHECK(6,0,0)
34#include <QtAndroidExtras>
36#include <QJniEnvironment>
37#define QAndroidJniEnvironment QJniEnvironment
65#if QT_VERSION < QT_VERSION_CHECK(6,0,0)
68#include <QStringDecoder>
83#include "libmythbase/mythconfig.h"
112using namespace std::string_view_literals;
114#define LOC QString("AFD: ")
124#if QT_VERSION < QT_VERSION_CHECK(6,0,0)
132 return {ctx.width >> ctx.lowres, ctx.height >> ctx.lowres};
136 float aspect_ratio = 0.0F;
138 if (ctx.sample_aspect_ratio.num && ctx.height)
140 aspect_ratio = av_q2d(ctx.sample_aspect_ratio) *
141 static_cast<double>(ctx.width);
142 aspect_ratio /= (float) ctx.height;
145 if (aspect_ratio <= 0.0F || aspect_ratio > 6.0F)
148 aspect_ratio = (float)ctx.width / (
float)ctx.height;
150 aspect_ratio = 4.0F / 3.0F;
157 static constexpr float kDefaultAspect = 4.0F / 3.0F;
158 int asp =
p.aspectRatio();
161 case 0:
return kDefaultAspect;
162 case 2:
return 4.0F / 3.0F;
163 case 3:
return 16.0F / 9.0F;
164 case 4:
return 2.21F;
168 float aspect_ratio = asp * 0.000001F;
169 if (aspect_ratio <= 0.0F || aspect_ratio > 6.0F)
171 if (
p.pictureHeight() &&
p.pictureWidth())
174 (float)
p.pictureWidth() /(float)
p.pictureHeight();
178 aspect_ratio = kDefaultAspect;
199#define FAIL(errmsg) do { \
200 LOG(VB_PLAYBACK, LOG_INFO, LOC + (errmsg)); \
211 switch (Stream->codecpar->codec_type)
215 case AVMEDIA_TYPE_VIDEO:
217 FAIL(
"No codec for video stream");
218 if (!Stream->codecpar->width || !Stream->codecpar->height)
219 FAIL(
"Unspecified video size");
220 if (Stream->codecpar->format == AV_PIX_FMT_NONE)
221 FAIL(
"Unspecified video pixel format");
228 case AVMEDIA_TYPE_AUDIO:
230 FAIL(
"No codec for audio stream");
248 case AVMEDIA_TYPE_SUBTITLE:
249 if (Stream->codecpar->codec_id == AV_CODEC_ID_HDMV_PGS_SUBTITLE && !Stream->codecpar->width)
250 FAIL(
"Unspecified subtitle size");
252 case AVMEDIA_TYPE_DATA:
253 if (Stream->codecpar->codec_id == AV_CODEC_ID_NONE)
260 if (Stream->codecpar->codec_id == AV_CODEC_ID_NONE)
261 FAIL(
"Unknown codec");
265static void myth_av_log(
void *ptr,
int level,
const char* fmt, va_list vl)
270 static QString s_fullLine(
"");
271 static QMutex s_stringLock;
272 uint64_t verbose_mask = VB_LIBAV;
273 LogLevel_t verbose_level = LOG_EMERG;
279 verbose_level = LOG_EMERG;
280 verbose_mask |= VB_GENERAL;
283 verbose_level = LOG_CRIT;
284 verbose_mask |= VB_GENERAL;
287 verbose_level = LOG_ERR;
290 verbose_level = LOG_WARNING;
293 verbose_level = LOG_INFO;
297 verbose_level = LOG_DEBUG;
300 verbose_level = LOG_TRACE;
310 if (s_fullLine.isEmpty() && ptr) {
311 AVClass* avc = *(AVClass**)ptr;
312 s_fullLine = QString(
"[%1 @ %2] ")
313 .arg(avc->item_name(ptr))
314 .arg((quintptr)avc, QT_POINTER_SIZE * 2, 16, QChar(
'0'));
317 s_fullLine += QString::vasprintf(fmt, vl);
318 if (s_fullLine.endsWith(
"\n"))
320 LOG(verbose_mask, verbose_level, s_fullLine.trimmed());
321 s_fullLine.truncate(0);
323 s_stringLock.unlock();
328 if (lang_cstr[0] ==
'\0' || lang_cstr[1] ==
'\0')
332 if (lang_cstr[2] ==
'\0')
334 QString tmp2 = lang_cstr;
352 case AVMEDIA_TYPE_UNKNOWN:
return "Unknown";
353 case AVMEDIA_TYPE_VIDEO:
return "Video";
354 case AVMEDIA_TYPE_AUDIO:
return "Audio";
355 case AVMEDIA_TYPE_DATA:
return "Data";
356 case AVMEDIA_TYPE_SUBTITLE:
return "Subtitle";
357 case AVMEDIA_TYPE_ATTACHMENT:
return "Attachment";
358 default:
return "Invalid Codec Type";
368 m_playerFlags(flags),
373 m_itv(parent->GetInteractiveTV()),
374 m_audioSamples((uint8_t *)av_mallocz(
AudioOutput::kMaxSizeBuffer))
388 LOG(VB_PLAYBACK, LOG_INFO,
LOC + QString(
"PlayerFlags: 0x%1, AudioReadAhead: %2 msec")
397 av_packet_free(&pkt);
415 lcd->setAudioFormatLEDs(
AUDIO_AC3,
false);
416 lcd->setVideoFormatLEDs(
VIDEO_MPG,
false);
433 for (
uint i = 0; i <
m_ic->nb_streams; i++)
435 AVStream *st =
m_ic->streams[i];
451 avformat_close_input(&
m_ic);
457static int64_t
lsb3full(int64_t lsb, int64_t base_ts,
int lsb_bits)
459 int64_t mask = (lsb_bits < 64) ? (1LL<<lsb_bits)-1 : -1LL;
460 return ((lsb - base_ts)&mask);
465 int64_t start_pts = 0;
467 AVStream *st =
nullptr;
468 for (
uint i = 0; i <
m_ic->nb_streams; i++)
470 AVStream *st1 =
m_ic->streams[i];
471 if (st1 && st1->codecpar->codec_type == AVMEDIA_TYPE_VIDEO)
480 if (
m_ic->start_time != AV_NOPTS_VALUE)
482 start_pts = av_rescale(
m_ic->start_time,
484 AV_TIME_BASE * (int64_t)st->time_base.num);
487 int64_t
pts = av_rescale(timecode.count() / 1000.0,
498 std::chrono::milliseconds timecode)
500 int64_t start_pts = 0;
502 if (
m_ic->start_time != AV_NOPTS_VALUE)
504 start_pts = av_rescale(
m_ic->start_time,
506 AV_TIME_BASE * (int64_t)st->time_base.num);
509 int64_t
pts = av_rescale(timecode.count() / 1000.0,
522 return m_ic->nb_chapters;
532 for (
int i = 0; i < total; i++)
534 int num =
m_ic->chapters[i]->time_base.num;
535 int den =
m_ic->chapters[i]->time_base.den;
536 int64_t start =
m_ic->chapters[i]->start;
537 long double total_secs = (
long double)start * (
long double)num /
539 times.push_back(std::chrono::seconds((
long long)total_secs));
548 for (
int i = (
m_ic->nb_chapters - 1); i > -1 ; i--)
550 int num =
m_ic->chapters[i]->time_base.num;
551 int den =
m_ic->chapters[i]->time_base.den;
552 int64_t start =
m_ic->chapters[i]->start;
553 long double total_secs = (
long double)start * (
long double)num /
555 auto framenum = (
long long)(total_secs *
m_fps);
556 if (framesPlayed >= framenum)
558 LOG(VB_PLAYBACK, LOG_INFO,
LOC +
559 QString(
"GetCurrentChapter(selected chapter %1 framenum %2)")
560 .arg(i + 1).arg(framenum));
572 int num =
m_ic->chapters[chapter - 1]->time_base.num;
573 int den =
m_ic->chapters[chapter - 1]->time_base.den;
574 int64_t start =
m_ic->chapters[chapter - 1]->start;
575 long double total_secs = (
long double)start * (
long double)num /
577 auto framenum = (
long long)(total_secs *
m_fps);
578 LOG(VB_PLAYBACK, LOG_INFO,
LOC + QString(
"GetChapter %1: framenum %2")
579 .arg(chapter).arg(framenum));
585 LOG(VB_PLAYBACK, LOG_INFO,
LOC + QString(
"DoRewind(%1, %2 discard frames)")
586 .arg(desiredFrame).arg( discardFrames ?
"do" :
"don't" ));
592 return do_av_seek(desiredFrame, discardFrames, AVSEEK_FLAG_BACKWARD);
597 LOG(VB_PLAYBACK, LOG_INFO,
LOC +
598 QString(
"DoFastForward(%1 (%2), %3 discard frames)")
600 .arg((discardFrames) ?
"do" :
"don't"));
608 if (seekDelta >= 0 && seekDelta < 2 && m_parent->GetPlaySpeed() == 0.0F)
614 return do_av_seek(desiredFrame, discardFrames, 0);
620 if (
m_ic->start_time != AV_NOPTS_VALUE)
621 ts =
m_ic->start_time;
624 long double seekts = desiredFrame * AV_TIME_BASE /
m_fps;
625 ts += (
long long)seekts;
632 flags |= AVSEEK_FLAG_BACKWARD;
635 int ret = av_seek_frame(
m_ic, -1, ts, flags);
638 LOG(VB_GENERAL, LOG_ERR,
LOC +
639 QString(
"av_seek_frame(m_ic, -1, %1, 0b%2) error: %3").arg(
641 QString::number(flags, 2),
648 reader->SeekFrame(ts, flags);
650 int normalframes = 0;
668 bool doflush,
bool discardFrames)
673 LOG(VB_PLAYBACK, LOG_INFO,
LOC +
674 QString(
"SeekReset(%1, %2, %3 flush, %4 discard)")
675 .arg(newKey).arg(skipFrames)
676 .arg((doflush) ?
"do" :
"don't",
677 (discardFrames) ?
"do" :
"don't"));
697 avformat_flush(
m_ic);
704 m_ic->pb->buf_ptr =
m_ic->pb->buffer;
705 m_ic->pb->buf_end =
m_ic->pb->buffer;
706 m_ic->pb->eof_reached = 0;
710 LOG(VB_PLAYBACK, LOG_INFO,
LOC +
"SeekReset() flushing");
711 for (
uint i = 0; i <
m_ic->nb_streams; i++)
717 if (codecContext && codecContext->internal)
718 avcodec_flush_buffers(codecContext);
725 av_packet_free(&pkt);
747 static constexpr std::chrono::milliseconds maxSeekTimeMs { 200ms };
748 int profileFrames = 0;
750 for (; (skipFrames > 0 && !
m_atEof &&
751 (exactSeeks || begin.
elapsed() < maxSeekTimeMs));
752 --skipFrames, ++profileFrames)
756 QElapsedTimer getframetimer;
757 getframetimer.start();
759 while (retry && !getframetimer.hasExpired(100))
764 std::this_thread::sleep_for(1ms);
772 if (!exactSeeks && profileFrames >= 5 && profileFrames < 10)
774 const int giveUpPredictionMs = 400;
775 int remainingTimeMs =
776 skipFrames * (float)begin.
elapsed().count() / profileFrames;
777 if (remainingTimeMs > giveUpPredictionMs)
779 LOG(VB_PLAYBACK, LOG_DEBUG,
780 QString(
"Frame-by-frame seeking would take "
781 "%1 ms to finish, skipping.").arg(remainingTimeMs));
798 LOG(VB_GENERAL, LOG_NOTICE,
LOC +
799 QString(
"Resetting byte context eof (livetv %1 was eof %2)")
801 m_ic->pb->eof_reached = 0;
809 LOG(VB_PLAYBACK, LOG_INFO,
LOC +
810 QString(
"Reset: Video %1, Seek %2, File %3")
811 .arg(reset_video_data).arg(seek_reset).arg(reset_file));
818 if (reset_video_data)
828 memset(&probe, 0,
sizeof(AVProbeData));
830 QByteArray fname =
filename.toLatin1();
831 probe.filename = fname.constData();
832 probe.buf = (
unsigned char *)testbuf.data();
833 probe.buf_size = testbuf.size();
835 int score = AVPROBE_SCORE_MAX/4;
847 memset(probe.buf + probe.buf_size, 0, AVPROBE_PADDING_SIZE);
849 return av_probe_input_format2(&probe,
static_cast<int>(
true), &score) !=
nullptr;
856 int cnt = decoder->
m_ic->nb_streams;
858 LOG(VB_PLAYBACK, LOG_INFO,
LOC +
859 QString(
"streams_changed 0x%1 -- program_number %2 stream count %3")
860 .arg((uint64_t)data,0,16).arg(QString::number(avprogram_id), QString::number(cnt)));
862 auto* program = decoder->get_current_AVProgram();
863 if (program !=
nullptr && program->id != avprogram_id)
867 decoder->m_streamsChanged =
true;
904 const AVInputFormat *fmt =
nullptr;
906 QByteArray fnamea = fnames.toLatin1();
907 const char *
filename = fnamea.constData();
910 memset(&probe, 0,
sizeof(AVProbeData));
912 probe.buf =
reinterpret_cast<unsigned char *
>(testbuf.data());
914 probe.buf_size = testbuf.size();
917 memset(probe.buf + probe.buf_size, 0, AVPROBE_PADDING_SIZE);
919 fmt = av_probe_input_format(&probe,
static_cast<int>(
true));
922 LOG(VB_GENERAL, LOG_ERR,
LOC + QString(
"Probe failed for '%1'").arg(
filename));
926 if (strcmp(fmt->name,
"mpegts") == 0 &&
929 const AVInputFormat *fmt2 = av_find_input_format(
"mpegts-ffmpeg");
933 LOG(VB_GENERAL, LOG_INFO,
LOC +
"Using FFmpeg MPEG-TS demuxer (forced)");
938 bool scancomplete =
false;
939 int remainingscans = 5;
941 while (!scancomplete && remainingscans--)
955 while (!found && --retries)
957 m_ic = avformat_alloc_context();
960 LOG(VB_GENERAL, LOG_ERR,
LOC +
"Could not allocate format context.");
967 LOG(VB_PLAYBACK, LOG_INFO,
LOC +
968 QString(
"Buffer size: %1 Streamed %2 Seekable %3 Available %4")
971 .arg(
m_ic->pb->seekable)
975 err = avformat_open_input(&
m_ic,
filename, fmt,
nullptr);
979 LOG(VB_PLAYBACK, LOG_INFO,
LOC + QString(
"Failed to open input ('%1')")
987 QThread::usleep(100000);
993 if (strcmp(fmt->name,
"mpegts") == 0)
995 fmt = av_find_input_format(
"mpegts-ffmpeg");
998 LOG(VB_GENERAL, LOG_ERR,
LOC +
"Attempting to use original FFmpeg MPEG-TS demuxer.");
1011 LOG(VB_GENERAL, LOG_ERR,
LOC +
"Fatal error opening input. Aborting");
1023 m_ic->max_analyze_duration = 60LL * AV_TIME_BASE;
1027 err = avformat_find_stream_info(
m_ic,
nullptr);
1031 LOG(VB_GENERAL, LOG_ERR,
LOC + QString(
"Could not find codec parameters for '%1'").arg(
filename));
1038 scancomplete =
true;
1043 scancomplete =
false;
1047 LOG(VB_PLAYBACK, LOG_INFO,
LOC +
"Stream scan incomplete - retrying");
1048 QThread::usleep(250000);
1056 LOG(VB_GENERAL, LOG_WARNING,
LOC +
"Scan incomplete - playback may not work");
1059 m_ic->stream_change_data =
this;
1071 QString extension = QFileInfo(fnames).suffix();
1072 if (strcmp(fmt->name,
"mp3") == 0 || strcmp(fmt->name,
"flac") == 0 ||
1073 strcmp(fmt->name,
"ogg") == 0 ||
1074 (extension.compare(
"m4a", Qt::CaseInsensitive) == 0))
1089 int initialAudio = -1;
1090 int initialVideo = -1;
1091 if (
m_itv ==
nullptr)
1093 if (
m_itv !=
nullptr)
1094 m_itv->GetInitialStreams(initialAudio, initialVideo);
1095 if (initialAudio >= 0)
1097 if (initialVideo >= 0)
1118 std::chrono::seconds dur = 0s;
1127 dur = duration_cast<std::chrono::seconds>(av_duration(
m_ic->duration));
1138 LOG(VB_PLAYBACK, LOG_INFO,
LOC +
1139 "Recording has no position -- using libavformat seeking.");
1148 float bytespersec = (float)
m_bitrate / 8 / 2;
1151 (int)(secs *
static_cast<float>(
m_fps)));
1160 if (strcmp(fmt->name,
"avi") == 0)
1173 LOG(VB_PLAYBACK, LOG_INFO,
LOC +
"Position map found");
1175 LOG(VB_PLAYBACK, LOG_INFO,
LOC +
"Partial position map found");
1176 LOG(VB_PLAYBACK, LOG_INFO,
LOC +
1177 QString(
"Successfully opened decoder for file: \"%1\". novideo(%2)")
1181 for (
unsigned int i=0; i <
m_ic->nb_chapters; i++)
1183 int num =
m_ic->chapters[i]->time_base.num;
1184 int den =
m_ic->chapters[i]->time_base.den;
1185 int64_t start =
m_ic->chapters[i]->start;
1186 auto total_secs =
static_cast<long double>(start) *
static_cast<long double>(num) /
1187 static_cast<long double>(den);
1189 auto framenum =
static_cast<long long>(total_secs *
static_cast<long double>(
m_fps));
1190 LOG(VB_PLAYBACK, LOG_INFO,
LOC +
1191 QString(
"Chapter %1 found @ [%2]->%3")
1194 QString::number(framenum)));
1207 Reset(
true,
true,
true);
1221 double avg_fps = (Stream->avg_frame_rate.den == 0) ? 0.0 : av_q2d(Stream->avg_frame_rate);
1222 double codec_fps = av_q2d(Context->framerate);
1223 double container_fps = (Stream->time_base.num == 0) ? 0.0 : av_q2d(av_inv_q(Stream->time_base));
1225 double estimated_fps = (Stream->r_frame_rate.den == 0) ? 0.0 : av_q2d(Stream->r_frame_rate);
1228 std::vector<double> rates;
1233 if (QString(
m_ic->iformat->name).contains(
"matroska") ||
1234 QString(
m_ic->iformat->name).contains(
"mov"))
1236 rates.emplace_back(avg_fps);
1240 if (QString(
m_ic->iformat->name).contains(
"avi"))
1242 rates.emplace_back(container_fps);
1245 rates.emplace_back(codec_fps);
1246 rates.emplace_back(container_fps);
1247 rates.emplace_back(avg_fps);
1249 rates.emplace_back(estimated_fps);
1251 rates.emplace_back(30000.0 / 1001.0);
1253 auto invalid_fps = [](
double rate) {
return rate < 3.0 || rate > 121.0; };
1254 rates.erase(std::remove_if(rates.begin(), rates.end(), invalid_fps), rates.end());
1256 auto FuzzyEquals = [](
double First,
double Second) {
return std::abs(First - Second) < 0.03; };
1259 if (!FuzzyEquals(rates.front(),
m_fps))
1261 LOG(VB_PLAYBACK, LOG_INFO,
LOC +
1262 QString(
"Selected FPS: %1 (Avg:%2 Mult:%3 Codec:%4 Container:%5 Estimated:%6)")
1263 .arg(
static_cast<double>(rates.front())).arg(avg_fps)
1264 .arg(
m_fpsMultiplier).arg(codec_fps).arg(container_fps).arg(estimated_fps));
1267 auto IsStandard = [&FuzzyEquals](
double Rate)
1270 static const std::set<double> k_standard_rates =
1289 if (Rate > 23.0 && Rate < 121.0)
1291 for (
auto standard_rate : k_standard_rates)
1292 if (FuzzyEquals(Rate, standard_rate))
1301 double detected = rates.front();
1302 if (Sanitise && !IsStandard(detected))
1304 for (
auto rate : rates)
1306 if (IsStandard(rate))
1308 LOG(VB_GENERAL, LOG_INFO,
LOC + QString(
"%1 is non-standard - using %2 instead.")
1309 .arg(rates.front()).arg(rate));
1317 if (rate > 33.0 && detected < 33.0)
1319 double half = rate / 2.0;
1320 if (std::abs(half - detected) < (half * 0.1))
1322 LOG(VB_GENERAL, LOG_INFO,
LOC +
1323 QString(
"Assuming %1 is a better choice than %2")
1324 .arg(half).arg(rate));
1325 return static_cast<float>(half);
1328 return static_cast<float>(rate);
1333 return static_cast<float>(detected);
1338 switch (Context->codec_id)
1340 case AV_CODEC_ID_H264:
1343 if (Context->extradata && (Context->extradata_size >= 7))
1346 if (Context->extradata[0] == 1)
1348 else if (AV_RB24(Context->extradata) == 0x01)
1350 else if (AV_RB32(Context->extradata) == 0x01)
1357 parser.parse_SPS(Context->extradata + offset,
1358 static_cast<uint>(Context->extradata_size - offset), dummy, result);
1363 case AV_CODEC_ID_H265:
return 16;
1364 case AV_CODEC_ID_VP9:
return 8;
1365 case AV_CODEC_ID_VP8:
return 3;
1371 bool selectedStream)
1373 LOG(VB_PLAYBACK, LOG_INFO,
LOC +
1374 QString(
"InitVideoCodec ID:%1 Type:%2 Size:%3x%4")
1375 .arg(avcodec_get_name(codecContext->codec_id),
1377 .arg(codecContext->width).arg(codecContext->height));
1382 codecContext->opaque =
static_cast<void*
>(
this);
1384 codecContext->slice_flags = 0;
1386 codecContext->err_recognition = AV_EF_COMPLIANT;
1387 codecContext->workaround_bugs = FF_BUG_AUTODETECT;
1388 codecContext->error_concealment = FF_EC_GUESS_MVS | FF_EC_DEBLOCK;
1389 codecContext->idct_algo = FF_IDCT_AUTO;
1390 codecContext->debug = 0;
1393 const AVCodec *codec1 = codecContext->codec;
1399 const AVPacketSideData *sd = av_packet_side_data_get(stream->codecpar->coded_side_data,
1400 stream->codecpar->nb_coded_side_data, AV_PKT_DATA_DISPLAYMATRIX);
1402 m_videoRotation =
static_cast<int>(-av_display_rotation_get(
reinterpret_cast<int32_t*
>(sd->data)));
1407 sd = av_packet_side_data_get(stream->codecpar->coded_side_data,
1408 stream->codecpar->nb_coded_side_data, AV_PKT_DATA_STEREO3D);
1411 auto * avstereo =
reinterpret_cast<AVStereo3D*
>(sd->data);
1436 bool doublerate =
true;
1440 if (codec1 && ((AV_CODEC_ID_MPEG2VIDEO == codec1->id) ||
1441 (AV_CODEC_ID_MPEG1VIDEO == codec1->id)))
1445 int total_blocks = (codecContext->height + 15) / 16;
1446 codecContext->skip_top = (total_blocks + 3) / 4;
1447 codecContext->skip_bottom = (total_blocks + 3) / 4;
1451 codecContext->lowres = 2;
1455 codecContext->flags &= ~AV_CODEC_FLAG_LOOP_FILTER;
1456 codecContext->skip_loop_filter = AVDISCARD_ALL;
1460 codecContext->skip_idct = AVDISCARD_ALL;
1472 if (!width || !height)
1474 LOG(VB_PLAYBACK, LOG_INFO,
LOC +
1475 "InitVideoCodec invalid dimensions, resetting decoder.");
1483 const AVCodec *codec2 = codecContext->codec;
1486 codecName = codec2->name;
1494 switch (codecContext->codec_id)
1496 case AV_CODEC_ID_H263:
1497 case AV_CODEC_ID_MPEG4:
1498 case AV_CODEC_ID_MSMPEG4V1:
1499 case AV_CODEC_ID_MSMPEG4V2:
1500 case AV_CODEC_ID_MSMPEG4V3:
1501 case AV_CODEC_ID_H263P:
1502 case AV_CODEC_ID_H263I:
1505 case AV_CODEC_ID_WMV1:
1506 case AV_CODEC_ID_WMV2:
1510 case AV_CODEC_ID_XVID:
1519 lcd->setVideoFormatLEDs(video_format,
true);
1531 static constexpr std::array<uint8_t, 256> odd_parity_LUT
1533 0, 1, 1, 0, 1, 0, 0, 1, 1, 0, 0, 1, 0, 1, 1, 0,
1534 1, 0, 0, 1, 0, 1, 1, 0, 0, 1, 1, 0, 1, 0, 0, 1,
1535 1, 0, 0, 1, 0, 1, 1, 0, 0, 1, 1, 0, 1, 0, 0, 1,
1536 0, 1, 1, 0, 1, 0, 0, 1, 1, 0, 0, 1, 0, 1, 1, 0,
1537 1, 0, 0, 1, 0, 1, 1, 0, 0, 1, 1, 0, 1, 0, 0, 1,
1538 0, 1, 1, 0, 1, 0, 0, 1, 1, 0, 0, 1, 0, 1, 1, 0,
1539 0, 1, 1, 0, 1, 0, 0, 1, 1, 0, 0, 1, 0, 1, 1, 0,
1540 1, 0, 0, 1, 0, 1, 1, 0, 0, 1, 1, 0, 1, 0, 0, 1,
1541 1, 0, 0, 1, 0, 1, 1, 0, 0, 1, 1, 0, 1, 0, 0, 1,
1542 0, 1, 1, 0, 1, 0, 0, 1, 1, 0, 0, 1, 0, 1, 1, 0,
1543 0, 1, 1, 0, 1, 0, 0, 1, 1, 0, 0, 1, 0, 1, 1, 0,
1544 1, 0, 0, 1, 0, 1, 1, 0, 0, 1, 1, 0, 1, 0, 0, 1,
1545 0, 1, 1, 0, 1, 0, 0, 1, 1, 0, 0, 1, 0, 1, 1, 0,
1546 1, 0, 0, 1, 0, 1, 1, 0, 0, 1, 1, 0, 1, 0, 0, 1,
1547 1, 0, 0, 1, 0, 1, 1, 0, 0, 1, 1, 0, 1, 0, 0, 1,
1548 0, 1, 1, 0, 1, 0, 0, 1, 1, 0, 0, 1, 0, 1, 1, 0,
1550 bool ret = (odd_parity_LUT[data & 0xff] == 1) &&
1551 (odd_parity_LUT[(data & 0xff00) >> 8] == 1);
1554 LOG(VB_VBI, LOG_ERR,
LOC +
1555 QString(
"VBI: Bad parity in EIA-608 data (%1)") .arg(data,0,16));
1562 if (program ==
nullptr)
1566 return program->pmt_section;
1571 AVProgram* program = av_find_program_from_stream(context,
nullptr, stream_index);
1585 if (!pmt_buffer.has_buffer())
1587 LOG(VB_GENERAL, LOG_DEBUG,
LOC +
1588 "ScanATSCCaptionStreams() called with no PMT");
1593 bool video_found =
false;
1617 desc_list.insert(desc_list.end(), desc_list2.begin(), desc_list2.end());
1619 for (
auto & desc : desc_list)
1661 std::array<std::map<int,uint>,2> lang_cc_cnt;
1678 else if (!pofr && sofr)
1704 LOG(VB_GENERAL, LOG_ERR,
LOC +
"in_tracks key too small");
1710 LOG(VB_PLAYBACK, LOG_INFO,
LOC +
1711 QString(
"%1 caption service #%2 is in the %3 language.")
1712 .arg((
type) ?
"EIA-708" :
"EIA-608")
1728 AVStream* st =
m_ic->streams[av_index];
1729 const AVDictionaryEntry* language_dictionary_entry =
1730 av_dict_get(st->metadata,
"language",
nullptr, 0);
1732 if (language_dictionary_entry ==
nullptr ||
1733 language_dictionary_entry->value ==
nullptr ||
1734 st->codecpar->extradata ==
nullptr
1740 std::vector<std::string_view> languages {
StringUtil::split_sv(language_dictionary_entry->value,
","sv)};
1742 if (st->codecpar->extradata_size !=
static_cast<int>(languages.size() * 2))
1746 for (
size_t i = 0; i < languages.size(); i++)
1748 if (languages[i].size() != 3)
1754 uint8_t teletext_type = st->codecpar->extradata[i * 2] >> 3;
1755 uint8_t teletext_magazine_number = st->codecpar->extradata[i * 2] & 0x7;
1756 if (teletext_magazine_number == 0)
1757 teletext_magazine_number = 8;
1758 uint8_t teletext_page_number = st->codecpar->extradata[(i * 2) + 1];
1759 if (teletext_type == 2 || teletext_type == 1)
1761 TrackType track = (teletext_type == 2) ?
1764 m_tracks[track].emplace_back(av_index, 0, language,
1765 (
static_cast<unsigned>(teletext_magazine_number) << 8) | teletext_page_number);
1766 LOG(VB_PLAYBACK, LOG_INFO,
LOC +
1767 QString(
"Teletext stream #%1 (%2) is in the %3 language on page %4 %5.")
1768 .arg(QString::number(i),
1769 (teletext_type == 2) ?
"Caption" :
"Menu",
1771 QString::number(teletext_magazine_number),
1772 QString::number(teletext_page_number)));
1781 AVDictionaryEntry *metatag =
1782 av_dict_get(
m_ic->streams[av_stream_index]->metadata,
"language",
nullptr,
1784 bool forced = (
m_ic->streams[av_stream_index]->disposition & AV_DISPOSITION_FORCED) != 0;
1787 LOG(VB_PLAYBACK, LOG_INFO,
LOC +
1788 QString(
"Text Subtitle track #%1 is A/V stream #%2 "
1789 "and is in the %3 language(%4), forced=%5.")
1792 StreamInfo si {av_stream_index, 0, lang, 0, forced};
1802 if (
m_itv ==
nullptr)
1804 if (
m_itv ==
nullptr)
1808 if (!pmt_buffer.has_buffer())
1819 LOG(VB_DSMCC, LOG_NOTICE, QString(
"ScanDSMCCStreams Found Object Carousel in Stream %1").arg(QString::number(i)));
1825 for (
const auto *desc : desc_list)
1828 uint length = *desc++;
1829 const unsigned char *endDesc = desc+length;
1830 uint dataBroadcastId = desc[0]<<8 | desc[1];
1831 LOG(VB_DSMCC, LOG_NOTICE, QString(
"ScanDSMCCStreams dataBroadcastId %1").arg(QString::number(dataBroadcastId)));
1832 if (dataBroadcastId != 0x0106)
1835 while (desc != endDesc)
1837 [[maybe_unused]]
uint appTypeCode = desc[0]<<8 | desc[1];
1839 uint appSpecDataLen = *desc++;
1841 LOG(VB_DSMCC, LOG_NOTICE, QString(
"ScanDSMCCStreams AppTypeCode %1").arg(QString::number(appTypeCode)));
1842 if (appTypeCode == 0x101)
1844 const unsigned char *subDescEnd = desc + appSpecDataLen;
1845 while (desc < subDescEnd)
1847 uint sub_desc_tag = *desc++;
1848 uint sub_desc_len = *desc++;
1850 if (sub_desc_tag == 1)
1851 m_itv->SetNetBootInfo(desc, sub_desc_len);
1852 desc += sub_desc_len;
1858 desc += appSpecDataLen;
1872 const AVCodec *codec =
nullptr;
1873 LOG(VB_PLAYBACK, LOG_INFO,
LOC +
"Trying to select best video track");
1887 int stream_index = av_find_best_stream(
m_ic, AVMEDIA_TYPE_VIDEO, -1, -1, &codec, 0);
1889 if (stream_index < 0)
1891 LOG(VB_PLAYBACK, LOG_INFO,
LOC +
"No video track found/selected.");
1892 return stream_index;
1895 AVStream *stream =
m_ic->streams[stream_index];
1906 if (codecContext->codec_type == AVMEDIA_TYPE_VIDEO)
1907 codectype += QString(
"(%1x%2)").arg(codecContext->width).arg(codecContext->height);
1908 LOG(VB_PLAYBACK, LOG_INFO,
LOC +
1909 QString(
"Selected track #%1: ID: 0x%2 Codec ID: %3 Profile: %4 Type: %5 Bitrate: %6")
1910 .arg(stream_index).arg(
static_cast<uint64_t
>(stream->id), 0, 16)
1911 .arg(avcodec_get_name(codecContext->codec_id),
1912 avcodec_profile_name(codecContext->codec_id, codecContext->profile),
1914 QString::number(codecContext->bit_rate)));
1921 if ((codecContext->width != stream->codecpar->width) || (codecContext->height != stream->codecpar->height))
1923 LOG(VB_GENERAL, LOG_INFO,
LOC + QString(
1924 "Video resolution mismatch: Context: %1x%2 Stream: %3x%4 Codec: %5 Stream change: %6")
1925 .arg(codecContext->width).arg(codecContext->height)
1926 .arg(stream->codecpar->width).arg(stream->codecpar->height)
1933 int width = std::max(dim.width(), 16);
1934 int height = std::max(dim.height(), 16);
1935 QString dec =
"ffmpeg";
1936 uint thread_count = 1;
1938 if (codecContext->codec)
1939 codecName = codecContext->codec->name;
1944 if (codecContext->framerate.den && codecContext->framerate.num)
1945 m_fps = float(codecContext->framerate.num) / float(codecContext->framerate.den);
1949 bool foundgpudecoder =
false;
1950 QStringList unavailabledecoders;
1960 LOG(VB_GENERAL, LOG_WARNING,
LOC + QString(
1961 "GPU/hardware decoder '%1' failed - forcing software decode")
1968 while (unavailabledecoders.size() < 10)
1972 if (!unavailabledecoders.isEmpty())
1974 LOG(VB_PLAYBACK, LOG_INFO,
LOC + QString(
"Unavailable decoders: %1")
1975 .arg(unavailabledecoders.join(
",")));
1981 if (!skip_loop_filter)
1982 codecContext->skip_loop_filter = AVDISCARD_NONKEY;
1990 if (
version && allowgpu && dec !=
"ffmpeg")
1994 codecContext->opaque =
static_cast<void*
>(
this);
1999 codecContext->opaque =
static_cast<void*
>(
this);
2001 foundgpudecoder =
true;
2006 unavailabledecoders.append(dec);
2014 LOG(VB_GENERAL, LOG_ERR,
LOC +
"Unknown video codec - defaulting to MPEG2");
2031 if (!foundgpudecoder)
2033 LOG(VB_PLAYBACK, LOG_INFO,
LOC + QString(
"Using %1 CPUs for decoding")
2034 .arg(HAVE_THREADS ? thread_count : 1));
2035 codecContext->thread_count =
static_cast<int>(thread_count);
2050 return stream_index;
2055 AVProgram* program = av_find_program_from_stream(
m_ic,
nullptr, stream_index);
2056 if (program ==
nullptr)
2061 LOG(VB_PLAYBACK, LOG_INFO,
2062 QString(
"Removing streams not in Program %1 from track selection.")
2063 .arg(QString::number(program->id)));
2065 const auto *
const begin = program->stream_index;
2066 const auto *
const end = program->stream_index + program->nb_stream_indexes;
2070 LOG(VB_PLAYBACK, LOG_DEBUG,
2071 QString(
"Size before: %1").arg(QString::number(track_list.size())));
2072 track_list.erase(std::remove_if(track_list.begin(), track_list.end(),
2075 return std::find(begin, end, i.m_av_stream_index) == end;
2076 }), track_list.end());
2077 LOG(VB_PLAYBACK, LOG_DEBUG,
2078 QString(
"Size after: %1").arg(QString::number(track_list.size())));
2084 return (ch_layout.order == AV_CHANNEL_ORDER_CUSTOM) &&
2085 (ch_layout.nb_channels == 2) &&
2086 (ch_layout.u.map[0].id == AV_CHAN_FRONT_CENTER) &&
2087 (ch_layout.u.map[1].id == AV_CHAN_FRONT_CENTER);
2095 bool unknownbitrate =
false;
2099 constexpr std::array<TrackType, 6>
types {
2113 std::map<int,uint> lang_sub_cnt;
2114 uint subtitleStreamCount = 0;
2115 std::map<int,uint> lang_aud_cnt;
2116 uint audioStreamCount = 0;
2125 if (
m_ic ==
nullptr)
2128 for (
uint strm = 0; strm <
m_ic->nb_streams; strm++)
2130 AVCodecParameters *par =
m_ic->streams[strm]->codecpar;
2133 if (par->codec_type == AVMEDIA_TYPE_VIDEO)
2134 codectype += QString(
"(%1x%2)").arg(par->width).arg(par->height);
2135 QString program_id =
"null";
2136 if (av_find_program_from_stream(
m_ic,
nullptr, strm) !=
nullptr)
2138 program_id = QString::number(av_find_program_from_stream(
m_ic,
nullptr, strm)->
id);
2140 LOG(VB_PLAYBACK, LOG_INFO,
LOC +
2141 QString(
"Stream #%1: ID: 0x%2 Program ID: %3 Codec ID: %4 Type: %5 Bitrate: %6").arg(
2142 QString::number(strm),
2143 QString::number(
static_cast<uint64_t
>(
m_ic->streams[strm]->id), 16),
2145 avcodec_get_name(par->codec_id),
2147 QString::number(par->bit_rate))
2150 switch (par->codec_type)
2152 case AVMEDIA_TYPE_VIDEO:
2160 if (ctx && (ctx->hw_frames_ctx || ctx->hw_device_ctx))
2167 LOG(VB_GENERAL, LOG_ERR,
LOC +
2168 QString(
"Stream #%1 has an unknown video "
2169 "codec id, skipping.").arg(strm));
2181 if (par->bit_rate == 0)
2183 static constexpr int64_t s_baseBitrate { 1000000LL };
2185 if (par->width && par->height)
2187 static const int s_baseSize = 1920 * 1080;
2188 multiplier = ((par->width * par->height) + s_baseSize - 1) / s_baseSize;
2189 multiplier = std::max(multiplier, 1);
2191 par->bit_rate = s_baseBitrate * multiplier;
2192 unknownbitrate =
true;
2198 case AVMEDIA_TYPE_AUDIO:
2200 LOG(VB_GENERAL, LOG_INFO,
LOC +
2201 QString(
"codec %1 has %2 channels")
2202 .arg(avcodec_get_name(par->codec_id))
2203 .arg(par->ch_layout.nb_channels));
2208 case AVMEDIA_TYPE_SUBTITLE:
2210 if (par->codec_id == AV_CODEC_ID_DVB_TELETEXT)
2212 if (par->codec_id == AV_CODEC_ID_TEXT)
2216 LOG(VB_PLAYBACK, LOG_INFO,
LOC + QString(
"subtitle codec (%1)")
2220 case AVMEDIA_TYPE_DATA:
2222 if (par->codec_id == AV_CODEC_ID_DVB_VBI)
2225 LOG(VB_PLAYBACK, LOG_INFO,
LOC + QString(
"data codec (%1)")
2229 case AVMEDIA_TYPE_ATTACHMENT:
2231 if (par->codec_id == AV_CODEC_ID_TTF)
2234 LOG(VB_PLAYBACK, LOG_INFO,
LOC +
2235 QString(
"Attachment codec (%1)")
2242 LOG(VB_PLAYBACK, LOG_ERR,
LOC +
2243 QString(
"Unknown codec type (%1)")
2249 if (par->codec_type != AVMEDIA_TYPE_AUDIO &&
2250 par->codec_type != AVMEDIA_TYPE_SUBTITLE)
2254 if (par->codec_type == AVMEDIA_TYPE_SUBTITLE &&
2255 (par->codec_id == AV_CODEC_ID_DVB_TELETEXT ||
2256 par->codec_id == AV_CODEC_ID_TEXT))
2259 LOG(VB_PLAYBACK, LOG_INFO,
LOC + QString(
"Looking for decoder for %1")
2260 .arg(avcodec_get_name(par->codec_id)));
2262 if (par->codec_id == AV_CODEC_ID_PROBE)
2264 LOG(VB_GENERAL, LOG_ERR,
LOC +
2265 QString(
"Probing of stream #%1 unsuccesful, ignoring.").arg(strm));
2271 if (codecContext ==
nullptr)
2273 LOG(VB_GENERAL, LOG_WARNING,
LOC +
2274 QString(
"Could not find decoder for codec (%1), ignoring.")
2275 .arg(avcodec_get_name(par->codec_id)));
2276 LOG(VB_LIBAV, LOG_INFO,
"For a list of all codecs, run `mythffmpeg -codecs`.");
2280 if (codecContext->codec && par->codec_id != codecContext->codec_id)
2282 LOG(VB_PLAYBACK, LOG_INFO,
LOC +
2283 QString(
"Already opened codec not matching (%1 vs %2). Reopening")
2284 .arg(avcodec_get_name(codecContext->codec_id),
2285 avcodec_get_name(codecContext->codec->id)));
2289 if (!
OpenAVCodec(codecContext, codecContext->codec))
2301 LOG(VB_PLAYBACK, LOG_INFO,
LOC +
2302 QString(
"Stream 0x%1 is not valid in this context - skipping")
2303 .arg(
m_ic->streams[strm]->id, 4, 16));
2307 if (par->codec_type == AVMEDIA_TYPE_SUBTITLE)
2309 bool forced = (
m_ic->streams[strm]->disposition & AV_DISPOSITION_FORCED) != 0;
2311 uint lang_indx = lang_sub_cnt[lang]++;
2312 subtitleStreamCount++;
2315 static_cast<int>(strm),
m_ic->streams[strm]->id, lang, lang_indx, forced);
2317 LOG(VB_PLAYBACK, LOG_INFO,
LOC +
2318 QString(
"Subtitle track #%1 is A/V stream #%2 "
2319 "and is in the %3 language(%4).")
2324 if (par->codec_type == AVMEDIA_TYPE_AUDIO)
2328 uint lang_indx = lang_aud_cnt[lang]++;
2331 int stream_id =
m_ic->streams[strm]->id;
2335 if (stream_id == -1)
2343 static_cast<int>(strm), stream_id, lang, lang_indx,
type);
2347 lang_indx = lang_aud_cnt[lang]++;
2349 static_cast<int>(strm), stream_id, lang, lang_indx,
type);
2352 LOG(VB_AUDIO, LOG_INFO,
LOC +
2353 QString(
"Audio Track #%1, of type (%2) is A/V stream #%3 (id=0x%4) "
2354 "and has %5 channels in the %6 language(%7).")
2356 .arg(strm).arg(
m_ic->streams[strm]->id,0,16).arg(codecContext->ch_layout.nb_channels)
2382 QString(
m_ic->iformat->name).contains(
"matroska"));
2424 for (
unsigned i = 0; i <
m_ic->nb_programs; i++)
2436#if CONFIG_MEDIACODEC
2437 if (QString(
"mediacodec") == codec->wrapper_name)
2438 av_jni_set_java_vm(QAndroidJniEnvironment::javaVM(),
nullptr);
2440 int ret = avcodec_open2(avctx, codec,
nullptr);
2445 LOG(VB_GENERAL, LOG_ERR,
LOC +
2446 QString(
"Could not open codec 0x%1, id(%2) type(%3) "
2447 "ignoring. reason %4").arg((uint64_t)avctx,0,16)
2448 .arg(avcodec_get_name(avctx->codec_id),
2454 LOG(VB_GENERAL, LOG_INFO,
LOC +
2455 QString(
"Opened codec 0x%1, id(%2) type(%3)")
2456 .arg((uint64_t)avctx,0,16)
2457 .arg(avcodec_get_name(avctx->codec_id),
2482 if (si.m_language_index == Index)
2483 return si.m_language;
2490 AVDictionaryEntry *metatag = av_dict_get(
m_ic->streams[StreamIndex]->metadata,
"language",
nullptr, 0);
2533 AVStream *stream =
m_ic->streams[StreamIndex];
2537 if (stream->disposition & AV_DISPOSITION_VISUAL_IMPAIRED)
2539 else if (stream->disposition & AV_DISPOSITION_COMMENT)
2541 else if (stream->disposition & AV_DISPOSITION_HEARING_IMPAIRED)
2543 else if (stream->disposition & AV_DISPOSITION_CLEAN_EFFECTS)
2570 if (
current->m_av_stream_index == streamIndex)
2576 LOG(VB_GENERAL, LOG_WARNING,
LOC +
2577 QString(
"Invalid stream index passed to "
2578 "SetupAudioStreamSubIndexes: %1").arg(streamIndex));
2585 if (
current->m_av_substream_index == -1)
2598 (next->m_av_stream_index != streamIndex))
2600 QString msg = QString(
2601 "Expected substream 1 (Language I) of stream %1\n\t\t\t"
2602 "following substream 0, found end of list or another stream.")
2605 LOG(VB_GENERAL, LOG_WARNING,
LOC + msg);
2627 bool do_flush =
false;
2628 for (
uint i = 0; i <
m_ic->nb_streams; i++)
2630 AVStream *st =
m_ic->streams[i];
2633 if (avctx && avctx->codec_type == AVMEDIA_TYPE_AUDIO)
2636 LOG(VB_LIBAV, LOG_DEBUG, QString(
"removing audio stream (id: 0x%1, index: %2, nb_streams: %3)")
2637 .arg(QString::number(st->id, 16),
2639 QString::number(
m_ic->nb_streams)
2643 if ((
m_ic->nb_streams - i) > 0) {
2644 std::memmove(
reinterpret_cast<void*
>(&
m_ic->streams[i]),
2645 reinterpret_cast<const void*
>(&
m_ic->streams[i + 1]),
2646 (
m_ic->nb_streams - i) *
sizeof(AVFormatContext*));
2650 m_ic->streams[i] =
nullptr;
2658 avformat_flush(
m_ic);
2667 if (!std::any_of(decoder->m_renderFormats->cbegin(), decoder->m_renderFormats->cend(),
2668 [&
type](
auto Format) { return type == Format; }))
2670 decoder->m_directRendering =
false;
2671 return avcodec_default_get_buffer2(c, pic, flags);
2674 decoder->m_directRendering =
true;
2675 MythVideoFrame *frame = decoder->GetPlayer()->GetNextVideoFrame();
2685 if ((frame->
m_type !=
type) || (pic->width > width) || (pic->height > height))
2702 for (
uint i = 0; i < 3; i++)
2708 pic->opaque = frame;
2711 AVBufferRef *buffer = av_buffer_create(
reinterpret_cast<uint8_t*
>(frame), 0,
2712 [](
void* Opaque, uint8_t* Data)
2716 if (avfd && avfd->GetPlayer())
2717 avfd->GetPlayer()->DeLimboFrame(vf);
2720 pic->buf[0] = buffer;
2726int get_avf_buffer_dxva2(
struct AVCodecContext *c,
AVFrame *pic,
int )
2731 for (
int i = 0; i < 4; i++)
2733 pic->data[i] =
nullptr;
2734 pic->linesize[i] = 0;
2736 pic->opaque = frame;
2738 pic->data[0] = (uint8_t*)frame->
m_buffer;
2739 pic->data[3] = (uint8_t*)frame->
m_buffer;
2742 AVBufferRef *buffer =
2743 av_buffer_create((uint8_t*)frame, 0,
2744 [](
void* Opaque, uint8_t* Data)
2752 pic->buf[0] = buffer;
2763 bool had_608 =
false;
2764 bool had_708 =
false;
2765 for (
uint cur = 0; cur + 2 < buf_size; cur += 3)
2767 uint cc_code = buf[cur];
2768 bool cc_valid = (cc_code & 0x04) != 0U;
2770 uint data1 = buf[cur+1];
2771 uint data2 = buf[cur+2];
2772 uint data = (data2 << 8) | data1;
2773 uint cc_type = cc_code & 0x03;
2798 bool check_608,
bool check_708)
2800 bool need_change_608 =
false;
2805 for (
uint i = 0; i < 4; i++)
2812 bool need_change_708 =
false;
2814 if (check_708 || need_change_608)
2817 for (
uint i = 1; i < 64 && !need_change_608 && !need_change_708; i++)
2822 if (need_change_708 && !check_608)
2826 if (!need_change_608 && !need_change_708)
2837 for (
int i = 1; i < 64; i++)
2846 for (
int i = 0; i < 4; i++)
2867 AVPacket *pkt,
bool can_reliably_parse_keyframes)
2872 bool reset_kfd =
false;
2876 LOG(VB_PLAYBACK, LOG_INFO,
LOC +
2877 "gopset not set, syncing positionMap");
2879 if (tempKeyFrameDist > 0 && !
m_livetv)
2881 LOG(VB_PLAYBACK, LOG_INFO,
LOC +
2882 QString(
"Initial key frame distance: %1.")
2888 else if (
m_keyframeDist != tempKeyFrameDist && tempKeyFrameDist > 0)
2890 LOG(VB_PLAYBACK, LOG_INFO,
LOC +
2891 QString(
"Key frame distance changed from %1 to %2.")
2919 if (can_reliably_parse_keyframes &&
2922 long long last_frame = 0;
2930 LOG(VB_PLAYBACK, LOG_DEBUG,
LOC +
2931 QString(
"framesRead: %1 last_frame: %2 keyframedist: %3")
2938 long long startpos = pkt->pos;
2940 LOG(VB_PLAYBACK | VB_TIMESTAMP, LOG_INFO,
LOC +
2941 QString(
"positionMap[ %1 ] == %2.")
2971 float bytespersec = (float)
m_bitrate / 8;
2988 const uint8_t *bufptr = pkt->data;
2989 const uint8_t *bufend = pkt->data + pkt->size;
2991 while (bufptr < bufend)
2995 float aspect_override = -1.0F;
3004 if (bufptr + 11 >= pkt->data + pkt->size)
3006 const auto *seq =
reinterpret_cast<const SequenceHeader*
>(bufptr);
3008 int width =
static_cast<int>(seq->width()) >> context->lowres;
3009 int height =
static_cast<int>(seq->height()) >> context->lowres;
3010 float aspect = seq->
aspect(context->codec_id == AV_CODEC_ID_MPEG1VIDEO);
3011 if (stream->sample_aspect_ratio.num)
3012 aspect =
static_cast<float>(av_q2d(stream->sample_aspect_ratio) * width / height);
3013 if (aspect_override > 0.0F)
3014 aspect = aspect_override;
3015 float seqFPS = seq->fps();
3019 changed |= (seqFPS >
static_cast<float>(
m_fps)+0.01F) ||
3020 (seqFPS < static_cast<float>(
m_fps)-0.01F);
3024 bool forceaspectchange = !qFuzzyCompare(
m_currentAspect + 10.0F, aspect + 10.0F) &&
3028 if (changed || forceaspectchange)
3033 bool doublerate =
false;
3036 forceaspectchange, 2,
3039 if (context->hw_frames_ctx)
3040 if (context->internal)
3041 avcodec_flush_buffers(context);
3055 if ((seqFPS > avFPS+0.01F) || (seqFPS < avFPS-0.01F))
3057 LOG(VB_PLAYBACK, LOG_INFO,
LOC + QString(
"avFPS(%1) != seqFPS(%2)")
3058 .arg(
static_cast<double>(avFPS)).arg(
static_cast<double>(seqFPS)));
3067 pkt->flags |= AV_PKT_FLAG_KEY;
3074 pkt->flags |= AV_PKT_FLAG_KEY;
3082 const uint8_t *buf = pkt->data;
3083 const uint8_t *buf_end = pkt->data + pkt->size;
3088 if (context->extradata && (context->extradata_size >= 7) && (context->extradata[0] == 0x01))
3090 if (pkt->flags & AV_PKT_FLAG_KEY)
3095 while (buf < buf_end)
3126 bool fps_changed = (seqFPS > 0.0) && ((seqFPS >
m_fps + 0.01) ||
3127 (seqFPS <
m_fps - 0.01));
3132 if (fps_changed || res_changed || forcechange)
3137 bool doublerate =
false;
3150 if (context->hw_frames_ctx && (forcechange || res_changed))
3151 if (context->internal)
3152 avcodec_flush_buffers(context);
3158 m_fps =
static_cast<float>(seqFPS);
3168 if ((seqFPS > avFPS + 0.01) || (seqFPS < avFPS - 0.01))
3170 LOG(VB_PLAYBACK, LOG_INFO,
LOC +
3171 QString(
"avFPS(%1) != seqFPS(%2)").arg(avFPS).arg(seqFPS));
3176 pkt->flags |= AV_PKT_FLAG_KEY;
3196 if (pkt->flags & AV_PKT_FLAG_KEY)
3212 !(pkt->flags & AV_PKT_FLAG_KEY))
3214 av_packet_unref(pkt);
3248 bool sentPacket =
false;
3268 if (ret == AVERROR(EAGAIN))
3272 if (ret==0 && !gotpicture)
3274 ret2 = avcodec_send_packet(context, pkt);
3275 if (ret2 == AVERROR(EAGAIN))
3287 if (ret < 0 || ret2 < 0)
3292 LOG(VB_GENERAL, LOG_ERR,
LOC +
3293 QString(
"video avcodec_receive_frame error: %1 (%2) gotpicture:%3")
3295 .arg(ret).arg(gotpicture));
3300 LOG(VB_GENERAL, LOG_ERR,
LOC +
3301 QString(
"video avcodec_send_packet error: %1 (%2) gotpicture:%3")
3303 .arg(ret2).arg(gotpicture));
3317 LOG(VB_GENERAL, LOG_INFO,
LOC +
"Decoder needs reset");
3321 if (ret == AVERROR_EXTERNAL || ret2 == AVERROR_EXTERNAL)
3323 LOG(VB_PLAYBACK, LOG_INFO,
LOC +
"FFmpeg external library error - assuming streams changed");
3335 LOG(VB_PLAYBACK | VB_TIMESTAMP, LOG_INFO,
LOC +
3336 QString(
"video timecodes packet-pts:%1 frame-pts:%2 packet-dts: %3 frame-dts:%4")
3337 .arg(pkt->pts).arg(mpa_pic->pts).arg(pkt->dts)
3338 .arg(mpa_pic->pkt_dts));
3347 auto *newPkt = av_packet_clone(pkt);
3357 auto * side_data = av_frame_get_side_data(AvFrame, AV_FRAME_DATA_A53_CC);
3358 if (side_data && (side_data->size > 0))
3371 frame->m_directRendering =
false;
3382 av_image_fill_arrays(tmppicture.data, tmppicture.linesize,
3383 frame->m_buffer, AV_PIX_FMT_YUV420P, AvFrame->width,
3384 AvFrame->height, IMAGE_ALIGN);
3385 tmppicture.data[0] = frame->m_buffer + frame->m_offsets[0];
3386 tmppicture.data[1] = frame->m_buffer + frame->m_offsets[1];
3387 tmppicture.data[2] = frame->m_buffer + frame->m_offsets[2];
3388 tmppicture.linesize[0] = frame->m_pitches[0];
3389 tmppicture.linesize[1] = frame->m_pitches[1];
3390 tmppicture.linesize[2] = frame->m_pitches[2];
3394 AvFrame->height,
static_cast<AVPixelFormat
>(AvFrame->format),
3395 AvFrame->width, AvFrame->height,
3396 AV_PIX_FMT_YUV420P, SWS_FAST_BILINEAR,
3397 nullptr,
nullptr,
nullptr);
3400 LOG(VB_GENERAL, LOG_ERR,
LOC +
"Failed to allocate sws context");
3403 sws_scale(
m_swsCtx, AvFrame->data, AvFrame->linesize, 0, dim.height(),
3404 tmppicture.data, tmppicture.linesize);
3412 oldframe->
m_interlaced = (AvFrame->flags & AV_FRAME_FLAG_INTERLACED) != 0;
3413 oldframe->
m_topFieldFirst = (AvFrame->flags & AV_FRAME_FLAG_TOP_FIELD_FIRST) != 0;
3439 LOG(VB_GENERAL, LOG_ERR,
LOC +
"NULL videoframe - direct rendering not "
3440 "correctly initialized.");
3445 if (AvFrame->best_effort_timestamp == AV_NOPTS_VALUE)
3447 LOG(VB_GENERAL, LOG_ERR,
LOC +
"No PTS found - unable to process video.");
3451 AvFrame->best_effort_timestamp * 1000);
3452 std::chrono::milliseconds temppts =
pts;
3469 double calcfps = 1000.0 /
ptsdiff.count();
3470 if (calcfps < 121.0 && calcfps > 3.0)
3474 double fpschange = calcfps /
m_fps;
3476 if (fpschange > 1.9 && fpschange < 2.1)
3478 if (fpschange > 0.9 && fpschange < 1.1)
3484 LOG(VB_PLAYBACK | VB_TIMESTAMP, LOG_INFO,
LOC +
3485 QString(
"video timecode %1 %2 %3 %4%5")
3486 .arg(AvFrame->best_effort_timestamp)
3487 .arg(
pts.count()).arg(temppts.count()).arg(
m_lastVPts.count())
3488 .arg((
pts != temppts) ?
" fixup" :
""));
3490 frame->m_interlaced = (AvFrame->flags & AV_FRAME_FLAG_INTERLACED) != 0;
3491 frame->m_topFieldFirst = (AvFrame->flags & AV_FRAME_FLAG_TOP_FIELD_FIRST) != 0;
3493 frame->m_repeatPic = AvFrame->repeat_pict != 0;
3498 frame->m_colorspace = AvFrame->colorspace;
3499 frame->m_colorrange = AvFrame->color_range;
3500 frame->m_colorprimaries = AvFrame->color_primaries;
3501 frame->m_colortransfer = AvFrame->color_trc;
3502 frame->m_chromalocation = AvFrame->chroma_location;
3503 frame->m_pixFmt = AvFrame->format;
3508 frame->m_dummy =
false;
3509 frame->m_pauseFrame =
false;
3510 frame->m_deinterlaceInuse2x =
false;
3511 frame->m_alreadyDeinterlaced =
false;
3512 frame->m_interlacedReverse =
false;
3542 [[maybe_unused]]
const AVStream *stream,
const AVPacket *pkt)
3544 const uint8_t *buf = pkt->data;
3545 uint64_t linemask = 0;
3550 if ((buf[0]==
't') && (buf[1]==
'v') && (buf[2] ==
'0'))
3553 memcpy(&linemask, buf + 3, 8);
3556 else if ((buf[0]==
'T') && (buf[1]==
'V') && (buf[2] ==
'0'))
3558 linemask = 0xffffffffffffffffLL;
3563 LOG(VB_VBI, LOG_ERR,
LOC + QString(
"Unknown VBI data stream '%1%2%3'")
3564 .arg(QChar(buf[0])).arg(QChar(buf[1])).arg(QChar(buf[2])));
3568 static constexpr uint kMinBlank = 6;
3569 for (
uint i = 0; i < 36; i++)
3571 if (!((linemask >> i) & 0x1))
3574 const uint line = ((i < 18) ? i : i-18) + kMinBlank;
3575 const uint field = (i<18) ? 0 : 1;
3576 const uint id2 = *buf & 0xf;
3600 int data = (buf[2] << 8) | buf[1];
3627 const AVStream* ,
const AVPacket *pkt)
3636 const uint8_t *buf = pkt->data;
3637 const uint8_t *buf_end = pkt->data + pkt->size;
3639 if (*buf >= 0x10 && *buf <= 0x1F)
3645 LOG(VB_VBI, LOG_WARNING,
LOC +
3646 QString(
"VBI: Unknown data_identier: %1 discarded").arg(*buf));
3651 while (buf < buf_end)
3656 if ((buf_end - buf) >= 42)
3660 else if (*buf == 0x03)
3663 if ((buf_end - buf) >= 42)
3667 else if (*buf == 0xff)
3673 LOG(VB_VBI, LOG_WARNING,
LOC +
3674 QString(
"VBI: Unsupported data_unit_id: %1 discarded").arg(*buf));
3684 [[maybe_unused]]
const AVPacket *pkt)
3687 if (
m_itv ==
nullptr)
3689 if (
m_itv ==
nullptr)
3693 uint8_t *data = pkt->data;
3694 int length = pkt->size;
3695 int componentTag = 0;
3696 int dataBroadcastId = 0;
3697 unsigned carouselId = 0;
3700 componentTag = str->component_tag;
3701 dataBroadcastId = str->data_id;
3702 carouselId = (unsigned) str->carousel_id;
3707 uint16_t sectionLen = (((data[1] & 0xF) << 8) | data[2]) + 3;
3709 if (sectionLen > length)
3712 m_itv->ProcessDSMCCSection(data, sectionLen,
3713 componentTag, carouselId,
3715 length -= sectionLen;
3726 long long pts = pkt->pts;
3727 if (
pts == AV_NOPTS_VALUE)
3729 if (
pts == AV_NOPTS_VALUE)
3731 LOG(VB_GENERAL, LOG_ERR,
LOC +
"No PTS found - unable to process subtitle.");
3734 pts =
static_cast<long long>(av_q2d(curstream->time_base) *
pts * 1000);
3740 bool isForcedTrack =
false;
3743 int gotSubtitles = 0;
3744 AVSubtitle subtitle;
3745 memset(&subtitle, 0,
sizeof(AVSubtitle));
3752 curstream->id,
pts);
3756 if (pkt->stream_index == subIdx)
3760 pkt->data, pkt->size,
pts);
3766 || pkt->stream_index == forcedSubIdx)
3769 avcodec_decode_subtitle2(codecContext, &subtitle, &gotSubtitles, pkt);
3772 subtitle.start_display_time +=
pts;
3773 subtitle.end_display_time +=
pts;
3775 if (pkt->stream_index != subIdx)
3776 isForcedTrack =
true;
3783 for (
unsigned i = 0; i < subtitle.num_rects; i++)
3785 subtitle.rects[i]->flags |= AV_SUBTITLE_FLAG_FORCED;
3788 LOG(VB_PLAYBACK | VB_TIMESTAMP, LOG_INFO,
LOC +
3789 QString(
"subtl timecode %1 %2 %3 %4")
3790 .arg(pkt->pts).arg(pkt->dts)
3791 .arg(subtitle.start_display_time)
3792 .arg(subtitle.end_display_time));
3795 subtitle, curstream->codecpar->codec_id == AV_CODEC_ID_XSUB,
3809 auto id =
static_cast<uint>(Packet->stream_index + 0x2000);
3813#if QT_VERSION < QT_VERSION_CHECK(6,0,0)
3814 const auto * codec = QTextCodec::codecForName(
"utf-8");
3815 auto text = codec->toUnicode(
reinterpret_cast<const char *
>(Packet->data), Packet->size - 1);
3817 auto toUtf16 = QStringDecoder(QStringDecoder::Utf8);
3818 QString text = toUtf16.decode(Packet->data);
3820 auto list = text.split(
'\n', Qt::SkipEmptyParts);
3828 enum AVCodecID codec_id = curstream->codecpar->codec_id;
3832 case AV_CODEC_ID_MPEG2VBI:
3835 case AV_CODEC_ID_DVB_VBI:
3838 case AV_CODEC_ID_DSMCC_B:
3863 LOG(VB_AUDIO, LOG_INFO,
LOC +
"Audio stream type " + msg +
"changed.");
3877 QString forcedString = forced ? QObject::tr(
" (forced)") :
"";
3879 int av_index =
m_tracks[
type][TrackNo].m_av_stream_index;
3880 AVStream *stream {
nullptr };
3881 if (av_index >= 0 && av_index < (
int)
m_ic->nb_streams)
3882 stream =
m_ic->streams[av_index];
3883 AVDictionaryEntry *entry =
3884 stream ? av_dict_get(stream->metadata,
"title",
nullptr, 0) :
nullptr;
3885 QString user_title = entry ? QString(R
"( "%1")").arg(entry->value) : "";
3897 AVCodecParameters *par = stream->codecpar;
3899 if (par->codec_id == AV_CODEC_ID_MP3)
3900 msg += QString(
" MP3");
3901 else if (ctx && ctx->codec)
3902 msg += QString(
" %1").arg(ctx->codec->name).toUpper();
3903 if (!user_title.isEmpty())
3906 int channels = par->ch_layout.nb_channels;
3909 msg += QString(
" ?ch");
3910 else if((channels > 4) && !(channels & 1))
3911 msg += QString(
" %1.1ch").arg(channels - 1);
3913 msg += QString(
" %1ch").arg(channels);
3923 if (!user_title.isEmpty())
3926 msg += QString(
" (%1)")
3930 return QString(
"%1: %2").arg(TrackNo + 1).arg(msg);
3934 return QObject::tr(
"Subtitle") + QString(
" %1: %2%3%4")
3935 .arg(QString::number(TrackNo + 1),
3963 return ctx ? QByteArray(
reinterpret_cast<char*
>(ctx->subtitle_header), ctx->subtitle_header_size) :
3974 AVDictionaryEntry *tag = av_dict_get(
m_ic->streams[index]->metadata,
"filename",
nullptr, 0);
3976 Filename = QByteArray(tag->value);
3977 AVCodecParameters *par =
m_ic->streams[index]->codecpar;
3978 Data = QByteArray(
reinterpret_cast<char*
>(par->extradata), par->extradata_size);
3988 if ((stream->component_tag == Tag) || ((Tag <= 0) && stream->component_tag <= 0))
3997 for (
uint i = 0; i <
m_ic->nb_streams; i++)
3999 AVStream *stream =
m_ic->streams[i];
4002 if (stream->component_tag == Tag)
4026 const std::vector<int> &ftype)
4028 std::vector<int> ret;
4030 for (
int index : ftype)
4032 if ((lang_key < 0) || tracks[index].m_language == lang_key)
4033 ret.push_back(index);
4041 std::vector<int> ret;
4043 for (
size_t i = 0; i < tracks.size(); i++)
4045 if (tracks[i].m_audio_type ==
type)
4054 const std::vector<int>&fs,
4055 enum AVCodecID codecId,
4058 int selectedTrack = -1;
4063 const int stream_index = tracks[f].m_av_stream_index;
4064 AVCodecParameters *par = ic->streams[stream_index]->codecpar;
4065 if ((codecId == AV_CODEC_ID_NONE || codecId == par->codec_id) &&
4066 (max_seen < par->ch_layout.nb_channels))
4068 if (codecId == AV_CODEC_ID_DTS &&
profile > 0)
4075 max_seen = par->ch_layout.nb_channels;
4079 return selectedTrack;
4087 std::vector<int> flang =
filter_lang(atracks, lang_key, ftype);
4092 FF_PROFILE_DTS_HD_MA);
4103 FF_PROFILE_DTS_HD_HRA);
4179 uint numStreams = atracks.size();
4183 if ((ctrack >= 0) && (ctrack < (
int)numStreams))
4186 LOG(VB_AUDIO, LOG_DEBUG, QString(
"%1 available audio streams").arg(numStreams));
4187 for (
const auto & track : atracks)
4189 AVCodecParameters *codecpar =
m_ic->streams[track.m_av_stream_index]->codecpar;
4190 LOG(VB_AUDIO, LOG_DEBUG, QString(
"%1: %2 bps, %3 Hz, %4 channels, passthrough(%5)")
4191 .arg(avcodec_get_name(codecpar->codec_id), QString::number(codecpar->bit_rate),
4192 QString::number(codecpar->sample_rate), QString::number(codecpar->ch_layout.nb_channels),
4197 if (1 == numStreams)
4207 LOG(VB_AUDIO, LOG_INFO,
LOC +
"Trying to reselect audio sub-stream");
4213 for (
uint i = 0; i < numStreams; i++)
4215 if (atracks[i].m_av_substream_index == substream_index)
4223 if ((selTrack < 0) && wlang >= -1)
4225 LOG(VB_AUDIO, LOG_INFO,
LOC +
"Trying to reselect audio track");
4230 for (
uint i = 0; i < numStreams; i++)
4232 if (wlang == atracks[i].m_language)
4236 if (windx == atracks[i].m_language_index)
4244 LOG(VB_AUDIO, LOG_INFO,
LOC +
"Trying to select audio track (w/lang)");
4251 LOG(VB_AUDIO, LOG_WARNING,
"No audio tracks matched the type filter, "
4252 "so trying all tracks.");
4253 for (
int i = 0; i < static_cast<int>(atracks.size()); i++)
4279 LOG(VB_AUDIO, LOG_INFO,
LOC +
"Trying to select default track");
4280 for (
size_t i = 0; i < atracks.size(); i++) {
4281 int idx = atracks[i].m_av_stream_index;
4282 if (
m_ic->streams[idx]->disposition & AV_DISPOSITION_DEFAULT)
4293 LOG(VB_AUDIO, LOG_INFO,
LOC +
4294 "Trying to select audio track (wo/lang)");
4304 if (ctrack != selTrack)
4306 LOG(VB_AUDIO, LOG_INFO,
LOC +
"No suitable audio track exists.");
4313 strack = atracks[selTrack];
4318 LOG(VB_AUDIO, LOG_INFO,
LOC + QString(
"Selected track %1 (A/V Stream #%2)")
4327 char *buffer,
int bufsize)
4338 const uint halfsample = samplesize >> 1;
4340 const char *from = (channel == 1) ? buffer + halfsample : buffer;
4341 char *to = (channel == 0) ? buffer + halfsample : buffer;
4344 (sample++), (from += samplesize), (to += samplesize))
4346 memmove(to, from, halfsample);
4355 bool firstloop =
true;
4356 int decoded_size = -1;
4363 AVPacket *tmp_pkt = av_packet_alloc();
4364 tmp_pkt->data = pkt->data;
4365 tmp_pkt->size = pkt->size;
4366 while (tmp_pkt->size > 0)
4368 bool reselectAudioTrack =
false;
4373 LOG(VB_AUDIO, LOG_INFO,
LOC +
4374 "Audio is disabled - trying to restart it");
4375 reselectAudioTrack =
true;
4380 bool wasDual = audSubIdx != -1;
4382 if ((wasDual && !isDual) || (!wasDual && isDual))
4385 reselectAudioTrack =
true;
4390 bool already_decoded =
false;
4391 if (!context->ch_layout.nb_channels)
4403 AVChannelLayout channel_layout;
4405 av_opt_set_chlayout(context->priv_data,
"downmix", &channel_layout, 0);
4407 if (context->codec_id == AV_CODEC_ID_AC3)
4412 decoded_size = data_size;
4413 already_decoded =
true;
4414 reselectAudioTrack |= context->ch_layout.nb_channels;
4418 if (reselectAudioTrack)
4428 if (!(decodetype &
kDecodeAudio) || (pkt->stream_index != audIdx)
4432 if (firstloop && pkt->pts != AV_NOPTS_VALUE)
4445 LOG(VB_GENERAL, LOG_INFO,
LOC +
"Audio stream changed");
4448 LOG(VB_GENERAL, LOG_INFO,
LOC + QString(
"Number of audio channels changed from %1 to %2")
4460 if (!already_decoded)
4465 decoded_size = data_size;
4473 data_size = tmp_pkt->size;
4479 if (!already_decoded)
4483 AVChannelLayout channel_layout;
4485 av_opt_set_chlayout(context->priv_data,
"downmix", &channel_layout, 0);
4489 decoded_size = data_size;
4496 LOG(VB_GENERAL, LOG_ERR,
LOC +
"Unknown audio decoding error");
4497 av_packet_free(&tmp_pkt);
4503 tmp_pkt->data += ret;
4504 tmp_pkt->size -= ret;
4508 std::chrono::milliseconds temppts =
m_lastAPts;
4515 int frames = (context->ch_layout.nb_channels <= 0 || decoded_size < 0 || !samplesize) ? -1 :
4516 decoded_size / (context->ch_layout.nb_channels * samplesize);
4525 ((
double)(frames * 1000) / context->sample_rate);
4528 LOG(VB_TIMESTAMP, LOG_INFO,
LOC + QString(
"audio timecode %1 %2 %3 %4")
4529 .arg(pkt->pts).arg(pkt->dts).arg(temppts.count()).arg(
m_lastAPts.count()));
4534 tmp_pkt->data += ret;
4535 tmp_pkt->size -= ret;
4539 av_packet_free(&tmp_pkt);
4546 AVPacket *pkt =
nullptr;
4547 bool have_err =
false;
4549 const DecodeType origDecodetype = decodetype;
4557 bool storevideoframes =
false;
4574 decodetype = (
DecodeType)((
int)decodetype & ~kDecodeVideo);
4590 decodetype = (
DecodeType)((
int)decodetype & ~kDecodeAudio);
4624 storevideoframes =
true;
4630 LOG(VB_GENERAL, LOG_WARNING,
LOC +
4631 QString(
"Audio %1 ms behind video but already %2 "
4632 "video frames queued. AV-Sync might be broken.")
4643 av_packet_free(&pkt);
4649 pkt = av_packet_alloc();
4652 if (
m_ic !=
nullptr)
4654 if ((
m_ic ==
nullptr) || (retval < 0))
4656 if (retval == -EAGAIN)
4660 av_packet_free(&pkt);
4662 LOG(VB_GENERAL, LOG_ERR, QString(
"decoding error %1 (%2)")
4664 QString::number(retval)));
4677 LOG(VB_GENERAL, LOG_ERR,
LOC +
"No context");
4678 av_packet_unref(pkt);
4682 if (pkt->stream_index >= (
int)
m_ic->nb_streams)
4684 LOG(VB_GENERAL, LOG_ERR,
LOC +
"Bad stream");
4685 av_packet_unref(pkt);
4689 AVStream *curstream =
m_ic->streams[pkt->stream_index];
4693 LOG(VB_GENERAL, LOG_ERR,
LOC +
"Bad stream (NULL)");
4694 av_packet_unref(pkt);
4698 enum AVMediaType codec_type = curstream->codecpar->codec_type;
4699 const AVCodecID codec_id = curstream->codecpar->codec_id;
4705 case AVMEDIA_TYPE_VIDEO:
4706 if (storevideoframes)
4713 case AVMEDIA_TYPE_AUDIO:
4715 if (codec_id == AV_CODEC_ID_AC4)
4717 av_packet_unref(pkt);
4721 case AVMEDIA_TYPE_SUBTITLE:
4724 case AV_CODEC_ID_TEXT:
4726 av_packet_unref(pkt);
4728 case AV_CODEC_ID_DVB_TELETEXT:
4730 av_packet_unref(pkt);
4736 case AVMEDIA_TYPE_DATA:
4738 av_packet_unref(pkt);
4746 if (context ==
nullptr)
4748 if (codec_type != AVMEDIA_TYPE_VIDEO)
4750 LOG(VB_PLAYBACK, LOG_ERR,
LOC +
4751 QString(
"No codec for stream index %1, type(%2) id(%3:%4)")
4752 .arg(QString::number(pkt->stream_index),
4754 avcodec_get_name(codec_id),
4755 QString::number(codec_id)
4762 av_packet_unref(pkt);
4770 case AVMEDIA_TYPE_AUDIO:
4779 case AVMEDIA_TYPE_VIDEO:
4793 av_packet_free(&pkt);
4797 if (pkt->pts != AV_NOPTS_VALUE)
4800 (av_q2d(curstream->time_base)*pkt->pts*1000000);
4815 case AVMEDIA_TYPE_SUBTITLE:
4824 LOG(VB_GENERAL, LOG_ERR,
LOC +
4825 QString(
"Decoding - id(%1) type(%2)")
4826 .arg(avcodec_get_name(codec_id),
4833 if (!have_err && !Retry)
4835 av_packet_unref(pkt);
4840 av_packet_free(&pkt);
4848 LOG(VB_PLAYBACK, LOG_INFO,
LOC + QString(
"StreamChangeCheck skip SeekReset"));
4858 int result = av_read_frame(ctx, pkt);
4866 if (pmt_buffer.has_buffer())
4923 if (stream < 0 || !
m_ic)
4925 return avcodec_get_name(
m_ic->streams[stream]->codecpar->codec_id);
4939 QString msg = (disable) ?
"Disabling" :
"Allowing";
4940 LOG(VB_AUDIO, LOG_INFO,
LOC + msg +
" pass through");
4963 switch (ctx->codec_id)
4965 case AV_CODEC_ID_AC3:
4966 case AV_CODEC_ID_TRUEHD:
4967 case AV_CODEC_ID_EAC3:
4968 case AV_CODEC_ID_MLP:
4969 case AV_CODEC_ID_DTS:
4978 bool passthru =
false;
4982 if (!withProfile && par->codec_id == AV_CODEC_ID_DTS && !
m_audio->
CanDTSHD())
4985 par->codec_id, FF_PROFILE_DTS);
4990 par->codec_id, par->profile);
5006 AVStream *curstream =
nullptr;
5007 AVCodecContext *ctx =
nullptr;
5009 int requested_channels = 0;
5013 (
int)
m_ic->nb_streams))
5016 .m_av_stream_index];
5017 if (curstream !=
nullptr)
5024 LOG(VB_PLAYBACK, LOG_INFO,
LOC +
"No codec context. Returning false");
5030 ctx->bits_per_raw_sample);
5032 if (av_sample_fmt_is_planar(ctx->sample_fmt))
5034 LOG(VB_AUDIO, LOG_INFO,
LOC + QString(
"Audio data is planar"));
5039 int bps = av_get_bytes_per_sample(ctx->sample_fmt) << 3;
5040 if (ctx->sample_fmt == AV_SAMPLE_FMT_S32 &&
5041 ctx->bits_per_raw_sample)
5042 bps = ctx->bits_per_raw_sample;
5043 LOG(VB_GENERAL, LOG_ERR,
LOC +
5044 QString(
"Unsupported sample format with %1 bits").arg(bps));
5048 bool using_passthru =
DoPassThrough(curstream->codecpar,
false);
5050 requested_channels = ctx->ch_layout.nb_channels;
5052 if (!using_passthru &&
5058 AVChannelLayout channel_layout;
5059 av_channel_layout_default(&channel_layout, requested_channels);
5060 av_opt_set_chlayout(ctx->priv_data,
"downmix", &channel_layout, 0);
5064 requested_channels, using_passthru, ctx->ch_layout.nb_channels,
5065 ctx->codec_id == AV_CODEC_ID_DTS ? ctx->profile : 0);
5069 LOG(VB_AUDIO, LOG_INFO,
LOC +
"Initializing audio parms from " +
5074 LOG(VB_AUDIO, LOG_INFO,
LOC +
"Audio format changed " +
5075 QString(
"\n\t\t\tfrom %1 to %2")
5091 switch (ctx->codec_id)
5093 case AV_CODEC_ID_MP2:
5096 case AV_CODEC_ID_MP3:
5099 case AV_CODEC_ID_AC3:
5102 case AV_CODEC_ID_DTS:
5105 case AV_CODEC_ID_VORBIS:
5108 case AV_CODEC_ID_WMAV1:
5111 case AV_CODEC_ID_WMAV2:
5119 lcd->setAudioFormatLEDs(audio_format,
true);
5154 int64_t start_time = INT64_MAX;
5155 int64_t end_time = INT64_MIN;
5156 AVStream *st =
nullptr;
5158 for (
uint i = 0; i < ic->nb_streams; i++)
5160 AVStream *st1 = ic->streams[i];
5161 if (st1 && st1->codecpar->codec_type == AVMEDIA_TYPE_VIDEO)
5170 int64_t duration = INT64_MIN;
5171 if (st->start_time != AV_NOPTS_VALUE && st->time_base.den) {
5172 int64_t start_time1= av_rescale_q(st->start_time, st->time_base, AV_TIME_BASE_Q);
5173 start_time = std::min(start_time1, start_time);
5174 if (st->duration != AV_NOPTS_VALUE) {
5175 int64_t end_time1 = start_time1 +
5176 av_rescale_q(st->duration, st->time_base, AV_TIME_BASE_Q);
5177 end_time = std::max(end_time1, end_time);
5180 if (st->duration != AV_NOPTS_VALUE) {
5181 int64_t duration1 = av_rescale_q(st->duration, st->time_base, AV_TIME_BASE_Q);
5182 duration = std::max(duration1, duration);
5184 if (start_time != INT64_MAX) {
5185 ic->start_time = start_time;
5186 if (end_time != INT64_MIN) {
5187 duration = std::max(end_time - start_time, duration);
5190 if (duration != INT64_MIN) {
5191 ic->duration = duration;
5194 int64_t filesize = avio_size(ic->pb);
5197 ic->bit_rate = (double)filesize * 8.0 * AV_TIME_BASE /
5198 (
double)ic->duration;
5214 if (
m_ic ==
nullptr)
5219 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.
static bool has_optimized_SIMD()
Returns true if the processor supports MythTV's optimized SIMD for AudioOutputUtil/AudioConvert.
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.
std::enable_if_t< std::chrono::__is_duration< T >::value, T > GetDurSetting(const QString &key, T defaultval=T::zero())
bool GetBoolSetting(const QString &key, bool defaultval=false)
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 const std::array< const uint64_t, 4 > samples
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.
MPUBLIC std::string av_make_error_stdstring_unknown(int errnum)
std::enable_if_t< std::is_floating_point_v< T >, std::chrono::milliseconds > millisecondsFromFloat(T value)
Helper function for convert a floating point number to a duration.
std::enable_if_t< std::is_floating_point_v< T >, std::chrono::seconds > secondsFromFloat(T value)
Helper function for convert a floating point number to a duration.
std::enable_if_t< std::is_floating_point_v< T >, std::chrono::microseconds > microsecondsFromFloat(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_)
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