footage: allow overriding YCbCr range

Fixes #1354
This commit is contained in:
itsmattkc
2022-08-08 12:49:50 -07:00
parent a3d6ecc4fd
commit 1ac205413c
23 changed files with 150 additions and 111 deletions
+7 -9
View File
@@ -93,7 +93,7 @@ bool Decoder::Open(const CodecStream &stream)
}
}
TexturePtr Decoder::RetrieveVideo(Renderer *renderer, const rational &timecode, const RetrieveVideoParams &divider, CancelAtom *cancelled)
TexturePtr Decoder::RetrieveVideo(const RetrieveVideoParams &p)
{
QMutexLocker locker(&mutex_);
@@ -109,16 +109,16 @@ TexturePtr Decoder::RetrieveVideo(Renderer *renderer, const rational &timecode,
return nullptr;
}
if (cancelled && cancelled->IsCancelled()) {
if (p.cancelled && p.cancelled->IsCancelled()) {
return nullptr;
}
if (cached_texture_ && cached_time_ == timecode) {
if (cached_texture_ && cached_time_ == p.time) {
return cached_texture_;
}
cached_texture_ = RetrieveVideoInternal(renderer, timecode, divider, cancelled);
cached_time_ = timecode;
cached_texture_ = RetrieveVideoInternal(p);
cached_time_ = p.time;
return cached_texture_;
}
@@ -280,11 +280,9 @@ int64_t Decoder::GetImageSequenceIndex(const QString &filename)
return number_only.toLongLong();
}
TexturePtr Decoder::RetrieveVideoInternal(Renderer *renderer, const rational &timecode, const RetrieveVideoParams &divider, CancelAtom *cancelled)
TexturePtr Decoder::RetrieveVideoInternal(const RetrieveVideoParams &p)
{
Q_UNUSED(timecode)
Q_UNUSED(divider)
Q_UNUSED(cancelled)
Q_UNUSED(p)
return nullptr;
}
+8 -25
View File
@@ -164,29 +164,12 @@ public:
struct RetrieveVideoParams
{
RetrieveVideoParams()
{
divider = 1;
maximum_format = VideoParams::kFormatInvalid;
}
int divider;
VideoParams::Format maximum_format;
void reset()
{
*this = RetrieveVideoParams();
}
bool operator==(const RetrieveVideoParams& rhs) const
{
return divider == rhs.divider && maximum_format == rhs.maximum_format;
}
bool operator!=(const RetrieveVideoParams& rhs) const
{
return !(*this == rhs);
}
Renderer *renderer = nullptr;
rational time;
int divider = 1;
VideoParams::Format maximum_format = VideoParams::kFormatInvalid;
CancelAtom *cancelled = nullptr;
VideoParams::ColorRange force_range = VideoParams::kColorRangeDefault;
};
/**
@@ -199,7 +182,7 @@ public:
*
* This function is thread safe and can only run while the decoder is open. \see Open()
*/
TexturePtr RetrieveVideo(Renderer *renderer, const rational& timecode, const RetrieveVideoParams& params, CancelAtom *cancelled = nullptr);
TexturePtr RetrieveVideo(const RetrieveVideoParams& p);
enum RetrieveAudioStatus {
kInvalid = -1,
@@ -294,7 +277,7 @@ protected:
* Sub-classes must override this function IF they support video. Function is already mutexed
* so sub-classes don't need to worry about thread safety.
*/
virtual TexturePtr RetrieveVideoInternal(Renderer *renderer, const rational& timecode, const RetrieveVideoParams& params, CancelAtom *cancelled);
virtual TexturePtr RetrieveVideoInternal(const RetrieveVideoParams& p);
virtual bool ConformAudioInternal(const QVector<QString>& filenames, const AudioParams &params, CancelAtom *cancelled);
-1
View File
@@ -90,7 +90,6 @@ EncodingParams::EncodingParams() :
video_buffer_size_(0),
video_threads_(0),
video_is_image_sequence_(false),
video_color_range_(kYUVDefault),
audio_enabled_(false),
audio_bit_rate_(0),
subtitles_enabled_(false),
-11
View File
@@ -43,14 +43,6 @@ using EncoderPtr = std::shared_ptr<Encoder>;
class EncodingParams {
public:
enum YUVRange
{
kYUVMPEG16_235,
kYUVJPEG0_255,
kYUVDefault = kYUVMPEG16_235
};
EncodingParams();
void SetFilename(const QString& filename) { filename_ = filename; }
@@ -75,7 +67,6 @@ public:
void set_video_threads(const int& threads) { video_threads_ = threads; }
void set_video_pix_fmt(const QString& s) { video_pix_fmt_ = s; }
void set_video_is_image_sequence(bool s) { video_is_image_sequence_ = s; }
void set_video_color_range(YUVRange r) { video_color_range_ = r; }
void set_color_transform(const ColorTransform& color_transform) { color_transform_ = color_transform; }
const QString& filename() const { return filename_; }
@@ -91,7 +82,6 @@ public:
const int& video_threads() const { return video_threads_; }
const QString& video_pix_fmt() const { return video_pix_fmt_; }
bool video_is_image_sequence() const { return video_is_image_sequence_; }
YUVRange video_color_range() const { return video_color_range_; }
const ColorTransform& color_transform() const { return color_transform_; }
bool audio_enabled() const { return audio_enabled_; }
@@ -126,7 +116,6 @@ private:
int video_threads_;
QString video_pix_fmt_;
bool video_is_image_sequence_;
YUVRange video_color_range_;
ColorTransform color_transform_;
bool audio_enabled_;
+27 -30
View File
@@ -141,28 +141,32 @@ bool FFmpegDecoder::OpenInternal()
return output_frame;
}*/
TexturePtr FFmpegDecoder::RetrieveVideoInternal(Renderer *renderer, const rational &timecode, const RetrieveVideoParams &params, CancelAtom *cancelled)
TexturePtr FFmpegDecoder::RetrieveVideoInternal(const RetrieveVideoParams &p)
{
if (AVFramePtr f = RetrieveFrame(timecode, cancelled)) {
if (cancelled && cancelled->IsCancelled()) {
if (AVFramePtr f = RetrieveFrame(p.time, p.cancelled)) {
if (p.cancelled && p.cancelled->IsCancelled()) {
return nullptr;
}
if (InitScaler(f.get(), params)) {
int &src_fmt = f.get()->format;
src_fmt = FFmpegUtils::ConvertJPEGSpaceToRegularSpace(static_cast<AVPixelFormat>(src_fmt));
f->color_range = p.force_range == VideoParams::kColorRangeFull ? AVCOL_RANGE_JPEG : AVCOL_RANGE_MPEG;
if (InitScaler(f.get(), p)) {
VideoParams vp(instance_.avstream()->codecpar->width,
instance_.avstream()->codecpar->height,
native_output_pix_fmt_,
native_channel_count_,
av_guess_sample_aspect_ratio(instance_.fmt_ctx(), instance_.avstream(), nullptr),
VideoParams::kInterlaceNone,
params.divider);
p.divider);
TexturePtr tex = nullptr;
const bool hwscale = true;
const bool hwscale = false;
// Attempt to use GLSL shader for faster YUV to RGB conversion
if (hwscale) {
AVPixelFormat src_fmt = AVPixelFormat(f.get()->format);
if (src_fmt == AV_PIX_FMT_YUV420P
|| src_fmt == AV_PIX_FMT_YUV422P
|| src_fmt == AV_PIX_FMT_YUV444P
@@ -171,13 +175,10 @@ TexturePtr FFmpegDecoder::RetrieveVideoInternal(Renderer *renderer, const ration
|| src_fmt == AV_PIX_FMT_YUV444P10LE
|| src_fmt == AV_PIX_FMT_YUV420P12LE
|| src_fmt == AV_PIX_FMT_YUV422P12LE
|| src_fmt == AV_PIX_FMT_YUV444P12LE
|| src_fmt == AV_PIX_FMT_YUVJ420P
|| src_fmt == AV_PIX_FMT_YUVJ422P
|| src_fmt == AV_PIX_FMT_YUVJ444P) {
|| src_fmt == AV_PIX_FMT_YUV444P12LE) {
if (Yuv2RgbShader.isNull()) {
// Compile shader
Yuv2RgbShader = renderer->CreateNativeShader(ShaderCode(FileFunctions::ReadFileAsString(QStringLiteral(":/shaders/yuv2rgb.frag"))));
Yuv2RgbShader = p.renderer->CreateNativeShader(ShaderCode(FileFunctions::ReadFileAsString(QStringLiteral(":/shaders/yuv2rgb.frag"))));
}
if (!Yuv2RgbShader.isNull()) {
@@ -187,9 +188,6 @@ TexturePtr FFmpegDecoder::RetrieveVideoInternal(Renderer *renderer, const ration
case AV_PIX_FMT_YUV420P:
case AV_PIX_FMT_YUV422P:
case AV_PIX_FMT_YUV444P:
case AV_PIX_FMT_YUVJ420P:
case AV_PIX_FMT_YUVJ422P:
case AV_PIX_FMT_YUVJ444P:
default:
px_size = 1;
bits_per_pixel = 8;
@@ -208,20 +206,14 @@ TexturePtr FFmpegDecoder::RetrieveVideoInternal(Renderer *renderer, const ration
break;
}
bool full_range = src_fmt == AV_PIX_FMT_YUVJ420P
|| src_fmt == AV_PIX_FMT_YUVJ422P
|| src_fmt == AV_PIX_FMT_YUVJ444P;
VideoParams plane_params = vp;
plane_params.set_channel_count(1);
plane_params.set_divider(1);
plane_params.set_format(native_internal_pix_fmt_);
TexturePtr y_plane = renderer->CreateTexture(plane_params, f->data[0], f->linesize[0] / px_size);
TexturePtr y_plane = p.renderer->CreateTexture(plane_params, f->data[0], f->linesize[0] / px_size);
if (src_fmt == AV_PIX_FMT_YUV420P
|| src_fmt == AV_PIX_FMT_YUV422P
|| src_fmt == AV_PIX_FMT_YUVJ420P
|| src_fmt == AV_PIX_FMT_YUVJ422P
|| src_fmt == AV_PIX_FMT_YUV420P10LE
|| src_fmt == AV_PIX_FMT_YUV422P10LE
|| src_fmt == AV_PIX_FMT_YUV420P12LE
@@ -230,21 +222,20 @@ TexturePtr FFmpegDecoder::RetrieveVideoInternal(Renderer *renderer, const ration
}
if (src_fmt == AV_PIX_FMT_YUV420P
|| src_fmt == AV_PIX_FMT_YUVJ420P
|| src_fmt == AV_PIX_FMT_YUV420P10LE
|| src_fmt == AV_PIX_FMT_YUV420P12LE) {
plane_params.set_height(plane_params.height()/2);
}
TexturePtr u_plane = renderer->CreateTexture(plane_params, f->data[1], f->linesize[1] / px_size);
TexturePtr v_plane = renderer->CreateTexture(plane_params, f->data[2], f->linesize[2] / px_size);
TexturePtr u_plane = p.renderer->CreateTexture(plane_params, f->data[1], f->linesize[1] / px_size);
TexturePtr v_plane = p.renderer->CreateTexture(plane_params, f->data[2], f->linesize[2] / px_size);
ShaderJob job;
job.Insert(QStringLiteral("y_channel"), NodeValue(NodeValue::kTexture, QVariant::fromValue(y_plane)));
job.Insert(QStringLiteral("u_channel"), NodeValue(NodeValue::kTexture, QVariant::fromValue(u_plane)));
job.Insert(QStringLiteral("v_channel"), NodeValue(NodeValue::kTexture, QVariant::fromValue(v_plane)));
job.Insert(QStringLiteral("bits_per_pixel"), NodeValue(NodeValue::kInt, bits_per_pixel));
job.Insert(QStringLiteral("full_range"), NodeValue(NodeValue::kBoolean, full_range));
job.Insert(QStringLiteral("full_range"), NodeValue(NodeValue::kBoolean, f->color_range == AVCOL_RANGE_JPEG));
const int *yuv_coeffs = sws_getCoefficients(FFmpegUtils::GetSwsColorspaceFromAVColorSpace(f.get()->colorspace));
job.Insert(QStringLiteral("yuv_crv"), NodeValue(NodeValue::kInt, yuv_coeffs[0]));
@@ -252,8 +243,8 @@ TexturePtr FFmpegDecoder::RetrieveVideoInternal(Renderer *renderer, const ration
job.Insert(QStringLiteral("yuv_cgv"), NodeValue(NodeValue::kInt, yuv_coeffs[3]));
job.Insert(QStringLiteral("yuv_cbu"), NodeValue(NodeValue::kInt, yuv_coeffs[1]));
tex = renderer->CreateTexture(vp);
renderer->BlitToTexture(Yuv2RgbShader, job, tex.get(), false);
tex = p.renderer->CreateTexture(vp);
p.renderer->BlitToTexture(Yuv2RgbShader, job, tex.get(), false);
}
}
}
@@ -261,6 +252,7 @@ TexturePtr FFmpegDecoder::RetrieveVideoInternal(Renderer *renderer, const ration
if (!tex) {
// Fallback to software pixel format conversion
int r;
r = av_buffersrc_add_frame_flags(buffersrc_ctx_, f.get(), AV_BUFFERSRC_FLAG_KEEP_REF);
if (r < 0) {
return nullptr;
@@ -270,7 +262,7 @@ TexturePtr FFmpegDecoder::RetrieveVideoInternal(Renderer *renderer, const ration
return nullptr;
}
tex = renderer->CreateTexture(vp, working_frame_->data[0], working_frame_->linesize[0] / vp.GetBytesPerPixel());
tex = p.renderer->CreateTexture(vp, working_frame_->data[0], working_frame_->linesize[0] / vp.GetBytesPerPixel());
av_frame_unref(working_frame_);
}
@@ -435,6 +427,7 @@ FootageDescription FFmpegDecoder::Probe(const QString &filename, CancelAtom *can
stream.set_start_time(avstream->start_time);
stream.set_time_base(avstream->time_base);
stream.set_duration(avstream->duration);
stream.set_color_range(avstream->codecpar->color_range == AVCOL_RANGE_JPEG ? VideoParams::kColorRangeFull : VideoParams::kColorRangeLimited);
// Defaults to false, requires user intervention if incorrect
stream.set_premultiplied_alpha(false);
@@ -900,7 +893,11 @@ AVFramePtr FFmpegDecoder::RetrieveFrame(const rational& time, CancelAtom *cancel
bool FFmpegDecoder::InitScaler(AVFrame *input, const RetrieveVideoParams& params)
{
if (params == filter_params_ && filter_graph_ && input_fmt_ == input->format) {
if (params.divider == filter_params_.divider
&& params.force_range == filter_params_.force_range
&& params.maximum_format == filter_params_.maximum_format
&& filter_graph_
&& input_fmt_ == input->format) {
// We have an appropriate filter for these parameters, just return true
return true;
}
+1 -1
View File
@@ -62,7 +62,7 @@ public:
protected:
virtual bool OpenInternal() override;
virtual TexturePtr RetrieveVideoInternal(Renderer *renderer, const rational& timecode, const RetrieveVideoParams& params, CancelAtom *cancelled) override;
virtual TexturePtr RetrieveVideoInternal(const RetrieveVideoParams& p) override;
virtual bool ConformAudioInternal(const QVector<QString>& filenames, const AudioParams &params, CancelAtom *cancelled) override;
virtual void CloseInternal() override;
+7 -2
View File
@@ -57,6 +57,11 @@ QStringList FFmpegEncoder::GetPixelFormatsForCodec(ExportCodec::Codec c) const
if (codec_info) {
for (int i=0; codec_info->pix_fmts[i]!=-1; i++) {
if (FFmpegUtils::ConvertJPEGSpaceToRegularSpace(codec_info->pix_fmts[i]) != codec_info->pix_fmts[i]) {
// This is a deprecated "JPEG" space, skip it
continue;
}
const char* pix_fmt_name = av_get_pix_fmt_name(codec_info->pix_fmts[i]);
pix_fmts.append(pix_fmt_name);
}
@@ -172,7 +177,7 @@ bool FFmpegEncoder::Open()
AVFilterContext* range_filter;
snprintf(filter_args, FILTER_ARG_SZ, "in_range=full:out_range=%s",
params().video_color_range() == EncodingParams::kYUVJPEG0_255 ? "full" : "limited");
params().video_params().color_range() == VideoParams::kColorRangeFull ? "full" : "limited");
avfilter_graph_create_filter(&range_filter, avfilter_get_by_name("scale"), "range", filter_args, nullptr, video_scale_ctx_);
@@ -610,7 +615,7 @@ bool FFmpegEncoder::InitializeStream(AVMediaType type, AVStream** stream_ptr, AV
codec_ctx->time_base = params().video_params().frame_rate_as_time_base().toAVRational();
codec_ctx->framerate = params().video_params().frame_rate().toAVRational();
codec_ctx->pix_fmt = av_get_pix_fmt(params().video_pix_fmt().toUtf8());
codec_ctx->color_range = params().video_color_range() == EncodingParams::kYUVJPEG0_255 ? AVCOL_RANGE_JPEG : AVCOL_RANGE_MPEG;
codec_ctx->color_range = params().video_params().color_range() == VideoParams::kColorRangeFull ? AVCOL_RANGE_JPEG : AVCOL_RANGE_MPEG;
if (params().video_params().interlacing() != VideoParams::kInterlaceNone) {
// FIXME: I actually don't know what these flags do, the documentation helpfully doesn't
+7 -9
View File
@@ -119,22 +119,20 @@ bool OIIODecoder::OpenInternal()
return OpenImageHandler(stream().filename(), stream().stream());
}
TexturePtr OIIODecoder::RetrieveVideoInternal(Renderer *renderer, const rational &timecode, const RetrieveVideoParams &params, CancelAtom *cancelled)
TexturePtr OIIODecoder::RetrieveVideoInternal(const RetrieveVideoParams &p)
{
Q_UNUSED(timecode)
Q_UNUSED(cancelled)
VideoParams vp = GetVideoParamsFromImageSpec(image_->spec());
vp.set_divider(params.divider);
vp.set_divider(p.divider);
if (!buffer_.is_allocated() || last_params_ != params) {
last_params_ = params;
if (!buffer_.is_allocated()
|| last_params_.divider != p.divider) {
last_params_ = p;
buffer_.destroy();
buffer_.set_video_params(vp);
buffer_.allocate();
if (params.divider == 1) {
if (p.divider == 1) {
// Just upload straight to the buffer
image_->read_image(oiio_pix_fmt_, buffer_.data(), OIIO::AutoStride, buffer_.linesize_bytes());
} else {
@@ -156,7 +154,7 @@ TexturePtr OIIODecoder::RetrieveVideoInternal(Renderer *renderer, const rational
}
}
return renderer->CreateTexture(vp, buffer_.data(), buffer_.linesize_pixels());
return p.renderer->CreateTexture(vp, buffer_.data(), buffer_.linesize_pixels());
}
void OIIODecoder::CloseInternal()
+1 -1
View File
@@ -44,7 +44,7 @@ public:
protected:
virtual bool OpenInternal() override;
virtual TexturePtr RetrieveVideoInternal(Renderer *renderer, const rational& timecode, const RetrieveVideoParams& params, CancelAtom *cancelled) override;
virtual TexturePtr RetrieveVideoInternal(const RetrieveVideoParams& p) override;
virtual void CloseInternal() override;
private:
+15
View File
@@ -133,6 +133,21 @@ int FFmpegUtils::GetSwsColorspaceFromAVColorSpace(AVColorSpace cs)
return SWS_CS_DEFAULT;
}
AVPixelFormat FFmpegUtils::ConvertJPEGSpaceToRegularSpace(AVPixelFormat f)
{
switch (f) {
case AV_PIX_FMT_YUVJ420P: return AV_PIX_FMT_YUV420P;
case AV_PIX_FMT_YUVJ422P: return AV_PIX_FMT_YUV422P;
case AV_PIX_FMT_YUVJ444P: return AV_PIX_FMT_YUV444P;
case AV_PIX_FMT_YUVJ440P: return AV_PIX_FMT_YUV440P;
case AV_PIX_FMT_YUVJ411P: return AV_PIX_FMT_YUV411P;
default:
break;
}
return f;
}
AVPixelFormat FFmpegUtils::GetFFmpegPixelFormat(const VideoParams::Format &pix_fmt, int channel_layout)
{
if (channel_layout == VideoParams::kRGBChannelCount) {
+9
View File
@@ -66,6 +66,15 @@ public:
* convenience function to do this conversion for us? Who knows, but here we are.
*/
static int GetSwsColorspaceFromAVColorSpace(AVColorSpace cs);
/**
* @brief Convert "JPEG"/full-range colorspace to its regular counterpart
*
* "JPEG "spaces are deprecated in favor of the regular space and setting `color_range`. For the
* time being, FFmpeg still uses these JPEG spaces, so for simplicity (since we *are* color_range
* aware), we use this function.
*/
static AVPixelFormat ConvertJPEGSpaceToRegularSpace(AVPixelFormat f);
};
using AVFramePtr = std::shared_ptr<AVFrame>;
+3 -1
View File
@@ -557,6 +557,9 @@ ExportParams ExportDialog::GenerateParams() const
if (video_enabled_->isChecked()) {
ExportCodec::Codec video_codec = video_tab_->GetSelectedCodec();
video_render_params.set_color_range(video_tab_->color_range());
params.EnableVideo(video_render_params, video_codec);
params.set_video_threads(video_tab_->threads());
@@ -568,7 +571,6 @@ ExportParams ExportDialog::GenerateParams() const
params.set_color_transform(video_tab_->CurrentOCIOColorSpace());
params.set_video_pix_fmt(video_tab_->pix_fmt());
params.set_video_color_range(video_tab_->yuv_range());
params.set_video_is_image_sequence(video_tab_->IsImageSequenceSet());
}
@@ -36,12 +36,12 @@ public:
pixel_format_combobox_->setCurrentText(s);
}
EncodingParams::YUVRange yuv_range() const
VideoParams::ColorRange yuv_range() const
{
return static_cast<EncodingParams::YUVRange>(yuv_color_range_combobox_->currentIndex());
return static_cast<VideoParams::ColorRange>(yuv_color_range_combobox_->currentIndex());
}
void set_yuv_range(EncodingParams::YUVRange i)
void set_yuv_range(VideoParams::ColorRange i)
{
yuv_color_range_combobox_->setCurrentIndex(i);
}
+3 -3
View File
@@ -37,7 +37,7 @@ ExportVideoTab::ExportVideoTab(ColorManager* color_manager, QWidget *parent) :
QWidget(parent),
color_manager_(color_manager),
threads_(0),
yuv_range_(EncodingParams::kYUVDefault)
color_range_(VideoParams::kColorRangeDefault)
{
QVBoxLayout* outer_layout = new QVBoxLayout(this);
@@ -212,12 +212,12 @@ void ExportVideoTab::OpenAdvancedDialog()
d.set_threads(threads_);
d.set_pix_fmt(pix_fmt_);
d.set_yuv_range(yuv_range_);
d.set_yuv_range(color_range_);
if (d.exec() == QDialog::Accepted) {
threads_ = d.threads();
pix_fmt_ = d.pix_fmt();
yuv_range_ = d.yuv_range();
color_range_ = d.yuv_range();
}
}
+3 -3
View File
@@ -138,9 +138,9 @@ public:
return pix_fmt_;
}
EncodingParams::YUVRange yuv_range() const
VideoParams::ColorRange color_range() const
{
return yuv_range_;
return color_range_;
}
public slots:
@@ -183,7 +183,7 @@ private:
int threads_;
QString pix_fmt_;
EncodingParams::YUVRange yuv_range_;
VideoParams::ColorRange color_range_;
ExportFormat::Format format_;
@@ -83,11 +83,6 @@ private:
*/
QStackedWidget* stacked_widget_;
/**
* @brief ComboBox for interlacing setting
*/
QComboBox* interlacing_box;
/**
* @brief Media name text field
*/
@@ -79,6 +79,17 @@ VideoStreamProperties::VideoStreamProperties(Footage *footage, int video_index)
video_layout->addWidget(video_color_space_, row, 1);
row++;
video_layout->addWidget(new QLabel(tr("Color Range:")), row, 0);
color_range_combo_ = new QComboBox();
color_range_combo_->addItem(tr("Limited (16-235)"), VideoParams::kColorRangeLimited);
color_range_combo_->addItem(tr("Full (0-255)"), VideoParams::kColorRangeFull);
color_range_combo_->setCurrentIndex(vp.color_range());
video_layout->addWidget(color_range_combo_, row, 1);
if (vp.channel_count() == VideoParams::kRGBAChannelCount) {
row++;
@@ -136,14 +147,16 @@ void VideoStreamProperties::Accept(MultiUndoCommand *parent)
if ((video_premultiply_alpha_ && video_premultiply_alpha_->isChecked() != vp.premultiplied_alpha())
|| set_colorspace != vp.colorspace()
|| static_cast<VideoParams::Interlacing>(video_interlace_combo_->currentIndex()) != vp.interlacing()
|| pixel_aspect_combo_->GetPixelAspectRatio() != vp.pixel_aspect_ratio()) {
|| pixel_aspect_combo_->GetPixelAspectRatio() != vp.pixel_aspect_ratio()
|| color_range_combo_->currentData().toInt() != vp.color_range()) {
parent->add_child(new VideoStreamChangeCommand(footage_,
video_index_,
video_premultiply_alpha_ ? video_premultiply_alpha_->isChecked() : vp.premultiplied_alpha(),
set_colorspace,
static_cast<VideoParams::Interlacing>(video_interlace_combo_->currentIndex()),
pixel_aspect_combo_->GetPixelAspectRatio()));
pixel_aspect_combo_->GetPixelAspectRatio(),
static_cast<VideoParams::ColorRange>(color_range_combo_->currentData().toInt())));
}
if (vp.video_type() == VideoParams::kVideoTypeImageSequence) {
@@ -181,13 +194,14 @@ VideoStreamProperties::VideoStreamChangeCommand::VideoStreamChangeCommand(Footag
bool premultiplied,
QString colorspace,
VideoParams::Interlacing interlacing,
const rational &pixel_ar) :
const rational &pixel_ar, VideoParams::ColorRange range) :
footage_(footage),
video_index_(video_index),
new_premultiplied_(premultiplied),
new_colorspace_(colorspace),
new_interlacing_(interlacing),
new_pixel_ar_(pixel_ar)
new_pixel_ar_(pixel_ar),
new_range_(range)
{
}
@@ -204,11 +218,13 @@ void VideoStreamProperties::VideoStreamChangeCommand::redo()
old_colorspace_ = vp.colorspace();
old_interlacing_ = vp.interlacing();
old_pixel_ar_ = vp.pixel_aspect_ratio();
old_range_ = vp.color_range();
vp.set_premultiplied_alpha(new_premultiplied_);
vp.set_colorspace(new_colorspace_);
vp.set_interlacing(new_interlacing_);
vp.set_pixel_aspect_ratio(new_pixel_ar_);
vp.set_color_range(new_range_);
footage_->SetVideoParams(vp, video_index_);
}
@@ -221,6 +237,7 @@ void VideoStreamProperties::VideoStreamChangeCommand::undo()
vp.set_colorspace(old_colorspace_);
vp.set_interlacing(old_interlacing_);
vp.set_pixel_aspect_ratio(old_pixel_ar_);
vp.set_color_range(old_range_);
footage_->SetVideoParams(vp, video_index_);
}
@@ -56,6 +56,11 @@ private:
*/
QComboBox* video_color_space_;
/**
* @brief Setting for this streams's color range
*/
QComboBox *color_range_combo_;
/**
* @brief Setting for video interlacing
*/
@@ -88,7 +93,8 @@ private:
bool premultiplied,
QString colorspace,
VideoParams::Interlacing interlacing,
const rational& pixel_ar);
const rational& pixel_ar,
VideoParams::ColorRange range);
virtual Project* GetRelevantProject() const override;
@@ -104,11 +110,13 @@ private:
QString new_colorspace_;
VideoParams::Interlacing new_interlacing_;
rational new_pixel_ar_;
VideoParams::ColorRange new_range_;
bool old_premultiplied_;
QString old_colorspace_;
VideoParams::Interlacing old_interlacing_;
rational old_pixel_ar_;
VideoParams::ColorRange old_range_;
};
+1
View File
@@ -519,6 +519,7 @@ VideoParams Footage::MergeVideoStream(const VideoParams &base, const VideoParams
merged.set_colorspace(over.colorspace());
merged.set_premultiplied_alpha(over.premultiplied_alpha());
merged.set_video_type(over.video_type());
merged.set_color_range(over.color_range());
if (merged.video_type() == VideoParams::kVideoTypeImageSequence) {
merged.set_start_time(over.start_time());
merged.set_duration(over.duration());
@@ -142,7 +142,7 @@ public:
}
private:
static constexpr unsigned kFootageMetaVersion = 4;
static constexpr unsigned kFootageMetaVersion = 5;
QString decoder_;
+8 -1
View File
@@ -475,7 +475,14 @@ void RenderProcessor::ProcessVideoFootage(TexturePtr destination, const FootageJ
VideoParams tex_params = stream.video_params();
if (tex_params.is_valid()) {
TexturePtr unmanaged_texture = decoder->RetrieveVideo(render_ctx_, (stream_data.video_type() == VideoParams::kVideoTypeVideo) ? input_time : Decoder::kAnyTimecode, p, GetCancelPointer());
TexturePtr unmanaged_texture;
p.renderer = render_ctx_;
p.time = (stream_data.video_type() == VideoParams::kVideoTypeVideo) ? input_time : Decoder::kAnyTimecode;
p.cancelled = GetCancelPointer();
p.force_range = stream_data.color_range();
unmanaged_texture = decoder->RetrieveVideo(p);
if (unmanaged_texture) {
// We convert to our rendering pixel format, since that will always be float-based which
+4
View File
@@ -270,6 +270,7 @@ void VideoParams::set_defaults_for_footage()
premultiplied_alpha_ = false;
x_ = 0;
y_ = 0;
color_range_ = kColorRangeDefault;
}
void VideoParams::calculate_square_pixel_width()
@@ -374,6 +375,8 @@ void VideoParams::Load(QXmlStreamReader *reader)
set_premultiplied_alpha(reader->readElementText().toInt());
} else if (reader->name() == QStringLiteral("colorspace")) {
set_colorspace(reader->readElementText());
} else if (reader->name() == QStringLiteral("colorrange")) {
set_color_range(static_cast<ColorRange>(reader->readElementText().toInt()));
} else {
reader->skipCurrentElement();
}
@@ -401,6 +404,7 @@ void VideoParams::Save(QXmlStreamWriter *writer) const
writer->writeTextElement(QStringLiteral("duration"), QString::number(duration_));
writer->writeTextElement(QStringLiteral("premultipliedalpha"), QString::number(premultiplied_alpha_));
writer->writeTextElement(QStringLiteral("colorspace"), colorspace_);
writer->writeTextElement(QStringLiteral("colorrange"), QString::number(color_range_));
}
}
+12
View File
@@ -66,6 +66,14 @@ public:
kVideoTypeStill,
kVideoTypeImageSequence
};
enum ColorRange
{
kColorRangeLimited, // 16_235
kColorRangeFull, // 0-255
kColorRangeDefault = kColorRangeLimited
};
VideoParams();
VideoParams(int width, int height, Format format, int nb_channels,
@@ -352,6 +360,9 @@ public:
colorspace_ = c;
}
const ColorRange &color_range() const { return color_range_; }
void set_color_range(const ColorRange &color_range) { color_range_ = color_range; }
int64_t get_time_in_timebase_units(const rational& time) const;
void Load(QXmlStreamReader* reader);
@@ -398,6 +409,7 @@ private:
QString colorspace_;
float x_;
float y_;
ColorRange color_range_;
};