[vlc-commits] [Git][videolan/vlc][master] 5 commits: qt: introduce `Common.glsl`
Steve Lhomme (@robUx4)
gitlab at videolan.org
Fri Jan 24 13:53:22 UTC 2025
Steve Lhomme pushed to branch master at VideoLAN / VLC
Commits:
828b81fd by Fatih Uzunoglu at 2025-01-24T13:29:23+00:00
qt: introduce `Common.glsl`
- - - - -
06f9e127 by Fatih Uzunoglu at 2025-01-24T13:29:23+00:00
qt: apply dithering in `FadingEdge.frag`
This fixes the color banding issue with dark background color.
- - - - -
90d858a1 by Fatih Uzunoglu at 2025-01-24T13:29:23+00:00
qt: introduce `DitheredTexture.frag`
- - - - -
c10d3bfc by Fatih Uzunoglu at 2025-01-24T13:29:23+00:00
qml: use `DitheredTexture.frag` in `DoubleShadow.qml`
- - - - -
9dc00813 by Fatih Uzunoglu at 2025-01-24T13:29:23+00:00
qml: use `DitheredTexture.frag` in `DropShadowImage.qml`
- - - - -
11 changed files:
- modules/gui/qt/Makefile.am
- + modules/gui/qt/shaders/Common.glsl
- + modules/gui/qt/shaders/DitheredTexture.frag
- modules/gui/qt/shaders/FadingEdge.frag
- modules/gui/qt/shaders/Noise.frag
- modules/gui/qt/shaders/PlayerBlurredBackground.frag
- modules/gui/qt/shaders/meson.build
- modules/gui/qt/shaders/shaders.qrc
- modules/gui/qt/widgets/qml/DoubleShadow.qml
- modules/gui/qt/widgets/qml/DropShadowImage.qml
- modules/gui/qt/widgets/qml/FadingEdge.qml
Changes:
=====================================
modules/gui/qt/Makefile.am
=====================================
@@ -1343,7 +1343,8 @@ libqt_plugin_la_SHADER := shaders/FadingEdge.frag \
shaders/HollowRectangularGlow.frag \
shaders/RectangularGlow.frag \
shaders/SDFAARoundedTexture.frag \
- shaders/SDFAARoundedTexture_cropsupport.frag
+ shaders/SDFAARoundedTexture_cropsupport.frag \
+ shaders/DitheredTexture.frag
if ENABLE_QT
libqt_plugin_la_LIBADD += libqml_module_dialogs.a \
@@ -1397,10 +1398,12 @@ QSB_PARAMS_VERBOSE_ = $(QSB_PARAMS_VERBOSE__$(AM_DEFAULT_VERBOSITY))
QSB_PARAMS_VERBOSE_0 = -s
QSB_PARAMS_VERBOSE__0 = $(QSB_PARAMS_VERBOSE_0)
-%.frag.qsb: %.frag
+EXTRA_DIST += shaders/Common.glsl
+
+%.frag.qsb: %.frag shaders/Common.glsl
$(qsb_verbose)PATH="$(QSB_EXTRA_PATH)$$PATH" $(QSB) $(QSB_PARAMS) $(QSB_PARAMS_VERBOSE) -o $@ $<
-%.vert.qsb: %.vert
+%.vert.qsb: %.vert shaders/Common.glsl
$(qsb_verbose)PATH="$(QSB_EXTRA_PATH)$$PATH" $(QSB) $(QSB_PARAMS) $(QSB_PARAMS_VERBOSE) -o $@ $<
shaders/shaders.cpp: $(srcdir)/shaders/shaders.qrc $(libqt_plugin_la_SHADER:.frag=.frag.qsb) $(libqt_plugin_la_SHADER:.vert=.vert.qsb)
=====================================
modules/gui/qt/shaders/Common.glsl
=====================================
@@ -0,0 +1,108 @@
+/*****************************************************************************
+ * Copyright (C) 2024 VLC authors and VideoLAN
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * ( at your option ) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
+ *****************************************************************************/
+
+/****************************************************************************
+**
+** Copyright (C) 2015 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the Qt Graphical Effects module.
+**
+** $QT_BEGIN_LICENSE:BSD$
+** You may use this file under the terms of the BSD license as follows:
+**
+** "Redistribution and use in source and binary forms, with or without
+** modification, are permitted provided that the following conditions are
+** met:
+** * Redistributions of source code must retain the above copyright
+** notice, this list of conditions and the following disclaimer.
+** * Redistributions in binary form must reproduce the above copyright
+** notice, this list of conditions and the following disclaimer in
+** the documentation and/or other materials provided with the
+** distribution.
+** * Neither the name of The Qt Company Ltd nor the names of its
+** contributors may be used to endorse or promote products derived
+** from this software without specific prior written permission.
+**
+**
+** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE."
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+//blending formulas are taken from Qt's Blend.qml implementation
+
+#define DITHERING_CUTOFF 0.01
+#define DITHERING_STRENGTH 0.01
+
+vec4 fromPremult(vec4 color) {
+ vec4 result = vec4(0.0);
+ result.rgb = color.rgb / max(1.0/256.0, color.a);
+ result.a = color.a;
+ return result;
+}
+
+vec4 toPremult(vec4 color) {
+ vec4 result = vec4(0.0);
+ result.rbg = color.rbg * color.a;
+ result.a = color.a;
+ return result;
+}
+
+vec4 screen(vec4 color1, vec4 color2) {
+ vec4 result = vec4(0.0);
+ float a = max(color1.a, color1.a * color2.a);
+
+ result.rgb = 1.0 - (vec3(1.0) - color1.rgb) * (vec3(1.0) - color2.rgb);
+
+ result.rgb = mix(color1.rgb, result.rgb, color2.a);
+ result.a = max(color1.a, color1.a * color2.a);
+ return result;
+}
+
+vec4 multiply(vec4 color1, vec4 color2) {
+ vec4 result = vec4(0.0);
+
+ result.rgb = color1.rgb * color2.rgb;
+
+ result.rgb = mix(color1.rgb, result.rgb, color2.a);
+ result.a = max(color1.a, color1.a * color2.a);
+ return result;
+}
+
+vec4 normal(vec4 color1, vec4 color2) {
+ vec4 result = vec4(0.0);
+ result.rgb = mix(color1.rgb, color2.rgb, color2.a);
+ result.a = max(color1.a, color2.a);
+ return result;
+}
+
+float rand(vec2 co){
+ return fract(sin(dot(co.xy, vec2(12.9898, 78.233))) * 43758.5453);
+}
=====================================
modules/gui/qt/shaders/DitheredTexture.frag
=====================================
@@ -0,0 +1,55 @@
+#version 440
+
+// TODO: Dithering is not necessary with light colors. It is pretty much
+// necessary with dark colors due to premultiplied alpha to prevent
+// color banding. So, this should ideally be used only when the
+// background color is dark. When the build system starts supporting
+// defines to feed qsb, we can have the non-dithering version as well.
+#define DITHERING
+
+/*****************************************************************************
+ * Copyright (C) 2025 VLC authors and VideoLAN
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * ( at your option ) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
+ *****************************************************************************/
+
+#extension GL_GOOGLE_include_directive : enable
+
+#include "Common.glsl"
+
+layout(location = 0) in vec2 qt_TexCoord0;
+
+layout(location = 0) out vec4 fragColor;
+
+layout(binding = 1) uniform sampler2D source;
+
+layout(std140, binding = 0) uniform buf {
+ mat4 qt_Matrix;
+ float qt_Opacity;
+};
+
+
+void main()
+{
+ vec4 texel = texture(source, qt_TexCoord0);
+
+ fragColor = texel * qt_Opacity;
+
+#ifdef DITHERING
+ float r = rand(qt_TexCoord0) - 0.5;
+ vec4 noise = vec4(r,r,r,r) * DITHERING_STRENGTH;
+ fragColor += noise * step(DITHERING_CUTOFF, fragColor.a); // additive
+#endif
+}
=====================================
modules/gui/qt/shaders/FadingEdge.frag
=====================================
@@ -1,5 +1,12 @@
#version 440
+// TODO: Dithering is not necessary with light colors. It is pretty much
+// necessary with dark colors due to premultiplied alpha to prevent
+// color banding. So, this should ideally be used only when the
+// background color is dark. When the build system starts supporting
+// defines to feed qsb, we can have the non-dithering version as well.
+#define DITHERING
+
/*****************************************************************************
* Copyright (C) 2024 VLC authors and VideoLAN
*
@@ -18,6 +25,10 @@
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
*****************************************************************************/
+#extension GL_GOOGLE_include_directive : enable
+
+#include "Common.glsl"
+
layout(location = 0) in vec2 coord;
layout(location = 0) out vec4 fragColor;
layout(std140, binding = 0) uniform buf {
@@ -30,7 +41,7 @@ layout(binding = 1) uniform sampler2D source;
layout(location = 1) in float pos;
void main() {
- lowp vec4 texel = texture(source, coord);
+ vec4 texel = texture(source, coord);
// Note that the whole texel is multiplied instead
// of only the alpha component because it must be
@@ -40,4 +51,12 @@ void main() {
// We still need to respect the accumulated scene graph opacity:
fragColor = texel * qt_Opacity;
+
+#ifdef DITHERING
+ float r = rand(coord) - 0.5;
+ vec4 noise = vec4(r,r,r,r) * DITHERING_STRENGTH;
+ vec4 beginningNoise = noise * (1.0 - step(beginningFadeSize, pos));
+ vec4 endNoise = noise * step(endFadePos, pos);
+ fragColor += (beginningNoise + endNoise) * step(DITHERING_CUTOFF, fragColor.a); // additive
+#endif
}
=====================================
modules/gui/qt/shaders/Noise.frag
=====================================
@@ -18,6 +18,10 @@
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
*****************************************************************************/
+#extension GL_GOOGLE_include_directive : enable
+
+#include "Common.glsl"
+
layout(location = 0) in vec2 qt_TexCoord0;
layout(location = 0) out vec4 fragColor;
@@ -28,10 +32,6 @@ layout(std140, binding = 0) uniform buf {
float strength;
};
-float rand(vec2 co){
- return fract(sin(dot(co.xy, vec2(12.9898, 78.233))) * 43758.5453);
-}
-
void main() {
float r = rand(qt_TexCoord0) - 0.5;
vec4 noise = vec4(r,r,r,1.0) * strength;
=====================================
modules/gui/qt/shaders/PlayerBlurredBackground.frag
=====================================
@@ -57,7 +57,9 @@
**
****************************************************************************/
-//blending formulas are taken from Qt's Blend.qml implementation
+#extension GL_GOOGLE_include_directive : enable
+
+#include "Common.glsl"
layout(location = 0) in vec2 qt_TexCoord0;
layout(location = 0) out vec4 fragColor;
@@ -69,48 +71,6 @@ layout(std140, binding = 0) uniform buf {
};
layout(binding = 1) uniform sampler2D backgroundSource;
-lowp vec4 fromPremult(lowp vec4 color) {
- lowp vec4 result = vec4(0.0);
- result.rgb = color.rgb / max(1.0/256.0, color.a);
- result.a = color.a;
- return result;
-}
-
-lowp vec4 toPremult(lowp vec4 color) {
- lowp vec4 result = vec4(0.0);
- result.rbg = color.rbg * color.a;
- result.a = color.a;
- return result;
-}
-
-lowp vec4 screen(lowp vec4 color1, lowp vec4 color2) {
- lowp vec4 result = vec4(0.0);
- highp float a = max(color1.a, color1.a * color2.a);
-
- result.rgb = 1.0 - (vec3(1.0) - color1.rgb) * (vec3(1.0) - color2.rgb);
-
- result.rgb = mix(color1.rgb, result.rgb, color2.a);
- result.a = max(color1.a, color1.a * color2.a);
- return result;
-}
-
-lowp vec4 multiply(lowp vec4 color1, lowp vec4 color2) {
- lowp vec4 result = vec4(0.0);
-
- result.rgb = color1.rgb * color2.rgb;
-
- result.rgb = mix(color1.rgb, result.rgb, color2.a);
- result.a = max(color1.a, color1.a * color2.a);
- return result;
-}
-
-lowp vec4 normal(lowp vec4 color1, lowp vec4 color2) {
- lowp vec4 result = vec4(0.0);
- result.rgb = mix(color1.rgb, color2.rgb, color2.a);
- result.a = max(color1.a, color2.a);
- return result;
-}
-
void main() {
lowp vec4 result = vec4(0.0);
lowp vec4 colorP = fromPremult(texture(backgroundSource, qt_TexCoord0));
=====================================
modules/gui/qt/shaders/meson.build
=====================================
@@ -17,7 +17,8 @@ shader_sources = [
'HollowRectangularGlow.frag',
'RectangularGlow.frag',
'SDFAARoundedTexture.frag',
- 'SDFAARoundedTexture_cropsupport.frag'
+ 'SDFAARoundedTexture_cropsupport.frag',
+ 'DitheredTexture.frag'
]
shader_files = files(shader_sources)
@@ -37,6 +38,7 @@ foreach shader: shader_sources
shader_target_name = shader + '.qsb'
target = custom_target(shader_target_name,
+ depend_files: ['Common.glsl'],
input: shader,
output: shader_target_name,
command: [qsb, qsb_params, '--output', '@OUTPUT@', '@INPUT@']
=====================================
modules/gui/qt/shaders/shaders.qrc
=====================================
@@ -12,5 +12,6 @@
<file alias="RectangularGlow.frag.qsb">RectangularGlow.frag.qsb</file>
<file alias="SDFAARoundedTexture.frag.qsb">SDFAARoundedTexture.frag.qsb</file>
<file alias="SDFAARoundedTexture_cropsupport.frag.qsb">SDFAARoundedTexture_cropsupport.frag.qsb</file>
+ <file alias="DitheredTexture.frag.qsb">DitheredTexture.frag.qsb</file>
</qresource>
</RCC>
=====================================
modules/gui/qt/widgets/qml/DoubleShadow.qml
=====================================
@@ -24,8 +24,9 @@ import VLC.Util
// A convenience file to encapsulate two drop shadow images stacked on top
// of each other
-ScaledImage {
- id: root
+Item {
+ implicitWidth: image.implicitWidth
+ implicitHeight: image.implicitHeight
property Item sourceItem: null
@@ -50,45 +51,84 @@ ScaledImage {
property real secondaryHorizontalOffset: 0
property real secondaryBlurRadius: 0
+ property alias sourceSize: image.sourceSize
+ property alias cache: image.cache
+ property alias asynchronous: image.asynchronous
+ property alias fillMode: image.fillMode
+
+ z: -1
+
+ visible: (width > 0 && height > 0)
+
//by default we request
sourceSize: Qt.size(viewportWidth, viewportHeight)
- cache: true
- asynchronous: true
+ ScaledImage {
+ id: image
+
+ anchors.fill: parent
+
+ cache: true
+ asynchronous: true
+
+ visible: !visualDelegate.readyForVisibility
+
+ fillMode: Image.Stretch
+
+ onSourceSizeChanged: {
+ // Do not load the image when size is not valid:
+ if (sourceSize.width > 0 && sourceSize.height > 0)
+ source = Qt.binding(() => {
+ return Effects.url(
+ Effects.DoubleRoundedRectDropShadow,
+ {
+ "viewportWidth" : viewportWidth,
+ "viewportHeight" :viewportHeight,
+
+ "rectWidth": rectWidth,
+ "rectHeight": rectHeight,
+ "xRadius": xRadius,
+ "yRadius": yRadius,
+
+ "primaryColor": primaryColor,
+ "primaryBlurRadius": primaryBlurRadius,
+ "primaryXOffset": primaryHorizontalOffset,
+ "primaryYOffset": primaryVerticalOffset,
+
+ "secondaryColor": secondaryColor,
+ "secondaryBlurRadius": secondaryBlurRadius,
+ "secondaryXOffset": secondaryHorizontalOffset,
+ "secondaryYOffset": secondaryVerticalOffset,
+ })
+ })
+ else
+ source = ""
+ }
+ }
- fillMode: Image.Stretch
+ ShaderEffect {
+ id: visualDelegate
- visible: (width > 0 && height > 0)
+ anchors.centerIn: parent
+ anchors.alignWhenCentered: true
- z: -1
+ implicitWidth: image.implicitWidth
+ implicitHeight: image.implicitHeight
+
+ width: image.paintedWidth
+ height: image.paintedHeight
+
+ visible: readyForVisibility
+
+ readonly property bool readyForVisibility: (GraphicsInfo.shaderType === GraphicsInfo.RhiShader)
+
+ supportsAtlasTextures: true
+ blending: true
+ // cullMode: ShaderEffect.BackFaceCulling
+
+ readonly property Image source: image
- onSourceSizeChanged: {
- // Do not load the image when size is not valid:
- if (sourceSize.width > 0 && sourceSize.height > 0)
- source = Qt.binding(() => {
- return Effects.url(
- Effects.DoubleRoundedRectDropShadow,
- {
- "viewportWidth" : viewportWidth,
- "viewportHeight" :viewportHeight,
-
- "rectWidth": rectWidth,
- "rectHeight": rectHeight,
- "xRadius": xRadius,
- "yRadius": yRadius,
-
- "primaryColor": primaryColor,
- "primaryBlurRadius": primaryBlurRadius,
- "primaryXOffset": primaryHorizontalOffset,
- "primaryYOffset": primaryVerticalOffset,
-
- "secondaryColor": secondaryColor,
- "secondaryBlurRadius": secondaryBlurRadius,
- "secondaryXOffset": secondaryHorizontalOffset,
- "secondaryYOffset": secondaryVerticalOffset,
- })
- })
- else
- source = ""
+ // TODO: Dithered texture is not necessary if theme is not dark.
+ fragmentShader: "qrc:///shaders/DitheredTexture.frag.qsb"
}
}
=====================================
modules/gui/qt/widgets/qml/DropShadowImage.qml
=====================================
@@ -20,7 +20,9 @@ import QtQuick
import VLC.Util
-ScaledImage {
+Item {
+ implicitWidth: image.implicitWidth
+ implicitHeight: image.implicitHeight
property Item sourceItem: null
@@ -38,33 +40,71 @@ ScaledImage {
property real xRadius: (sourceItem ? (sourceItem.effectiveRadius ?? sourceItem.radius) : 0) ?? 0
property real yRadius: (sourceItem ? (sourceItem.effectiveRadius ?? sourceItem.radius) : 0) ?? 0
+ property alias sourceSize: image.sourceSize
+ property alias cache: image.cache
+ property alias asynchronous: image.asynchronous
+ property alias fillMode: image.fillMode
+
sourceSize: Qt.size(viewportWidth, viewportHeight)
- cache: true
- asynchronous: true
-
- fillMode: Image.Stretch
-
- onSourceSizeChanged: {
- // Do not load the image when size is not valid:
- if (sourceSize.width > 0 && sourceSize.height > 0)
- source = Qt.binding(function() {
- return Effects.url((xRadius > 0 || yRadius > 0) ? Effects.RoundedRectDropShadow
- : Effects.RectDropShadow,
- {
- "viewportWidth" : viewportWidth,
- "viewportHeight" :viewportHeight,
-
- "blurRadius": blurRadius,
- "color": color,
- "rectWidth": rectWidth,
- "rectHeight": rectHeight,
- "xOffset": xOffset,
- "yOffset": yOffset,
- "xRadius": xRadius,
- "yRadius": yRadius})
- })
- else
- source = ""
+ Image {
+ id: image
+
+ cache: true
+ asynchronous: true
+
+ visible: !visualDelegate.readyForVisibility
+
+ fillMode: Image.Stretch
+
+ onSourceSizeChanged: {
+ // Do not load the image when size is not valid:
+ if (sourceSize.width > 0 && sourceSize.height > 0)
+ source = Qt.binding(function() {
+ return Effects.url((xRadius > 0 || yRadius > 0) ? Effects.RoundedRectDropShadow
+ : Effects.RectDropShadow,
+ {
+ "viewportWidth" : viewportWidth,
+ "viewportHeight" :viewportHeight,
+
+ "blurRadius": blurRadius,
+ "color": color,
+ "rectWidth": rectWidth,
+ "rectHeight": rectHeight,
+ "xOffset": xOffset,
+ "yOffset": yOffset,
+ "xRadius": xRadius,
+ "yRadius": yRadius
+ })
+ })
+ else
+ source = ""
+ }
+ }
+
+ ShaderEffect {
+ id: visualDelegate
+
+ anchors.centerIn: parent
+ anchors.alignWhenCentered: true
+
+ implicitWidth: image.implicitWidth
+ implicitHeight: image.implicitHeight
+
+ width: image.paintedWidth
+ height: image.paintedHeight
+
+ visible: readyForVisibility
+
+ readonly property bool readyForVisibility: (GraphicsInfo.shaderType === GraphicsInfo.RhiShader)
+
+ supportsAtlasTextures: true
+ blending: true
+ // cullMode: ShaderEffect.BackFaceCulling
+
+ readonly property Image source: image
+
+ // TODO: Dithered texture is not necessary if theme is not dark.
+ fragmentShader: "qrc:///shaders/DitheredTexture.frag.qsb"
}
}
=====================================
modules/gui/qt/widgets/qml/FadingEdge.qml
=====================================
@@ -163,6 +163,8 @@ Item {
// cullMode: ShaderEffect.BackFaceCulling // Does not work sometimes. Qt bug?
vertexShader: "qrc:///shaders/FadingEdge%1.vert.qsb".arg(vertical ? "Y" : "X")
+
+ // TODO: Dithering is not necessary if background color is not dark.
fragmentShader: "qrc:///shaders/FadingEdge.frag.qsb"
}
}
View it on GitLab: https://code.videolan.org/videolan/vlc/-/compare/bba1e9dea95d00f2c0713270f7f22b652754bdf9...9dc00813c79e659c873315cc58fac8642a395e1b
--
View it on GitLab: https://code.videolan.org/videolan/vlc/-/compare/bba1e9dea95d00f2c0713270f7f22b652754bdf9...9dc00813c79e659c873315cc58fac8642a395e1b
You're receiving this email because of your account on code.videolan.org.
VideoLAN code repository instance
More information about the vlc-commits
mailing list