2 changes: 2 additions & 0 deletions mythtv/external/FFmpeg/libavcodec/utils-mythtv.c
Original file line number Diff line number Diff line change
Expand Up @@ -117,6 +117,8 @@ const char *ff_codec_id_string(enum AVCodecID codec_id)
case AV_CODEC_ID_TRUEMOTION2: return "TRUEMOTION2";
case AV_CODEC_ID_BMP: return "BMP";
case AV_CODEC_ID_VP8: return "VP8";
case AV_CODEC_ID_VP9: return "VP9";
case AV_CODEC_ID_AV1: return "AV1";

/* various pcm "codecs" */
case AV_CODEC_ID_PCM_S16LE: return "PCM_S16LE";
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@
#if !defined(FFNV_DYNLINK_CUDA_H) && !defined(CUDA_VERSION)
#define FFNV_DYNLINK_CUDA_H

#include <cstddef>
#include <stddef.h>

#define CUDA_VERSION 7050

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@
#ifndef FFNV_CUDA_DYNLINK_LOADER_H
#define FFNV_CUDA_DYNLINK_LOADER_H

#include <cstdlib>
#include <stdlib.h>

#include "dynlink_cuda.h"
#include "dynlink_nvcuvid.h"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@
#ifndef _NV_ENCODEAPI_H_
#define _NV_ENCODEAPI_H_

#include <cstdlib>
#include <stdlib.h>

#ifdef _WIN32
#include <windows.h>
Expand All @@ -55,7 +55,7 @@ typedef short int16_t;
typedef unsigned short uint16_t;
#endif
#else
#include <cstdint>
#include <stdint.h>
#endif

#ifdef __cplusplus
Expand Down
2 changes: 1 addition & 1 deletion mythtv/libs/libmythbase/mythversion.h
Original file line number Diff line number Diff line change
Expand Up @@ -75,7 +75,7 @@
* mythtv/bindings/php/MythBackend.php
*/

#define MYTH_DATABASE_VERSION "1359"
#define MYTH_DATABASE_VERSION "1360"


