mirror of https://github.com/odrling/Aegisub
Add color matrix conversion to the resolution resampler
This commit is contained in:
parent
7a06e08ad0
commit
ad33fdb109
|
@ -17,6 +17,8 @@
|
|||
#include <array>
|
||||
#include <cstdint>
|
||||
|
||||
#include <libaegisub/color.h>
|
||||
|
||||
namespace agi {
|
||||
enum class ycbcr_matrix {
|
||||
bt601,
|
||||
|
@ -84,6 +86,11 @@ public:
|
|||
return to_uint8_t(prod(from_ycbcr,
|
||||
add(add(prod(to_ycbcr, input), shift_to), shift_from)));
|
||||
}
|
||||
|
||||
Color rgb_to_rgb(Color c) const {
|
||||
auto arr = rgb_to_rgb(std::array<uint8_t, 3>{{c.r, c.g, c.b}});
|
||||
return Color{arr[0], arr[1], arr[2]};
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
|
|
|
@ -294,10 +294,10 @@ static void load_protos() {
|
|||
proto[++i].Set("\\fr", VariableDataType::FLOAT); // \fr<degrees>
|
||||
proto[++i].Set("\\fax", VariableDataType::FLOAT); // \fax<factor>
|
||||
proto[++i].Set("\\fay", VariableDataType::FLOAT); // \fay<factor>
|
||||
proto[++i].Set("\\1c", VariableDataType::TEXT); // \1c&H<bbggrr>&
|
||||
proto[++i].Set("\\2c", VariableDataType::TEXT); // \2c&H<bbggrr>&
|
||||
proto[++i].Set("\\3c", VariableDataType::TEXT); // \3c&H<bbggrr>&
|
||||
proto[++i].Set("\\4c", VariableDataType::TEXT); // \4c&H<bbggrr>&
|
||||
proto[++i].Set("\\1c", VariableDataType::TEXT, AssParameterClass::COLOR); // \1c&H<bbggrr>&
|
||||
proto[++i].Set("\\2c", VariableDataType::TEXT, AssParameterClass::COLOR); // \2c&H<bbggrr>&
|
||||
proto[++i].Set("\\3c", VariableDataType::TEXT, AssParameterClass::COLOR); // \3c&H<bbggrr>&
|
||||
proto[++i].Set("\\4c", VariableDataType::TEXT, AssParameterClass::COLOR); // \4c&H<bbggrr>&
|
||||
proto[++i].Set("\\1a", VariableDataType::TEXT, AssParameterClass::ALPHA); // \1a&H<aa>&
|
||||
proto[++i].Set("\\2a", VariableDataType::TEXT, AssParameterClass::ALPHA); // \2a&H<aa>&
|
||||
proto[++i].Set("\\3a", VariableDataType::TEXT, AssParameterClass::ALPHA); // \3a&H<aa>&
|
||||
|
@ -312,7 +312,7 @@ static void load_protos() {
|
|||
proto[++i].Set("\\fs-", VariableDataType::FLOAT); // \fs-<size>
|
||||
proto[++i].Set("\\fs", VariableDataType::FLOAT, AssParameterClass::ABSOLUTE_SIZE); // \fs<size>
|
||||
proto[++i].Set("\\an", VariableDataType::INT); // \an<alignment>
|
||||
proto[++i].Set("\\c", VariableDataType::TEXT); // \c&H<bbggrr>&
|
||||
proto[++i].Set("\\c", VariableDataType::TEXT, AssParameterClass::COLOR); // \c&H<bbggrr>&
|
||||
proto[++i].Set("\\b", VariableDataType::INT); // \b<0/1/weight>
|
||||
proto[++i].Set("\\i", VariableDataType::BOOL); // \i<0/1>
|
||||
proto[++i].Set("\\u", VariableDataType::BOOL); // \u<0/1>
|
||||
|
|
|
@ -49,7 +49,8 @@ enum class AssParameterClass {
|
|||
RELATIVE_TIME_END,
|
||||
KARAOKE,
|
||||
DRAWING,
|
||||
ALPHA
|
||||
ALPHA,
|
||||
COLOR
|
||||
};
|
||||
|
||||
enum class VariableDataType {
|
||||
|
|
|
@ -39,6 +39,7 @@
|
|||
#include "help_button.h"
|
||||
#include "include/aegisub/context.h"
|
||||
#include "libresrc/libresrc.h"
|
||||
#include "resolution_resampler.h"
|
||||
#include "validators.h"
|
||||
#include "video_context.h"
|
||||
|
||||
|
@ -90,15 +91,8 @@ DialogProperties::DialogProperties(agi::Context *c)
|
|||
res_sizer->Add(ResY, 1, wxRIGHT | wxALIGN_CENTER_VERTICAL, 5);
|
||||
res_sizer->Add(FromVideo, 1, 0, 0);
|
||||
|
||||
wxString matricies[] = {
|
||||
"None",
|
||||
"TV.601", "PC.601",
|
||||
"TV.709", "PC.709",
|
||||
"TV.FCC", "PC.FCC",
|
||||
"TV.240M", "PC.240M"
|
||||
};
|
||||
YCbCrMatrix = new wxComboBox(this, -1, c->ass->GetScriptInfo("YCbCr Matrix"),
|
||||
wxDefaultPosition, wxDefaultSize, boost::size(matricies), matricies, wxCB_READONLY);
|
||||
wxDefaultPosition, wxDefaultSize, to_wx(MatrixNames()), wxCB_READONLY);
|
||||
|
||||
auto matrix_sizer = new wxBoxSizer(wxHORIZONTAL);
|
||||
matrix_sizer->Add(new wxStaticText(this, -1, "YCbCr Matrix:"), wxSizerFlags().Center());
|
||||
|
|
|
@ -20,8 +20,10 @@
|
|||
#include "dialog_resample.h"
|
||||
|
||||
#include "ass_file.h"
|
||||
#include "include/aegisub/context.h"
|
||||
#include "compat.h"
|
||||
#include "help_button.h"
|
||||
#include "include/aegisub/context.h"
|
||||
#include "include/aegisub/video_provider.h"
|
||||
#include "libresrc/libresrc.h"
|
||||
#include "resolution_resampler.h"
|
||||
#include "validators.h"
|
||||
|
@ -29,6 +31,7 @@
|
|||
|
||||
#include <boost/range/size.hpp>
|
||||
#include <wx/checkbox.h>
|
||||
#include <wx/combobox.h>
|
||||
#include <wx/sizer.h>
|
||||
#include <wx/spinctrl.h>
|
||||
#include <wx/statbox.h>
|
||||
|
@ -52,14 +55,18 @@ DialogResample::DialogResample(agi::Context *c, ResampleSettings &settings)
|
|||
c->ass->GetResolution(script_w, script_h);
|
||||
settings.source_x = script_w;
|
||||
settings.source_y = script_h;
|
||||
settings.source_matrix = script_mat = MatrixFromString(c->ass->GetScriptInfo("YCbCr Matrix"));
|
||||
|
||||
if (c->videoController->IsLoaded()) {
|
||||
settings.dest_x = video_w = c->videoController->GetWidth();
|
||||
settings.dest_y = video_h = c->videoController->GetHeight();
|
||||
settings.dest_matrix = video_mat = MatrixFromString(c->videoController->GetProvider()->GetRealColorSpace());
|
||||
}
|
||||
else {
|
||||
settings.dest_x = script_w;
|
||||
settings.dest_y = script_h;
|
||||
settings.dest_matrix = script_mat;
|
||||
video_mat = YCbCrMatrix::rgb;
|
||||
}
|
||||
|
||||
// Create all controls and set validators
|
||||
|
@ -76,13 +83,19 @@ DialogResample::DialogResample(agi::Context *c, ResampleSettings &settings)
|
|||
|
||||
source_x = new wxSpinCtrl(this, -1, "", wxDefaultPosition, wxSize(50, -1), wxSP_ARROW_KEYS, 1, INT_MAX);
|
||||
source_y = new wxSpinCtrl(this, -1, "", wxDefaultPosition, wxSize(50, -1), wxSP_ARROW_KEYS, 1, INT_MAX);
|
||||
source_matrix = new wxComboBox(this, -1, "", wxDefaultPosition,
|
||||
wxDefaultSize, to_wx(MatrixNames()), wxCB_READONLY);
|
||||
dest_x = new wxSpinCtrl(this, -1, "", wxDefaultPosition, wxSize(50, -1), wxSP_ARROW_KEYS, 1, INT_MAX);
|
||||
dest_y = new wxSpinCtrl(this, -1, "", wxDefaultPosition, wxSize(50, -1), wxSP_ARROW_KEYS, 1, INT_MAX);
|
||||
dest_matrix = new wxComboBox(this, -1, "", wxDefaultPosition, wxDefaultSize,
|
||||
to_wx(MatrixNames()), wxCB_READONLY);
|
||||
|
||||
source_x->SetValidator(wxGenericValidator(&settings.source_x));
|
||||
source_y->SetValidator(wxGenericValidator(&settings.source_y));
|
||||
source_matrix->SetValidator(MakeEnumBinder(&settings.source_matrix));
|
||||
dest_x->SetValidator(wxGenericValidator(&settings.dest_x));
|
||||
dest_y->SetValidator(wxGenericValidator(&settings.dest_y));
|
||||
dest_matrix->SetValidator(MakeEnumBinder(&settings.dest_matrix));
|
||||
|
||||
from_video = new wxButton(this, -1, _("From &video"));
|
||||
from_video->Enable(false);
|
||||
|
@ -108,25 +121,38 @@ DialogResample::DialogResample(agi::Context *c, ResampleSettings &settings)
|
|||
auto margin_box = new wxStaticBoxSizer(wxVERTICAL, this, _("Margin offset"));
|
||||
margin_box->Add(margin_sizer, wxSizerFlags(1).Expand().Border(wxBOTTOM));
|
||||
|
||||
auto source_res_sizer = new wxStaticBoxSizer(wxHORIZONTAL, this, _("Source Resolution"));
|
||||
auto source_res_sizer = new wxBoxSizer(wxHORIZONTAL);
|
||||
source_res_sizer->Add(source_x, wxSizerFlags(1).Border(wxRIGHT).Align(wxALIGN_CENTER_VERTICAL));
|
||||
source_res_sizer->Add(new wxStaticText(this, -1, _("x")), wxSizerFlags().Center().Border(wxRIGHT));
|
||||
source_res_sizer->Add(source_y, wxSizerFlags(1).Border(wxRIGHT).Align(wxALIGN_CENTER_VERTICAL));
|
||||
source_res_sizer->Add(from_script, wxSizerFlags(1));
|
||||
|
||||
auto source_matrix_sizer = new wxBoxSizer(wxHORIZONTAL);
|
||||
source_matrix_sizer->Add(new wxStaticText(this, -1, _("YCbCr Matrix:")), wxSizerFlags().Border(wxRIGHT).Center());
|
||||
source_matrix_sizer->Add(source_matrix, wxSizerFlags(1).Center().Right());
|
||||
|
||||
auto source_res_box = new wxStaticBoxSizer(wxVERTICAL, this, _("Source Resolution"));
|
||||
source_res_box->Add(source_res_sizer, wxSizerFlags(1).Expand().Border(wxBOTTOM));
|
||||
source_res_box->Add(source_matrix_sizer, wxSizerFlags(1).Expand());
|
||||
|
||||
auto dest_res_sizer = new wxBoxSizer(wxHORIZONTAL);
|
||||
dest_res_sizer->Add(dest_x, wxSizerFlags(1).Border(wxRIGHT).Align(wxALIGN_CENTER_VERTICAL));
|
||||
dest_res_sizer->Add(new wxStaticText(this, -1, _("x")), wxSizerFlags().Center().Border(wxRIGHT));
|
||||
dest_res_sizer->Add(dest_y, wxSizerFlags(1).Border(wxRIGHT).Align(wxALIGN_CENTER_VERTICAL));
|
||||
dest_res_sizer->Add(from_video, wxSizerFlags(1));
|
||||
|
||||
auto dest_matrix_sizer = new wxBoxSizer(wxHORIZONTAL);
|
||||
dest_matrix_sizer->Add(new wxStaticText(this, -1, _("YCbCr Matrix:")), wxSizerFlags().Border(wxRIGHT).Center());
|
||||
dest_matrix_sizer->Add(dest_matrix, wxSizerFlags(1).Center().Right());
|
||||
|
||||
auto dest_res_box = new wxStaticBoxSizer(wxVERTICAL, this, _("Destination Resolution"));
|
||||
dest_res_box->Add(dest_res_sizer, wxSizerFlags(1).Expand().Border(wxBOTTOM));
|
||||
dest_res_box->Add(dest_matrix_sizer, wxSizerFlags(1).Expand());
|
||||
|
||||
auto main_sizer = new wxBoxSizer(wxVERTICAL);
|
||||
main_sizer->Add(source_res_sizer, wxSizerFlags(0).Expand().Border());
|
||||
main_sizer->Add(dest_res_box, wxSizerFlags(0).Expand().Border());
|
||||
main_sizer->Add(ar_mode, wxSizerFlags(0).Expand().Border());
|
||||
main_sizer->Add(source_res_box, wxSizerFlags().Expand().Border());
|
||||
main_sizer->Add(dest_res_box, wxSizerFlags().Expand().Border());
|
||||
main_sizer->Add(ar_mode, wxSizerFlags().Expand().Border());
|
||||
main_sizer->Add(margin_box, wxSizerFlags(1).Expand().Border());
|
||||
main_sizer->Add(CreateStdDialogButtonSizer(wxOK | wxCANCEL | wxHELP), wxSizerFlags().Expand().Border(wxALL & ~wxTOP));
|
||||
SetSizerAndFit(main_sizer);
|
||||
|
@ -150,11 +176,13 @@ DialogResample::DialogResample(agi::Context *c, ResampleSettings &settings)
|
|||
void DialogResample::SetDestFromVideo(wxCommandEvent &) {
|
||||
dest_x->SetValue(video_w);
|
||||
dest_y->SetValue(video_h);
|
||||
dest_matrix->SetSelection((int)video_mat);
|
||||
}
|
||||
|
||||
void DialogResample::SetSourceFromScript(wxCommandEvent&) {
|
||||
source_x->SetValue(script_w);
|
||||
source_y->SetValue(script_h);
|
||||
source_matrix->SetSelection((int)script_mat);
|
||||
}
|
||||
|
||||
void DialogResample::UpdateButtons() {
|
||||
|
|
|
@ -22,8 +22,10 @@
|
|||
namespace agi { struct Context; }
|
||||
class AssFile;
|
||||
class wxCheckBox;
|
||||
class wxComboBox;
|
||||
class wxRadioBox;
|
||||
class wxSpinCtrl;
|
||||
enum class YCbCrMatrix : int;
|
||||
struct ResampleSettings;
|
||||
|
||||
/// @class DialogResample
|
||||
|
@ -35,13 +37,17 @@ class DialogResample final : public wxDialog {
|
|||
|
||||
int script_w;
|
||||
int script_h;
|
||||
YCbCrMatrix script_mat;
|
||||
int video_w = 0;
|
||||
int video_h = 0;
|
||||
YCbCrMatrix video_mat;
|
||||
|
||||
wxSpinCtrl *source_x;
|
||||
wxSpinCtrl *source_y;
|
||||
wxSpinCtrl *dest_x;
|
||||
wxSpinCtrl *dest_y;
|
||||
wxComboBox *source_matrix;
|
||||
wxComboBox *dest_matrix;
|
||||
wxCheckBox *symmetrical;
|
||||
wxRadioBox *ar_mode;
|
||||
wxSpinCtrl *margin_ctrl[4];
|
||||
|
|
|
@ -134,9 +134,10 @@ bool UpdateVideoProperties(AssFile *file, const VideoProvider *new_provider, wxW
|
|||
// Fallthrough to prompt if the AR changed
|
||||
if (!ar_changed) {
|
||||
ResampleResolution(file, {
|
||||
{0, 0, 0, 0},
|
||||
sx, sy, vx, vy,
|
||||
ResampleARMode::Stretch
|
||||
{0, 0, 0, 0},
|
||||
sx, sy, vx, vy,
|
||||
ResampleARMode::Stretch,
|
||||
YCbCrMatrix::rgb, YCbCrMatrix::rgb
|
||||
});
|
||||
return true;
|
||||
}
|
||||
|
@ -147,9 +148,10 @@ bool UpdateVideoProperties(AssFile *file, const VideoProvider *new_provider, wxW
|
|||
OPT_SET("Video/Last Script Resolution Mismatch Choice")->SetInt(res);
|
||||
|
||||
ResampleResolution(file, {
|
||||
{0, 0, 0, 0},
|
||||
sx, sy, vx, vy,
|
||||
static_cast<ResampleARMode>(res - FIX_RESAMPLE)
|
||||
{0, 0, 0, 0},
|
||||
sx, sy, vx, vy,
|
||||
static_cast<ResampleARMode>(res - FIX_RESAMPLE),
|
||||
YCbCrMatrix::rgb, YCbCrMatrix::rgb
|
||||
});
|
||||
return true;
|
||||
}
|
||||
|
|
|
@ -61,6 +61,7 @@ public:
|
|||
/// @return A string describing the source colorspace or "None" if it is
|
||||
/// unknown or meaningless
|
||||
virtual std::string GetColorSpace() const = 0;
|
||||
virtual std::string GetRealColorSpace() const { return GetColorSpace(); }
|
||||
|
||||
/// @brief Use this to set any post-loading warnings, such as "being loaded with unreliable seeking"
|
||||
virtual std::string GetWarning() const { return ""; }
|
||||
|
|
|
@ -24,6 +24,7 @@
|
|||
#include <libaegisub/of_type_adaptor.h>
|
||||
#include <libaegisub/split.h>
|
||||
#include <libaegisub/util.h>
|
||||
#include <libaegisub/ycbcr_conv.h>
|
||||
|
||||
#include <algorithm>
|
||||
#include <boost/algorithm/string/predicate.hpp>
|
||||
|
@ -38,6 +39,30 @@ enum {
|
|||
BOTTOM = 3
|
||||
};
|
||||
|
||||
static const std::string names[] = {
|
||||
"None",
|
||||
"TV.601", "PC.601",
|
||||
"TV.709", "PC.709",
|
||||
"TV.FCC", "PC.FCC",
|
||||
"TV.240M", "PC.240M"
|
||||
};
|
||||
|
||||
YCbCrMatrix MatrixFromString(std::string const& str) {
|
||||
if (str.empty()) return YCbCrMatrix::tv_601;
|
||||
auto pos = std::find(std::begin(names), std::end(names), str);
|
||||
if (pos == std::end(names))
|
||||
return YCbCrMatrix::rgb;
|
||||
return static_cast<YCbCrMatrix>(std::distance(std::begin(names), pos));
|
||||
}
|
||||
|
||||
std::string MatrixToString(YCbCrMatrix mat) {
|
||||
return names[static_cast<int>(mat)];
|
||||
}
|
||||
|
||||
std::vector<std::string> MatrixNames() {
|
||||
return {std::begin(names), std::end(names)};
|
||||
}
|
||||
|
||||
namespace {
|
||||
std::string transform_drawing(std::string const& drawing, int shift_x, int shift_y, double scale_x, double scale_y) {
|
||||
bool is_x = true;
|
||||
|
@ -76,6 +101,8 @@ namespace {
|
|||
double rx;
|
||||
double ry;
|
||||
double ar;
|
||||
agi::ycbcr_converter conv;
|
||||
bool convert_colors;
|
||||
};
|
||||
|
||||
void resample_tags(std::string const& name, AssOverrideParameter *cur, void *ud) {
|
||||
|
@ -113,6 +140,11 @@ namespace {
|
|||
return;
|
||||
}
|
||||
|
||||
case AssParameterClass::COLOR:
|
||||
if (state->convert_colors)
|
||||
cur->Set<std::string>(state->conv.rgb_to_rgb(agi::Color{cur->Get<std::string>()}).GetAssOverrideFormatted());
|
||||
return;
|
||||
|
||||
default:
|
||||
return;
|
||||
}
|
||||
|
@ -152,8 +184,42 @@ namespace {
|
|||
style.scalex *= state->ar;
|
||||
for (int i = 0; i < 3; i++)
|
||||
style.Margin[i] = int((style.Margin[i] + state->margin[i]) * (i < 2 ? state->rx : state->ry) + 0.5);
|
||||
if (state->convert_colors) {
|
||||
style.primary = state->conv.rgb_to_rgb(style.primary);
|
||||
style.secondary = state->conv.rgb_to_rgb(style.secondary);
|
||||
style.outline = state->conv.rgb_to_rgb(style.outline);
|
||||
style.shadow = state->conv.rgb_to_rgb(style.shadow);
|
||||
}
|
||||
style.UpdateData();
|
||||
}
|
||||
|
||||
agi::ycbcr_matrix matrix(YCbCrMatrix mat) {
|
||||
switch (mat) {
|
||||
case YCbCrMatrix::rgb: return agi::ycbcr_matrix::bt601;
|
||||
case YCbCrMatrix::tv_601: case YCbCrMatrix::pc_601: return agi::ycbcr_matrix::bt601;
|
||||
case YCbCrMatrix::tv_709: case YCbCrMatrix::pc_709: return agi::ycbcr_matrix::bt709;
|
||||
case YCbCrMatrix::tv_fcc: case YCbCrMatrix::pc_fcc: return agi::ycbcr_matrix::fcc;
|
||||
case YCbCrMatrix::tv_240m: case YCbCrMatrix::pc_240m: return agi::ycbcr_matrix::smpte_240m;
|
||||
}
|
||||
throw agi::InternalError("Invalid matrix", nullptr);
|
||||
}
|
||||
|
||||
agi::ycbcr_range range(YCbCrMatrix mat) {
|
||||
switch (mat) {
|
||||
case YCbCrMatrix::rgb:
|
||||
case YCbCrMatrix::tv_601:
|
||||
case YCbCrMatrix::tv_709:
|
||||
case YCbCrMatrix::tv_fcc:
|
||||
case YCbCrMatrix::tv_240m:
|
||||
return agi::ycbcr_range::tv;
|
||||
case YCbCrMatrix::pc_601:
|
||||
case YCbCrMatrix::pc_709:
|
||||
case YCbCrMatrix::pc_fcc:
|
||||
case YCbCrMatrix::pc_240m:
|
||||
return agi::ycbcr_range::pc;
|
||||
}
|
||||
throw agi::InternalError("Invalid matrix", nullptr);
|
||||
}
|
||||
}
|
||||
|
||||
void ResampleResolution(AssFile *ass, ResampleSettings settings) {
|
||||
|
@ -191,11 +257,23 @@ void ResampleResolution(AssFile *ass, ResampleSettings settings) {
|
|||
settings.source_x += settings.margin[LEFT] + settings.margin[RIGHT];
|
||||
settings.source_y += settings.margin[TOP] + settings.margin[BOTTOM];
|
||||
|
||||
bool resample_colors =
|
||||
settings.source_matrix != settings.dest_matrix &&
|
||||
settings.source_matrix != YCbCrMatrix::rgb &&
|
||||
settings.dest_matrix != YCbCrMatrix::rgb;
|
||||
|
||||
resample_state state = {
|
||||
settings.margin,
|
||||
double(settings.dest_x) / double(settings.source_x),
|
||||
double(settings.dest_y) / double(settings.source_y),
|
||||
horizontal_stretch
|
||||
horizontal_stretch,
|
||||
agi::ycbcr_converter{
|
||||
matrix(settings.source_matrix),
|
||||
range(settings.source_matrix),
|
||||
matrix(settings.dest_matrix),
|
||||
range(settings.dest_matrix),
|
||||
},
|
||||
resample_colors
|
||||
};
|
||||
|
||||
for (auto& line : ass->Styles)
|
||||
|
@ -205,6 +283,7 @@ void ResampleResolution(AssFile *ass, ResampleSettings settings) {
|
|||
|
||||
ass->SetScriptInfo("PlayResX", std::to_string(settings.dest_x));
|
||||
ass->SetScriptInfo("PlayResY", std::to_string(settings.dest_y));
|
||||
ass->SetScriptInfo("YCbCr Matrix", MatrixToString(settings.dest_matrix));
|
||||
|
||||
ass->Commit(_("resolution resampling"), AssFile::COMMIT_SCRIPTINFO | AssFile::COMMIT_DIAG_FULL);
|
||||
}
|
||||
|
|
|
@ -14,6 +14,9 @@
|
|||
//
|
||||
// Aegisub Project http://www.aegisub.org/
|
||||
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
class AssFile;
|
||||
|
||||
enum class ResampleARMode {
|
||||
|
@ -23,6 +26,22 @@ enum class ResampleARMode {
|
|||
Manual
|
||||
};
|
||||
|
||||
enum class YCbCrMatrix : int {
|
||||
rgb,
|
||||
tv_601,
|
||||
pc_601,
|
||||
tv_709,
|
||||
pc_709,
|
||||
tv_fcc,
|
||||
pc_fcc,
|
||||
tv_240m,
|
||||
pc_240m
|
||||
};
|
||||
|
||||
YCbCrMatrix MatrixFromString(std::string const& str);
|
||||
std::string MatrixToString(YCbCrMatrix mat);
|
||||
std::vector<std::string> MatrixNames();
|
||||
|
||||
/// Configuration parameters for a resample
|
||||
struct ResampleSettings {
|
||||
int margin[4]; ///< Amount to add to each margin
|
||||
|
@ -31,6 +50,8 @@ struct ResampleSettings {
|
|||
int dest_x; ///< New X resolution
|
||||
int dest_y; ///< New Y resolution
|
||||
ResampleARMode ar_mode; ///< What to do if the old AR and new AR don't match
|
||||
YCbCrMatrix source_matrix;
|
||||
YCbCrMatrix dest_matrix;
|
||||
};
|
||||
|
||||
/// Resample the subtitles in the project
|
||||
|
|
|
@ -79,7 +79,9 @@ class EnumBinder final : public wxValidator {
|
|||
bool Validate(wxWindow *) override { return true; }
|
||||
|
||||
bool TransferFromWindow() override {
|
||||
if (wxRadioBox *rb = dynamic_cast<wxRadioBox*>(GetWindow()))
|
||||
if (auto rb = dynamic_cast<wxRadioBox*>(GetWindow()))
|
||||
*value = static_cast<T>(rb->GetSelection());
|
||||
else if (auto rb = dynamic_cast<wxComboBox*>(GetWindow()))
|
||||
*value = static_cast<T>(rb->GetSelection());
|
||||
else
|
||||
throw agi::InternalError("Control type not supported by EnumBinder", nullptr);
|
||||
|
@ -87,8 +89,10 @@ class EnumBinder final : public wxValidator {
|
|||
}
|
||||
|
||||
bool TransferToWindow() override {
|
||||
if (wxRadioBox *rb = dynamic_cast<wxRadioBox*>(GetWindow()))
|
||||
if (auto rb = dynamic_cast<wxRadioBox*>(GetWindow()))
|
||||
rb->SetSelection(static_cast<int>(*value));
|
||||
else if (auto cb = dynamic_cast<wxComboBox*>(GetWindow()))
|
||||
cb->SetSelection(static_cast<int>(*value));
|
||||
else
|
||||
throw agi::InternalError("Control type not supported by EnumBinder", nullptr);
|
||||
return true;
|
||||
|
|
|
@ -65,6 +65,7 @@ class AvisynthVideoProvider: public VideoProvider {
|
|||
std::vector<int> keyframes;
|
||||
std::string warning;
|
||||
std::string colorspace;
|
||||
std::string real_colorspace;
|
||||
|
||||
PClip RGB32Video;
|
||||
VideoInfo vi;
|
||||
|
@ -85,6 +86,7 @@ public:
|
|||
std::string GetWarning() const override { return warning; }
|
||||
std::string GetDecoderName() const override { return decoder_name; }
|
||||
std::string GetColorSpace() const override { return colorspace; }
|
||||
std::string GetRealColorSpace() const override { return real_colorspace; }
|
||||
};
|
||||
|
||||
AvisynthVideoProvider::AvisynthVideoProvider(agi::fs::path const& filename, std::string const& colormatrix) {
|
||||
|
@ -176,22 +178,24 @@ file_exit:
|
|||
throw VideoNotSupported("No usable video found");
|
||||
|
||||
vi = script.AsClip()->GetVideoInfo();
|
||||
if (!vi.IsRGB()) {
|
||||
if (vi.IsRGB())
|
||||
real_colorspace = colorspace = "None";
|
||||
else {
|
||||
/// @todo maybe read ColorMatrix hints for d2v files?
|
||||
AVSValue args[2] = { script, "Rec601" };
|
||||
bool force_bt601 = OPT_GET("Video/Force BT.601")->GetBool() || colormatrix == "TV.601";
|
||||
bool bt709 = vi.width > 1024 || vi.height >= 600;
|
||||
if (bt709 && (!force_bt601 || colormatrix == "TV.709")) {
|
||||
args[1] = "Rec709";
|
||||
colorspace = "TV.709";
|
||||
real_colorspace = colorspace = "TV.709";
|
||||
}
|
||||
else
|
||||
else {
|
||||
colorspace = "TV.601";
|
||||
real_colorspace = bt709 ? "TV.709" : "TV.601";
|
||||
}
|
||||
const char *argnames[2] = { 0, "matrix" };
|
||||
script = avs.GetEnv()->Invoke("ConvertToRGB32", AVSValue(args, 2), argnames);
|
||||
}
|
||||
else
|
||||
colorspace = "None";
|
||||
|
||||
RGB32Video = avs.GetEnv()->Invoke("Cache", script).AsClip();
|
||||
vi = RGB32Video->GetVideoInfo();
|
||||
|
|
|
@ -68,6 +68,7 @@ public:
|
|||
std::string GetWarning() const override { return master->GetWarning(); }
|
||||
std::string GetDecoderName() const override { return master->GetDecoderName(); }
|
||||
std::string GetColorSpace() const override { return master->GetColorSpace(); }
|
||||
std::string GetRealColorSpace() const override { return master->GetRealColorSpace(); }
|
||||
};
|
||||
|
||||
std::shared_ptr<VideoFrame> VideoProviderCache::GetFrame(int n) {
|
||||
|
|
|
@ -62,6 +62,7 @@ class FFmpegSourceVideoProvider final : public VideoProvider, FFmpegSourceProvid
|
|||
std::vector<int> KeyFramesList; ///< list of keyframes
|
||||
agi::vfr::Framerate Timecodes; ///< vfr object
|
||||
std::string ColorSpace; ///< Colorspace name
|
||||
std::string RealColorSpace; ///< Colorspace name
|
||||
|
||||
char FFMSErrMsg[1024]; ///< FFMS error message
|
||||
FFMS_ErrorInfo ErrInfo; ///< FFMS error codes/messages
|
||||
|
@ -79,6 +80,7 @@ public:
|
|||
double GetDAR() const override { return DAR; }
|
||||
agi::vfr::Framerate GetFPS() const override { return Timecodes; }
|
||||
std::string GetColorSpace() const override { return ColorSpace; }
|
||||
std::string GetRealColorSpace() const override { return RealColorSpace; }
|
||||
std::vector<int> GetKeyFrames() const override { return KeyFramesList; };
|
||||
std::string GetDecoderName() const override { return "FFmpegSource"; }
|
||||
bool WantsCaching() const override { return true; }
|
||||
|
@ -91,7 +93,6 @@ std::string colormatrix_description(int cs, int cr) {
|
|||
switch (cs) {
|
||||
case FFMS_CS_RGB:
|
||||
return "None";
|
||||
break;
|
||||
case FFMS_CS_BT709:
|
||||
return str + ".709";
|
||||
case FFMS_CS_FCC:
|
||||
|
@ -227,7 +228,7 @@ void FFmpegSourceVideoProvider::LoadVideo(agi::fs::path const& filename, std::st
|
|||
auto CS = TempFrame->ColorSpace;
|
||||
if (CS == FFMS_CS_UNSPECIFIED)
|
||||
CS = Width > 1024 || Height >= 600 ? FFMS_CS_BT709 : FFMS_CS_BT470BG;
|
||||
ColorSpace = colormatrix_description(CS, TempFrame->ColorRange);
|
||||
RealColorSpace = ColorSpace = colormatrix_description(CS, TempFrame->ColorRange);
|
||||
|
||||
#if FFMS_VERSION >= ((2 << 24) | (17 << 16) | (1 << 8) | 0)
|
||||
if (CS != FFMS_CS_RGB && CS != FFMS_CS_BT470BG && ColorSpace != colormatrix && (colormatrix == "TV.601" || OPT_GET("Video/Force BT.601")->GetBool())) {
|
||||
|
|
Loading…
Reference in New Issue