diff --git a/build/Aegisub/Aegisub.vcxproj b/build/Aegisub/Aegisub.vcxproj
index 4241a63c2..ce9b19969 100644
--- a/build/Aegisub/Aegisub.vcxproj
+++ b/build/Aegisub/Aegisub.vcxproj
@@ -1,4 +1,4 @@
-
+
@@ -173,6 +173,7 @@
+
@@ -370,6 +371,7 @@
+
diff --git a/build/Aegisub/Aegisub.vcxproj.filters b/build/Aegisub/Aegisub.vcxproj.filters
index 64750b2fd..c29884ca8 100644
--- a/build/Aegisub/Aegisub.vcxproj.filters
+++ b/build/Aegisub/Aegisub.vcxproj.filters
@@ -621,6 +621,9 @@
Subtitle formats
+
+ Features\Resolution resampler
+
@@ -1175,9 +1178,12 @@
Subtitle formats
+
+ Features\Resolution resampler
+
-
+
\ No newline at end of file
diff --git a/src/Makefile b/src/Makefile
index 3cfde47f0..32b187536 100644
--- a/src/Makefile
+++ b/src/Makefile
@@ -184,6 +184,7 @@ SRC += \
dialog_translation.cpp \
dialog_version_check.cpp \
dialog_video_details.cpp \
+ dialog_video_properties.cpp \
export_fixstyle.cpp \
export_framerate.cpp \
fft.cpp \
diff --git a/src/dialog_video_properties.cpp b/src/dialog_video_properties.cpp
new file mode 100644
index 000000000..b0a687881
--- /dev/null
+++ b/src/dialog_video_properties.cpp
@@ -0,0 +1,156 @@
+// Copyright (c) 2014, Thomas Goyne
+//
+// Permission to use, copy, modify, and distribute this software for any
+// purpose with or without fee is hereby granted, provided that the above
+// copyright notice and this permission notice appear in all copies.
+//
+// THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+// WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+// MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+// ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+// WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+// ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+// OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+//
+// Aegisub Project http://www.aegisub.org/
+
+#include "dialog_video_properties.h"
+
+#include "ass_file.h"
+#include "include/aegisub/video_provider.h"
+#include "options.h"
+#include "resolution_resampler.h"
+
+#include
+#include
+#include
+#include
+
+namespace {
+enum {
+ MISMATCH_IGNORE,
+ MISMATCH_PROMPT,
+ MISMATCH_RESAMPLE,
+ MISMATCH_SET
+};
+enum {
+ FIX_IGNORE,
+ FIX_SET,
+ FIX_RESAMPLE
+};
+
+class Prompt : public wxDialog {
+public:
+ Prompt(wxWindow *parent, bool ar_changed, int sx, int sy, int vx, int vy)
+ : wxDialog(parent, -1, _("Resolution mismatch"))
+ {
+ auto label_text = wxString::Format(_("The resolution of the loaded video and the resolution specified for the subtitles don't match.\n\nVideo resolution:\t%d x %d\nScript resolution:\t%d x %d\n\nChange subtitles resolution to match video?"), vx, vy, sx, sy);
+
+ auto sizer = new wxBoxSizer(wxVERTICAL);
+ sizer->Add(new wxStaticText(this, -1, label_text), wxSizerFlags().Border());
+
+ wxRadioBox *rb;
+ if (ar_changed) {
+ wxString choices[] = {
+ _("Set to video resolution"),
+ _("Resample script (stretch to new aspect ratio)"),
+ _("Resample script (add borders)"),
+ _("Resample script (remove borders)")
+ };
+ rb = new wxRadioBox(this, -1, "", wxDefaultPosition, wxDefaultSize, 4, choices, 1);
+ }
+ else {
+ wxString choices[] = {
+ _("Set to video resolution"),
+ _("Resample script"),
+ };
+ rb = new wxRadioBox(this, -1, "", wxDefaultPosition, wxDefaultSize, 2, choices, 1);
+ }
+ sizer->Add(rb, wxSizerFlags().Border(wxALL & ~wxTOP).Expand());
+ sizer->Add(CreateStdDialogButtonSizer(wxOK | wxCANCEL | wxHELP), wxSizerFlags().Border().Expand());
+
+ unsigned int sel = OPT_GET("Video/Last Script Resolution Mismatch Choice")->GetInt();
+ rb->SetSelection(std::min(sel - 1, rb->GetCount()));
+
+ SetSizerAndFit(sizer);
+ CenterOnParent();
+
+ Bind(wxEVT_BUTTON, [=](wxCommandEvent&) { EndModal(rb->GetSelection() + 1); }, wxID_OK);
+ Bind(wxEVT_BUTTON, [=](wxCommandEvent&) { EndModal(0); }, wxID_CANCEL);
+ }
+};
+}
+
+bool UpdateVideoProperties(AssFile *file, const VideoProvider *new_provider, wxWindow *parent) {
+ bool commit_subs = false;
+
+ // When opening dummy video only want to set the script properties if
+ // they were previously unset
+ bool set_properties = new_provider->ShouldSetVideoProperties();
+
+ auto matrix = new_provider->GetColorSpace();
+ if (set_properties && matrix != file->GetScriptInfo("YCbCr Matrix")) {
+ file->SetScriptInfo("YCbCr Matrix", matrix);
+ commit_subs = true;
+ }
+
+ // Check that the script resolution matches the video resolution
+ int sx = file->GetScriptInfoAsInt("PlayResX");
+ int sy = file->GetScriptInfoAsInt("PlayResY");
+ int vx = new_provider->GetWidth();
+ int vy = new_provider->GetHeight();
+
+ // If the script resolution hasn't been set at all just force it to the
+ // video resolution
+ if (sx == 0 && sy == 0) {
+ file->SetScriptInfo("PlayResX", std::to_string(vx));
+ file->SetScriptInfo("PlayResY", std::to_string(vy));
+ return true;
+ }
+
+ if (!set_properties)
+ return false;
+
+ // Treat exact multiples of the video resolution as equaling the resolution
+ // for the people who use that for subpixel precision (which is mostly
+ // pointless these days due to decimals being supported almost everywhere)
+ if (sx % vx == 0 && sy % vy == 0)
+ return commit_subs;
+
+ auto sar = double(sx) / sy;
+ auto var = double(vx) / vy;
+ bool ar_changed = abs(sar - var) / var > .01;
+
+ switch (OPT_GET("Video/Script Resolution Mismatch")->GetInt()) {
+ case MISMATCH_IGNORE: default:
+ return commit_subs;
+
+ case MISMATCH_SET:
+ file->SetScriptInfo("PlayResX", std::to_string(vx));
+ file->SetScriptInfo("PlayResY", std::to_string(vy));
+ return true;
+
+ case MISMATCH_RESAMPLE:
+ // Fallthrough to prompt if the AR changed
+ if (!ar_changed) {
+ ResampleResolution(file, {
+ {0, 0, 0, 0},
+ sx, sy, vx, vy,
+ ResampleARMode::Stretch
+ });
+ return true;
+ }
+
+ case MISMATCH_PROMPT:
+ int res = Prompt(parent, ar_changed, sx, sy, vx, vy).ShowModal();
+ if (res == FIX_IGNORE) return commit_subs;
+ OPT_SET("Video/Last Script Resolution Mismatch Choice")->SetInt(res);
+
+ ResampleResolution(file, {
+ {0, 0, 0, 0},
+ sx, sy, vx, vy,
+ static_cast(res - FIX_RESAMPLE)
+ });
+ return true;
+ }
+}
diff --git a/src/dialog_video_properties.h b/src/dialog_video_properties.h
new file mode 100644
index 000000000..5d48445a4
--- /dev/null
+++ b/src/dialog_video_properties.h
@@ -0,0 +1,23 @@
+// Copyright (c) 2014, Thomas Goyne
+//
+// Permission to use, copy, modify, and distribute this software for any
+// purpose with or without fee is hereby granted, provided that the above
+// copyright notice and this permission notice appear in all copies.
+//
+// THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+// WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+// MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+// ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+// WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+// ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+// OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+//
+// Aegisub Project http://www.aegisub.org/
+
+class AssFile;
+class VideoProvider;
+class wxWindow;
+
+/// Update the video properties for a newly opened video, possibly prompting the user about what to do
+/// @return Does the file need to be committed?
+bool UpdateVideoProperties(AssFile *file, const VideoProvider *new_provider, wxWindow *parent);
\ No newline at end of file
diff --git a/src/libresrc/default_config.json b/src/libresrc/default_config.json
index d0ef192d0..9a5e8916e 100644
--- a/src/libresrc/default_config.json
+++ b/src/libresrc/default_config.json
@@ -572,7 +572,6 @@
},
"Video" : {
- "Check Script Res" : 1,
"Default Zoom" : 7,
"Detached" : {
"Enabled" : false,
@@ -592,9 +591,11 @@
"Pattern" : false
},
"Force BT.601" : true,
+ "Last Script Resolution Mismatch Choice" : 2,
"Open Audio" : false,
"Overscan Mask" : false,
"Provider" : "ffmpegsource",
+ "Script Resolution Mismatch" : 1,
"Slider" : {
"Fast Jump Step" : 10,
"Show Keyframes" : true
diff --git a/src/libresrc/osx/default_config.json b/src/libresrc/osx/default_config.json
index 458cf0d2c..91615704a 100644
--- a/src/libresrc/osx/default_config.json
+++ b/src/libresrc/osx/default_config.json
@@ -572,7 +572,6 @@
},
"Video" : {
- "Check Script Res" : 1,
"Default Zoom" : 7,
"Detached" : {
"Enabled" : false,
@@ -592,9 +591,11 @@
"Pattern" : false
},
"Force BT.601" : true,
+ "Last Script Resolution Mismatch Choice" : 2,
"Open Audio" : false,
"Overscan Mask" : false,
"Provider" : "ffmpegsource",
+ "Script Resolution Mismatch" : 1,
"Slider" : {
"Fast Jump Step" : 10,
"Show Keyframes" : true
diff --git a/src/preferences.cpp b/src/preferences.cpp
index 8e93cac05..0f2fab6cb 100644
--- a/src/preferences.cpp
+++ b/src/preferences.cpp
@@ -220,9 +220,9 @@ Video::Video(wxTreebook *book, Preferences *parent): OptionPage(book, parent, _(
DisableIfChecked(autocb,
OptionAdd(resolution, _("Default height"), "Subtitle/Default Resolution/Height"));
- const wxString cres_arr[3] = { _("Never"), _("Ask"), _("Always") };
- wxArrayString choice_res(3, cres_arr);
- OptionChoice(resolution, _("Match video resolution on open"), choice_res, "Video/Check Script Res");
+ const wxString cres_arr[] = {_("Never"), _("Ask"), _("Always set"), _("Always resample")};
+ wxArrayString choice_res(4, cres_arr);
+ OptionChoice(resolution, _("Match video resolution on open"), choice_res, "Video/Script Resolution Mismatch");
SetSizerAndFit(sizer);
}
diff --git a/src/video_context.cpp b/src/video_context.cpp
index 2ba0f2b10..2d099e691 100644
--- a/src/video_context.cpp
+++ b/src/video_context.cpp
@@ -40,6 +40,7 @@
#include "audio_controller.h"
#include "compat.h"
#include "dialog_progress.h"
+#include "dialog_video_properties.h"
#include "include/aegisub/context.h"
#include "include/aegisub/video_provider.h"
#include "mkv_wrap.h"
@@ -121,51 +122,7 @@ void VideoContext::SetVideo(const agi::fs::path &filename) {
video_provider = provider->GetVideoProvider();
video_filename = filename;
- // When opening dummy video only want to set the script properties if
- // they were previously unset
- bool set_properties = video_provider->ShouldSetVideoProperties();
-
- auto matrix = video_provider->GetColorSpace();
- if (set_properties && matrix != old_matrix) {
- context->ass->SetScriptInfo("YCbCr Matrix", matrix);
- commit_subs = true;
- }
-
- // Check that the script resolution matches the video resolution
- int sx = context->ass->GetScriptInfoAsInt("PlayResX");
- int sy = context->ass->GetScriptInfoAsInt("PlayResY");
- int vx = GetWidth();
- int vy = GetHeight();
-
- // If the script resolution hasn't been set at all just force it to the
- // video resolution
- if (sx == 0 && sy == 0) {
- context->ass->SetScriptInfo("PlayResX", std::to_string(vx));
- context->ass->SetScriptInfo("PlayResY", std::to_string(vy));
- commit_subs = true;
- }
- // If it has been set to something other than a multiple of the video
- // resolution, ask the user if they want it to be fixed
- else if (set_properties && (sx % vx != 0 || sy % vy != 0)) {
- switch (OPT_GET("Video/Check Script Res")->GetInt()) {
- case 1: // Ask to change on mismatch
- if (wxYES != wxMessageBox(
- wxString::Format(_("The resolution of the loaded video and the resolution specified for the subtitles don't match.\n\nVideo resolution:\t%d x %d\nScript resolution:\t%d x %d\n\nChange subtitles resolution to match video?"), vx, vy, sx, sy),
- _("Resolution mismatch"),
- wxYES_NO | wxCENTER,
- context->parent))
-
- break;
- // Fallthrough to case 2
- case 2: // Always change script res
- context->ass->SetScriptInfo("PlayResX", std::to_string(vx));
- context->ass->SetScriptInfo("PlayResY", std::to_string(vy));
- commit_subs = true;
- break;
- default: // Never change
- break;
- }
- }
+ bool needs_commit = UpdateVideoProperties(context->ass.get(), video_provider, context->parent);
keyframes = video_provider->GetKeyFrames();