diff --git a/Source/WebCore/platform/GStreamer.cmake b/Source/WebCore/platform/GStreamer.cmake index 14541acd646e..be938528dfac 100644 --- a/Source/WebCore/platform/GStreamer.cmake +++ b/Source/WebCore/platform/GStreamer.cmake @@ -170,7 +170,7 @@ if (ENABLE_VIDEO OR ENABLE_WEB_AUDIO) if (VIDEO_DECODING_LIMIT) # Specify video decoding limits. - set_source_files_properties(platform/graphics/gstreamer/mse/MediaPlayerPrivateGStreamerMSE.cpp PROPERTIES COMPILE_DEFINITIONS VIDEO_DECODING_LIMIT="${VIDEO_DECODING_LIMIT}") + set_source_files_properties(platform/graphics/gstreamer/GStreamerRegistryScanner.cpp PROPERTIES COMPILE_DEFINITIONS VIDEO_DECODING_LIMIT="${VIDEO_DECODING_LIMIT}") endif () endif () diff --git a/Source/WebCore/platform/graphics/gstreamer/GStreamerRegistryScanner.cpp b/Source/WebCore/platform/graphics/gstreamer/GStreamerRegistryScanner.cpp index d2c9fcff8c18..f473f06d49e6 100644 --- a/Source/WebCore/platform/graphics/gstreamer/GStreamerRegistryScanner.cpp +++ b/Source/WebCore/platform/graphics/gstreamer/GStreamerRegistryScanner.cpp @@ -41,6 +41,92 @@ #include "VideoEncoderPrivateGStreamer.h" #endif +namespace { +struct VideoDecodingLimits { + unsigned mediaMaxWidth = 0; + unsigned mediaMaxHeight = 0; + unsigned mediaMaxFrameRate = 0; + VideoDecodingLimits(unsigned mediaMaxWidth, unsigned mediaMaxHeight, unsigned mediaMaxFrameRate) + : mediaMaxWidth(mediaMaxWidth) + , mediaMaxHeight(mediaMaxHeight) + , mediaMaxFrameRate(mediaMaxFrameRate) + { + } +}; + +// Parses a video decoding limit string in format WIDTHxHEIGHT@FRAMERATE. +static std::optional parseVideoDecodingLimit(const String& videoDecodingLimit) +{ + if (videoDecodingLimit.isEmpty()) + return { }; + + Vector entries; + + // Extract frame rate part: WIDTHxHEIGHT@FRAMERATE. + videoDecodingLimit.split('@', [&entries](StringView item) { + entries.append(item.toString()); + }); + + if (entries.size() != 2) + return { }; + + auto frameRate = parseIntegerAllowingTrailingJunk(entries[1]); + + if (!frameRate.has_value()) + return { }; + + const auto widthAndHeight = entries[0].split('x'); + + if (widthAndHeight.size() != 2) + return { }; + + const auto width = parseIntegerAllowingTrailingJunk(widthAndHeight[0]); + + if (!width.has_value()) + return { }; + + const auto height = parseIntegerAllowingTrailingJunk(widthAndHeight[1]); + + if (!height.has_value()) + return { }; + + return { VideoDecodingLimits(width.value(), height.value(), frameRate.value()) }; +} + +// Returns the active VideoDecodingLimits, resolved once at first call. +// WEBKIT_GST_VIDEO_DECODING_LIMIT env var takes precedence over the compile-time VIDEO_DECODING_LIMIT. +// Format for both: WIDTHxHEIGHT@FRAMERATE (e.g. "1920x1080@30"). +static VideoDecodingLimits* resolveVideoDecodingLimits() +{ + static std::optional limits; + static std::once_flag onceFlag; + std::call_once(onceFlag, [] { + if (const char* envLimit = g_getenv("WEBKIT_GST_VIDEO_DECODING_LIMIT")) { + GST_DEBUG("WEBKIT_GST_VIDEO_DECODING_LIMIT env var is set: %s", envLimit); + limits = parseVideoDecodingLimit(String::fromUTF8(envLimit)); + if (!limits) + GST_WARNING("Parsing WEBKIT_GST_VIDEO_DECODING_LIMIT env var failed: %s", envLimit); + } +#ifdef VIDEO_DECODING_LIMIT + if (!limits) { + GST_DEBUG("VIDEO_DECODING_LIMIT compile-time definition is set: %s", VIDEO_DECODING_LIMIT); + limits = parseVideoDecodingLimit(String::fromUTF8(VIDEO_DECODING_LIMIT)); + if (!limits) { + GST_WARNING("Parsing VIDEO_DECODING_LIMIT failed: %s", VIDEO_DECODING_LIMIT); + ASSERT_NOT_REACHED(); + } + } +#endif + if (limits) { + GST_DEBUG("Video decoding limits: max width=%u, max height=%u, max frame rate=%u", + limits->mediaMaxWidth, limits->mediaMaxHeight, limits->mediaMaxFrameRate); + } + }); + return limits ? &*limits : nullptr; +} + +} // namespace + namespace WebCore { GST_DEBUG_CATEGORY_STATIC(webkit_media_gst_registry_scanner_debug); @@ -50,11 +136,6 @@ GST_DEBUG_CATEGORY_STATIC(webkit_media_gst_registry_scanner_debug); // AAC supports up to 96 channels. #define MEDIA_MAX_AAC_CHANNELS 96 -// Assume hardware video decoding acceleration up to 8K@60fps for the generic case. Some embedded platforms might want to tune this. -#define MEDIA_MAX_WIDTH 7680.0f -#define MEDIA_MAX_HEIGHT 4320.0f -#define MEDIA_MAX_FRAMERATE 60.0f - static bool singletonInitialized = false; bool GStreamerRegistryScanner::singletonWasInitialized() @@ -705,6 +786,10 @@ bool GStreamerRegistryScanner::supportsFeatures(const String& features) const MediaPlayerEnums::SupportsType GStreamerRegistryScanner::isContentTypeSupported(Configuration configuration, const ContentType& contentType, const Vector& contentTypesRequiringHardwareSupport) const { + VideoDecodingLimits* videoDecodingLimits = nullptr; + if (configuration == Configuration::Decoding) + videoDecodingLimits = resolveVideoDecodingLimits(); + using SupportsType = MediaPlayerEnums::SupportsType; const auto& containerType = contentType.containerType().convertToASCIILowercase(); @@ -714,10 +799,23 @@ MediaPlayerEnums::SupportsType GStreamerRegistryScanner::isContentTypeSupported( int channels = parseInteger(contentType.parameter("channels"_s)).value_or(1); String features = contentType.parameter("features"_s); if (channels > MEDIA_MAX_AAC_CHANNELS || channels <= 0 - || !(features.isEmpty() || supportsFeatures(features)) - || parseInteger(contentType.parameter("width"_s)).value_or(0) > MEDIA_MAX_WIDTH - || parseInteger(contentType.parameter("height"_s)).value_or(0) > MEDIA_MAX_HEIGHT - || parseInteger(contentType.parameter("framerate"_s)).value_or(0) > MEDIA_MAX_FRAMERATE) + || !(features.isEmpty() || supportsFeatures(features))) + return SupportsType::IsNotSupported; + + bool ok; + float width = contentType.parameter("width"_s).toFloat(&ok); + if (!ok) + width = 0; + float height = contentType.parameter("height"_s).toFloat(&ok); + if (!ok) + height = 0; + + float frameRate = contentType.parameter("framerate"_s).toFloat(&ok); + if (!ok) + frameRate = 0; + + if (videoDecodingLimits && (width > videoDecodingLimits->mediaMaxWidth || height > videoDecodingLimits->mediaMaxHeight + || frameRate > videoDecodingLimits->mediaMaxFrameRate)) return SupportsType::IsNotSupported; const auto& codecs = contentType.codecs(); diff --git a/Source/WebCore/platform/graphics/gstreamer/mse/MediaPlayerPrivateGStreamerMSE.cpp b/Source/WebCore/platform/graphics/gstreamer/mse/MediaPlayerPrivateGStreamerMSE.cpp index 813811a58c95..ec8b46fd2056 100644 --- a/Source/WebCore/platform/graphics/gstreamer/mse/MediaPlayerPrivateGStreamerMSE.cpp +++ b/Source/WebCore/platform/graphics/gstreamer/mse/MediaPlayerPrivateGStreamerMSE.cpp @@ -56,73 +56,6 @@ #include #include -namespace { -struct VideoDecodingLimits { - unsigned mediaMaxWidth = 0; - unsigned mediaMaxHeight = 0; - unsigned mediaMaxFrameRate = 0; - VideoDecodingLimits(unsigned mediaMaxWidth, unsigned mediaMaxHeight, unsigned mediaMaxFrameRate) - : mediaMaxWidth(mediaMaxWidth) - , mediaMaxHeight(mediaMaxHeight) - , mediaMaxFrameRate(mediaMaxFrameRate) - { - } -}; -} - -#ifdef VIDEO_DECODING_LIMIT -static std::optional videoDecoderLimitsDefaults() -{ - // VIDEO_DECODING_LIMIT should be in format: WIDTHxHEIGHT@FRAMERATE. - String videoDecodingLimit(String::fromUTF8(VIDEO_DECODING_LIMIT)); - - if (videoDecodingLimit.isEmpty()) - return { }; - - Vector entries; - - // Extract frame rate part from the VIDEO_DECODING_LIMIT: WIDTHxHEIGHT@FRAMERATE. - videoDecodingLimit.split('@', [&entries](StringView item) { - entries.append(item.toString()); - }); - - if (entries.size() != 2) - return { }; - - auto frameRate = parseIntegerAllowingTrailingJunk(entries[1]); - - if (!frameRate.has_value()) - return { }; - - String widthAndHeight = entries[0]; - entries.clear(); - - // Extract WIDTH and HEIGHT from: WIDTHxHEIGHT. - widthAndHeight.split('x', [&entries](StringView item) { - entries.append(item.toString()); - }); - - if (entries.size() != 2) - return { }; - - auto width = parseIntegerAllowingTrailingJunk(entries[0]); - - if (!width.has_value()) - return { }; - - auto height = parseIntegerAllowingTrailingJunk(entries[1]); - - if (!height.has_value()) - return { }; - - return { VideoDecodingLimits(width.value(), height.value(), frameRate.value()) }; -} -#endif - -// We shouldn't accept media that the player can't actually play. -// AAC supports up to 96 channels. -#define MEDIA_MAX_AAC_CHANNELS 96 - static const char* dumpReadyState(WebCore::MediaPlayer::ReadyState readyState) { switch (readyState) { @@ -521,36 +454,6 @@ MediaPlayer::SupportsType MediaPlayerPrivateGStreamerMSE::supportsType(const Med return result; } - unsigned channels = parseIntegerAllowingTrailingJunk(parameters.type.parameter("channels"_s)).value_or(0); - if (channels > MEDIA_MAX_AAC_CHANNELS) - return result; - - bool ok; - float width = parameters.type.parameter("width"_s).toFloat(&ok); - if (!ok) - width = 0; - float height = parameters.type.parameter("height"_s).toFloat(&ok); - if (!ok) - height = 0; - - static std::optional videoDecodingLimits; -#ifdef VIDEO_DECODING_LIMIT - static std::once_flag onceFlag; - std::call_once(onceFlag, [] { - videoDecodingLimits = videoDecoderLimitsDefaults(); - if (!videoDecodingLimits) - GST_WARNING("Parsing VIDEO_DECODING_LIMIT failed"); - }); -#endif - - if (videoDecodingLimits && (width > videoDecodingLimits->mediaMaxWidth || height > videoDecodingLimits->mediaMaxHeight)) - return result; - - float frameRate = parameters.type.parameter("framerate"_s).toFloat(&ok); - // Limit frameRate only in case of highest supported resolution. - if (ok && videoDecodingLimits && width == videoDecodingLimits->mediaMaxWidth && height == videoDecodingLimits->mediaMaxHeight && frameRate > videoDecodingLimits->mediaMaxFrameRate) - return result; - registerWebKitGStreamerElements(); GST_DEBUG("Checking mime-type \"%s\"", parameters.type.raw().utf8().data());