mirror of
https://github.com/jellyfin/jellyfin-media-player.git
synced 2024-11-27 00:00:38 +00:00
Probe certain aspects system codecs on Windows and OSX
Roughly probe which resolutions are supported by the Windows h264 decoder. Newer Windows versions support higher resolutions. Exclude the AudioToolbox AC3 decoder on older OSX versions. Apple didn't provive an AC3 decoder yet, so a buggy Perian decoder could be picked up.
This commit is contained in:
parent
75399e6856
commit
7efd4111b1
7
resources/testmedia/README.txt
Normal file
7
resources/testmedia/README.txt
Normal file
@ -0,0 +1,7 @@
|
||||
Produced with:
|
||||
|
||||
x264 input.png --profile=high --tune=stillimage --level=5.1 -o out.h264
|
||||
|
||||
where input.png was a black image with the appropriate resolution.
|
||||
|
||||
x264 was patched to remove the SEI message (because it doubled the size).
|
BIN
resources/testmedia/high_1920x1080.h264
Normal file
BIN
resources/testmedia/high_1920x1080.h264
Normal file
Binary file not shown.
BIN
resources/testmedia/high_4096x2160.h264
Normal file
BIN
resources/testmedia/high_4096x2160.h264
Normal file
Binary file not shown.
BIN
resources/testmedia/high_4096x2304.h264
Normal file
BIN
resources/testmedia/high_4096x2304.h264
Normal file
Binary file not shown.
@ -9,6 +9,8 @@
|
||||
#include <QUuid>
|
||||
#include <QUrl>
|
||||
#include <QUrlQuery>
|
||||
#include <QResource>
|
||||
#include <QSysInfo>
|
||||
#include "system/SystemComponent.h"
|
||||
#include "settings/SettingsComponent.h"
|
||||
#include "utils/Utils.h"
|
||||
@ -41,12 +43,12 @@ static const Codec Encoders[] = {
|
||||
// We might want to use Codec.quality to decide this one day.
|
||||
// But for now, it's better if we can quickly change these.
|
||||
static QSet<QString> g_systemVideoDecoderWhitelist = {
|
||||
// definitely work
|
||||
// RPI
|
||||
"h264_mmal",
|
||||
"mpeg2_mmal",
|
||||
"mpeg4_mmal",
|
||||
"vc1_mmal",
|
||||
// still sketchy at best, partially broken
|
||||
// Windows
|
||||
"h264_mf",
|
||||
"hevc_mf",
|
||||
"vc1_mf",
|
||||
@ -60,12 +62,13 @@ static QSet<QString> g_systemVideoDecoderWhitelist = {
|
||||
};
|
||||
|
||||
static QSet<QString> g_systemAudioDecoderWhitelist = {
|
||||
// should work well
|
||||
// OSX
|
||||
"aac_at",
|
||||
"ac3_at",
|
||||
"mp1_at",
|
||||
"mp2_at",
|
||||
"mp3_at",
|
||||
// Windows
|
||||
"ac3_mf",
|
||||
"eac3_mf",
|
||||
"aac_mf",
|
||||
@ -77,6 +80,8 @@ static QSet<QString> g_systemAudioDecoderWhitelist = {
|
||||
static QSet<QString> g_systemAudioEncoderWhitelist = {
|
||||
};
|
||||
|
||||
static QSize g_mediaFoundationH264MaxResolution;
|
||||
|
||||
static QString g_codecVersion;
|
||||
static QList<CodecDriver> g_cachedCodecList;
|
||||
|
||||
@ -269,9 +274,7 @@ static QString getDeviceID()
|
||||
static QString getFFmpegVersion()
|
||||
{
|
||||
auto mpv = mpv::qt::Handle::FromRawHandle(mpv_create());
|
||||
if (!mpv)
|
||||
return "";
|
||||
if (mpv_initialize(mpv) < 0)
|
||||
if (!mpv || mpv_initialize(mpv) < 0)
|
||||
return "";
|
||||
return mpv::qt::get_property_variant(mpv, "ffmpeg-version").toString();
|
||||
}
|
||||
@ -303,6 +306,77 @@ void Codecs::preinitCodecs()
|
||||
getDeviceID();
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
static bool probeDecoder(QString decoder, QString resourceName)
|
||||
{
|
||||
QResource resource(resourceName);
|
||||
|
||||
QLOG_DEBUG() << "Testing decoding of" << resource.fileName();
|
||||
|
||||
if (!resource.isValid())
|
||||
return false;
|
||||
|
||||
auto mpv = mpv::qt::Handle::FromRawHandle(mpv_create());
|
||||
|
||||
// Disable any output.
|
||||
mpv::qt::set_option_variant(mpv, "vo", "null");
|
||||
|
||||
if (!mpv || mpv_initialize(mpv) < 0)
|
||||
return false;
|
||||
|
||||
// Force the decoder. The ",-" means that if the first entry fails, the next codec in the global
|
||||
// codec list will not be tried, and decoding fails.
|
||||
mpv::qt::set_option_variant(mpv, "vd", "lavc:" + decoder + ",-");
|
||||
|
||||
// Attempt decoding, and return success.
|
||||
auto data = QByteArray::fromRawData((const char *)resource.data(), resource.size());
|
||||
if (resource.isCompressed())
|
||||
data = qUncompress(data);
|
||||
auto hex = data.toHex();
|
||||
mpv::qt::command_variant(mpv, QVariantList{"loadfile", "hex://" + QString::fromLatin1(hex)});
|
||||
bool result = false;
|
||||
while (1) {
|
||||
mpv_event *event = mpv_wait_event(mpv, 0);
|
||||
if (event->event_id == MPV_EVENT_SHUTDOWN)
|
||||
break;
|
||||
if (event->event_id == MPV_EVENT_END_FILE)
|
||||
{
|
||||
mpv_event_end_file *endFile = (mpv_event_end_file *)event->data;
|
||||
result = endFile->reason == MPV_END_FILE_REASON_EOF;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
QLOG_DEBUG() << "Result:" << result;
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
void Codecs::probeCodecs()
|
||||
{
|
||||
#ifdef Q_OS_WIN32
|
||||
if (probeDecoder("h264_mf", ":/testmedia/high_4096x2304.h264"))
|
||||
g_mediaFoundationH264MaxResolution = QSize(4096, 2304);
|
||||
else if (probeDecoder("h264_mf", ":/testmedia/high_4096x2160.h264"))
|
||||
g_mediaFoundationH264MaxResolution = QSize(4096, 2160);
|
||||
else if (probeDecoder("h264_mf", ":/testmedia/high_4096x1080.h264"))
|
||||
g_mediaFoundationH264MaxResolution = QSize(4096, 1080);
|
||||
else
|
||||
g_systemVideoDecoderWhitelist.remove("h264_mf");
|
||||
|
||||
QLOG_DEBUG() << "h264_mf max. resolution:" << g_mediaFoundationH264MaxResolution;
|
||||
#endif
|
||||
|
||||
#ifdef Q_OS_MAC
|
||||
// Unsupported, but avoid picking up broken Perian decoders.
|
||||
if (QSysInfo::MacintoshVersion <= QSysInfo::MV_10_10)
|
||||
g_systemAudioDecoderWhitelist.remove("ac3_at");
|
||||
#endif
|
||||
|
||||
Codecs::updateCachedCodecList();
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
bool CodecsFetcher::codecNeedsDownload(const CodecDriver& codec)
|
||||
{
|
||||
@ -566,6 +640,16 @@ static CodecDriver selectBestDecoder(const StreamInfo& stream)
|
||||
if (stream.profile != "" && stream.profile != "main" && stream.profile != "baseline" && stream.profile != "high")
|
||||
score = 1;
|
||||
}
|
||||
if (codec.driver == "h264_mf")
|
||||
{
|
||||
if (!stream.videoResolution.isEmpty())
|
||||
{
|
||||
QSize res = stream.videoResolution;
|
||||
if (res.width() > g_mediaFoundationH264MaxResolution.width() ||
|
||||
res.height() > g_mediaFoundationH264MaxResolution.height())
|
||||
score = 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
|
@ -120,6 +120,8 @@ class Codecs
|
||||
public:
|
||||
static void preinitCodecs();
|
||||
|
||||
static void probeCodecs();
|
||||
|
||||
static QString plexNameToFF(QString plex);
|
||||
|
||||
static QString plexNameFromFF(QString ffname);
|
||||
|
@ -166,7 +166,7 @@ bool PlayerComponent::componentInitialize()
|
||||
this, &PlayerComponent::setAudioConfiguration);
|
||||
|
||||
initializeCodecSupport();
|
||||
Codecs::updateCachedCodecList();
|
||||
Codecs::probeCodecs();
|
||||
|
||||
QString codecInfo;
|
||||
for (auto codec : Codecs::getCachedCodecList())
|
||||
@ -1112,7 +1112,10 @@ PlaybackInfo PlayerComponent::getPlaybackInfo()
|
||||
auto streamInfoMap = streamInfo.toMap();
|
||||
bool ok = false;
|
||||
if (streamInfoMap["index"].toInt(&ok) == index && ok)
|
||||
{
|
||||
stream.profile = streamInfoMap["profile"].toString();
|
||||
QLOG_DEBUG() << "h264profile:" << stream.profile;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user