diff --git a/Changelog b/Changelog
index c9f1200..562fbc4 100644
--- a/Changelog
+++ b/Changelog
@@ -7,6 +7,7 @@ version <next>:
 - amplify filter
 - fftdnoiz filter
 - aderivative and aintegral audio filters
+- pal75bars and pal100bars video filter sources
 
 
 version 4.0:
diff --git a/doc/filters.texi b/doc/filters.texi
index 7646efb..cf15186 100644
--- a/doc/filters.texi
+++ b/doc/filters.texi
@@ -17825,13 +17825,15 @@ ffplay -f lavfi life=s=300x200:mold=10:r=60:ratio=0.1:death_color=#C83232:life_c
 @anchor{color}
 @anchor{haldclutsrc}
 @anchor{nullsrc}
+@anchor{pal75bars}
+@anchor{pal100bars}
 @anchor{rgbtestsrc}
 @anchor{smptebars}
 @anchor{smptehdbars}
 @anchor{testsrc}
 @anchor{testsrc2}
 @anchor{yuvtestsrc}
-@section allrgb, allyuv, color, haldclutsrc, nullsrc, rgbtestsrc, smptebars, smptehdbars, testsrc, testsrc2, yuvtestsrc
+@section allrgb, allyuv, color, haldclutsrc, nullsrc, pal75bars, pal100bars, rgbtestsrc, smptebars, smptehdbars, testsrc, testsrc2, yuvtestsrc
 
 The @code{allrgb} source returns frames of size 4096x4096 of all rgb colors.
 
@@ -17846,6 +17848,12 @@ The @code{nullsrc} source returns unprocessed video frames. It is
 mainly useful to be employed in analysis / debugging tools, or as the
 source for filters which ignore the input data.
 
+The @code{pal75bars} source generates a color bars pattern, based on
+EBU PAL recommendations with 75% color levels.
+
+The @code{pal100bars} source generates a color bars pattern, based on
+EBU PAL recommendations with 100% color levels.
+
 The @code{rgbtestsrc} source generates an RGB test pattern useful for
 detecting RGB vs BGR issues. You should see a red, green and blue
 stripe from top to bottom.
diff --git a/libavfilter/Makefile b/libavfilter/Makefile
index f83a2b3..c68ef05 100644
--- a/libavfilter/Makefile
+++ b/libavfilter/Makefile
@@ -390,6 +390,8 @@ OBJS-$(CONFIG_MANDELBROT_FILTER)             += vsrc_mandelbrot.o
 OBJS-$(CONFIG_MPTESTSRC_FILTER)              += vsrc_mptestsrc.o
 OBJS-$(CONFIG_NULLSRC_FILTER)                += vsrc_testsrc.o
 OBJS-$(CONFIG_OPENCLSRC_FILTER)              += vf_program_opencl.o opencl.o
+OBJS-$(CONFIG_PAL75BARS_FILTER)              += vsrc_testsrc.o
+OBJS-$(CONFIG_PAL100BARS_FILTER)             += vsrc_testsrc.o
 OBJS-$(CONFIG_RGBTESTSRC_FILTER)             += vsrc_testsrc.o
 OBJS-$(CONFIG_SMPTEBARS_FILTER)              += vsrc_testsrc.o
 OBJS-$(CONFIG_SMPTEHDBARS_FILTER)            += vsrc_testsrc.o
diff --git a/libavfilter/allfilters.c b/libavfilter/allfilters.c
index 099c191..b44093d 100644
--- a/libavfilter/allfilters.c
+++ b/libavfilter/allfilters.c
@@ -380,6 +380,8 @@ extern AVFilter ff_vsrc_mandelbrot;
 extern AVFilter ff_vsrc_mptestsrc;
 extern AVFilter ff_vsrc_nullsrc;
 extern AVFilter ff_vsrc_openclsrc;
+extern AVFilter ff_vsrc_pal75bars;
+extern AVFilter ff_vsrc_pal100bars;
 extern AVFilter ff_vsrc_rgbtestsrc;
 extern AVFilter ff_vsrc_smptebars;
 extern AVFilter ff_vsrc_smptehdbars;
diff --git a/libavfilter/version.h b/libavfilter/version.h
index b1c73be..c32afce 100644
--- a/libavfilter/version.h
+++ b/libavfilter/version.h
@@ -30,7 +30,7 @@
 #include "libavutil/version.h"
 
 #define LIBAVFILTER_VERSION_MAJOR   7
