From a6d6b753316ed4fb4655e45d50c918365df44e7c Mon Sep 17 00:00:00 2001 From: Final AI Agent Date: Mon, 3 Aug 2026 20:16:03 +0000 Subject: [PATCH 1/4] Make media file filters provider-aware --- src/command/audio.cpp | 7 ++-- src/command/video.cpp | 6 ++-- src/meson.build | 1 + src/project.cpp | 58 +++++---------------------------- src/provider_file_formats.cpp | 61 +++++++++++++++++++++++++++++++++++ src/provider_file_formats.h | 15 +++++++++ 6 files changed, 93 insertions(+), 55 deletions(-) create mode 100644 src/provider_file_formats.cpp create mode 100644 src/provider_file_formats.h diff --git a/src/command/audio.cpp b/src/command/audio.cpp index b2097c73fb..ceaf7ecc26 100644 --- a/src/command/audio.cpp +++ b/src/command/audio.cpp @@ -42,6 +42,7 @@ #include "../libresrc/libresrc.h" #include "../options.h" #include "../project.h" +#include "../provider_file_formats.h" #include "../selection_controller.h" #include "../utils.h" #include "../video_controller.h" @@ -79,9 +80,9 @@ struct audio_open final : public Command { STR_HELP("Open an audio file") void operator()(agi::Context *c) override { - auto str = from_wx(_("Audio Formats") + " (*.aac,*.ac3,*.ape,*.dts,*.eac3,*.flac,*.m4a,*.mka,*.mp3,*.mp4,*.ogg,*.opus,*.w64,*.wav,*.wma)|*.aac;*.ac3;*.ape;*.dts;*.eac3;*.flac;*.m4a;*.mka;*.mp3;*.mp4;*.ogg;*.opus;*.w64;*.wav;*.wma|" - + _("Video Formats") + " (*.asf,*.avi,*.avs,*.d2v,*.m2ts,*.m4v,*.mkv,*.mov,*.mp4,*.mpeg,*.mpg,*.ogm,*.webm,*.wmv,*.ts)|*.asf;*.avi;*.avs;*.d2v;*.m2ts;*.m4v;*.mkv;*.mov;*.mp4;*.mpeg;*.mpg;*.ogm;*.webm;*.wmv;*.ts|" - + _("All Files") + " (*.*)|*.*"); + auto formats = MakeWildcard(GetAudioFileExtensions()); + auto str = from_wx(_("Audio and Video Formats")) + " (" + formats + ")|" + formats + "|" + + from_wx(_("All Files")) + " (*.*)|*.*"; auto filename = OpenFileSelector(wxGETTEXT_IN_CONTEXT("dialog title", "Open Audio File"), "Path/Last/Audio", "", "", str, c->parent); if (!filename.empty()) c->project->LoadAudio(filename); diff --git a/src/command/video.cpp b/src/command/video.cpp index f85b670240..7369e57eb9 100644 --- a/src/command/video.cpp +++ b/src/command/video.cpp @@ -44,6 +44,7 @@ #include "../libresrc/libresrc.h" #include "../options.h" #include "../project.h" +#include "../provider_file_formats.h" #include "../selection_controller.h" #include "../utils.h" #include "../video_controller.h" @@ -588,8 +589,9 @@ struct video_open final : public Command { STR_HELP("Open a video file") void operator()(agi::Context *c) override { - auto str = from_wx(_("Video Formats") + " (*.asf,*.avi,*.avs,*.d2v,*.h264,*.hevc,*.m2ts,*.m4v,*.mkv,*.mov,*.mp4,*.mpeg,*.mpg,*.ogm,*.webm,*.wmv,*.ts,*.y4m,*.yuv)|*.asf;*.avi;*.avs;*.d2v;*.h264;*.hevc;*.m2ts;*.m4v;*.mkv;*.mov;*.mp4;*.mpeg;*.mpg;*.ogm;*.webm;*.wmv;*.ts;*.y4m;*.yuv|" - + _("All Files") + " (*.*)|*.*"); + auto formats = MakeWildcard(GetVideoFileExtensions()); + auto str = from_wx(_("Video Formats")) + " (" + formats + ")|" + formats + "|" + + from_wx(_("All Files")) + " (*.*)|*.*"; auto filename = OpenFileSelector(_("Open Video File"), "Path/Last/Video", "", "", str, c->parent); if (!filename.empty()) c->project->LoadVideo(filename); diff --git a/src/meson.build b/src/meson.build index b5350d7bb5..876d551ffb 100644 --- a/src/meson.build +++ b/src/meson.build @@ -105,6 +105,7 @@ aegisub_src = files( 'preferences.cpp', 'preferences_base.cpp', 'project.cpp', + 'provider_file_formats.cpp', 'resolution_resampler.cpp', 'search_replace_engine.cpp', 'selection_controller.cpp', diff --git a/src/project.cpp b/src/project.cpp index b8a30dc815..64413d4abf 100644 --- a/src/project.cpp +++ b/src/project.cpp @@ -31,6 +31,7 @@ #include "include/aegisub/video_provider.h" #include "mkv_wrap.h" #include "options.h" +#include "provider_file_formats.h" #include "selection_controller.h" #include "subs_controller.h" #include "utils.h" @@ -431,31 +432,6 @@ void Project::CloseKeyframes() { void Project::LoadList(std::vector const& files) { // Keep these lists sorted - // Video formats - const char *videoList[] = { - ".asf", - ".avi", - ".avs", - ".d2v", - ".h264", - ".hevc", - ".m2ts", - ".m4v", - ".mkv", - ".mov", - ".mp4", - ".mpeg", - ".mpg", - ".ogm", - ".rm", - ".rmvb", - ".ts", - ".webm", - ".wmv", - ".y4m", - ".yuv" - }; - // Subtitle formats const char *subsList[] = { ".ass", @@ -465,28 +441,10 @@ void Project::LoadList(std::vector const& files) { ".ttxt" }; - // Audio formats - const char *audioList[] = { - ".aac", - ".ac3", - ".ape", - ".dts", - ".eac3", - ".flac", - ".m4a", - ".mka", - ".mp3", - ".ogg", - ".opus", - ".w64", - ".wav", - ".wma" - }; - - auto search = [](const char **begin, const char **end, std::string const& str) { - return std::binary_search(begin, end, str.c_str(), [](const char *a, const char *b) { - return strcmp(a, b) < 0; - }); + auto video_formats = GetVideoFileExtensions(); + auto audio_formats = GetAudioFileExtensions(); + auto search = [](auto const& formats, std::string const& str) { + return std::binary_search(formats.begin(), formats.end(), str); }; agi::fs::path audio, video, subs, timecodes, keyframes; @@ -520,11 +478,11 @@ void Project::LoadList(std::vector const& files) { continue; } - if (subs.empty() && search(std::begin(subsList), std::end(subsList), ext)) + if (subs.empty() && std::binary_search(std::begin(subsList), std::end(subsList), ext.c_str(), [](const char *a, const char *b) { return strcmp(a, b) < 0; })) subs = file; - if (video.empty() && search(std::begin(videoList), std::end(videoList), ext)) + if (video.empty() && search(video_formats, ext)) video = file; - if (audio.empty() && search(std::begin(audioList), std::end(audioList), ext)) + if (audio.empty() && search(audio_formats, ext)) audio = file; } diff --git a/src/provider_file_formats.cpp b/src/provider_file_formats.cpp new file mode 100644 index 0000000000..c66992e57c --- /dev/null +++ b/src/provider_file_formats.cpp @@ -0,0 +1,61 @@ +// Copyright (c) 2026, Aegisub contributors +// Permission to use, copy, modify, and distribute this software for any +// purpose with or without fee is hereby granted. + +#include "provider_file_formats.h" + +#include +#include + +namespace { +void Add(std::vector& formats, std::initializer_list added) { + formats.insert(formats.end(), added.begin(), added.end()); +} + +void Finish(std::vector& formats) { + std::sort(formats.begin(), formats.end()); + formats.erase(std::unique(formats.begin(), formats.end()), formats.end()); +} +} + +std::vector GetVideoFileExtensions() { + // YUV4MPEG is always available. + std::vector formats = {".y4m", ".yuv"}; +#ifdef WITH_FFMS2 + Add(formats, {".asf", ".avi", ".avs", ".d2v", ".h264", ".hevc", ".m2ts", + ".m4v", ".mkv", ".mov", ".mp4", ".mpeg", ".mpg", ".ogm", ".ts", + ".webm", ".wmv"}); +#endif +#ifdef WITH_AVISYNTH + // Other formats may work through installed source filters, but these are the + // formats which the built-in AviSynth provider handles explicitly. + Add(formats, {".avi", ".avs", ".d2v"}); +#endif + Finish(formats); + return formats; +} + +std::vector GetAudioFileExtensions() { + // The PCM provider is always available. + std::vector formats = {".wav"}; +#ifdef WITH_FFMS2 + Add(formats, {".aac", ".ac3", ".ape", ".asf", ".avi", ".avs", ".d2v", ".dts", + ".eac3", ".flac", ".m2ts", ".m4a", ".m4v", ".mka", ".mkv", ".mov", + ".mp3", ".mp4", ".mpeg", ".mpg", ".ogg", ".ogm", ".opus", ".ts", + ".w64", ".webm", ".wma", ".wmv"}); +#endif +#ifdef WITH_AVISYNTH + Add(formats, {".avi", ".avs"}); +#endif + Finish(formats); + return formats; +} + +std::string MakeWildcard(std::vector const& extensions) { + std::string result; + for (auto const& extension : extensions) { + if (!result.empty()) result += ';'; + result += '*' + extension; + } + return result; +} diff --git a/src/provider_file_formats.h b/src/provider_file_formats.h new file mode 100644 index 0000000000..f4b5351090 --- /dev/null +++ b/src/provider_file_formats.h @@ -0,0 +1,15 @@ +// Copyright (c) 2026, Aegisub contributors +// Permission to use, copy, modify, and distribute this software for any +// purpose with or without fee is hereby granted. + +#pragma once + +#include +#include + +/// File extensions (including the leading dot) handled by compiled providers. +std::vector GetAudioFileExtensions(); +std::vector GetVideoFileExtensions(); + +/// Turn an extension list into the pattern portion of a wx file-dialog filter. +std::string MakeWildcard(std::vector const& extensions); From e0dfd58a502fa579b54dff85482be48c1611ba29 Mon Sep 17 00:00:00 2001 From: Final AI Agent Date: Thu, 13 Aug 2026 19:32:12 +0000 Subject: [PATCH 2/4] Move media formats into provider factories --- src/audio_provider_factory.cpp | 24 ++++++++++++++--- src/audio_provider_factory.h | 1 + src/command/audio.cpp | 3 ++- src/command/video.cpp | 3 ++- src/project.cpp | 5 ++-- src/provider_file_formats.cpp | 47 ---------------------------------- src/provider_file_formats.h | 4 --- src/video_provider_manager.cpp | 27 ++++++++++++++----- src/video_provider_manager.h | 1 + 9 files changed, 50 insertions(+), 65 deletions(-) diff --git a/src/audio_provider_factory.cpp b/src/audio_provider_factory.cpp index d849f019b9..58c375bb03 100644 --- a/src/audio_provider_factory.cpp +++ b/src/audio_provider_factory.cpp @@ -26,6 +26,9 @@ #include #include +#include +#include + using namespace agi; std::unique_ptr CreateAvisynthAudioProvider(fs::path const& filename, BackgroundRunner *); @@ -36,16 +39,20 @@ struct factory { const char *name; std::unique_ptr (*create)(fs::path const&, BackgroundRunner *); bool hidden; + std::vector extensions; }; const std::initializer_list providers = { - {"Dummy", CreateDummyAudioProvider, true}, - {"PCM", CreatePCMAudioProvider, true}, + {"Dummy", CreateDummyAudioProvider, true, {}}, + {"PCM", CreatePCMAudioProvider, true, {".w64", ".wav"}}, #ifdef WITH_FFMS2 - {"FFmpegSource", CreateFFmpegSourceAudioProvider, false}, + {"FFmpegSource", CreateFFmpegSourceAudioProvider, false, + {".aac", ".ac3", ".ape", ".asf", ".avi", ".avs", ".d2v", ".dts", ".eac3", ".flac", ".m2ts", + ".m4a", ".m4v", ".mka", ".mkv", ".mov", ".mp3", ".mp4", ".mpeg", ".mpg", ".ogg", ".ogm", ".opus", + ".ts", ".w64", ".wav", ".webm", ".wma", ".wmv"}}, #endif #ifdef WITH_AVISYNTH - {"Avisynth", CreateAvisynthAudioProvider, false}, + {"Avisynth", CreateAvisynthAudioProvider, false, {".avi", ".avs"}}, #endif }; } @@ -54,6 +61,15 @@ std::vector GetAudioProviderNames() { return ::GetClasses(providers); } +std::vector GetAudioProviderFileExtensions() { + std::vector extensions; + for (auto const& provider : providers) + extensions.insert(extensions.end(), provider.extensions.begin(), provider.extensions.end()); + std::sort(extensions.begin(), extensions.end()); + extensions.erase(std::unique(extensions.begin(), extensions.end()), extensions.end()); + return extensions; +} + std::unique_ptr GetAudioProvider(fs::path const& filename, Path const& path_helper, BackgroundRunner *br) { diff --git a/src/audio_provider_factory.h b/src/audio_provider_factory.h index 7e0c6b0649..0ac92b2568 100644 --- a/src/audio_provider_factory.h +++ b/src/audio_provider_factory.h @@ -28,3 +28,4 @@ std::unique_ptr GetAudioProvider(agi::fs::path const& filena agi::Path const& path_helper, agi::BackgroundRunner *br); std::vector GetAudioProviderNames(); +std::vector GetAudioProviderFileExtensions(); diff --git a/src/command/audio.cpp b/src/command/audio.cpp index ceaf7ecc26..58f5fd5529 100644 --- a/src/command/audio.cpp +++ b/src/command/audio.cpp @@ -42,6 +42,7 @@ #include "../libresrc/libresrc.h" #include "../options.h" #include "../project.h" +#include "../audio_provider_factory.h" #include "../provider_file_formats.h" #include "../selection_controller.h" #include "../utils.h" @@ -80,7 +81,7 @@ struct audio_open final : public Command { STR_HELP("Open an audio file") void operator()(agi::Context *c) override { - auto formats = MakeWildcard(GetAudioFileExtensions()); + auto formats = MakeWildcard(GetAudioProviderFileExtensions()); auto str = from_wx(_("Audio and Video Formats")) + " (" + formats + ")|" + formats + "|" + from_wx(_("All Files")) + " (*.*)|*.*"; auto filename = OpenFileSelector(wxGETTEXT_IN_CONTEXT("dialog title", "Open Audio File"), "Path/Last/Audio", "", "", str, c->parent); diff --git a/src/command/video.cpp b/src/command/video.cpp index 7369e57eb9..deb7cd6925 100644 --- a/src/command/video.cpp +++ b/src/command/video.cpp @@ -45,6 +45,7 @@ #include "../options.h" #include "../project.h" #include "../provider_file_formats.h" +#include "../video_provider_manager.h" #include "../selection_controller.h" #include "../utils.h" #include "../video_controller.h" @@ -589,7 +590,7 @@ struct video_open final : public Command { STR_HELP("Open a video file") void operator()(agi::Context *c) override { - auto formats = MakeWildcard(GetVideoFileExtensions()); + auto formats = MakeWildcard(VideoProviderFactory::GetFileExtensions()); auto str = from_wx(_("Video Formats")) + " (" + formats + ")|" + formats + "|" + from_wx(_("All Files")) + " (*.*)|*.*"; auto filename = OpenFileSelector(_("Open Video File"), "Path/Last/Video", "", "", str, c->parent); diff --git a/src/project.cpp b/src/project.cpp index 64413d4abf..35c7f59ef3 100644 --- a/src/project.cpp +++ b/src/project.cpp @@ -23,6 +23,7 @@ #include "audio_provider_factory.h" #include "base_grid.h" #include "charset_detect.h" +#include "audio_provider_factory.h" #include "compat.h" #include "dialog_progress.h" #include "dialogs.h" @@ -441,8 +442,8 @@ void Project::LoadList(std::vector const& files) { ".ttxt" }; - auto video_formats = GetVideoFileExtensions(); - auto audio_formats = GetAudioFileExtensions(); + auto video_formats = VideoProviderFactory::GetFileExtensions(); + auto audio_formats = GetAudioProviderFileExtensions(); auto search = [](auto const& formats, std::string const& str) { return std::binary_search(formats.begin(), formats.end(), str); }; diff --git a/src/provider_file_formats.cpp b/src/provider_file_formats.cpp index c66992e57c..d84500403f 100644 --- a/src/provider_file_formats.cpp +++ b/src/provider_file_formats.cpp @@ -4,53 +4,6 @@ #include "provider_file_formats.h" -#include -#include - -namespace { -void Add(std::vector& formats, std::initializer_list added) { - formats.insert(formats.end(), added.begin(), added.end()); -} - -void Finish(std::vector& formats) { - std::sort(formats.begin(), formats.end()); - formats.erase(std::unique(formats.begin(), formats.end()), formats.end()); -} -} - -std::vector GetVideoFileExtensions() { - // YUV4MPEG is always available. - std::vector formats = {".y4m", ".yuv"}; -#ifdef WITH_FFMS2 - Add(formats, {".asf", ".avi", ".avs", ".d2v", ".h264", ".hevc", ".m2ts", - ".m4v", ".mkv", ".mov", ".mp4", ".mpeg", ".mpg", ".ogm", ".ts", - ".webm", ".wmv"}); -#endif -#ifdef WITH_AVISYNTH - // Other formats may work through installed source filters, but these are the - // formats which the built-in AviSynth provider handles explicitly. - Add(formats, {".avi", ".avs", ".d2v"}); -#endif - Finish(formats); - return formats; -} - -std::vector GetAudioFileExtensions() { - // The PCM provider is always available. - std::vector formats = {".wav"}; -#ifdef WITH_FFMS2 - Add(formats, {".aac", ".ac3", ".ape", ".asf", ".avi", ".avs", ".d2v", ".dts", - ".eac3", ".flac", ".m2ts", ".m4a", ".m4v", ".mka", ".mkv", ".mov", - ".mp3", ".mp4", ".mpeg", ".mpg", ".ogg", ".ogm", ".opus", ".ts", - ".w64", ".webm", ".wma", ".wmv"}); -#endif -#ifdef WITH_AVISYNTH - Add(formats, {".avi", ".avs"}); -#endif - Finish(formats); - return formats; -} - std::string MakeWildcard(std::vector const& extensions) { std::string result; for (auto const& extension : extensions) { diff --git a/src/provider_file_formats.h b/src/provider_file_formats.h index f4b5351090..6742d29e5a 100644 --- a/src/provider_file_formats.h +++ b/src/provider_file_formats.h @@ -7,9 +7,5 @@ #include #include -/// File extensions (including the leading dot) handled by compiled providers. -std::vector GetAudioFileExtensions(); -std::vector GetVideoFileExtensions(); - /// Turn an extension list into the pattern portion of a wx file-dialog filter. std::string MakeWildcard(std::vector const& extensions); diff --git a/src/video_provider_manager.cpp b/src/video_provider_manager.cpp index dffefd444e..1e586ee821 100644 --- a/src/video_provider_manager.cpp +++ b/src/video_provider_manager.cpp @@ -27,6 +27,9 @@ #include +#include +#include + std::unique_ptr CreateDummyVideoProvider(agi::fs::path const&, agi::ycbcr::Header, agi::BackgroundRunner *); std::unique_ptr CreateYUV4MPEGVideoProvider(agi::fs::path const&, agi::ycbcr::Header, agi::BackgroundRunner *); std::unique_ptr CreateFFmpegSourceVideoProvider(agi::fs::path const&, agi::ycbcr::Header, agi::BackgroundRunner *); @@ -37,18 +40,21 @@ std::unique_ptr CreateCacheVideoProvider(std::unique_ptr (*create)(agi::fs::path const&, agi::ycbcr::Header, agi::BackgroundRunner *); - bool hidden; + std::unique_ptr (*create)(agi::fs::path const&, agi::ycbcr::Header, agi::BackgroundRunner *); + bool hidden; + std::vector extensions; }; const std::initializer_list providers = { - {"Dummy", CreateDummyVideoProvider, true}, - {"YUV4MPEG", CreateYUV4MPEGVideoProvider, true}, + {"Dummy", CreateDummyVideoProvider, true, {}}, + {"YUV4MPEG", CreateYUV4MPEGVideoProvider, true, {".y4m", ".yuv"}}, #ifdef WITH_FFMS2 - {"FFmpegSource", CreateFFmpegSourceVideoProvider, false}, + {"FFmpegSource", CreateFFmpegSourceVideoProvider, false, + {".asf", ".avi", ".avs", ".d2v", ".h264", ".hevc", ".m2ts", ".m4v", ".mkv", ".mov", ".mp4", + ".mpeg", ".mpg", ".ogm", ".ts", ".webm", ".wmv"}}, #endif #ifdef WITH_AVISYNTH - {"Avisynth", CreateAvisynthVideoProvider, false}, + {"Avisynth", CreateAvisynthVideoProvider, false, {".avi", ".avs", ".d2v"}}, #endif }; } @@ -57,6 +63,15 @@ std::vector VideoProviderFactory::GetClasses() { return ::GetClasses(providers); } +std::vector VideoProviderFactory::GetFileExtensions() { + std::vector extensions; + for (auto const& provider : providers) + extensions.insert(extensions.end(), provider.extensions.begin(), provider.extensions.end()); + std::sort(extensions.begin(), extensions.end()); + extensions.erase(std::unique(extensions.begin(), extensions.end()), extensions.end()); + return extensions; +} + std::unique_ptr VideoProviderFactory::GetProvider(agi::fs::path const& filename, agi::ycbcr::Header colormatrix, agi::BackgroundRunner *br) { auto preferred = OPT_GET("Video/Provider")->GetString(); auto sorted = GetSorted(providers, preferred); diff --git a/src/video_provider_manager.h b/src/video_provider_manager.h index 4c5c4bc750..3b1e86ea2e 100644 --- a/src/video_provider_manager.h +++ b/src/video_provider_manager.h @@ -25,5 +25,6 @@ namespace agi { class BackgroundRunner; } struct VideoProviderFactory { static std::vector GetClasses(); + static std::vector GetFileExtensions(); static std::unique_ptr GetProvider(agi::fs::path const& video_file, agi::ycbcr::Header colormatrix, agi::BackgroundRunner *br); }; From 892f6b986b8c39fb06bf2911bc73d2b151b84ee9 Mon Sep 17 00:00:00 2001 From: Final AI Agent Date: Thu, 13 Aug 2026 21:56:26 +0000 Subject: [PATCH 3/4] Include video provider manager in project --- src/project.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/src/project.cpp b/src/project.cpp index 35c7f59ef3..5787701ac8 100644 --- a/src/project.cpp +++ b/src/project.cpp @@ -38,6 +38,7 @@ #include "utils.h" #include "video_controller.h" #include "video_display.h" +#include "video_provider_manager.h" #include #include From 0b4a9c028dac85f6951547cd6b72bd0f333061fc Mon Sep 17 00:00:00 2001 From: arch1t3cht Date: Fri, 14 Aug 2026 17:36:43 +0200 Subject: [PATCH 4/4] Fix indentation --- src/video_provider_manager.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/video_provider_manager.cpp b/src/video_provider_manager.cpp index 1e586ee821..97983f50a0 100644 --- a/src/video_provider_manager.cpp +++ b/src/video_provider_manager.cpp @@ -40,9 +40,9 @@ std::unique_ptr CreateCacheVideoProvider(std::unique_ptr (*create)(agi::fs::path const&, agi::ycbcr::Header, agi::BackgroundRunner *); - bool hidden; - std::vector extensions; + std::unique_ptr (*create)(agi::fs::path const&, agi::ycbcr::Header, agi::BackgroundRunner *); + bool hidden; + std::vector extensions; }; const std::initializer_list providers = {