diff --git a/app/codec/encoder.cpp b/app/codec/encoder.cpp index 458c71d8e..7abf5d39f 100644 --- a/app/codec/encoder.cpp +++ b/app/codec/encoder.cpp @@ -90,17 +90,13 @@ 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) { } -void EncodingParams::SetFilename(const QString &filename) -{ - filename_ = filename; -} - void EncodingParams::EnableVideo(const VideoParams &video_params, const ExportCodec::Codec &vcodec) { video_enabled_ = true; @@ -121,131 +117,6 @@ void EncodingParams::EnableSubtitles(const ExportCodec::Codec &scodec) subtitles_codec_ = scodec; } -void EncodingParams::set_video_option(const QString &key, const QString &value) -{ - video_opts_.insert(key, value); -} - -void EncodingParams::set_video_bit_rate(const int64_t &rate) -{ - video_bit_rate_ = rate; -} - -void EncodingParams::set_video_min_bit_rate(const int64_t &rate) -{ - video_min_bit_rate_ = rate; -} - -void EncodingParams::set_video_max_bit_rate(const int64_t &rate) -{ - video_max_bit_rate_ = rate; -} - -void EncodingParams::set_video_buffer_size(const int64_t &sz) -{ - video_buffer_size_ = sz; -} - -void EncodingParams::set_video_threads(const int &threads) -{ - video_threads_ = threads; -} - -void EncodingParams::set_video_pix_fmt(const QString &s) -{ - video_pix_fmt_ = s; -} - -const QString &EncodingParams::filename() const -{ - return filename_; -} - -bool EncodingParams::video_enabled() const -{ - return video_enabled_; -} - -const ExportCodec::Codec &EncodingParams::video_codec() const -{ - return video_codec_; -} - -const VideoParams &EncodingParams::video_params() const -{ - return video_params_; -} - -const QHash &EncodingParams::video_opts() const -{ - return video_opts_; -} - -const int64_t &EncodingParams::video_bit_rate() const -{ - return video_bit_rate_; -} - -const int64_t &EncodingParams::video_min_bit_rate() const -{ - return video_min_bit_rate_; -} - -const int64_t &EncodingParams::video_max_bit_rate() const -{ - return video_max_bit_rate_; -} - -const int64_t &EncodingParams::video_buffer_size() const -{ - return video_buffer_size_; -} - -const int &EncodingParams::video_threads() const -{ - return video_threads_; -} - -const QString &EncodingParams::video_pix_fmt() const -{ - return video_pix_fmt_; -} - -bool EncodingParams::audio_enabled() const -{ - return audio_enabled_; -} - -const ExportCodec::Codec &EncodingParams::audio_codec() const -{ - return audio_codec_; -} - -const AudioParams &EncodingParams::audio_params() const -{ - return audio_params_; -} - -bool EncodingParams::subtitles_enabled() const -{ - return subtitles_enabled_; -} - -ExportCodec::Codec EncodingParams::subtitles_codec() const -{ - return subtitles_codec_; -} - -const rational &EncodingParams::GetExportLength() const -{ - return export_length_; -} - -void EncodingParams::SetExportLength(const rational &export_length) -{ - export_length_ = export_length; -} - void EncodingParams::Save(QXmlStreamWriter *writer) const { writer->writeTextElement(QStringLiteral("filename"), filename_); diff --git a/app/codec/encoder.h b/app/codec/encoder.h index e1535290b..7b95fa7fb 100644 --- a/app/codec/encoder.h +++ b/app/codec/encoder.h @@ -43,62 +43,59 @@ using EncoderPtr = std::shared_ptr; class EncodingParams { public: + enum YUVRange + { + kYUVMPEG16_235, + kYUVJPEG0_255, + + kYUVDefault = kYUVMPEG16_235 + }; + EncodingParams(); - void SetFilename(const QString& filename); + void SetFilename(const QString& filename) { filename_ = filename; } void EnableVideo(const VideoParams& video_params, const ExportCodec::Codec& vcodec); void EnableAudio(const AudioParams& audio_params, const ExportCodec::Codec &acodec); void EnableSubtitles(const ExportCodec::Codec &scodec); - void set_video_option(const QString& key, const QString& value); - void set_video_bit_rate(const int64_t& rate); - void set_video_min_bit_rate(const int64_t& rate); - void set_video_max_bit_rate(const int64_t& rate); - void set_video_buffer_size(const int64_t& sz); - void set_video_threads(const int& threads); - void set_video_pix_fmt(const QString& s); - void set_video_is_image_sequence(bool s) - { - video_is_image_sequence_ = s; - } + void set_video_option(const QString& key, const QString& value) { video_opts_.insert(key, value); } + void set_video_bit_rate(const int64_t& rate) { video_bit_rate_ = rate; } + void set_video_min_bit_rate(const int64_t& rate) { video_min_bit_rate_ = rate; } + void set_video_max_bit_rate(const int64_t& rate) { video_max_bit_rate_ = rate; } + void set_video_buffer_size(const int64_t& sz) { video_buffer_size_ = sz; } + 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; } - const QString& filename() const; + const QString& filename() const { return filename_; } - bool video_enabled() const; - const ExportCodec::Codec& video_codec() const; - const VideoParams& video_params() const; - const QHash& video_opts() const; - const int64_t& video_bit_rate() const; - const int64_t& video_min_bit_rate() const; - const int64_t& video_max_bit_rate() const; - const int64_t& video_buffer_size() const; - const int& video_threads() const; - const QString& video_pix_fmt() const; - bool video_is_image_sequence() const - { - return video_is_image_sequence_; - } + bool video_enabled() const { return video_enabled_; } + const ExportCodec::Codec& video_codec() const { return video_codec_; } + const VideoParams& video_params() const { return video_params_; } + const QHash& video_opts() const { return video_opts_; } + const int64_t& video_bit_rate() const { return video_bit_rate_; } + const int64_t& video_min_bit_rate() const { return video_min_bit_rate_; } + const int64_t& video_max_bit_rate() const { return video_max_bit_rate_; } + const int64_t& video_buffer_size() const { return video_buffer_size_; } + 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_; } - bool audio_enabled() const; - const ExportCodec::Codec &audio_codec() const; - const AudioParams& audio_params() const; + bool audio_enabled() const { return audio_enabled_; } + const ExportCodec::Codec &audio_codec() const { return audio_codec_; } + const AudioParams& audio_params() const { return audio_params_; } + const int64_t& audio_bit_rate() const { return audio_bit_rate_; } - const int64_t& audio_bit_rate() const - { - return audio_bit_rate_; - } + void set_audio_bit_rate(const int64_t& b) { audio_bit_rate_ = b; } - void set_audio_bit_rate(const int64_t& b) - { - audio_bit_rate_ = b; - } + bool subtitles_enabled() const { return subtitles_enabled_; } + ExportCodec::Codec subtitles_codec() const { return subtitles_codec_; } - bool subtitles_enabled() const; - ExportCodec::Codec subtitles_codec() const; - - const rational& GetExportLength() const; - void SetExportLength(const rational& GetExportLength); + const rational& GetExportLength() const { return export_length_; } + void SetExportLength(const rational& export_length) { export_length_ = export_length; } virtual void Save(QXmlStreamWriter* writer) const; @@ -116,6 +113,7 @@ private: int video_threads_; QString video_pix_fmt_; bool video_is_image_sequence_; + YUVRange video_color_range_; bool audio_enabled_; ExportCodec::Codec audio_codec_; diff --git a/app/codec/ffmpeg/ffmpegdecoder.cpp b/app/codec/ffmpeg/ffmpegdecoder.cpp index 7469408c7..2ab14eadb 100644 --- a/app/codec/ffmpeg/ffmpegdecoder.cpp +++ b/app/codec/ffmpeg/ffmpegdecoder.cpp @@ -171,7 +171,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_YUV444P12LE + || src_fmt == AV_PIX_FMT_YUVJ420P + || src_fmt == AV_PIX_FMT_YUVJ422P + || src_fmt == AV_PIX_FMT_YUVJ444P) { if (Yuv2RgbShader.isNull()) { // Compile shader Yuv2RgbShader = renderer->CreateNativeShader(ShaderCode(FileFunctions::ReadFileAsString(QStringLiteral(":/shaders/yuv2rgb.frag")))); @@ -184,6 +187,9 @@ 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; @@ -202,6 +208,10 @@ TexturePtr FFmpegDecoder::RetrieveVideoInternal(Renderer *renderer, const ration break; } + bool jpeg_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); @@ -210,6 +220,8 @@ TexturePtr FFmpegDecoder::RetrieveVideoInternal(Renderer *renderer, const ration 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 @@ -218,6 +230,7 @@ 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); @@ -231,6 +244,7 @@ TexturePtr FFmpegDecoder::RetrieveVideoInternal(Renderer *renderer, const ration 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("jpeg_range"), NodeValue(NodeValue::kBoolean, jpeg_range)); tex = renderer->CreateTexture(vp); renderer->BlitToTexture(Yuv2RgbShader, job, tex.get(), false); diff --git a/app/codec/ffmpeg/ffmpegencoder.cpp b/app/codec/ffmpeg/ffmpegencoder.cpp index f5fc96357..03d640fc1 100644 --- a/app/codec/ffmpeg/ffmpegencoder.cpp +++ b/app/codec/ffmpeg/ffmpegencoder.cpp @@ -219,6 +219,7 @@ bool FFmpegEncoder::WriteFrame(FramePtr frame, rational time) encoded_frame->width = frame->width(); encoded_frame->height = frame->height(); encoded_frame->format = video_codec_ctx_->pix_fmt; + encoded_frame->color_range = video_codec_ctx_->color_range; // Set interlacing if (frame->video_params().interlacing() != VideoParams::kInterlaceNone) { diff --git a/app/dialog/export/export.cpp b/app/dialog/export/export.cpp index f93bb6177..8797b3caa 100644 --- a/app/dialog/export/export.cpp +++ b/app/dialog/export/export.cpp @@ -548,6 +548,7 @@ 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()); } diff --git a/app/dialog/export/exportadvancedvideodialog.cpp b/app/dialog/export/exportadvancedvideodialog.cpp index 71143b50b..57851f424 100644 --- a/app/dialog/export/exportadvancedvideodialog.cpp +++ b/app/dialog/export/exportadvancedvideodialog.cpp @@ -31,6 +31,12 @@ ExportAdvancedVideoDialog::ExportAdvancedVideoDialog(const QList &pix_f pixel_layout->addWidget(pixel_format_combobox_, row, 1); row++; + + pixel_layout->addWidget(new QLabel(tr("YUV Color Range:")), row, 0); + + yuv_color_range_combobox_ = new QComboBox(); + yuv_color_range_combobox_->addItems({tr("MPEG (16-235)"), tr("JPEG (0-255)")}); + pixel_layout->addWidget(yuv_color_range_combobox_, row, 1); } { diff --git a/app/dialog/export/exportadvancedvideodialog.h b/app/dialog/export/exportadvancedvideodialog.h index 275ae44f9..b6d17214c 100644 --- a/app/dialog/export/exportadvancedvideodialog.h +++ b/app/dialog/export/exportadvancedvideodialog.h @@ -4,6 +4,7 @@ #include #include +#include "codec/encoder.h" #include "widget/slider/integerslider.h" namespace olive { @@ -35,11 +36,23 @@ public: pixel_format_combobox_->setCurrentText(s); } + EncodingParams::YUVRange yuv_range() const + { + return static_cast(yuv_color_range_combobox_->currentIndex()); + } + + void set_yuv_range(EncodingParams::YUVRange i) + { + yuv_color_range_combobox_->setCurrentIndex(i); + } + private: IntegerSlider* thread_slider_; QComboBox* pixel_format_combobox_; + QComboBox* yuv_color_range_combobox_; + }; } diff --git a/app/dialog/export/exportvideotab.cpp b/app/dialog/export/exportvideotab.cpp index 1c493eecf..4373eb75f 100644 --- a/app/dialog/export/exportvideotab.cpp +++ b/app/dialog/export/exportvideotab.cpp @@ -36,7 +36,8 @@ namespace olive { ExportVideoTab::ExportVideoTab(ColorManager* color_manager, QWidget *parent) : QWidget(parent), color_manager_(color_manager), - threads_(0) + threads_(0), + yuv_range_(EncodingParams::kYUVDefault) { QVBoxLayout* outer_layout = new QVBoxLayout(this); @@ -211,10 +212,12 @@ void ExportVideoTab::OpenAdvancedDialog() d.set_threads(threads_); d.set_pix_fmt(pix_fmt_); + d.set_yuv_range(yuv_range_); if (d.exec() == QDialog::Accepted) { threads_ = d.threads(); pix_fmt_ = d.pix_fmt(); + yuv_range_ = d.yuv_range(); } } diff --git a/app/dialog/export/exportvideotab.h b/app/dialog/export/exportvideotab.h index c2be1aebd..0a83753ee 100644 --- a/app/dialog/export/exportvideotab.h +++ b/app/dialog/export/exportvideotab.h @@ -133,10 +133,16 @@ public: return threads_; } - const QString& pix_fmt() const { + const QString& pix_fmt() const + { return pix_fmt_; } + EncodingParams::YUVRange yuv_range() const + { + return yuv_range_; + } + public slots: void VideoCodecChanged(); @@ -177,6 +183,7 @@ private: int threads_; QString pix_fmt_; + EncodingParams::YUVRange yuv_range_; ExportFormat::Format format_; diff --git a/app/shaders/yuv2rgb.frag b/app/shaders/yuv2rgb.frag index 62c73e149..537df26e2 100644 --- a/app/shaders/yuv2rgb.frag +++ b/app/shaders/yuv2rgb.frag @@ -3,6 +3,7 @@ uniform sampler2D u_channel; uniform sampler2D v_channel; uniform int bits_per_pixel; +uniform bool jpeg_range; in vec2 ove_texcoord; out vec4 frag_color; @@ -31,5 +32,10 @@ void main() { rgba.b = yuv.r + 2.017 * yuv.g; rgba.a = 1.0; + if (jpeg_range) { + rgba.rgb *= 219.0 / 255.0; + rgba.rgb += 16.0 / 255.0; + } + frag_color = rgba; }