Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion Source/WebCore/platform/GStreamer.cmake
Original file line number Diff line number Diff line change
Expand Up @@ -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 ()

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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<VideoDecodingLimits> parseVideoDecodingLimit(const String& videoDecodingLimit)
{
if (videoDecodingLimit.isEmpty())
return { };

Vector<String> entries;

// Extract frame rate part: WIDTHxHEIGHT@FRAMERATE.
videoDecodingLimit.split('@', [&entries](StringView item) {
entries.append(item.toString());
});

if (entries.size() != 2)
return { };

auto frameRate = parseIntegerAllowingTrailingJunk<unsigned>(entries[1]);

if (!frameRate.has_value())
return { };

const auto widthAndHeight = entries[0].split('x');

if (widthAndHeight.size() != 2)
return { };

const auto width = parseIntegerAllowingTrailingJunk<unsigned>(widthAndHeight[0]);

if (!width.has_value())
return { };

const auto height = parseIntegerAllowingTrailingJunk<unsigned>(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<VideoDecodingLimits> 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);
Expand All @@ -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()
Expand Down Expand Up @@ -705,6 +786,10 @@ bool GStreamerRegistryScanner::supportsFeatures(const String& features) const

MediaPlayerEnums::SupportsType GStreamerRegistryScanner::isContentTypeSupported(Configuration configuration, const ContentType& contentType, const Vector<ContentType>& contentTypesRequiringHardwareSupport) const
{
VideoDecodingLimits* videoDecodingLimits = nullptr;
if (configuration == Configuration::Decoding)
videoDecodingLimits = resolveVideoDecodingLimits();

using SupportsType = MediaPlayerEnums::SupportsType;

const auto& containerType = contentType.containerType().convertToASCIILowercase();
Expand All @@ -714,10 +799,23 @@ MediaPlayerEnums::SupportsType GStreamerRegistryScanner::isContentTypeSupported(
int channels = parseInteger<int>(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<unsigned>(contentType.parameter("width"_s)).value_or(0) > MEDIA_MAX_WIDTH
|| parseInteger<unsigned>(contentType.parameter("height"_s)).value_or(0) > MEDIA_MAX_HEIGHT
|| parseInteger<unsigned>(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();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -56,73 +56,6 @@
#include <wtf/text/AtomStringHash.h>
#include <wtf/text/StringToIntegerConversion.h>

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<VideoDecodingLimits> videoDecoderLimitsDefaults()
{
// VIDEO_DECODING_LIMIT should be in format: WIDTHxHEIGHT@FRAMERATE.
String videoDecodingLimit(String::fromUTF8(VIDEO_DECODING_LIMIT));

if (videoDecodingLimit.isEmpty())
return { };

Vector<String> 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<unsigned>(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<unsigned>(entries[0]);

if (!width.has_value())
return { };

auto height = parseIntegerAllowingTrailingJunk<unsigned>(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) {
Expand Down Expand Up @@ -521,36 +454,6 @@ MediaPlayer::SupportsType MediaPlayerPrivateGStreamerMSE::supportsType(const Med
return result;
}

unsigned channels = parseIntegerAllowingTrailingJunk<unsigned>(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> 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());
Expand Down