MBASE_PUBLIC const char *GetMythSourceVersion();
Expand Down
2 changes: 1 addition & 1 deletion mythtv/libs/libmythfreemheg/Presentable.h
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ class MHPresentable : public MHIngredient
{
public:
MHPresentable() = default;
MHPresentable(const MHPresentable &ref) = default;
MHPresentable(const MHPresentable&) = default;
// No new components.

// Actions.
Expand Down
2 changes: 1 addition & 1 deletion mythtv/libs/libmythfreemheg/Visible.h
Original file line number Diff line number Diff line change
Expand Up @@ -122,7 +122,7 @@ class MHRectangle : public MHLineArt
{
public:
MHRectangle() = default;
MHRectangle(const MHRectangle &ref) = default;
MHRectangle(const MHRectangle&) = default;
const char *ClassName() override // MHLineArt
{ return "Rectangle"; }
void PrintMe(FILE *fd, int nTabs) const override; // MHLineArt
Expand Down
2 changes: 1 addition & 1 deletion mythtv/libs/libmythtv/channelgroup.h
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ using namespace std;
class MTV_PUBLIC ChannelGroupItem
{
public:
ChannelGroupItem(const ChannelGroupItem &other) = default;
ChannelGroupItem(const ChannelGroupItem&) = default;
ChannelGroupItem(const uint grpid, QString name) :
m_grpId(grpid), m_name(std::move(name)) {}

Expand Down
2 changes: 1 addition & 1 deletion mythtv/libs/libmythtv/channelinfo.h
Original file line number Diff line number Diff line change
Expand Up @@ -203,7 +203,7 @@ class MTV_PUBLIC ChannelInsertInfo
m_decryptionStatus(_decryption_status) {}

ChannelInsertInfo(const ChannelInsertInfo &other) { (*this = other); }
ChannelInsertInfo &operator=(const ChannelInsertInfo &other) = default;
ChannelInsertInfo &operator=(const ChannelInsertInfo&) = default;

bool IsSameChannel(const ChannelInsertInfo &other, int relaxed = 0) const;

Expand Down
102 changes: 11 additions & 91 deletions mythtv/libs/libmythtv/channelscan/channelscan_sm.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -76,7 +76,7 @@ const uint ChannelScanSM::kATSCTableTimeout = 10 * 1000;
/// No logic here, lets just wait at least 15 seconds.
const uint ChannelScanSM::kMPEGTableTimeout = 15 * 1000;

// Astra 28.2E satellite Freesat/BSkyB
// Freesat and Sky
static const uint kRegionUndefined = 0xFFFF; // Not regional

QString ChannelScanSM::loc(const ChannelScanSM *siscan)
Expand Down Expand Up @@ -118,7 +118,6 @@ class ScannedChannelInfo
nit_vec_t m_nits;
sdt_map_t m_sdts;
bat_vec_t m_bats;
QMap<uint64_t,uint64_t> m_opentv_channels;
};

/** \class ChannelScanSM
Expand Down Expand Up @@ -159,9 +158,6 @@ ChannelScanSM::ChannelScanSM(ScanMonitor *_scan_monitor,
m_channelTimeout(channel_timeout),
m_inputName(std::move(_inputname)),
m_testDecryption(test_decryption),
m_scanOpenTVBouquet(0),
m_scanOpenTVRegion(0),
m_scanOpenTVRegionMask(0),
// Misc
m_analogSignalHandler(new AnalogSignalHandler(this))
{
Expand Down Expand Up @@ -196,7 +192,7 @@ ChannelScanSM::ChannelScanSM(ScanMonitor *_scan_monitor,
}

LOG(VB_CHANSCAN, LOG_INFO, LOC +
QString("Freesat/BSkyB/OpenTV bouquet_id:%1 region_id:%2")
QString("Freesat/Sky bouquet_id:%1 region_id:%2")
.arg(m_bouquetId).arg(m_regionId));

dtvSigMon->SetStreamData(data);
Expand Down Expand Up @@ -255,27 +251,6 @@ void ChannelScanSM::SetAnalog(bool is_analog)
m_signalMonitor->AddListener(m_analogSignalHandler);
}

void ChannelScanSM::SetOpenTV(void)
{
if (m_bouquetId > 0)
{
m_scanOpenTVBouquet = m_bouquetId;
m_scanOpenTVRegion = m_regionId;
if (m_regionId)
m_scanOpenTVRegionMask = 1 << m_regionId;
else
m_scanOpenTVRegionMask = (uint)-1;
LOG(VB_GENERAL, LOG_INFO, LOC +
QString("Scan for OpenTV channels on bouquet ID %1 and region ID %2")
.arg(m_scanOpenTVBouquet).arg(m_scanOpenTVRegion));
}
else
{
LOG(VB_GENERAL, LOG_WARNING, LOC +
QString("Cannot scan for OpenTV channels, bouquet ID is 0"));
}
}

void ChannelScanSM::HandleAllGood(void)
{
QMutexLocker locker(&m_lock);
Expand Down Expand Up @@ -571,44 +546,6 @@ void ChannelScanSM::HandleBAT(const BouquetAssociationTable *bat)
m_defAuthorities[index] = authority.DefaultAuthority();
}
}

if (m_scanOpenTVBouquet > 0)
{
const unsigned char *otv_chan_list =
MPEGDescriptor::Find(parsed, PrivateDescriptorID::opentv_channel_list);
if (otv_chan_list)
{
OpenTVChannelListDescriptor opentvChannelList(otv_chan_list);

uint64_t regionMask = UINT64_MAX;
if (opentvChannelList.RegionID() > 0 && opentvChannelList.RegionID() < 32)
regionMask = ((uint64_t)1) << opentvChannelList.RegionID();

for (uint j = 0; j < opentvChannelList.ChannelCount(); j++)
{
uint64_t index = ((uint64_t)netid << 32) |
bat->BouquetID() << 16 |
opentvChannelList.ServiceID(j);
if (!m_currentInfo)
m_currentInfo = new ScannedChannelInfo();
if (m_currentInfo->m_opentv_channels.contains(index))
{
m_currentInfo->m_opentv_channels[index] |= regionMask << 32;
}
else
{
m_currentInfo->m_opentv_channels[index] =
regionMask << 32 |
(opentvChannelList.ChannelID(j) << 16);
}
if (regionMask & m_scanOpenTVRegionMask)
{
m_currentInfo->m_opentv_channels[index] |=
opentvChannelList.ChannelNumber(j);
}
}
}
}
}
UpdateChannelInfo(true);
}
Expand Down Expand Up @@ -1525,7 +1462,7 @@ ChannelScanSM::GetChannelList(transport_scan_items_it_t trans_info,

// BAT

// Channel numbers for Freesat and BSkyB on Astra 28.2E
// Channel numbers for Freesat and Sky on Astra 28.2E
//
// Get the Logical Channel Number (LCN) information from the BAT.
// The first filter is on the bouquet ID.
Expand All @@ -1537,7 +1474,7 @@ ChannelScanSM::GetChannelList(transport_scan_items_it_t trans_info,
// This works because the BAT of each transport contains
// the LCN of all transports and services for all bouquets.
//
// For reference, this website has the Freesat and BSkyB channel numbers
// For reference, this website has the Freesat and Sky channel numbers
// for each bouquet and region:
// https://www.satellite-calculations.com/DVB/28.2E/28E_FreeSat_ChannelNumber.php
// https://www.satellite-calculations.com/DVB/28.2E/28E_Sky_ChannelNumber.php
Expand All @@ -1556,11 +1493,13 @@ ChannelScanSM::GetChannelList(transport_scan_items_it_t trans_info,
{
uint netid = bat->OriginalNetworkID(t);

// No network check to allow scanning on all Sky satellites
#if 0
if (!(netid == OriginalNetworkID::SES2 ||
netid == OriginalNetworkID::BBC ||
netid == OriginalNetworkID::SKYNZ ))
continue;

#endif
desc_list_t parsed =
MPEGDescriptor::Parse(bat->TransportDescriptors(t),
bat->TransportDescriptorsLength(t));
Expand Down Expand Up @@ -1603,11 +1542,11 @@ ChannelScanSM::GetChannelList(transport_scan_items_it_t trans_info,
}
}

// BSkyB logical channels
// Sky logical channels
if (priv_dsid == PrivateDataSpecifierID::BSB1 &&
item[0] == PrivateDescriptorID::bskyb_lcn_table)
item[0] == PrivateDescriptorID::sky_lcn_table)
{
BSkyBLCNDescriptor ld(item);
SkyLCNDescriptor ld(item);
if (ld.IsValid())
{
uint region_id = ld.RegionID();
Expand Down Expand Up @@ -1707,7 +1646,7 @@ ChannelScanSM::GetChannelList(transport_scan_items_it_t trans_info,
}
}

// DVB satellite Astra 28.2E Freesat or BSkyB channel numbers
// Freesat and Sky channel numbers
if (info.m_chanNum.isEmpty())
{
qlonglong key = ((qlonglong)info.m_origNetId<<32) | info.m_serviceId;
Expand All @@ -1719,25 +1658,6 @@ ChannelScanSM::GetChannelList(transport_scan_items_it_t trans_info,
}
}

// OpenTV Logical Channel Numbers
if (info.m_chanNum.isEmpty())
{
if (m_scanOpenTVBouquet > 0)
{
qlonglong key =
((qlonglong)info.m_origNetId<<32) | m_scanOpenTVBouquet << 16 | info.m_serviceId;
QMap<uint64_t, uint64_t>::const_iterator it = scan_info->m_opentv_channels.find(key);
if (it != scan_info->m_opentv_channels.end())
{
uint chanNum = (*it) & 0xffff;
if (chanNum > 0)
{
info.m_chanNum = chanNum;
}
}
}
}

LOG(VB_CHANSCAN, LOG_INFO, LOC +
QString("GetChannelList: service %1 (0x%2) chan_num '%3' callsign '%4'")
.arg(info.m_serviceId).arg(info.m_serviceId,4,16,QChar('0'))
Expand Down
6 changes: 0 additions & 6 deletions mythtv/libs/libmythtv/channelscan/channelscan_sm.h
Original file line number Diff line number Diff line change
Expand Up @@ -121,7 +121,6 @@ class ChannelScanSM : public MPEGStreamListener,
void SetChannelTimeout(uint val) { m_channelTimeout = val; }
void SetScanDTVTunerType(DTVTunerType t) { m_scanDTVTunerType = t; }
void SetScanDTVTunerType(int t) { m_scanDTVTunerType = DTVTunerType(t); }
void SetOpenTV(void);

uint GetSignalTimeout(void) const { return m_signalTimeout; }
uint GetChannelTimeout(void) const { return m_channelTimeout; }
Expand Down Expand Up @@ -226,11 +225,6 @@ class ChannelScanSM : public MPEGStreamListener,
// Optional info
DTVTunerType m_scanDTVTunerType {DTVTunerType::kTunerTypeUnknown};

// OpenTV
uint m_scanOpenTVBouquet {0};
uint m_scanOpenTVRegion {0};
uint m_scanOpenTVRegionMask {0};

/// The big lock
mutable QMutex m_lock;

Expand Down
12 changes: 0 additions & 12 deletions mythtv/libs/libmythtv/channelscan/channelscanmiscsettings.h
Original file line number Diff line number Diff line change
Expand Up @@ -201,18 +201,6 @@ class TrustEncSISetting : public TransMythUICheckBoxSetting
}
};

class ScanOpenTV: public TransMythUICheckBoxSetting
{
public:
ScanOpenTV()
{
setLabel(QObject::tr("Scan OpenTV"));
setHelpText(QObject::tr("Scan for OpenTV channel numbers.\n"
"Set the Bouquet ID and Region ID in the Video Source."));
setValue(false);
};
};

class ScanFrequencykHz: public TransTextEditSetting
{
public:
Expand Down
7 changes: 0 additions & 7 deletions mythtv/libs/libmythtv/channelscan/channelscanner.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -121,7 +121,6 @@ void ChannelScanner::Scan(
bool do_complete_only,
bool do_full_channel_search,
bool do_add_full_ts,
bool do_scanOpenTV,
ServiceRequirements service_requirements,
// stuff needed for particular scans
uint mplexid /* TransportScan */,
Expand All @@ -137,7 +136,6 @@ void ChannelScanner::Scan(
m_completeOnly = do_complete_only;
m_fullSearch = do_full_channel_search;
m_addFullTS = do_add_full_ts;
m_scanOpenTV = do_scanOpenTV;
m_serviceRequirements = service_requirements;
m_sourceid = sourceid;

Expand All @@ -157,11 +155,6 @@ void ChannelScanner::Scan(

bool ok = false;

if (do_scanOpenTV)
{
m_sigmonScanner->SetOpenTV();
}

if ((ScanTypeSetting::FullScan_ATSC == scantype) ||
(ScanTypeSetting::FullScan_DVBC == scantype) ||
(ScanTypeSetting::FullScan_DVBT == scantype) ||
Expand Down
4 changes: 0 additions & 4 deletions mythtv/libs/libmythtv/channelscan/channelscanner.h
Original file line number Diff line number Diff line change
Expand Up @@ -80,7 +80,6 @@ class MTV_PUBLIC ChannelScanner
bool do_complete_only,
bool do_full_channel_search,
bool do_add_full_ts,
bool do_scanOpenTV,
ServiceRequirements service_requirements,
// stuff needed for particular scans
uint mplexid,
Expand Down Expand Up @@ -151,9 +150,6 @@ class MTV_PUBLIC ChannelScanner
/// Add MPTS "full transport stream" channels
bool m_addFullTS {false};

/// Scan for OpenTV channel numbers
bool m_scanOpenTV {false};

int m_sourceid {-1};

/// Services desired post scan
Expand Down
4 changes: 3 additions & 1 deletion mythtv/libs/libmythtv/channelscan/frequencytablesetting.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@
#include "mythcorecontext.h"
#include "mythlocale.h"

// Frequency tables for USA/ATSC broadcast and cable networks
ScanFrequencyTable::ScanFrequencyTable()
{
addSelection(QObject::tr("Broadcast"), "us", true);
Expand All @@ -54,6 +55,7 @@ ScanFrequencyTable::ScanFrequencyTable()
"digital channels are on the higher frequencies."));
}

// Frequency tables for DVB-T/T2 terrestrial broadcast per country
ScanCountry::ScanCountry()
{
// Default to saved country
Expand All @@ -77,7 +79,7 @@ ScanCountry::ScanCountry()
addSelection(QObject::tr("United Kingdom"), "gb", country == "gb");
}


// Frequency tables for DVB-C cable networks per country
ScanNetwork::ScanNetwork()
{
// Default to saved country
Expand Down
7 changes: 0 additions & 7 deletions mythtv/libs/libmythtv/channelscan/scanwizardconfig.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,6 @@ void ScanWizard::SetupConfig(
m_fullSearch = new FullChannelSearch();
m_addFullTS = new AddFullTS();
m_trustEncSI = new TrustEncSISetting();
m_scanOpenTV = new ScanOpenTV();

setLabel(tr("Channel Scan"));

Expand All @@ -48,7 +47,6 @@ void ScanWizard::SetupConfig(
addChild(m_fullSearch);
addChild(m_addFullTS);
addChild(m_trustEncSI);
addChild(m_scanOpenTV);

addChild(m_videoSource);
addChild(m_input);
Expand Down Expand Up @@ -112,11 +110,6 @@ bool ScanWizard::DoTestDecryption(void) const
return m_trustEncSI->boolValue();
}

bool ScanWizard::DoScanOpenTV(void) const
{
return m_scanOpenTV->boolValue();
}

void ScanWizard::SetPaneDefaults(const QString &cardid_inputname)
{
const int sourceid = m_videoSource->getValue().toInt();
Expand Down
1 change: 0 additions & 1 deletion mythtv/libs/libmythtv/channelscan/scanwizardconfig.h
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,6 @@ class CompleteChannelsOnly;
class FullChannelSearch;
class AddFullTS;
class TrustEncSISetting;
class ScanOpenTV;

class PaneAll;
class PaneATSC;
Expand Down
13 changes: 13 additions & 0 deletions mythtv/libs/libmythtv/dbcheck.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -3702,6 +3702,19 @@ nullptr
return false;
}

if (dbver == "1359")
{
// XineramaMonitorAspectRatio was previously ignored for single screen
// setups but now acts as an override for the display aspect ratio.
// 0.0 indicates 'Auto' - which should be the default.
const char *updates[] = {
"UPDATE settings SET data='0.0' WHERE value='XineramaMonitorAspectRatio'",
nullptr
};
if (!performActualUpdate(updates, "1360", dbver))
return false;
}

return true;
}

Expand Down
133 changes: 84 additions & 49 deletions mythtv/libs/libmythtv/decoders/avformatdecoder.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -345,6 +345,9 @@ AvFormatDecoder::AvFormatDecoder(MythPlayer *parent,
m_ccd708(new CC708Decoder(parent->GetCC708Reader())),
m_ttd(new TeletextDecoder(parent->GetTeletextReader()))
{
// this will be deleted and recreated once decoder is set up
m_mythCodecCtx = new MythCodecContext(this, kCodec_NONE);

m_audioSamples = (uint8_t *)av_mallocz(AudioOutput::kMaxSizeBuffer);
m_ccd608->SetIgnoreTimecode(true);

Expand Down Expand Up @@ -1295,75 +1298,107 @@ int AvFormatDecoder::OpenFile(RingBuffer *rbuffer, bool novideo,
return m_recordingHasPositionMap;
}

float AvFormatDecoder::normalized_fps(AVStream *stream, AVCodecContext *enc)
float AvFormatDecoder::GetVideoFrameRate(AVStream *Stream, AVCodecContext *Context, bool Sanitise)
{
double fps = 0.0;
double avg_fps = 0.0;
double codec_fps = 0.0;
double container_fps = 0.0;
double estimated_fps = 0.0;

if (stream->avg_frame_rate.den && stream->avg_frame_rate.num)
avg_fps = av_q2d(stream->avg_frame_rate); // MKV default_duration
if (Stream->avg_frame_rate.den && Stream->avg_frame_rate.num)
avg_fps = av_q2d(Stream->avg_frame_rate); // MKV default_duration

if (enc->time_base.den && enc->time_base.num) // tbc
codec_fps = 1.0 / av_q2d(enc->time_base) / enc->ticks_per_frame;
if (Context->time_base.den && Context->time_base.num) // tbc
codec_fps = 1.0 / av_q2d(Context->time_base) / Context->ticks_per_frame;
// Some formats report fps waaay too high. (wrong time_base)
if (codec_fps > 121.0 && (enc->time_base.den > 10000) &&
(enc->time_base.num == 1))
if (codec_fps > 121.0 && (Context->time_base.den > 10000) &&
(Context->time_base.num == 1))
{
enc->time_base.num = 1001; // seems pretty standard
if (av_q2d(enc->time_base) > 0)
codec_fps = 1.0 / av_q2d(enc->time_base);
Context->time_base.num = 1001; // seems pretty standard
if (av_q2d(Context->time_base) > 0)
codec_fps = 1.0 / av_q2d(Context->time_base);
}
if (stream->time_base.den && stream->time_base.num) // tbn
container_fps = 1.0 / av_q2d(stream->time_base);
if (stream->r_frame_rate.den && stream->r_frame_rate.num) // tbr
estimated_fps = av_q2d(stream->r_frame_rate);
if (Stream->time_base.den && Stream->time_base.num) // tbn
container_fps = 1.0 / av_q2d(Stream->time_base);
if (Stream->r_frame_rate.den && Stream->r_frame_rate.num) // tbr
estimated_fps = av_q2d(Stream->r_frame_rate);

// build a list of possible rates, best first
vector<double> rates;

// matroska demuxer sets the default_duration to avg_frame_rate
// mov,mp4,m4a,3gp,3g2,mj2 demuxer sets avg_frame_rate
if ((QString(m_ic->iformat->name).contains("matroska") ||
QString(m_ic->iformat->name).contains("mov")) &&
avg_fps < 121.0 && avg_fps > 3.0)
{ // NOLINT(bugprone-branch-clone)
fps = avg_fps;
}
else if (QString(m_ic->iformat->name).contains("avi") &&
container_fps < 121.0 && container_fps > 3.0)
{ // NOLINT(bugprone-branch-clone)
fps = container_fps; // avi uses container fps for timestamps // NOLINT(bugprone-branch-clone)
}
else if (codec_fps < 121.0 && codec_fps > 3.0)
{
fps = codec_fps;
}
else if (container_fps < 121.0 && container_fps > 3.0)
{
fps = container_fps;
rates.emplace_back(avg_fps);
}
else if (avg_fps < 121.0 && avg_fps > 3.0)

if (QString(m_ic->iformat->name).contains("avi") &&
container_fps < 121.0 && container_fps > 3.0)
{
fps = avg_fps;
// avi uses container fps for timestamps
rates.emplace_back(container_fps);
}

if (codec_fps < 121.0 && codec_fps > 3.0)
rates.emplace_back(codec_fps);

if (container_fps < 121.0 && container_fps > 3.0)
rates.emplace_back(container_fps);

if (avg_fps < 121.0 && avg_fps > 3.0)
rates.emplace_back(avg_fps);

// certain H.264 interlaced streams are detected at 2x using estimated (i.e. wrong)
else if (estimated_fps < 121.0 && estimated_fps > 3.0)
if (estimated_fps < 121.0 && estimated_fps > 3.0)
rates.emplace_back(estimated_fps);

// last resort
rates.emplace_back(static_cast<float>(30000.0 / 1001.0));

// debug
if (!qFuzzyCompare(static_cast<float>(rates.front()), m_fps))
{
fps = estimated_fps;
LOG(VB_PLAYBACK, LOG_INFO, LOC +
QString("Selected FPS: %1 (Avg:%2 Mult:%3 Codec:%4 Container:%5 Estimated:%6)")
.arg(static_cast<double>(rates.front())).arg(avg_fps)
.arg(m_fpsMultiplier).arg(codec_fps).arg(container_fps).arg(estimated_fps));
}
else

auto IsStandard = [](double Rate)
{
fps = 30000.0 / 1001.0; // 29.97 fps
}
// List of known, standards based frame rates
static const vector<double> s_normRates =
{
24000.0 / 1001.0, 23.976, 25.0, 30000.0 / 1001.0,
29.97, 30.0, 50.0, 60000.0 / 1001.0, 59.94, 60.0, 100.0,
120000.0 / 1001.0, 119.88, 120.0
};

if (Rate > 1.0 && Rate < 121.0)
for (auto rate : s_normRates)
if (qFuzzyCompare(rate, Rate))
return true;
return false;
};

if (!qFuzzyCompare(static_cast<float>(fps), m_fps))
// If the first choice rate is unusual, see if there is something more 'usual'
if (Sanitise && !IsStandard(rates.front()))
{
LOG(VB_PLAYBACK, LOG_INFO, LOC +
QString("Selected FPS: %1 (Avg:%2 Mult:%3 Codec:%4 Container:%5 Estimated:%6)")
.arg(fps).arg(avg_fps).arg(m_fpsMultiplier).arg(codec_fps).arg(container_fps).arg(estimated_fps));
for (auto rate : rates)
{
if (IsStandard(rate))
{
LOG(VB_GENERAL, LOG_INFO, LOC + QString("%1 is non-standard. Selecting %2 instead.")
.arg(rates.front()).arg(rate));
return static_cast<float>(rate);
}
}
}

return static_cast<float>(fps);
return static_cast<float>(rates.front());
}

#ifdef USING_DXVA2
Expand Down Expand Up @@ -1513,7 +1548,7 @@ void AvFormatDecoder::InitVideoCodec(AVStream *stream, AVCodecContext *enc,

if (selectedStream)
{
m_fps = normalized_fps(stream, enc);
m_fps = GetVideoFrameRate(stream, enc, true);
QSize dim = get_video_dim(*enc);
int width = m_currentWidth = dim.width();
int height = m_currentHeight = dim.height();
Expand Down Expand Up @@ -2250,7 +2285,8 @@ int AvFormatDecoder::ScanStreams(bool novideo)
QString("Selected track #%1: ID: 0x%2 Codec ID: %3 Profile: %4 Type: %5 Bitrate: %6")
.arg(selTrack).arg(static_cast<uint64_t>(stream->id), 0, 16)
.arg(ff_codec_id_string(enc->codec_id))
.arg(enc->profile).arg(codectype).arg(enc->bit_rate));
.arg(avcodec_profile_name(enc->codec_id, enc->profile))
.arg(codectype).arg(enc->bit_rate));

// If ScanStreams has been called on a stream change triggered by a
// decoder error - because the decoder does not handle resolution
Expand Down Expand Up @@ -2340,9 +2376,8 @@ int AvFormatDecoder::ScanStreams(bool novideo)

// N.B. MediaCodec and NVDEC require frame timing
m_useFrameTiming = false;
if ((!m_ringBuffer->IsDVD() && (codec_sw_copy(m_videoCodecId) ||
codec_is_mediacodec(m_videoCodecId) || codec_is_v4l2(m_videoCodecId))) ||
codec_is_nvdec(m_videoCodecId))
if ((!m_ringBuffer->IsDVD() && (codec_sw_copy(m_videoCodecId) || codec_is_v4l2(m_videoCodecId))) ||
(codec_is_nvdec(m_videoCodecId) || codec_is_mediacodec(m_videoCodecId) || codec_is_mediacodec_dec(m_videoCodecId)))
{
m_useFrameTiming = true;
}
Expand Down Expand Up @@ -3131,7 +3166,7 @@ void AvFormatDecoder::MpegPreProcessPkt(AVStream *stream, AVPacket *pkt)
m_reorderedPtsDetected = false;

// fps debugging info
float avFPS = normalized_fps(stream, context);
float avFPS = GetVideoFrameRate(stream, context);
if ((seqFPS > avFPS+0.01F) || (seqFPS < avFPS-0.01F))
{
LOG(VB_PLAYBACK, LOG_INFO, LOC + QString("avFPS(%1) != seqFPS(%2)")
Expand Down Expand Up @@ -3218,7 +3253,7 @@ int AvFormatDecoder::H264PreProcessPkt(AVStream *stream, AVPacket *pkt)
// size and rate is extremely error prone and FFmpeg gets it right far more often.
// N.B. if a decoder deinterlacer is in use - the stream must be progressive
bool doublerate = false;
bool decoderdeint = m_mythCodecCtx->IsDeinterlacing(doublerate, true);
bool decoderdeint = m_mythCodecCtx ? m_mythCodecCtx->IsDeinterlacing(doublerate, true) : false;
m_parent->SetVideoParams(width, height, seqFPS, m_currentAspect, forcechange,
static_cast<int>(m_h264Parser->getRefFrames()),
decoderdeint ? kScan_Progressive : kScan_Ignore);
Expand All @@ -3240,7 +3275,7 @@ int AvFormatDecoder::H264PreProcessPkt(AVStream *stream, AVPacket *pkt)
m_reorderedPtsDetected = false;

// fps debugging info
auto avFPS = static_cast<double>(normalized_fps(stream, context));
auto avFPS = static_cast<double>(GetVideoFrameRate(stream, context));
if ((seqFPS > avFPS + 0.01) || (seqFPS < avFPS - 0.01))
{
LOG(VB_PLAYBACK, LOG_INFO, LOC +
Expand Down
2 changes: 1 addition & 1 deletion mythtv/libs/libmythtv/decoders/avformatdecoder.h
Original file line number Diff line number Diff line change
Expand Up @@ -246,7 +246,7 @@ class AvFormatDecoder : public DecoderBase

bool GenerateDummyVideoFrames(void);
bool HasVideo(const AVFormatContext *ic);
float normalized_fps(AVStream *stream, AVCodecContext *enc);
float GetVideoFrameRate(AVStream *Stream, AVCodecContext *Context, bool Sanitise = false);
static void av_update_stream_timings_video(AVFormatContext *ic);
static bool OpenAVCodec(AVCodecContext *avctx, const AVCodec *codec);

Expand Down
4 changes: 1 addition & 3 deletions mythtv/libs/libmythtv/decoders/decoderbase.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -21,9 +21,7 @@ DecoderBase::DecoderBase(MythPlayer *parent, const ProgramInfo &pginfo)
m_totalDuration(AVRationalInit(0)),

// language preference
m_languagePreference(iso639_get_language_key_list()),
// this will be deleted and recreated once decoder is set up
m_mythCodecCtx(new MythCodecContext(this, kCodec_NONE))
m_languagePreference(iso639_get_language_key_list())
{
ResetTracks();
m_tracks[kTrackTypeAudio].push_back(StreamInfo(0, 0, 0, 0, 0));
Expand Down
205 changes: 200 additions & 5 deletions mythtv/libs/libmythtv/decoders/mythcodeccontext.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -111,6 +111,19 @@ MythCodecContext *MythCodecContext::CreateContext(DecoderBase *Parent, MythCodec
return mctx;
}

QStringList MythCodecContext::GetDecoderDescription(void)
{
QStringList decoders;

#ifdef USING_VAAPI
MythVAAPIContext::GetDecoderList(decoders);
#endif
#ifdef USING_MEDIACODEC
MythMediaCodecContext::GetDecoderList(decoders);
#endif
return decoders;
}

void MythCodecContext::GetDecoders(RenderOptions &Opts)
{
#ifdef USING_VDPAU
Expand All @@ -130,7 +143,7 @@ void MythCodecContext::GetDecoders(RenderOptions &Opts)

#ifdef USING_VAAPI
// Only enable VAAPI if it is actually present and isn't actually VDPAU
if (MythVAAPIContext::HaveVAAPI())
if (!MythVAAPIContext::HaveVAAPI().isEmpty())
{
Opts.decoders->append("vaapi");
(*Opts.equiv_decoders)["vaapi"].append("dummy");
Expand All @@ -149,10 +162,13 @@ void MythCodecContext::GetDecoders(RenderOptions &Opts)
}
#endif
#ifdef USING_MEDIACODEC
Opts.decoders->append("mediacodec");
(*Opts.equiv_decoders)["mediacodec"].append("dummy");
Opts.decoders->append("mediacodec-dec");
(*Opts.equiv_decoders)["mediacodec-dec"].append("dummy");
if (MythMediaCodecContext::HaveMediaCodec())
{
Opts.decoders->append("mediacodec");
(*Opts.equiv_decoders)["mediacodec"].append("dummy");
Opts.decoders->append("mediacodec-dec");
(*Opts.equiv_decoders)["mediacodec-dec"].append("dummy");
}
#endif
#ifdef USING_VTB
Opts.decoders->append("vtb");
Expand Down Expand Up @@ -607,3 +623,182 @@ bool MythCodecContext::RetrieveHWFrame(VideoFrame *Frame, AVFrame *AvFrame)
av_frame_free(&temp);
return ret >= 0;
}

MythCodecContext::CodecProfile MythCodecContext::FFmpegToMythProfile(AVCodecID CodecID, int Profile)
{
switch (CodecID)
{
case AV_CODEC_ID_MPEG2VIDEO:
switch (Profile)
{
case FF_PROFILE_MPEG2_422: return MPEG2422;
case FF_PROFILE_MPEG2_HIGH: return MPEG2High;
case FF_PROFILE_MPEG2_SS: return MPEG2Spatial;
case FF_PROFILE_MPEG2_SNR_SCALABLE: return MPEG2SNR;
case FF_PROFILE_MPEG2_SIMPLE: return MPEG2Simple;
case FF_PROFILE_MPEG2_MAIN: return MPEG2Main;
default: break;
}
break;
case AV_CODEC_ID_MPEG4:
switch (Profile)
{
case FF_PROFILE_MPEG4_SIMPLE: return MPEG4Simple;
case FF_PROFILE_MPEG4_SIMPLE_SCALABLE: return MPEG4SimpleScaleable;
case FF_PROFILE_MPEG4_CORE: return MPEG4Core;
case FF_PROFILE_MPEG4_MAIN: return MPEG4Main;
case FF_PROFILE_MPEG4_N_BIT: return MPEG4NBit;
case FF_PROFILE_MPEG4_SCALABLE_TEXTURE: return MPEG4ScaleableTexture;
case FF_PROFILE_MPEG4_SIMPLE_FACE_ANIMATION: return MPEG4SimpleFace;
case FF_PROFILE_MPEG4_BASIC_ANIMATED_TEXTURE: return MPEG4BasicAnimated;
case FF_PROFILE_MPEG4_HYBRID: return MPEG4Hybrid;
case FF_PROFILE_MPEG4_ADVANCED_REAL_TIME: return MPEG4AdvancedRT;
case FF_PROFILE_MPEG4_CORE_SCALABLE: return MPEG4CoreScaleable;
case FF_PROFILE_MPEG4_ADVANCED_CODING: return MPEG4AdvancedCoding;
case FF_PROFILE_MPEG4_ADVANCED_CORE: return MPEG4AdvancedCore;
case FF_PROFILE_MPEG4_ADVANCED_SCALABLE_TEXTURE: return MPEG4AdvancedScaleableTexture;
case FF_PROFILE_MPEG4_SIMPLE_STUDIO: return MPEG4SimpleStudio;
case FF_PROFILE_MPEG4_ADVANCED_SIMPLE: return MPEG4AdvancedSimple;
}
break;
case AV_CODEC_ID_H263: return H263;
case AV_CODEC_ID_H264:
switch (Profile)
{
// Mapping of H264MainExtended, H264ConstrainedHigh?
case FF_PROFILE_H264_BASELINE: return H264Baseline;
case FF_PROFILE_H264_CONSTRAINED_BASELINE: return H264ConstrainedBaseline;
case FF_PROFILE_H264_MAIN: return H264Main;
case FF_PROFILE_H264_EXTENDED: return H264Extended;
case FF_PROFILE_H264_HIGH: return H264High;
case FF_PROFILE_H264_HIGH_10: return H264High10;
//case FF_PROFILE_H264_HIGH_10_INTRA:
//case FF_PROFILE_H264_MULTIVIEW_HIGH:
case FF_PROFILE_H264_HIGH_422: return H264High422;
//case FF_PROFILE_H264_HIGH_422_INTRA:
//case FF_PROFILE_H264_STEREO_HIGH:
case FF_PROFILE_H264_HIGH_444: return H264High444;
//case FF_PROFILE_H264_HIGH_444_PREDICTIVE:
//case FF_PROFILE_H264_HIGH_444_INTRA:
//case FF_PROFILE_H264_CAVLC_444:
}
break;
case AV_CODEC_ID_HEVC:
switch (Profile)
{
case FF_PROFILE_HEVC_MAIN: return HEVCMain;
case FF_PROFILE_HEVC_MAIN_10: return HEVCMain10;
case FF_PROFILE_HEVC_MAIN_STILL_PICTURE: return HEVCMainStill;
case FF_PROFILE_HEVC_REXT: return HEVCRext;
}
break;
case AV_CODEC_ID_VC1:
switch (Profile)
{
case FF_PROFILE_VC1_SIMPLE: return VC1Simple;
case FF_PROFILE_VC1_MAIN: return VC1Main;
case FF_PROFILE_VC1_COMPLEX: return VC1Complex;
case FF_PROFILE_VC1_ADVANCED: return VC1Advanced;
}
break;
case AV_CODEC_ID_VP8: return VP8;
case AV_CODEC_ID_VP9:
switch (Profile)
{
case FF_PROFILE_VP9_0: return VP9_0;
case FF_PROFILE_VP9_1: return VP9_1;
case FF_PROFILE_VP9_2: return VP9_2;
case FF_PROFILE_VP9_3: return VP9_3;
}
break;
case AV_CODEC_ID_AV1:
switch (Profile)
{
case FF_PROFILE_AV1_MAIN: return AV1Main;
case FF_PROFILE_AV1_HIGH: return AV1High;
case FF_PROFILE_AV1_PROFESSIONAL: return AV1Professional;
}
break;
case AV_CODEC_ID_MJPEG: return MJPEG;
default: break;
}

return NoProfile;
}

QString MythCodecContext::GetProfileDescription(CodecProfile Profile, QSize Size)
{
QString profile;
switch (Profile)
{
case NoProfile: profile = QObject::tr("Unknown/Unsupported"); break;
case MPEG2: profile = "MPEG2"; break;
case MPEG2Simple: profile = "MPEG2 Simple"; break;
case MPEG2Main: profile = "MPEG2 Main"; break;
case MPEG2422: profile = "MPEG2 422"; break;
case MPEG2High: profile = "MPEG2 High"; break;
case MPEG2Spatial: profile = "MPEG2 Spatial"; break;
case MPEG2SNR: profile = "MPEG2 SNR"; break;
case MPEG4: profile = "MPEG4"; break;
case MPEG4Simple: profile = "MPEG4 Simple"; break;
case MPEG4SimpleScaleable: profile = "MPEG4 Simple Scaleable"; break;
case MPEG4Core: profile = "MPEG4 Core"; break;
case MPEG4Main: profile = "MPEG4 Main"; break;
case MPEG4NBit: profile = "MPEG4 NBit"; break;
case MPEG4ScaleableTexture: profile = "MPEG4 Scaleable Texture"; break;
case MPEG4SimpleFace: profile = "MPEG4 Simple Face"; break;
case MPEG4BasicAnimated: profile = "MPEG4 Basic Animated"; break;
case MPEG4Hybrid: profile = "MPEG4 Hybrid"; break;
case MPEG4AdvancedRT: profile = "MPEG4 Advanced RT"; break;
case MPEG4CoreScaleable: profile = "MPEG4 Core Scaleable"; break;
case MPEG4AdvancedCoding: profile = "MPEG4 Advanced Coding"; break;
case MPEG4AdvancedCore: profile = "MPEG4 Advanced Core"; break;
case MPEG4AdvancedScaleableTexture: profile = "MPEG4 Advanced Scaleable Texture"; break;
case MPEG4SimpleStudio: profile = "MPEG4 Simple Studio"; break;
case MPEG4AdvancedSimple: profile = "MPEG4 Advanced Simple"; break;
case H263: profile = "H263"; break;
case H264: profile = "H264"; break;
case H264Baseline: profile = "H264 Baseline"; break;
case H264ConstrainedBaseline: profile = "H264 Constrained"; break;
case H264Main: profile = "H264 Main"; break;
case H264MainExtended: profile = "H264 Main Extended"; break;
case H264High: profile = "H264 High"; break;
case H264High10: profile = "H264 High10"; break;
case H264Extended: profile = "H264 Extended"; break;
case H264High422: profile = "H264 High 422"; break;
case H264High444: profile = "H264 High 444"; break;
case H264ConstrainedHigh: profile = "H264 Constrained High"; break;
case HEVC: profile = "HEVC"; break;
case HEVCMain: profile = "HEVC Main"; break;
case HEVCMain10: profile = "HEVC Main10"; break;
case HEVCMainStill: profile = "HEVC Main Still"; break;
case HEVCRext: profile = "HEVC Rext"; break;
case HEVCMain10HDR: profile = "HEVC Main10HDR"; break;
case HEVCMain10HDRPlus: profile = "HEVC Main10HDRPlus"; break;
case VC1: profile = "VC1"; break;
case VC1Simple: profile = "VC1 Simple"; break;
case VC1Main: profile = "VC1 Main"; break;
case VC1Complex: profile = "VC1 Complex"; break;
case VC1Advanced: profile = "VC1 Advanced"; break;
case VP8: profile = "VP8"; break;
case VP9: profile = "VP9"; break;
case VP9_0: profile = "VP9 Level 0"; break;
case VP9_1: profile = "VP9 Level 1"; break;
case VP9_2: profile = "VP9 Level 2"; break;
case VP9_2HDR: profile = "VP9 Level 2 HDR"; break;
case VP9_2HDRPlus: profile = "VP9 Level 2 HDRPlus"; break;
case VP9_3: profile = "VP9 Level 3"; break;
case VP9_3HDR: profile = "VP9 Level 3 HDR"; break;
case VP9_3HDRPlus: profile = "VP9 Level 3 HDRPlus"; break;
case AV1: profile = "AV1"; break;
case AV1Main: profile = "AV1 Main"; break;
case AV1High: profile = "AV1 High"; break;
case AV1Professional: profile = "AV1 Professional"; break;
case MJPEG: profile = "MJPEG";
}

if (Size.isEmpty())
return profile;

return QObject::tr("%1 (Max size: %2x%3)").arg(profile).arg(Size.width()).arg(Size.height());
}
71 changes: 71 additions & 0 deletions mythtv/libs/libmythtv/decoders/mythcodeccontext.h
Original file line number Diff line number Diff line change
Expand Up @@ -50,11 +50,80 @@ class VideoDisplayProfile;
class MTV_PUBLIC MythCodecContext
{
public:
enum CodecProfile
{
NoProfile = 0,
MPEG2,
MPEG2Simple,
MPEG2Main,
MPEG2422,
MPEG2High,
MPEG2Spatial,
MPEG2SNR,
MPEG4,
MPEG4Simple,
MPEG4SimpleScaleable,
MPEG4Core,
MPEG4Main,
MPEG4NBit,
MPEG4ScaleableTexture,
MPEG4SimpleFace,
MPEG4BasicAnimated,
MPEG4Hybrid,
MPEG4AdvancedRT,
MPEG4CoreScaleable,
MPEG4AdvancedCoding,
MPEG4AdvancedCore,
MPEG4AdvancedScaleableTexture,
MPEG4SimpleStudio,
MPEG4AdvancedSimple,
H263,
H264,
H264Baseline,
H264ConstrainedBaseline,
H264Main,
H264MainExtended,
H264High,
H264High10,
H264Extended,
H264High422,
H264High444,
H264ConstrainedHigh,
HEVC,
HEVCMain,
HEVCMain10,
HEVCMainStill,
HEVCRext,
HEVCMain10HDR,
HEVCMain10HDRPlus,
VC1,
VC1Simple,
VC1Main,
VC1Complex,
VC1Advanced,
VP8,
VP9,
VP9_0,
VP9_1,
VP9_2,
VP9_3,
VP9_2HDR,
VP9_2HDRPlus,
VP9_3HDR,
VP9_3HDRPlus,
AV1,
AV1Main,
AV1High,
AV1Professional,
MJPEG
};

explicit MythCodecContext(DecoderBase *Parent, MythCodecID CodecID);
virtual ~MythCodecContext() = default;

static MythCodecContext* CreateContext (DecoderBase *Parent, MythCodecID Codec);
static void GetDecoders (RenderOptions &Opts);
static QStringList GetDecoderDescription(void);
static MythCodecID FindDecoder (const QString &Decoder, AVStream *Stream,
AVCodecContext **Context, AVCodec **Codec);
static int GetBuffer (struct AVCodecContext *Context, AVFrame *Frame, int Flags);
Expand All @@ -68,6 +137,8 @@ class MTV_PUBLIC MythCodecContext
static void CreateDecoderCallback (void *Wait, void *Context, void *Callback);
static AVBufferRef* CreateDevice (AVHWDeviceType Type, MythOpenGLInterop *Interop, const QString &Device = QString());
static bool IsUnsupportedProfile (AVCodecContext *Context);
static QString GetProfileDescription (CodecProfile Profile, QSize Size);
static CodecProfile FFmpegToMythProfile(AVCodecID CodecID, int Profile);

virtual void InitVideoCodec (AVCodecContext *Context,
bool SelectedStream, bool &DirectRendering);
Expand Down
381 changes: 366 additions & 15 deletions mythtv/libs/libmythtv/decoders/mythmediacodeccontext.cpp

Large diffs are not rendered by default.

5 changes: 5 additions & 0 deletions mythtv/libs/libmythtv/decoders/mythmediacodeccontext.h
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,8 @@ extern "C" {
#include "libavcodec/avcodec.h"
}

typedef QList<QPair<MythCodecContext::CodecProfile,QSize> > MCProfiles;

class MythMediaCodecContext : public MythCodecContext
{
public:
Expand All @@ -28,8 +30,11 @@ class MythMediaCodecContext : public MythCodecContext
static AVPixelFormat GetFormat (AVCodecContext*, const AVPixelFormat *PixFmt);
void PostProcessFrame (AVCodecContext*, VideoFrame*) override;
bool IsDeinterlacing (bool &DoubleRate, bool = false) override;
static void GetDecoderList (QStringList &Decoders);
static bool HaveMediaCodec (void);

private:
static MCProfiles& GetProfiles (void);
static int InitialiseDecoder (AVCodecContext *Context);
};

Expand Down
297 changes: 182 additions & 115 deletions mythtv/libs/libmythtv/decoders/mythvaapicontext.cpp

Large diffs are not rendered by default.

7 changes: 6 additions & 1 deletion mythtv/libs/libmythtv/decoders/mythvaapicontext.h
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,9 @@ extern "C" {
#include "libavfilter/buffersrc.h"
}

typedef QPair<MythCodecContext::CodecProfile,QPair<QSize,QSize>> VAAPIProfile;
typedef QList<VAAPIProfile> VAAPIProfiles;

class MTV_PUBLIC MythVAAPIContext : public MythCodecContext
{
public:
Expand All @@ -39,14 +42,16 @@ class MTV_PUBLIC MythVAAPIContext : public MythCodecContext
const AVPixelFormat *PixFmt);
static enum AVPixelFormat GetFormat2 (AVCodecContext *Context,
const AVPixelFormat *PixFmt);
static bool HaveVAAPI (bool ReCheck = false);
static QString HaveVAAPI (bool ReCheck = false);
static void GetDecoderList (QStringList &Decoders);

private:
static int InitialiseContext (AVCodecContext *Context);
static int InitialiseContext2 (AVCodecContext *Context);
static VAProfile VAAPIProfileForCodec(const AVCodecContext *Codec);
static AVPixelFormat FramesFormat (AVPixelFormat Format);
void DestroyDeinterlacer (void);
static const VAAPIProfiles& GetProfiles(void);

MythDeintType m_deinterlacer { DEINT_NONE };
bool m_deinterlacer2x { false };
Expand Down
55 changes: 24 additions & 31 deletions mythtv/libs/libmythtv/dtvmultiplex.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -250,14 +250,12 @@ bool DTVMultiplex::ParseDVB_C(
m_modSys.Parse(_mod_sys);
if (DTVModulationSystem::kModulationSystem_UNDEFINED == m_modSys)
{
LOG(VB_GENERAL, LOG_WARNING, LOC + "Undefined modulation system " +
QString("parameter '%1', using DVB-C/A.").arg(_mod_sys));
m_modSys = DTVModulationSystem::kModulationSystem_DVBC_ANNEX_A;
}

LOG(VB_GENERAL, LOG_DEBUG, LOC +
QString("%1 ").arg(__FUNCTION__) +
QString("_mod_sys:%1 ok:%2 ").arg(_mod_sys).arg(ok) +
QString("m_mod_sys:%1 %2 ").arg(m_modSys).arg(m_modSys.toString()));

// Only DVB-C variants can be used with a DVB-C tuner.
if ((DTVModulationSystem::kModulationSystem_DVBC_ANNEX_A != m_modSys) &&
(DTVModulationSystem::kModulationSystem_DVBC_ANNEX_B != m_modSys) &&
(DTVModulationSystem::kModulationSystem_DVBC_ANNEX_C != m_modSys))
Expand All @@ -279,12 +277,8 @@ bool DTVMultiplex::ParseDVB_S2(
bool ok = ParseDVB_S_and_C(_frequency, _inversion, _symbol_rate,
_fec_inner, _modulation, _polarity);

if (!m_modSys.Parse(_mod_sys))
{
LOG(VB_GENERAL, LOG_ERR, LOC + "Invalid DVB-S2 modulation system " +
QString("parameter '%1', aborting.").arg(_mod_sys));
return false;
}
m_modSys = DTVModulationSystem::kModulationSystem_UNDEFINED;
m_modSys.Parse(_mod_sys);

// For #10153, guess at modulation system based on modulation
if (DTVModulationSystem::kModulationSystem_UNDEFINED == m_modSys)
Expand All @@ -294,6 +288,7 @@ bool DTVMultiplex::ParseDVB_S2(
DTVModulationSystem::kModulationSystem_DVBS2;
}

// Only DVB-S and DVB_S2 can be used with a DVB-S2 tuner.
if ((DTVModulationSystem::kModulationSystem_DVBS != m_modSys) &&
(DTVModulationSystem::kModulationSystem_DVBS2 != m_modSys))
{
Expand All @@ -319,41 +314,39 @@ bool DTVMultiplex::ParseDVB_T2(
_coderate_hp, _coderate_lp, _modulation,
_trans_mode, _guard_interval, _hierarchy);

QString l_mod_sys = _mod_sys;
m_modSys = DTVModulationSystem::kModulationSystem_UNDEFINED;
m_modSys.Parse(_mod_sys);

// Accept "0" for "DVB-T" and "1" for "DVB-T2"
if (_mod_sys == "1")
{
LOG(VB_GENERAL, LOG_WARNING, LOC + "Invalid DVB-T2 modulation system " +
QString("parameter '%1', using DVB-T2.").arg(_mod_sys));
m_modSys = DTVModulationSystem::kModulationSystem_DVBT2;
l_mod_sys = m_modSys.toString();
}
else if (_mod_sys == "0")
// Accept 0 for DVB-T
if (_mod_sys == "0")
{
LOG(VB_GENERAL, LOG_WARNING, LOC + "Invalid DVB-T modulation system " +
QString("parameter '%1', using DVB-T.").arg(_mod_sys));
m_modSys = DTVModulationSystem::kModulationSystem_DVBT;
l_mod_sys = m_modSys.toString();
LOG(VB_GENERAL, LOG_WARNING, LOC + "Deprecated DVB-T modulation system " +
QString("parameter '%1', using %2.").arg(_mod_sys).arg(m_modSys.toString()));
}

if (!m_modSys.Parse(l_mod_sys))
// Accept 1 for DVB-T2
if (_mod_sys == "1")
{
LOG(VB_GENERAL, LOG_WARNING, LOC + "Invalid DVB-T/T2 modulation system " +
QString("parameter '%1', aborting.").arg(l_mod_sys));
return false;
m_modSys = DTVModulationSystem::kModulationSystem_DVBT2;
LOG(VB_GENERAL, LOG_WARNING, LOC + "Deprecated DVB-T2 modulation system " +
QString("parameter '%1', using %2.").arg(_mod_sys).arg(m_modSys.toString()));
}

if (m_modSys == DTVModulationSystem::kModulationSystem_UNDEFINED)
// We have a DVB-T2 tuner, change undefined modulation system to DVB-T2
if (DTVModulationSystem::kModulationSystem_UNDEFINED == m_modSys)
{
m_modSys = DTVModulationSystem::kModulationSystem_DVBT;
m_modSys = DTVModulationSystem::kModulationSystem_DVBT2;
LOG(VB_GENERAL, LOG_WARNING, LOC + "Undefined modulation system, " +
QString("using %1.").arg(m_modSys.toString()));
}

// Only DVB-T and DVB-T2 can be used with a DVB-T2 tuner.
if ((DTVModulationSystem::kModulationSystem_DVBT != m_modSys) &&
(DTVModulationSystem::kModulationSystem_DVBT2 != m_modSys))
{
LOG(VB_GENERAL, LOG_ERR, LOC + "Unsupported DVB-T2 modulation system " +
QString("parameter '%1', aborting.").arg(l_mod_sys));
QString("%1, aborting.").arg(m_modSys.toString()));
return false;
}

Expand Down
2 changes: 2 additions & 0 deletions mythtv/libs/libmythtv/frequencytables.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -526,6 +526,7 @@ static void init_freq_tables(freq_table_map_t &fmap)
DTVCodeRate::kFECAuto, DTVModulation::kModulationQAMAuto,
6900000, 0, 0);

// DVB-C United Kingdom
fmap["dvbc_qam_gb0"] = new FrequencyTable(
12324000, 12324000+1, 10, "Channel %1", 1,
DTVCodeRate::kFEC_3_4, DTVModulation::kModulationQAMAuto,
Expand All @@ -535,6 +536,7 @@ static void init_freq_tables(freq_table_map_t &fmap)
DTVCodeRate::kFEC_3_4, DTVModulation::kModulationQAM64,
6952000, 0, 0);

// DVB-C Unknown (British Forces ?)
fmap["dvbc_qam_bf0"] = new FrequencyTable(
203000000, 795000000, 100000, "BF Channel %1", 1,
DTVCodeRate::kFECAuto, DTVModulation::kModulationQAMAuto,
Expand Down
4 changes: 2 additions & 2 deletions mythtv/libs/libmythtv/inputinfo.h
Original file line number Diff line number Diff line change
Expand Up @@ -27,8 +27,8 @@ class MTV_PUBLIC InputInfo

virtual ~InputInfo() = default;

InputInfo(const InputInfo &other) = default;
InputInfo &operator=(const InputInfo &other) = default;
InputInfo(const InputInfo&) = default;
InputInfo &operator=(const InputInfo&) = default;

bool operator == (uint inputid) const
{ return m_inputId == inputid; }
Expand Down
4 changes: 2 additions & 2 deletions mythtv/libs/libmythtv/mheg/dsmcccache.h
Original file line number Diff line number Diff line change
Expand Up @@ -39,8 +39,8 @@ class DSMCCCacheReference
m_nCarouselId(car), m_nModuleId(m),
m_nStreamTag(s), m_key(std::move(k)) {}

DSMCCCacheReference(const DSMCCCacheReference &r) = default;
DSMCCCacheReference& operator=(const DSMCCCacheReference &rhs) = default;
DSMCCCacheReference(const DSMCCCacheReference&) = default;
DSMCCCacheReference& operator=(const DSMCCCacheReference&) = default;

bool Equal(const DSMCCCacheReference &r) const;
bool Equal(const DSMCCCacheReference *p) const;
Expand Down
8 changes: 4 additions & 4 deletions mythtv/libs/libmythtv/mpeg/dvbdescriptors.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -617,9 +617,9 @@ QString DVBSimulcastChannelDescriptor::toString() const
return ret;
}

QString BSkyBLCNDescriptor::toString() const
QString SkyLCNDescriptor::toString() const
{
QString ret = "BSkyB Logical Channel Number Descriptor ";
QString ret = "Sky Logical Channel Number Descriptor ";
ret += QString("(0x%1) ").arg(DescriptorTag(),2,16,QChar('0'));
ret += QString("length(%1)").arg(DescriptorLength());

Expand All @@ -631,8 +631,8 @@ QString BSkyBLCNDescriptor::toString() const
ret += QString("\n ServiceID (%1) (0x%2) ").arg(ServiceID(i)).arg(ServiceID(i),4,16,QChar('0'));
ret += QString("ServiceType (0x%1) ").arg(ServiceType(i),2,16,QChar('0'));
ret += QString("LCN (%1) ").arg(LogicalChannelNumber(i));
ret += QString("U1(0x%1) ").arg(Unknown1(i),4,16,QChar('0'));
ret += QString("U2(0x%1) ").arg(Unknown2(i),4,16,QChar('0'));
ret += QString("ChannelID(0x%1) ").arg(ChannelID(i),4,16,QChar('0'));
ret += QString("Flags(0x%1) ").arg(Flags(i),4,16,QChar('0'));
}

return ret;
Expand Down
17 changes: 9 additions & 8 deletions mythtv/libs/libmythtv/mpeg/dvbdescriptors.h
Original file line number Diff line number Diff line change
Expand Up @@ -2270,7 +2270,7 @@ class FreesatCallsignDescriptor : public MPEGDescriptor
};

/**
* \brief BSkyB Logical Channel Number descriptor
* \brief Sky Logical Channel Number descriptor
*
* BAT descriptor ID 0xb1 (Private Extension)
*
Expand All @@ -2280,13 +2280,13 @@ class FreesatCallsignDescriptor : public MPEGDescriptor
* function dvb_bskyb_local_channels
*/

class BSkyBLCNDescriptor : public MPEGDescriptor
class SkyLCNDescriptor : public MPEGDescriptor
{
public:
explicit BSkyBLCNDescriptor(const unsigned char *data, int len = 300) :
MPEGDescriptor(data, len, PrivateDescriptorID::bskyb_lcn_table)
explicit SkyLCNDescriptor(const unsigned char *data, int len = 300) :
MPEGDescriptor(data, len, PrivateDescriptorID::sky_lcn_table)
{
assert(PrivateDescriptorID::bskyb_lcn_table== DescriptorTag());
assert(PrivateDescriptorID::sky_lcn_table== DescriptorTag());
}
// Name bits loc expected value
// descriptor_tag 8 0.0 0xd3
Expand Down Expand Up @@ -2315,18 +2315,19 @@ class BSkyBLCNDescriptor : public MPEGDescriptor
uint ServiceType(int i) const
{ return *(m_data + 6 + i*9); }

uint Unknown1(int i) const
uint ChannelID(int i) const
{ return *(m_data + 7 + i*9) << 8 | *(m_data + 8 + i*9); }

uint LogicalChannelNumber(int i) const
{ return *(m_data + 9 + i*9) << 8 | *(m_data + 10 + i*9); }

uint Unknown2(int i) const
uint Flags(int i) const
{ return *(m_data + 11 + i*9) << 8 | *(m_data + 12 + i*9); }

QString toString(void) const override; // MPEGDescriptor
};

// Descriptor layout similar to SkyLCNDescriptor
class OpenTVChannelListDescriptor : public MPEGDescriptor
{
public:
Expand Down Expand Up @@ -2356,7 +2357,7 @@ class OpenTVChannelListDescriptor : public MPEGDescriptor
uint Flags(uint i) const
{ return ((m_data[4 + 7 + (i*9)] << 8) | m_data[4 + 8 + (i*9)]) & 0xf; }

QString toString(void) const override;
QString toString(void) const override; // MPEGDescriptor
};

// ETSI TS 102 323 (TV Anytime)
Expand Down
14 changes: 9 additions & 5 deletions mythtv/libs/libmythtv/mpeg/dvbstreamdata.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -470,22 +470,24 @@ bool DVBStreamData::GetEITPIDChanges(const uint_vec_t &cur_pids,
add_pids.push_back(DVB_BVLONG_EIT_PID);
}

// opentv eit pids
#if 0
// OpenTV EIT pids
if (m_dvbEitDishnetLong)
{
for(uint pid=OTV_EIT_TIT_PID_START; pid <= OTV_EIT_TIT_PID_END; pid++)
for (uint pid = OTV_EIT_TIT_PID_START; pid <= OTV_EIT_TIT_PID_END; pid++)
{
if (find(cur_pids.begin(), cur_pids.end(),
pid) == cur_pids.end())
add_pids.push_back(pid);
}
for(uint pid=OTV_EIT_SUP_PID_START; pid <= OTV_EIT_SUP_PID_END; pid++)
for (uint pid = OTV_EIT_SUP_PID_START; pid <= OTV_EIT_SUP_PID_END; pid++)
{
if (find(cur_pids.begin(), cur_pids.end(),
pid) == cur_pids.end())
add_pids.push_back(pid);
}
}
#endif

if (m_desiredNetId == PREMIERE_ONID &&
find(cur_pids.begin(), cur_pids.end(),
Expand Down Expand Up @@ -537,10 +539,11 @@ bool DVBStreamData::GetEITPIDChanges(const uint_vec_t &cur_pids,
del_pids.push_back(DVB_BVLONG_EIT_PID);
}

// opentv eit pids
#if 0
// OpenTV EIT pids
if (m_dvbEitDishnetLong)
{
for(uint pid=OTV_EIT_TIT_PID_START; pid <= OTV_EIT_TIT_PID_END; pid++)
for (uint pid = OTV_EIT_TIT_PID_START; pid <= OTV_EIT_TIT_PID_END; pid++)
{
if (find(cur_pids.begin(), cur_pids.end(),
pid) != cur_pids.end())
Expand All @@ -553,6 +556,7 @@ bool DVBStreamData::GetEITPIDChanges(const uint_vec_t &cur_pids,
del_pids.push_back(pid);
}
}
#endif

if (m_desiredNetId == PREMIERE_ONID &&
find(cur_pids.begin(), cur_pids.end(),
Expand Down
15 changes: 5 additions & 10 deletions mythtv/libs/libmythtv/mpeg/mpegdescriptors.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -363,6 +363,9 @@ QString MPEGDescriptor::DescriptorTagString(void) const
case PrivateDescriptorID::dish_event_tags: /* 0x96 */
comma_list_append(str, "Possibly Dishnet Tag");
break;
case PrivateDescriptorID::opentv_channel_list: /* 0xB1 */
comma_list_append(str, "Possibly DVB Sky/OpenTV Channel List");
break;
case PrivateDescriptorID::premiere_content_order: /* 0xF0 */
comma_list_append(str, "Possibly Premiere DE Content Order");
break;
Expand All @@ -372,9 +375,6 @@ QString MPEGDescriptor::DescriptorTagString(void) const
case PrivateDescriptorID::premiere_content_transmission: /* 0xF2 */
comma_list_append(str, "Possibly Premiere DE Content Transmission");
break;
case PrivateDescriptorID::opentv_channel_list: /* 0xB1 */
comma_list_append(str, "Possibly DVB OpenTV Channel List");
break;
}

if (str.isEmpty())
Expand Down Expand Up @@ -494,9 +494,9 @@ QString MPEGDescriptor::toStringPD(uint priv_dsid) const
//
// User Defined DVB descriptors, range 0x80-0xFE
else if (priv_dsid == PrivateDataSpecifierID::BSB1 &&
PrivateDescriptorID::bskyb_lcn_table== DescriptorTag())
PrivateDescriptorID::sky_lcn_table== DescriptorTag())
{
SET_STRING(BSkyBLCNDescriptor);
SET_STRING(SkyLCNDescriptor);
}
else if (priv_dsid == PrivateDataSpecifierID::FSAT &&
PrivateDescriptorID::freesat_region_table == DescriptorTag())
Expand Down Expand Up @@ -560,11 +560,6 @@ QString MPEGDescriptor::toStringPD(uint priv_dsid) const
{
SET_STRING(ComponentNameDescriptor);
}
// OpenTV descriptors
else if (PrivateDescriptorID::opentv_channel_list == DescriptorTag())
{
SET_STRING(OpenTVChannelListDescriptor);
}
// POSSIBLY UNSAFE ! -- end
else
{
Expand Down
24 changes: 12 additions & 12 deletions mythtv/libs/libmythtv/mpeg/mpegdescriptors.h
Original file line number Diff line number Diff line change
Expand Up @@ -202,8 +202,8 @@ class PrivateDescriptorID
// Private -- CH UPC Cablecom
upc_event_episode_title = 0xA7,

// Private -- BSkyB Astra-2 28.2E
bskyb_lcn_table = 0xb1, /* implemented */
// Private -- Sky Astra-2 28.2E and other Sky satellites
sky_lcn_table = 0xb1, /* implemented */

// Private -- FreeSat Astra-2 28.2E
freesat_lcn_table = 0xd3, /* implemented */
Expand All @@ -220,15 +220,15 @@ class PrivateDescriptorID
premiere_content_transmission = 0xF2,

// Private -- OpenTV
opentv_titles_1 = 0xA0, /* implemented */
opentv_titles_2 = 0xA1, /* implemented */
opentv_titles_3 = 0xA2, /* implemented */
opentv_titles_4 = 0xA3, /* implemented */
opentv_summaries_1 = 0xA8, /* implemented */
opentv_summaries_2 = 0xA9, /* implemented */
opentv_summaries_3 = 0xAA, /* implemented */
opentv_summaries_4 = 0xAB, /* implemented */
opentv_channel_list = 0xB1, /* partial */
opentv_titles_1 = 0xA0,
opentv_titles_2 = 0xA1,
opentv_titles_3 = 0xA2,
opentv_titles_4 = 0xA3,
opentv_summaries_1 = 0xA8,
opentv_summaries_2 = 0xA9,
opentv_summaries_3 = 0xAA,
opentv_summaries_4 = 0xAB,
opentv_channel_list = 0xB1, /* sky_lcn_table */
};
};

Expand All @@ -240,7 +240,7 @@ class PrivateDataSpecifierID
public:
enum
{
BSB1 = 0x00000002, // UK BSkyB (Astra 28.2E), Sky New Zealand (Optus D1 160E0)
BSB1 = 0x00000002, // UK Sky (Astra 28.2E), Sky New Zealand (Optus D1 160E0)
CASEMA = 0x00000016, // NL Casema
EACEM = 0x00000028, // NL Ziggo
NORDIG = 0x00000029, // EU Nordig
Expand Down
6 changes: 3 additions & 3 deletions mythtv/libs/libmythtv/mpeg/mpegtables.h
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@

/** Leap seconds as of June 30th, 2012. */
#define GPS_LEAP_SECONDS 16
// Note: You can optain this number by adding one
// Note: You can obtain this number by adding one
// for every leap second added to UTC since Jan 6th, 1980
// and subtracting one for every leap second removed.
// See http://en.wikipedia.org/wiki/Leap_second
Expand Down Expand Up @@ -371,7 +371,7 @@ class MTV_PUBLIC TableID
TSS = 0xA2,
CMPNAME = 0xA3,

// opentv
// OpenTV
OTV_EIT_TITbeg = 0xA0, // always on pids config (0x30-0x37)
OTV_EIT_TITend = 0xA3, // always on pids config (0x30-0x37)
OTV_EIT_SUMbeg = 0xA8, // always on pids config (0x40-0x47)
Expand Down Expand Up @@ -446,7 +446,7 @@ class MTV_PUBLIC PSIPTable : public PESPacket
m_pesDataSize = SectionLength();
}
public:
PSIPTable(const PSIPTable& table) = default;
PSIPTable(const PSIPTable&) = default;
// section_syntax_ind 1 1.0 8 should always be 1
// private_indicator 1 1.1 9 should always be 1
explicit PSIPTable(const PESPacket& table) : PESPacket(table)
Expand Down
55 changes: 55 additions & 0 deletions mythtv/libs/libmythtv/mythcodecid.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ QString toString(MythCodecID codecid)
case kCodec_VP8: return "VP8";
case kCodec_VP9: return "VP9";
case kCodec_HEVC: return "HEVC";
case kCodec_AV1: return "AV1";

case kCodec_MPEG1_VDPAU: return "MPEG1 VDPAU";
case kCodec_MPEG2_VDPAU: return "MPEG2 VDPAU";
Expand All @@ -36,6 +37,7 @@ QString toString(MythCodecID codecid)
case kCodec_VP8_VDPAU: return "VP8 VDPAU";
case kCodec_VP9_VDPAU: return "VP9 VDPAU";
case kCodec_HEVC_VDPAU: return "HEVC VDPAU";
case kCodec_AV1_VDPAU: return "AV1 VDPAU";

case kCodec_MPEG1_VDPAU_DEC: return "MPEG1 VDPAU DEC";
case kCodec_MPEG2_VDPAU_DEC: return "MPEG2 VDPAU DEC";
Expand All @@ -47,6 +49,7 @@ QString toString(MythCodecID codecid)
case kCodec_VP8_VDPAU_DEC: return "VP8 VDPAU DEC";
case kCodec_VP9_VDPAU_DEC: return "VP9 VDPAU DEC";
case kCodec_HEVC_VDPAU_DEC: return "HEVC VDPAU DEC";
case kCodec_AV1_VDPAU_DEC: return "AV1 VDPAU DEC";

case kCodec_MPEG1_VAAPI: return "MPEG1 VAAPI";
case kCodec_MPEG2_VAAPI: return "MPEG2 VAAPI";
Expand All @@ -58,6 +61,7 @@ QString toString(MythCodecID codecid)
case kCodec_VP8_VAAPI: return "VP8 VAAPI";
case kCodec_VP9_VAAPI: return "VP9 VAAPI";
case kCodec_HEVC_VAAPI: return "HEVC VAAPI";
case kCodec_AV1_VAAPI: return "AV1 VAAPI";

case kCodec_MPEG1_VAAPI_DEC: return "MPEG1 VAAPI DEC";
case kCodec_MPEG2_VAAPI_DEC: return "MPEG2 VAAPI DEC";
Expand All @@ -69,6 +73,7 @@ QString toString(MythCodecID codecid)
case kCodec_VP8_VAAPI_DEC: return "VP8 VAAPI DEC";
case kCodec_VP9_VAAPI_DEC: return "VP9 VAAPI DEC";
case kCodec_HEVC_VAAPI_DEC: return "HEVC VAAPI DEC";
case kCodec_AV1_VAAPI_DEC: return "AV1 VAAPI DEC";

case kCodec_MPEG1_DXVA2: return "MPEG1 DXVA2";
case kCodec_MPEG2_DXVA2: return "MPEG2 DXVA2";
Expand All @@ -80,6 +85,7 @@ QString toString(MythCodecID codecid)
case kCodec_VP8_DXVA2: return "VP8 DXVA2";
case kCodec_VP9_DXVA2: return "VP9 DXVA2";
case kCodec_HEVC_DXVA2: return "HEVC DXVA2";
case kCodec_AV1_DXVA2: return "AV1 DXVA2";

case kCodec_MPEG1_MEDIACODEC: return "MPEG1 MEDIACODEC";
case kCodec_MPEG2_MEDIACODEC: return "MPEG2 MEDIACODEC";
Expand All @@ -91,6 +97,7 @@ QString toString(MythCodecID codecid)
case kCodec_VP8_MEDIACODEC: return "VP8 MEDIACODEC";
case kCodec_VP9_MEDIACODEC: return "VP9 MEDIACODEC";
case kCodec_HEVC_MEDIACODEC: return "HEVC MEDIACODEC";
case kCodec_AV1_MEDIACODEC: return "AV1 MEDIACODEC";

case kCodec_MPEG1_MEDIACODEC_DEC: return "MPEG1 MEDIACODEC DEC";
case kCodec_MPEG2_MEDIACODEC_DEC: return "MPEG2 MEDIACODEC DEC";
Expand All @@ -102,6 +109,7 @@ QString toString(MythCodecID codecid)
case kCodec_VP8_MEDIACODEC_DEC: return "VP8 MEDIACODEC DEC";
case kCodec_VP9_MEDIACODEC_DEC: return "VP9 MEDIACODEC DEC";
case kCodec_HEVC_MEDIACODEC_DEC: return "HEVC MEDIACODEC DEC";
case kCodec_AV1_MEDIACODEC_DEC: return "AV1 MEDIACODEC DEC";

case kCodec_MPEG1_NVDEC: return "MPEG1 NVDEC";
case kCodec_MPEG2_NVDEC: return "MPEG2 NVDEC";
Expand All @@ -113,6 +121,7 @@ QString toString(MythCodecID codecid)
case kCodec_VP8_NVDEC: return "VP8 NVDEC";
case kCodec_VP9_NVDEC: return "VP9 NVDEC";
case kCodec_HEVC_NVDEC: return "HEVC NVDEC";
case kCodec_AV1_NVDEC: return "AV1 NVDEC";

case kCodec_MPEG1_NVDEC_DEC: return "MPEG1 NVDEC DEC";
case kCodec_MPEG2_NVDEC_DEC: return "MPEG2 NVDEC DEC";
Expand All @@ -124,6 +133,7 @@ QString toString(MythCodecID codecid)
case kCodec_VP8_NVDEC_DEC: return "VP8 NVDEC DEC";
case kCodec_VP9_NVDEC_DEC: return "VP9 NVDEC DEC";
case kCodec_HEVC_NVDEC_DEC: return "HEVC NVDEC DEC";
case kCodec_AV1_NVDEC_DEC: return "AV1 NVDEC DEC";

case kCodec_MPEG1_VTB: return "MPEG1 VTB";
case kCodec_MPEG2_VTB: return "MPEG2 VTB";
Expand All @@ -135,6 +145,7 @@ QString toString(MythCodecID codecid)
case kCodec_VP8_VTB: return "VP8 VTB";
case kCodec_VP9_VTB: return "VP9 VTB";
case kCodec_HEVC_VTB: return "HEVC VTB";
case kCodec_AV1_VTB: return "AV1 VTB";

case kCodec_MPEG1_VTB_DEC: return "MPEG1 VTB DEC";
case kCodec_MPEG2_VTB_DEC: return "MPEG2 VTB DEC";
Expand All @@ -146,6 +157,7 @@ QString toString(MythCodecID codecid)
case kCodec_VP8_VTB_DEC: return "VP8 VTB DEC";
case kCodec_VP9_VTB_DEC: return "VP9 VTB DEC";
case kCodec_HEVC_VTB_DEC: return "HEVC VTB DEC";
case kCodec_AV1_VTB_DEC: return "AV1 VTB DEC";

case kCodec_MPEG1_V4L2: return "MPEG1 V4L2";
case kCodec_MPEG2_V4L2: return "MPEG2 V4L2";
Expand All @@ -157,6 +169,7 @@ QString toString(MythCodecID codecid)
case kCodec_VP8_V4L2: return "VP8 V4L2";
case kCodec_VP9_V4L2: return "VP9 V4L2";
case kCodec_HEVC_V4L2: return "HEVC V4L2";
case kCodec_AV1_V4L2: return "AV1 V4L2";

case kCodec_MPEG1_V4L2_DEC: return "MPEG1 V4L2 DEC";
case kCodec_MPEG2_V4L2_DEC: return "MPEG2 V4L2 DEC";
Expand All @@ -168,6 +181,7 @@ QString toString(MythCodecID codecid)
case kCodec_VP8_V4L2_DEC: return "VP8 V4L2 DEC";
case kCodec_VP9_V4L2_DEC: return "VP9 V4L2 DEC";
case kCodec_HEVC_V4L2_DEC: return "HEVC V4L2 DEC";
case kCodec_AV1_V4L2_DEC: return "AV1 V4L2 DEC";

case kCodec_MPEG1_MMAL: return "MPEG1 MMAL";
case kCodec_MPEG2_MMAL: return "MPEG2 MMAL";
Expand All @@ -179,6 +193,7 @@ QString toString(MythCodecID codecid)
case kCodec_VP8_MMAL: return "VP8 MMAL";
case kCodec_VP9_MMAL: return "VP9 MMAL";
case kCodec_HEVC_MMAL: return "HEVC MMAL";
case kCodec_AV1_MMAL: return "AV1 MMAL";

case kCodec_MPEG1_MMAL_DEC: return "MPEG1 MMAL DEC";
case kCodec_MPEG2_MMAL_DEC: return "MPEG2 MMAL DEC";
Expand All @@ -190,6 +205,7 @@ QString toString(MythCodecID codecid)
case kCodec_VP8_MMAL_DEC: return "VP8 MMAL DEC";
case kCodec_VP9_MMAL_DEC: return "VP9 MMAL DEC";
case kCodec_HEVC_MMAL_DEC: return "HEVC MMAL DEC";
case kCodec_AV1_MMAL_DEC: return "AV1 MMAL DEC";

case kCodec_MPEG1_DRMPRIME: return "MPEG1 DRMPRIME";
case kCodec_MPEG2_DRMPRIME: return "MPEG2 DRMPRIME";
Expand All @@ -201,6 +217,7 @@ QString toString(MythCodecID codecid)
case kCodec_VP8_DRMPRIME: return "VP8 DRMPRIME";
case kCodec_VP9_DRMPRIME: return "VP9 DRMPRIME";
case kCodec_HEVC_DRMPRIME: return "HEVC DRMPRIME";
case kCodec_AV1_DRMPRIME: return "AV1 DRMPRIME";
default:
break;
}
Expand Down Expand Up @@ -396,6 +413,24 @@ AVCodecID myth2av_codecid(MythCodecID codec_id)
case kCodec_HEVC_DRMPRIME:
case kCodec_HEVC_V4L2_DEC: return AV_CODEC_ID_HEVC;

case kCodec_AV1:
case kCodec_AV1_VDPAU:
case kCodec_AV1_VDPAU_DEC:
case kCodec_AV1_VAAPI:
case kCodec_AV1_VAAPI_DEC:
case kCodec_AV1_DXVA2:
case kCodec_AV1_MEDIACODEC:
case kCodec_AV1_MEDIACODEC_DEC:
case kCodec_AV1_NVDEC:
case kCodec_AV1_NVDEC_DEC:
case kCodec_AV1_VTB:
case kCodec_AV1_VTB_DEC:
case kCodec_AV1_MMAL:
case kCodec_AV1_MMAL_DEC:
case kCodec_AV1_V4L2:
case kCodec_AV1_DRMPRIME:
case kCodec_AV1_V4L2_DEC: return AV_CODEC_ID_AV1;

case kCodec_NORMAL_END:
case kCodec_VDPAU_END:
case kCodec_VDPAU_DEC_END:
Expand Down Expand Up @@ -431,6 +466,7 @@ uint mpeg_version(int codec_id)
case AV_CODEC_ID_VP8: return 8;
case AV_CODEC_ID_VP9: return 9;
case AV_CODEC_ID_HEVC: return 10;
case AV_CODEC_ID_AV1: return 11;
default: break;
}
return 0;
Expand Down Expand Up @@ -632,6 +668,25 @@ QString get_encoding_type(MythCodecID codecid)
case kCodec_HEVC_DRMPRIME:
return "HEVC";

case kCodec_AV1:
case kCodec_AV1_VDPAU:
case kCodec_AV1_VDPAU_DEC:
case kCodec_AV1_VAAPI:
case kCodec_AV1_VAAPI_DEC:
case kCodec_AV1_DXVA2:
case kCodec_AV1_MEDIACODEC:
case kCodec_AV1_MEDIACODEC_DEC:
case kCodec_AV1_NVDEC:
case kCodec_AV1_NVDEC_DEC:
case kCodec_AV1_VTB:
case kCodec_AV1_VTB_DEC:
case kCodec_AV1_V4L2:
case kCodec_AV1_V4L2_DEC:
case kCodec_AV1_MMAL:
case kCodec_AV1_MMAL_DEC:
case kCodec_AV1_DRMPRIME:
return "AV1";

case kCodec_NONE:
case kCodec_NORMAL_END:
case kCodec_VDPAU_END:
Expand Down
17 changes: 17 additions & 0 deletions mythtv/libs/libmythtv/mythcodecid.h
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ enum MythCodecID
kCodec_VP8,
kCodec_VP9,
kCodec_HEVC,
kCodec_AV1,

kCodec_NORMAL_END,

Expand All @@ -43,6 +44,7 @@ enum MythCodecID
kCodec_VP8_VDPAU,
kCodec_VP9_VDPAU,
kCodec_HEVC_VDPAU,
kCodec_AV1_VDPAU,

kCodec_VDPAU_END,

Expand All @@ -58,6 +60,7 @@ enum MythCodecID
kCodec_VP8_VDPAU_DEC,
kCodec_VP9_VDPAU_DEC,
kCodec_HEVC_VDPAU_DEC,
kCodec_AV1_VDPAU_DEC,

kCodec_VDPAU_DEC_END,

Expand All @@ -73,6 +76,7 @@ enum MythCodecID
kCodec_VP8_VAAPI,
kCodec_VP9_VAAPI,
kCodec_HEVC_VAAPI,
kCodec_AV1_VAAPI,

kCodec_VAAPI_END,

Expand All @@ -88,6 +92,7 @@ enum MythCodecID
kCodec_VP8_VAAPI_DEC,
kCodec_VP9_VAAPI_DEC,
kCodec_HEVC_VAAPI_DEC,
kCodec_AV1_VAAPI_DEC,

kCodec_VAAPI_DEC_END,

Expand All @@ -103,6 +108,7 @@ enum MythCodecID
kCodec_VP8_DXVA2,
kCodec_VP9_DXVA2,
kCodec_HEVC_DXVA2,
kCodec_AV1_DXVA2,

kCodec_DXVA2_END,

Expand All @@ -118,6 +124,7 @@ enum MythCodecID
kCodec_VP8_MEDIACODEC,
kCodec_VP9_MEDIACODEC,
kCodec_HEVC_MEDIACODEC,
kCodec_AV1_MEDIACODEC,

kCodec_MEDIACODEC_END,

Expand All @@ -133,6 +140,7 @@ enum MythCodecID
kCodec_VP8_MEDIACODEC_DEC,
kCodec_VP9_MEDIACODEC_DEC,
kCodec_HEVC_MEDIACODEC_DEC,
kCodec_AV1_MEDIACODEC_DEC,

kCodec_MEDIACODEC_DEC_END,

Expand All @@ -148,6 +156,7 @@ enum MythCodecID
kCodec_VP8_NVDEC,
kCodec_VP9_NVDEC,
kCodec_HEVC_NVDEC,
kCodec_AV1_NVDEC,

kCodec_NVDEC_END,

Expand All @@ -163,6 +172,7 @@ enum MythCodecID
kCodec_VP8_NVDEC_DEC,
kCodec_VP9_NVDEC_DEC,
kCodec_HEVC_NVDEC_DEC,
kCodec_AV1_NVDEC_DEC,

kCodec_NVDEC_DEC_END,

Expand All @@ -178,6 +188,7 @@ enum MythCodecID
kCodec_VP8_VTB,
kCodec_VP9_VTB,
kCodec_HEVC_VTB,
kCodec_AV1_VTB,

kCodec_VTB_END,

Expand All @@ -193,6 +204,7 @@ enum MythCodecID
kCodec_VP8_VTB_DEC,
kCodec_VP9_VTB_DEC,
kCodec_HEVC_VTB_DEC,
kCodec_AV1_VTB_DEC,

kCodec_VTB_DEC_END,

Expand All @@ -208,6 +220,7 @@ enum MythCodecID
kCodec_VP8_V4L2,
kCodec_VP9_V4L2,
kCodec_HEVC_V4L2,
kCodec_AV1_V4L2,

kCodec_V4L2_END,

Expand All @@ -223,6 +236,7 @@ enum MythCodecID
kCodec_VP8_V4L2_DEC,
kCodec_VP9_V4L2_DEC,
kCodec_HEVC_V4L2_DEC,
kCodec_AV1_V4L2_DEC,

kCodec_V4L2_DEC_END,

Expand All @@ -238,6 +252,7 @@ enum MythCodecID
kCodec_VP8_MMAL,
kCodec_VP9_MMAL,
kCodec_HEVC_MMAL,
kCodec_AV1_MMAL,

kCodec_MMAL_END,

Expand All @@ -253,6 +268,7 @@ enum MythCodecID
kCodec_VP8_MMAL_DEC,
kCodec_VP9_MMAL_DEC,
kCodec_HEVC_MMAL_DEC,
kCodec_AV1_MMAL_DEC,

kCodec_MMAL_DEC_END,

Expand All @@ -268,6 +284,7 @@ enum MythCodecID
kCodec_VP8_DRMPRIME,
kCodec_VP9_DRMPRIME,
kCodec_HEVC_DRMPRIME,
kCodec_AV1_DRMPRIME,

kCodec_DRMPRIME_END
};
Expand Down
128 changes: 36 additions & 92 deletions mythtv/libs/libmythtv/mythvideoout.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -261,8 +261,6 @@ MythVideoOutput *MythVideoOutput::Create(const QString &Decoder, MythCodecID
MythVideoOutput::MythVideoOutput()
: m_display(nullptr)
{
m_dbDisplayDimensionsMM = QSize(gCoreContext->GetNumSetting("DisplaySizeWidth", 0),
gCoreContext->GetNumSetting("DisplaySizeHeight", 0));
m_dbAspectOverride = static_cast<AspectOverrideMode>(gCoreContext->GetNumSetting("AspectOverride", 0));
m_dbAdjustFill = static_cast<AdjustFillMode>(gCoreContext->GetNumSetting("AdjustFill", 0));
m_dbLetterboxColour = static_cast<LetterBoxColour>(gCoreContext->GetNumSetting("LetterboxColour", 0));
Expand Down Expand Up @@ -461,7 +459,7 @@ QRect MythVideoOutput::GetVisibleOSDBounds(float &VisibleAspect,
QRect dvr = m_window.GetDisplayVisibleRect();
float dispPixelAdj = 1.0F;
if (dvr.height() && dvr.width())
dispPixelAdj = (GetDisplayAspect() * dvr.height()) / dvr.width();
dispPixelAdj = (m_window.GetDisplayAspect() * dvr.height()) / dvr.width();

float ova = m_window.GetOverridenVideoAspect();
QRect vr = m_window.GetVideoRect();
Expand Down Expand Up @@ -680,11 +678,6 @@ AdjustFillMode MythVideoOutput::GetAdjustFill(void) const
return m_window.GetAdjustFill();
}

float MythVideoOutput::GetDisplayAspect(void) const
{
return m_window.GetDisplayAspect();
}

/// \bug not implemented correctly. vpos is not updated.
VideoFrame* MythVideoOutput::GetLastDecodedFrame(void)
{
Expand Down Expand Up @@ -948,8 +941,11 @@ void MythVideoOutput::ResizeForVideo(QSize Size)
{
// Switching to custom display resolution succeeded
// Make a note of the new size
m_window.SetDisplayProperties(m_display->GetPhysicalSize(),
static_cast<float>(m_display->GetAspectRatio()));
QString source;
double aspect = m_display->GetAspectRatio(source);
LOG(VB_PLAYBACK, LOG_INFO, LOC + QString("Aspect ratio: %1 (%2)")
.arg(aspect).arg(source));
m_window.SetDisplayAspect(static_cast<float>(aspect));
m_window.SetWindowSize(m_display->GetResolution());

bool fullscreen = !m_window.UsingGuiSize();
Expand Down Expand Up @@ -982,96 +978,44 @@ void MythVideoOutput::ResizeForVideo(QSize Size)
window->Show();
}

/**
* \brief Init display measurements based on database settings and
* actual screen parameters.
*/
/*! \brief Initialise display measurement
*
* The sole intent here is to ensure that VideoOutWindow has the correct aspect
* ratio when it calculates the video display rectangle.
*/
void MythVideoOutput::InitDisplayMeasurements(void)
{
if (!m_display)
return;

QString source = "Actual";

// get the physical dimensions (in mm) of the display. If using
// DisplayRes, this will be overridden when we call ResizeForVideo
float disp_aspect = m_window.GetDisplayAspect();
QSize disp_dim = m_dbDisplayDimensionsMM;
if (disp_dim.isEmpty())
disp_dim = m_display->GetPhysicalSize();
else
source = "Database";
m_window.SetDisplayProperties(disp_dim, disp_aspect);

// Determine window and screen dimensions in pixels
QSize screen_size = m_display->GetResolution();
QSize window_size = m_window.GetWindowRect().size();

if (screen_size.isEmpty())
screen_size = window_size.isEmpty() ? QSize(1920, 1080): window_size;
if (window_size.isEmpty())
window_size = screen_size;

float pixel_aspect = static_cast<float>(screen_size.width()) / screen_size.height();

LOG(VB_PLAYBACK, LOG_INFO, LOC +
QString("Pixel dimensions: Screen %1x%2, window %3x%4")
.arg(screen_size.width()).arg(screen_size.height())
.arg(window_size.width()).arg(window_size.height()));

// Check the display dimensions
// disp_aspect = m_window.GetDisplayAspect();
disp_dim = m_window.GetDisplayDim();

// If we are using Xinerama the display dimensions cannot be trusted.
// We need to use the Xinerama monitor aspect ratio from the DB to set
// the physical screen width. This assumes the height is correct, which
// is more or less true in the typical side-by-side monitor setup.
if (m_window.UsingXinerama())
{
source = "Xinerama";
disp_aspect = static_cast<float>(gCoreContext->GetFloatSettingOnHost(
"XineramaMonitorAspectRatio",
gCoreContext->GetHostName(), static_cast<double>(pixel_aspect)));
// Auto setting
if (disp_aspect < 0.1F)
disp_aspect = static_cast<float>(m_display->EstimateVirtualAspectRatio());
if (disp_dim.height() <= 0)
disp_dim.setHeight(300);
disp_dim.setWidth(static_cast<int>(lroundf(disp_dim.height() * disp_aspect)));
}

if (disp_dim.isEmpty())
// Retrieve the display aspect ratio.
// This will be, in priority order:-
// - aspect ratio override when using resolution/mode switching (if not 'Default')
// - aspect ratio override for setups where detection does not work/is broken (multiscreen, broken EDID etc)
// - aspect ratio based on detected physical size (this should be the common/default value)
// - aspect ratio fallback using screen resolution
// - 16:9
QString source;
double displayaspect = m_display->GetAspectRatio(source);
LOG(VB_PLAYBACK, LOG_INFO, LOC + QString("Display aspect ratio: %1 (%2)")
.arg(displayaspect).arg(source));

// Get the window and screen resolutions
QSize window = m_window.GetWindowRect().size();
QSize screen = m_display->GetResolution();

// If not running fullscreen, adjust for window size and ignore any video
// mode overrides as they do not apply when in a window
if (!window.isEmpty() && !screen.isEmpty() && window != screen)
{
source = "Guessed!";
LOG(VB_GENERAL, LOG_WARNING, LOC +
"Physical size of display unknown. Assuming 17\" monitor with square pixels.");
disp_dim = QSize(static_cast<int>(lroundf(300 * pixel_aspect)), 300);
displayaspect = m_display->GetAspectRatio(source, true);
double screenaspect = screen.width() / static_cast<double>(screen.height());
double windowaspect = window.width() / static_cast<double>(window.height());
displayaspect = displayaspect * (1.0 / screenaspect) * windowaspect;
LOG(VB_PLAYBACK, LOG_INFO, LOC + QString("Window aspect ratio: %1").arg(displayaspect));
}

disp_aspect = static_cast<float>(disp_dim.width()) / disp_dim.height();
LOG(VB_PLAYBACK, LOG_INFO, LOC +
QString("%1 display dimensions: %2x%3 mm Aspect: %4")
.arg(source).arg(disp_dim.width()).arg(disp_dim.height())
.arg(static_cast<double>(disp_aspect)));

// Save the unscaled size and dimensions for window resizing
m_monitorSize = screen_size;
m_monitorDimensions = disp_dim;

// We must now scale the display measurements to our window size and save
// them. If we are running fullscreen this is a no-op.
disp_dim = QSize((disp_dim.width() * window_size.width()) /
screen_size.width(),
(disp_dim.height() * window_size.height()) /
screen_size.height());
disp_aspect = static_cast<float>(disp_dim.width()) / disp_dim.height();

// If we are using XRandR, use the aspect ratio from it
if (m_display->UsingVideoModes())
disp_aspect = static_cast<float>(m_display->GetAspectRatio());

m_window.SetDisplayProperties(disp_dim, disp_aspect);
m_window.SetDisplayAspect(static_cast<float>(displayaspect));
}

///\note Probably no longer required
Expand Down
4 changes: 0 additions & 4 deletions mythtv/libs/libmythtv/mythvideoout.h
Original file line number Diff line number Diff line change
Expand Up @@ -76,7 +76,6 @@ class MythVideoOutput
float &VisibleAspect, float &FontScaling,
float ThemeAspect) const;
QRect GetMHEGBounds(void);
virtual float GetDisplayAspect(void) const;
AspectOverrideMode GetAspectOverride(void) const;
virtual void ToggleAspectOverride(AspectOverrideMode AspectMode = kAspect_Toggle);
AdjustFillMode GetAdjustFill(void) const;
Expand Down Expand Up @@ -158,7 +157,6 @@ class MythVideoOutput

MythDisplay* m_display {nullptr};
VideoOutWindow m_window;
QSize m_dbDisplayDimensionsMM {0,0};
VideoColourSpace m_videoColourSpace;
AspectOverrideMode m_dbAspectOverride {kAspect_Off};
AdjustFillMode m_dbAdjustFill {kAdjustFill_Off};
Expand All @@ -169,8 +167,6 @@ class MythVideoOutput
VideoBuffers m_videoBuffers;
VideoErrorState m_errorState {kError_None};
long long m_framesPlayed {0};
QSize m_monitorSize {640,480};
QSize m_monitorDimensions {400,300};
VideoVisual *m_visual {nullptr};
StereoscopicMode m_stereo {kStereoscopicModeNone};
MythAVCopy m_copyFrame;
Expand Down
2 changes: 1 addition & 1 deletion mythtv/libs/libmythtv/opengl/mythmediacodecinterop.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,7 @@ void* MythMediaCodecInterop::GetSurface(void)
return m_surface.object();
}

void Java_org_mythtv_android_SurfaceTextureListener_frameAvailable(JNIEnv*, jobject, jlong Wait, jobject)
void Java_org_mythtv_video_SurfaceTextureListener_frameAvailable(JNIEnv*, jobject, jlong Wait, jobject)
{
QWaitCondition *wait = reinterpret_cast<QWaitCondition*>(Wait);
if (wait)
Expand Down
2 changes: 1 addition & 1 deletion mythtv/libs/libmythtv/opengl/mythmediacodecinterop.h
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@
// MythTV
#include "mythopenglinterop.h"

extern "C" MTV_PUBLIC void Java_org_mythtv_android_SurfaceTextureListener_frameAvailable(JNIEnv*, jobject, jlong Wait, jobject);
extern "C" MTV_PUBLIC void Java_org_mythtv_video_SurfaceTextureListener_frameAvailable(JNIEnv*, jobject, jlong Wait, jobject);

class MythMediaCodecInterop : public MythOpenGLInterop
{
Expand Down
22 changes: 22 additions & 0 deletions mythtv/libs/libmythtv/opengl/mythvideooutopengl.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -251,6 +251,20 @@ bool MythVideoOutputOpenGL::Init(const QSize &VideoDim, const QSize &VideoDispDi
return true;
}

void MythVideoOutputOpenGL::SetVideoFrameRate(float NewRate)
{
if (!m_dbDisplayProfile)
return;

if (qFuzzyCompare(m_dbDisplayProfile->GetOutput() + 1.0F, NewRate + 1.0F))
return;

LOG(VB_PLAYBACK, LOG_INFO, LOC + QString("Video frame rate changed: %1->%2)")
.arg(static_cast<double>(m_dbDisplayProfile->GetOutput())).arg(static_cast<double>(NewRate)));
m_dbDisplayProfile->SetOutput(NewRate);
m_newFrameRate = true;
}

bool MythVideoOutputOpenGL::InputChanged(const QSize &VideoDim, const QSize &VideoDispDim,
float Aspect, MythCodecID CodecId, bool &AspectOnly,
MythMultiLocker* /*Locks*/, int ReferenceFrames,
Expand Down Expand Up @@ -418,13 +432,21 @@ void MythVideoOutputOpenGL::ProcessFrame(VideoFrame *Frame, OSD */*osd*/,
m_newVideoDim = QSize();
m_newVideoDispDim = QSize();
m_newAspect = 0.0F;
m_newFrameRate = false;

if (wasembedding && ok)
EmbedInWidget(oldrect);

if (!ok)
return;
}
else if (m_newFrameRate)
{
// If we are switching mode purely for a refresh rate change, then there
// is no need to recreate buffers etc etc
ResizeForVideo();
m_newFrameRate = false;
}

if (Frame)
m_window.SetRotation(Frame->rotation);
Expand Down
2 changes: 2 additions & 0 deletions mythtv/libs/libmythtv/opengl/mythvideooutopengl.h
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,7 @@ class MythVideoOutputOpenGL : public MythVideoOutput
void DiscardFrames(bool KeyFrame, bool Flushed) override;
VideoFrameType* DirectRenderFormats(void) override;
void WindowResized(const QSize &Size) override;
void SetVideoFrameRate(float NewRate) override;

protected:
void DestroyBuffers(void);
Expand All @@ -69,6 +70,7 @@ class MythVideoOutputOpenGL : public MythVideoOutput
QSize m_newVideoDim;
QSize m_newVideoDispDim;
float m_newAspect { 0.0F };
bool m_newFrameRate { false };
bool m_buffersCreated { false };

// performance monitoring (-v gpu)
Expand Down
4 changes: 2 additions & 2 deletions mythtv/libs/libmythtv/recorders/rtp/rtpdatapacket.h
Original file line number Diff line number Diff line change
Expand Up @@ -30,12 +30,12 @@
class RTPDataPacket : public UDPPacket
{
public:
RTPDataPacket(const RTPDataPacket &o) = default;
RTPDataPacket(const RTPDataPacket&) = default;
explicit RTPDataPacket(const UDPPacket &o) : UDPPacket(o), m_off(0) { }
explicit RTPDataPacket(uint64_t key) : UDPPacket(key), m_off(0) { }
RTPDataPacket(void) : UDPPacket(0ULL) { }

RTPDataPacket& operator=(const RTPDataPacket &rhs) = default;
RTPDataPacket& operator=(const RTPDataPacket&) = default;

bool IsValid(void) const override // UDPPacket
{
Expand Down
4 changes: 2 additions & 2 deletions mythtv/libs/libmythtv/recorders/rtp/udppacket.h
Original file line number Diff line number Diff line change
Expand Up @@ -20,12 +20,12 @@
class UDPPacket
{
public:
UDPPacket(const UDPPacket &o) = default;
UDPPacket(const UDPPacket&) = default;
explicit UDPPacket(uint64_t key) : m_key(key) { }
UDPPacket(void) = default;
virtual ~UDPPacket() = default;

UDPPacket& operator=(const UDPPacket &rhs) = default;
UDPPacket& operator=(const UDPPacket&) = default;

/// IsValid() must return true before any data access methods are called,
/// other than GetDataReference() and GetData()
Expand Down
1 change: 0 additions & 1 deletion mythtv/libs/libmythtv/scanwizard.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -186,7 +186,6 @@ void ScanWizard::Scan()
DoChannelNumbersOnly(), DoCompleteChannelsOnly(),
DoFullChannelSearch(),
DoAddFullTS(),
DoScanOpenTV(),
GetServiceRequirements(),

// stuff needed for particular scans
Expand Down
3 changes: 1 addition & 2 deletions mythtv/libs/libmythtv/scanwizard.h
Original file line number Diff line number Diff line change
Expand Up @@ -108,8 +108,7 @@ class MTV_PUBLIC ScanWizard : public GroupSetting
FullChannelSearch *m_fullSearch {nullptr};
AddFullTS *m_addFullTS {nullptr};
TrustEncSISetting *m_trustEncSI {nullptr};
ScanOpenTV *m_scanOpenTV {nullptr};
// End of members moved from ScanWizardConfig
// End of members moved from ScanWizardConfig
};

#endif // SCANWIZARD_H
4 changes: 2 additions & 2 deletions mythtv/libs/libmythtv/textsubtitleparser.h
Original file line number Diff line number Diff line change
Expand Up @@ -21,8 +21,8 @@ class text_subtitle_t
public:
text_subtitle_t(long start_, long end_) : m_start(start_), m_end(end_) {}
text_subtitle_t() = default;
text_subtitle_t(const text_subtitle_t &other) = default;
text_subtitle_t& operator= (const text_subtitle_t &rhs) = default;
text_subtitle_t(const text_subtitle_t&) = default;
text_subtitle_t& operator= (const text_subtitle_t&) = default;

public:
uint64_t m_start {0}; ///< Starting time in msec or starting frame
Expand Down
13 changes: 8 additions & 5 deletions mythtv/libs/libmythtv/transporteditor.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -256,7 +256,10 @@ void TransportListEditor::Load()
QString tid = query.value(5).toUInt() ?
QString("tid %1").arg(query.value(5).toUInt(), 5) : "";

QString hz = (CardUtil::QPSK == m_cardtype) ? "kHz" : "Hz";
QString hz = "Hz";
if (CardUtil::QPSK == m_cardtype ||
CardUtil::DVBS2 == m_cardtype)
hz = "kHz";

QString type = "";
if (CardUtil::OFDM == m_cardtype)
Expand Down Expand Up @@ -682,9 +685,9 @@ class DVBTModulationSystem : public MythUIComboBoxSetting, public MuxDBStorage
MythUIComboBoxSetting(this), MuxDBStorage(this, id, "mod_sys")
{
setLabel(QObject::tr("Modulation System"));
setHelpText(QObject::tr("Modulation System (Default: DVB-T)"));
setHelpText(QObject::tr("Modulation System (Default: DVB-T2)"));
addSelection(QObject::tr("DVB-T"), "DVB-T");
addSelection(QObject::tr("DVB-T2"), "DVB-T2");
addSelection(QObject::tr("DVB-T2"), "DVB-T2", true);
};
};

Expand All @@ -695,9 +698,9 @@ class DVBSModulationSystem : public MythUIComboBoxSetting, public MuxDBStorage
MythUIComboBoxSetting(this), MuxDBStorage(this, id, "mod_sys")
{
setLabel(QObject::tr("Modulation System"));
setHelpText(QObject::tr("Modulation System (Default: DVB-S)"));
setHelpText(QObject::tr("Modulation System (Default: DVB-S2)"));
addSelection(QObject::tr("DVB-S"), "DVB-S");
addSelection(QObject::tr("DVB-S2"), "DVB-S2");
addSelection(QObject::tr("DVB-S2"), "DVB-S2", true);
}
};

Expand Down
5 changes: 1 addition & 4 deletions mythtv/libs/libmythtv/tv_play.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1175,10 +1175,7 @@ bool TV::Init(bool createWindow)
GetMythMainWindow()->size());

// adjust for window manager wierdness.
float dummy1 = 0.0F;
float dummy2 = 0.0F;
QRect screen;
GetMythUI()->GetScreenSettings(screen, dummy1, dummy2);
QRect screen = GetMythUI()->GetScreenSettings();
if ((abs(m_savedGuiBounds.x() - screen.left()) < 3) &&
(abs(m_savedGuiBounds.y() - screen.top()) < 3))
{
Expand Down
85 changes: 57 additions & 28 deletions mythtv/libs/libmythtv/videocolourspace.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ extern "C" {
const VideoColourSpace::ColourPrimaries VideoColourSpace::kBT709 =
{{{0.640F, 0.330F}, {0.300F, 0.600F}, {0.150F, 0.060F}}, {0.3127F, 0.3290F}};
const VideoColourSpace::ColourPrimaries VideoColourSpace::kBT610_525 =
{{{0.640F, 0.340F}, {0.310F, 0.595F}, {0.155F, 0.070F}}, {0.3127F, 0.3290F}};
{{{0.630F, 0.340F}, {0.310F, 0.595F}, {0.155F, 0.070F}}, {0.3127F, 0.3290F}};
const VideoColourSpace::ColourPrimaries VideoColourSpace::kBT610_625 =
{{{0.640F, 0.330F}, {0.290F, 0.600F}, {0.150F, 0.060F}}, {0.3127F, 0.3290F}};
const VideoColourSpace::ColourPrimaries VideoColourSpace::kBT2020 =
Expand Down Expand Up @@ -77,6 +77,7 @@ VideoColourSpace::VideoColourSpace(VideoColourSpace *Parent)
m_dbSettings[kPictureAttribute_Colour] = gCoreContext->GetNumSetting("PlaybackColour", 50);
m_dbSettings[kPictureAttribute_Hue] = gCoreContext->GetNumSetting("PlaybackHue", 0);
m_dbSettings[kPictureAttribute_Range] = gCoreContext->GetBoolSetting("GUIRGBLevels", true);
m_primariesMode = toPrimariesMode(gCoreContext->GetSetting("ColourPrimariesMode", "auto"));
}

SetBrightness(m_dbSettings[kPictureAttribute_Brightness]);
Expand All @@ -89,12 +90,23 @@ VideoColourSpace::VideoColourSpace(VideoColourSpace *Parent)
MythDisplay* display = MythDisplay::AcquireRelease();
MythEDID& edid = display->GetEDID();
// We assume sRGB/Rec709 by default
if (edid.Valid() && !edid.IsSRGB())
bool custom = edid.Valid() && !edid.IsSRGB();
bool likesrgb = custom && edid.IsLikeSRGB() && m_primariesMode != PrimariesExact;
if (custom)
{
m_customDisplayGamma = edid.Gamma();
m_customDisplayPrimaries = new ColourPrimaries;
MythEDID::Primaries displayprimaries = edid.ColourPrimaries();
memcpy(m_customDisplayPrimaries, &displayprimaries, sizeof(ColourPrimaries));
// Use sRGB if we don't want exact matching (i.e. close is good enough)
// and the display primaries are similar to sRGB.
if (likesrgb && qFuzzyCompare(edid.Gamma() + 1.0F, 2.2F + 1.0F))
{
LOG(VB_PLAYBACK, LOG_INFO, LOC + "sRGB primaries preferred as close match to display primaries");
}
else
{
m_customDisplayGamma = edid.Gamma();
m_customDisplayPrimaries = new ColourPrimaries;
MythEDID::Primaries displayprimaries = edid.ColourPrimaries();
memcpy(m_customDisplayPrimaries, &displayprimaries, sizeof(ColourPrimaries));
}
}
MythDisplay::AcquireRelease(false);
}
Expand Down Expand Up @@ -483,51 +495,68 @@ void VideoColourSpace::SaveValue(PictureAttribute AttributeType, int Value)

QMatrix4x4 VideoColourSpace::GetPrimaryConversion(int Source, int Dest)
{
QMatrix4x4 result; // identity
auto source = static_cast<AVColorPrimaries>(Source);
auto dest = static_cast<AVColorPrimaries>(Dest);
auto force = m_customDisplayPrimaries != nullptr;
// Default to identity
QMatrix4x4 result;

if (!force && ((source == dest) || (m_primariesMode == PrimariesDisabled)))
// User isn't interested in quality
if (PrimariesDisabled == m_primariesMode)
return result;

ColourPrimaries srcprimaries {};
ColourPrimaries dstprimaries {};
GetPrimaries(source, srcprimaries, m_colourGamma);
GetPrimaries(dest, dstprimaries, m_displayGamma);
auto source = static_cast<AVColorPrimaries>(Source);
auto dest = static_cast<AVColorPrimaries>(Dest);
auto custom = m_customDisplayPrimaries != nullptr;

// Auto will only enable if there is a significant difference between source
// and destination. Most people will not notice the difference bt709 and bt610 etc
// and we avoid extra GPU processing.
// BT2020 is currently the main target - which is easily differentiated by its gamma.
if (!force && (m_primariesMode == PrimariesAuto) && qFuzzyCompare(m_colourGamma + 1.0F, m_displayGamma + 1.0F))
// No-op
if (!custom && (source == dest))
return result;

// Use the display's chromaticities if not sRGB
if (force)
ColourPrimaries srcprimaries = GetPrimaries(source, m_colourGamma);
ColourPrimaries dstprimaries = GetPrimaries(dest, m_displayGamma);
if (custom)
{
dstprimaries = *m_customDisplayPrimaries;
dstprimaries = *m_customDisplayPrimaries;
m_displayGamma = m_customDisplayGamma;
}

// If 'exact' is not requested and the primaries and gamma are similar, then
// ignore. Note: 0.021F should cover any differences between Rec.709/sRGB and Rec.610
if ((m_primariesMode == PrimariesRelaxed) && qFuzzyCompare(m_colourGamma + 1.0F, m_displayGamma + 1.0F) &&
Similar(srcprimaries, dstprimaries, 0.021F))
{
return result;
}

return (RGBtoXYZ(srcprimaries) * RGBtoXYZ(dstprimaries).inverted());
}

void VideoColourSpace::GetPrimaries(int Primary, ColourPrimaries &Out, float &Gamma)
VideoColourSpace::ColourPrimaries VideoColourSpace::GetPrimaries(int Primary, float &Gamma)
{
auto primary = static_cast<AVColorPrimaries>(Primary);
Gamma = 2.2F;
switch (primary)
{
case AVCOL_PRI_BT470BG:
case AVCOL_PRI_BT470M: Out = kBT610_625; return;
case AVCOL_PRI_BT470M: return kBT610_625;
case AVCOL_PRI_SMPTE170M:
case AVCOL_PRI_SMPTE240M: Out = kBT610_525; return;
case AVCOL_PRI_BT2020: Out = kBT2020; Gamma = 2.4F; return;
default: Out = kBT709; return;
case AVCOL_PRI_SMPTE240M: return kBT610_525;
case AVCOL_PRI_BT2020: Gamma = 2.4F; return kBT2020;
default: return kBT709;
}
}

bool VideoColourSpace::Similar(const ColourPrimaries &First, const ColourPrimaries &Second, float Fuzz)
{
auto cmp = [=](float One, float Two) { return (abs(One - Two) < Fuzz); };
return cmp(First.primaries[0][0], Second.primaries[0][0]) &&
cmp(First.primaries[0][1], Second.primaries[0][1]) &&
cmp(First.primaries[1][0], Second.primaries[1][0]) &&
cmp(First.primaries[1][1], Second.primaries[1][1]) &&
cmp(First.primaries[2][0], Second.primaries[2][0]) &&
cmp(First.primaries[2][1], Second.primaries[2][1]) &&
cmp(First.whitepoint[0], Second.whitepoint[0]) &&
cmp(First.whitepoint[1], Second.whitepoint[1]);
}

inline float CalcBy(const float p[3][2], const float w[2])
{
float val = ((1-w[0])/w[1] - (1-p[0][0])/p[0][1]) * (p[1][0]/p[1][1] - p[0][0]/p[0][1]) -
Expand Down
8 changes: 5 additions & 3 deletions mythtv/libs/libmythtv/videocolourspace.h
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,8 @@ class VideoColourSpace : public QObject, public QMatrix4x4, public ReferenceCoun
static const ColourPrimaries kBT610_525;
static const ColourPrimaries kBT610_625;
static const ColourPrimaries kBT2020;
static bool Similar(const ColourPrimaries &First, const ColourPrimaries &Second,
float Fuzz);

public slots:
int SetPictureAttribute(PictureAttribute Attribute, int Value);
Expand All @@ -66,7 +68,7 @@ class VideoColourSpace : public QObject, public QMatrix4x4, public ReferenceCoun
void Update(void);
void Debug(void);
QMatrix4x4 GetPrimaryConversion(int Source, int Dest);
static void GetPrimaries(int Primary, ColourPrimaries &Out, float &Gamma);
static ColourPrimaries GetPrimaries(int Primary, float &Gamma);
static QMatrix4x4 RGBtoXYZ(ColourPrimaries Primaries);

private:
Expand All @@ -85,13 +87,13 @@ class VideoColourSpace : public QObject, public QMatrix4x4, public ReferenceCoun
bool m_updatesDisabled { true };
int m_colourShifted { 0 };
int m_colourTransfer { AVCOL_TRC_BT709 };
PrimariesMode m_primariesMode { PrimariesAuto };
PrimariesMode m_primariesMode { PrimariesRelaxed };
int m_colourPrimaries { AVCOL_PRI_BT709 };
int m_displayPrimaries { AVCOL_PRI_BT709 };
float m_colourGamma { 2.2F };
float m_displayGamma { 2.2F };
QMatrix4x4 m_primaryMatrix { };
float m_customDisplayGamma { 2.2F };
float m_customDisplayGamma { 0.0F };
ColourPrimaries *m_customDisplayPrimaries { nullptr };
VideoColourSpace *m_parent { nullptr };
};
Expand Down
Loading