-#define LIBAVFILTER_VERSION_MINOR  23
+#define LIBAVFILTER_VERSION_MINOR  24
 #define LIBAVFILTER_VERSION_MICRO 100
 
 #define LIBAVFILTER_VERSION_INT AV_VERSION_INT(LIBAVFILTER_VERSION_MAJOR, \
diff --git a/libavfilter/vsrc_testsrc.c b/libavfilter/vsrc_testsrc.c
index a790974..8d76ae9 100644
--- a/libavfilter/vsrc_testsrc.c
+++ b/libavfilter/vsrc_testsrc.c
@@ -1252,7 +1252,7 @@ AVFilter ff_vsrc_yuvtestsrc = {
 
 #endif /* CONFIG_YUVTESTSRC_FILTER */
 
-#if CONFIG_SMPTEBARS_FILTER || CONFIG_SMPTEHDBARS_FILTER
+#if CONFIG_PAL75_FILTER || CONFIG_PAL100_FILTER || CONFIG_SMPTEBARS_FILTER || CONFIG_SMPTEHDBARS_FILTER
 
 static const uint8_t rainbow[7][4] = {
     { 180, 128, 128, 255 },     /* 75% white */
@@ -1264,6 +1264,16 @@ static const uint8_t rainbow[7][4] = {
     {  35, 212, 114, 255 },     /* 75% blue */
 };
 
+static const uint8_t rainbow100[7][4] = {
+    { 235, 128, 128, 255 },     /* 100% white */
+    { 210,  16, 146, 255 },     /* 100% yellow */
+    { 170, 166,  16, 255 },     /* 100% cyan */
+    { 145,  54,  34, 255 },     /* 100% green */
+    { 106, 202, 222, 255 },     /* 100% magenta */
+    {  81,  90, 240, 255 },     /* 100% red */
+    {  41, 240, 110, 255 },     /* 100% blue */
+};
+
 static const uint8_t rainbowhd[7][4] = {
     { 180, 128, 128, 255 },     /* 75% white */
     { 168,  44, 136, 255 },     /* 75% yellow */
@@ -1371,6 +1381,100 @@ static const AVFilterPad smptebars_outputs[] = {
     { NULL }
 };
 
+#if CONFIG_PAL75BARS_FILTER
+
+#define pal75bars_options options
+AVFILTER_DEFINE_CLASS(pal75bars);
+
+static void pal75bars_fill_picture(AVFilterContext *ctx, AVFrame *picref)
+{
+    TestSourceContext *test = ctx->priv;
+    int r_w, i, x = 0;
+    const AVPixFmtDescriptor *pixdesc = av_pix_fmt_desc_get(picref->format);
+
+    picref->color_range = AVCOL_RANGE_MPEG;
+    picref->colorspace = AVCOL_SPC_BT470BG;
+
+    r_w = FFALIGN((test->w + 7) / 8, 1 << pixdesc->log2_chroma_w);
+
+    draw_bar(test, white, x, 0, r_w, test->h, picref);
+    x += r_w;
+    for (i = 1; i < 7; i++) {
+        draw_bar(test, rainbow[i], x, 0, r_w, test->h, picref);
+        x += r_w;
+    }
+    draw_bar(test, black0, x, 0, r_w, test->h, picref);
+}
+
+static av_cold int pal75bars_init(AVFilterContext *ctx)
+{
+    TestSourceContext *test = ctx->priv;
+
+    test->fill_picture_fn = pal75bars_fill_picture;
+    test->draw_once = 1;
+    return init(ctx);
+}
+
+AVFilter ff_vsrc_pal75bars = {
+    .name          = "pal75bars",
+    .description   = NULL_IF_CONFIG_SMALL("Generate PAL 75% color bars."),
+    .priv_size     = sizeof(TestSourceContext),
+    .priv_class    = &pal75bars_class,
+    .init          = pal75bars_init,
+    .uninit        = uninit,
+    .query_formats = smptebars_query_formats,
+    .inputs        = NULL,
+    .outputs       = smptebars_outputs,
+};
+
+#endif  /* CONFIG_PAL75BARS_FILTER */
+
+#if CONFIG_PAL100BARS_FILTER
+
+#define pal100bars_options options
+AVFILTER_DEFINE_CLASS(pal100bars);
+
+static void pal100bars_fill_picture(AVFilterContext *ctx, AVFrame *picref)
+{
+    TestSourceContext *test = ctx->priv;
+    int r_w, i, x = 0;
+    const AVPixFmtDescriptor *pixdesc = av_pix_fmt_desc_get(picref->format);
+
+    picref->color_range = AVCOL_RANGE_MPEG;
+    picref->colorspace = AVCOL_SPC_BT470BG;
+
+    r_w = FFALIGN((test->w + 7) / 8, 1 << pixdesc->log2_chroma_w);
+
+    for (i = 0; i < 7; i++) {
+        draw_bar(test, rainbow100[i], x, 0, r_w, test->h, picref);
+        x += r_w;
+    }
+    draw_bar(test, black0, x, 0, r_w, test->h, picref);
+}
+
+static av_cold int pal100bars_init(AVFilterContext *ctx)
+{
+    TestSourceContext *test = ctx->priv;
+
+    test->fill_picture_fn = pal100bars_fill_picture;
+    test->draw_once = 1;
+    return init(ctx);
+}
+
+AVFilter ff_vsrc_pal100bars = {
+    .name          = "pal100bars",
+    .description   = NULL_IF_CONFIG_SMALL("Generate PAL 100% color bars."),
+    .priv_size     = sizeof(TestSourceContext),
+    .priv_class    = &pal100bars_class,
+    .init          = pal100bars_init,
+    .uninit        = uninit,
+    .query_formats = smptebars_query_formats,
+    .inputs        = NULL,
+    .outputs       = smptebars_outputs,
+};
+
+#endif  /* CONFIG_PAL100BARS_FILTER */
+
 #if CONFIG_SMPTEBARS_FILTER
 
 #define smptebars_options options
diff --git a/tests/fate/filter-video.mak b/tests/fate/filter-video.mak
index f2ab263..edd51e1 100644
--- a/tests/fate/filter-video.mak
+++ b/tests/fate/filter-video.mak
@@ -89,6 +89,12 @@ fate-filter-allrgb: CMD = framecrc -lavfi allrgb=rate=5:duration=1 -pix_fmt rgb2
 FATE_FILTER-$(call ALLYES, LAVFI_INDEV ALLYUV_FILTER) += fate-filter-allyuv
 fate-filter-allyuv: CMD = framecrc -lavfi allyuv=rate=5:duration=1 -pix_fmt yuv444p
 
+FATE_FILTER-$(call ALLYES, LAVFI_INDEV PAL75BARS_FILTER) += fate-filter-pal75bars
+fate-filter-pal75bars: CMD = framecrc -lavfi pal75bars=rate=5:duration=1 -pix_fmt yuv420p
+
+FATE_FILTER-$(call ALLYES, LAVFI_INDEV PAL100BARS_FILTER) += fate-filter-pal100bars
+fate-filter-pal100bars: CMD = framecrc -lavfi pal100bars=rate=5:duration=1 -pix_fmt yuv420p
+
 FATE_FILTER-$(call ALLYES, LAVFI_INDEV RGBTESTSRC_FILTER) += fate-filter-rgbtestsrc
 fate-filter-rgbtestsrc: CMD = framecrc -lavfi rgbtestsrc=rate=5:duration=1 -pix_fmt rgb24
 
diff --git a/tests/ref/fate/filter-pal100bars b/tests/ref/fate/filter-pal100bars
new file mode 100644
index 0000000..0ee8d22
--- /dev/null
+++ b/tests/ref/fate/filter-pal100bars
@@ -0,0 +1,10 @@
+#tb 0: 1/5
+#media_type 0: video
+#codec_id 0: rawvideo
+#dimensions 0: 320x240
+#sar 0: 1/1
+0,          0,          0,        1,   115200, 0x97a31f02
+0,          1,          1,        1,   115200, 0x97a31f02
+0,          2,          2,        1,   115200, 0x97a31f02
+0,          3,          3,        1,   115200, 0x97a31f02
+0,          4,          4,        1,   115200, 0x97a31f02
diff --git a/tests/ref/fate/filter-pal75bars b/tests/ref/fate/filter-pal75bars
new file mode 100644
index 0000000..a2d2e17
--- /dev/null
+++ b/tests/ref/fate/filter-pal75bars
@@ -0,0 +1,10 @@
+#tb 0: 1/5
+#media_type 0: video
+#codec_id 0: rawvideo
+#dimensions 0: 320x240
+#sar 0: 1/1
+0,          0,          0,        1,   115200, 0xa131179a
+0,          1,          1,        1,   115200, 0xa131179a
+0,          2,          2,        1,   115200, 0xa131179a
+0,          3,          3,        1,   115200, 0xa131179a
+0,          4,          4,        1,   115200, 0xa131179a
