// 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 "async_video_provider.h" #include "options.h" #include "resolution_resampler.h" #include #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 update_video_properties(AssFile *file, const AsyncVideoProvider *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, YCbCrMatrix::rgb, YCbCrMatrix::rgb }); 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), YCbCrMatrix::rgb, YCbCrMatrix::rgb }); return true; } } } void UpdateVideoProperties(AssFile *file, const AsyncVideoProvider *new_provider, wxWindow *parent) { if (update_video_properties(file, new_provider, parent)) file->Commit(_("change script resolution"), AssFile::COMMIT_SCRIPTINFO); }