diff --git a/test/libmpv_test_sdh_filter.c b/test/libmpv_test_sdh_filter.c
new file mode 100644
index 0000000000..50961ed601
--- /dev/null
+++ b/test/libmpv_test_sdh_filter.c
@@ -0,0 +1,101 @@
+/*
+ * This file is part of mpv.
+ *
+ * mpv is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * mpv 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 Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with mpv. If not, see .
+ */
+
+#ifdef _WIN32
+#include
+#else
+#include
+#endif
+
+#include "libmpv_common.h"
+
+#ifndef F_OK
+#define F_OK 0
+#endif
+
+static void test_sdh_filter(char *file, char *path, char *harder)
+{
+ int ret = access(path, F_OK);
+ if (ret)
+ fail("Test file, '%s', was not found!\n", path);
+
+ check_api_error(mpv_set_property_string(ctx, "sub-filter-sdh", "yes"));
+ if (harder)
+ check_api_error(mpv_set_property_string(ctx, "sub-filter-sdh-harder", "yes"));
+
+ char *expect = "";
+ if (strcmp(file, "sdh_default") == 0 && harder) {
+ expect = "Filter from string.";
+ } else if (strcmp(file, "sdh_default") == 0) {
+ expect = "Filter (things) from (random) string.";
+ } else if (strcmp(file, "sdh_mixed") == 0 && harder) {
+ expect = "漢字 and وotherو non-ASCII characters、";
+ } else if (strcmp(file, "sdh_mixed") == 0) {
+ expect = "all: 漢字 and وotherو non-ASCII characters、(together)";
+ } else if (strcmp(file, "sdh_all") == 0 && harder) {
+ expect = "";
+ } else if (strcmp(file, "sdh_all") == 0) {
+ expect = "(this)";
+ } else if (strcmp(file, "sdh_mismatch") == 0 && harder) {
+ expect = "(No] (filter) (should) (be) [applied)";
+ } else if (strcmp(file, "sdh_mismatch") == 0) {
+ expect = "(No] (filter) (should) (be) [applied)";
+ }
+
+ reload_file(path);
+ bool sub_text = false;
+ while (!sub_text) {
+ mpv_event *event = wrap_wait_event();
+ switch (event->event_id) {
+ case MPV_EVENT_PROPERTY_CHANGE: {
+ mpv_event_property *prop = event->data;
+ if (strcmp(prop->name, "sub-text") == 0) {
+ char *value = *(char **)(prop->data);
+ if (!value || strcmp(expect, value) != 0)
+ fail("String: expected '%s' but got '%s'!\n", expect, value);
+ sub_text = true;
+ }
+ break;
+ }
+ }
+ }
+}
+
+int main(int argc, char *argv[])
+{
+ if (argc < 3)
+ return 1;
+
+ ctx = mpv_create();
+ if (!ctx)
+ return 1;
+
+ atexit(exit_cleanup);
+
+ initialize();
+
+ const char *fmt = "================ TEST: %s %s ================\n";
+ printf(fmt, "test_sdh_filter", argv[1]);
+ mpv_observe_property(ctx, 0, "sub-text", MPV_FORMAT_STRING);
+ test_sdh_filter(argv[1], argv[2], argv[3]);
+ printf("================ SHUTDOWN ================\n");
+
+ mpv_command_string(ctx, "quit");
+ while (wrap_wait_event()->event_id != MPV_EVENT_SHUTDOWN) {}
+
+ return 0;
+}
diff --git a/test/samples/meson.build b/test/samples/meson.build
index d59a810ec5..2b5756e880 100644
--- a/test/samples/meson.build
+++ b/test/samples/meson.build
@@ -72,3 +72,44 @@ foreach name, cmd: samples
test(testname, exe, args: [name, target.full_path()],
depends: target, env: env, suite: 'libmpv')
endforeach
+
+
+sdh_default = join_paths(source_root, 'test', 'samples', 'sdh_default.srt')
+sdh_mixed = join_paths(source_root, 'test', 'samples', 'sdh_mixed.srt')
+sdh_all = join_paths(source_root, 'test', 'samples', 'sdh_all.srt')
+sdh_mismatch = join_paths(source_root, 'test', 'samples', 'sdh_mismatch.srt')
+
+sdh_samples = {
+ 'sdh_default':
+ [ffmpeg, '-v', 'error', '-y', '-i', audio, '-f', 'srt',
+ '-i', sdh_default, '-map', '0:0', '-map', '1:0', '-disposition:s:0',
+ 'default', '@OUTPUT@'],
+ 'sdh_mixed':
+ [ffmpeg, '-v', 'error', '-y', '-i', audio, '-f', 'srt',
+ '-i', sdh_mixed, '-map', '0:0', '-map', '1:0', '-disposition:s:0',
+ 'default', '@OUTPUT@'],
+ 'sdh_all':
+ [ffmpeg, '-v', 'error', '-y', '-i', audio, '-f', 'srt',
+ '-i', sdh_all, '-map', '0:0', '-map', '1:0', '-disposition:s:0',
+ 'default', '@OUTPUT@'],
+ 'sdh_mismatch':
+ [ffmpeg, '-v', 'error', '-y', '-i', audio, '-f', 'srt',
+ '-i', sdh_mismatch, '-map', '0:0', '-map', '1:0', '-disposition:s:0',
+ 'default', '@OUTPUT@'],
+}
+
+foreach name, cmd: sdh_samples
+ target = custom_target(name,
+ output: name + '.mkv',
+ depends: [audio],
+ command: cmd,
+ )
+ defaultname = 'libmpv-test-' + name
+ exe = executable(defaultname, '../libmpv_test_sdh_filter.c',
+ include_directories: incdir, dependencies: libmpv_dep)
+ hardername = 'libmpv-test-' + name + '_harder'
+ test(defaultname, exe, args: [name, target.full_path()],
+ depends: target, suite: 'libmpv')
+ test(hardername, exe, args: [name, target.full_path(), 'yes'],
+ depends: target, suite: 'libmpv')
+endforeach
diff --git a/test/samples/sdh_all.srt b/test/samples/sdh_all.srt
new file mode 100644
index 0000000000..72b36fb43d
--- /dev/null
+++ b/test/samples/sdh_all.srt
@@ -0,0 +1,3 @@
+1
+00:00:00,000 --> 00:00:02,000
+[Everything][should][be][removed][except][maybe](this)
diff --git a/test/samples/sdh_default.srt b/test/samples/sdh_default.srt
new file mode 100644
index 0000000000..ec231a3f83
--- /dev/null
+++ b/test/samples/sdh_default.srt
@@ -0,0 +1,3 @@
+1
+00:00:00,000 --> 00:00:02,000
+MAN: Filter (SOME) (things) from [this] (random) string.
diff --git a/test/samples/sdh_mismatch.srt b/test/samples/sdh_mismatch.srt
new file mode 100644
index 0000000000..b87c021b33
--- /dev/null
+++ b/test/samples/sdh_mismatch.srt
@@ -0,0 +1,3 @@
+1
+00:00:00,000 --> 00:00:02,000
+(No] (filter) (should) (be) [applied)
diff --git a/test/samples/sdh_mixed.srt b/test/samples/sdh_mixed.srt
new file mode 100644
index 0000000000..41e7cccc41
--- /dev/null
+++ b/test/samples/sdh_mixed.srt
@@ -0,0 +1,3 @@
+1
+00:00:00,000 --> 00:00:02,000
+all: (MIX) [some] 漢字 and وotherو non-ASCII characters、(together)