diff --git a/app/audio/CMakeLists.txt b/app/audio/CMakeLists.txt index b8b8e49a2..5b0976dc0 100644 --- a/app/audio/CMakeLists.txt +++ b/app/audio/CMakeLists.txt @@ -24,8 +24,6 @@ set(OLIVE_SOURCES audio/outputdeviceproxy.cpp audio/outputmanager.h audio/outputmanager.cpp - audio/sampleformat.h - audio/sampleformat.cpp audio/tempoprocessor.h audio/tempoprocessor.cpp PARENT_SCOPE diff --git a/app/audio/audiomanager.cpp b/app/audio/audiomanager.cpp index a0afa7cce..48daa0c9b 100644 --- a/app/audio/audiomanager.cpp +++ b/app/audio/audiomanager.cpp @@ -124,36 +124,8 @@ void AudioManager::SetOutputDevice(const QAudioDeviceInfo &info) format.setChannelCount(output_params_.channel_count()); format.setCodec("audio/pcm"); format.setByteOrder(QAudioFormat::LittleEndian); - - switch (output_params_.format()) { - case SampleFormat::SAMPLE_FMT_U8: - format.setSampleSize(8); - format.setSampleType(QAudioFormat::UnSignedInt); - break; - case SampleFormat::SAMPLE_FMT_S16: - format.setSampleSize(16); - format.setSampleType(QAudioFormat::SignedInt); - break; - case SampleFormat::SAMPLE_FMT_S32: - format.setSampleSize(32); - format.setSampleType(QAudioFormat::SignedInt); - break; - case SampleFormat::SAMPLE_FMT_S64: - format.setSampleSize(64); - format.setSampleType(QAudioFormat::SignedInt); - break; - case SampleFormat::SAMPLE_FMT_FLT: - format.setSampleSize(32); - format.setSampleType(QAudioFormat::Float); - break; - case SampleFormat::SAMPLE_FMT_DBL: - format.setSampleSize(64); - format.setSampleType(QAudioFormat::Float); - break; - case SampleFormat::SAMPLE_FMT_COUNT: - case SampleFormat::SAMPLE_FMT_INVALID: - abort(); - } + format.setSampleSize(output_params_.bits_per_sample()); + format.setSampleType(AudioParams::GetQtSampleType(output_params_.format())); if (info.isFormatSupported(format)) { QMetaObject::invokeMethod(output_manager_, diff --git a/app/audio/sampleformat.cpp b/app/audio/sampleformat.cpp deleted file mode 100644 index 27bbbb0a4..000000000 --- a/app/audio/sampleformat.cpp +++ /dev/null @@ -1,52 +0,0 @@ -/*** - - Olive - Non-Linear Video Editor - Copyright (C) 2019 Olive Team - - This program is free software: you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program. If not, see . - -***/ - -#include "sampleformat.h" - -#include - -OLIVE_NAMESPACE_ENTER - -const SampleFormat::Format SampleFormat::kInternalFormat = SAMPLE_FMT_FLT; - -QString SampleFormat::GetSampleFormatName(const SampleFormat::Format &f) -{ - switch (f) { - case SAMPLE_FMT_U8: - return QCoreApplication::translate("SampleFormat", "Unsigned 8-bit"); - case SAMPLE_FMT_S16: - return QCoreApplication::translate("SampleFormat", "Signed 16-bit"); - case SAMPLE_FMT_S32: - return QCoreApplication::translate("SampleFormat", "Signed 32-bit"); - case SAMPLE_FMT_S64: - return QCoreApplication::translate("SampleFormat", "Signed 64-bit"); - case SAMPLE_FMT_FLT: - return QCoreApplication::translate("SampleFormat", "32-bit Float"); - case SAMPLE_FMT_DBL: - return QCoreApplication::translate("SampleFormat", "64-bit Float"); - case SAMPLE_FMT_COUNT: - case SAMPLE_FMT_INVALID: - break; - } - - return QCoreApplication::translate("SampleFormat", "Invalid"); -} - -OLIVE_NAMESPACE_EXIT diff --git a/app/audio/tempoprocessor.cpp b/app/audio/tempoprocessor.cpp index 2deda4f33..1cb56b468 100644 --- a/app/audio/tempoprocessor.cpp +++ b/app/audio/tempoprocessor.cpp @@ -28,7 +28,7 @@ extern "C" { #include -#include "codec/ffmpeg/ffmpegcommon.h" +#include "common/ffmpegutils.h" OLIVE_NAMESPACE_ENTER @@ -75,7 +75,7 @@ bool TempoProcessor::Open(const AudioParams ¶ms, const double& speed) 1, params_.sample_rate(), params_.sample_rate(), - FFmpegCommon::GetFFmpegSampleFormat(params_.format()), + FFmpegUtils::GetFFmpegSampleFormat(params_.format()), params.channel_layout()); // Create buffer and buffersink @@ -171,7 +171,7 @@ void TempoProcessor::Push(const char *data, int length) // Allocate a buffer for the number of samples we got src_frame->sample_rate = params_.sample_rate(); - src_frame->format = FFmpegCommon::GetFFmpegSampleFormat(params_.format()); + src_frame->format = FFmpegUtils::GetFFmpegSampleFormat(params_.format()); src_frame->channel_layout = params_.channel_layout(); src_frame->nb_samples = params_.bytes_to_samples(length); src_frame->pts = timestamp_; diff --git a/app/codec/decoder.cpp b/app/codec/decoder.cpp index e8a5bf71b..9841fbf4f 100644 --- a/app/codec/decoder.cpp +++ b/app/codec/decoder.cpp @@ -24,11 +24,11 @@ #include #include -#include "codec/ffmpeg/ffmpegcommon.h" #include "codec/ffmpeg/ffmpegdecoder.h" #include "codec/oiio/oiiodecoder.h" #include "codec/waveinput.h" #include "codec/waveoutput.h" +#include "common/ffmpegutils.h" #include "common/filefunctions.h" #include "common/timecodefunctions.h" #ifdef USE_OTIO diff --git a/app/codec/encoder.h b/app/codec/encoder.h index 2d4e2d245..9cd9547a0 100644 --- a/app/codec/encoder.h +++ b/app/codec/encoder.h @@ -122,9 +122,9 @@ public: virtual void Close() = 0; - virtual PixelFormat::Format GetDesiredPixelFormat() const + virtual VideoParams::Format GetDesiredPixelFormat() const { - return PixelFormat::PIX_FMT_INVALID; + return VideoParams::kFormatInvalid; } private: diff --git a/app/codec/ffmpeg/CMakeLists.txt b/app/codec/ffmpeg/CMakeLists.txt index 12267fe76..7c26e24bf 100644 --- a/app/codec/ffmpeg/CMakeLists.txt +++ b/app/codec/ffmpeg/CMakeLists.txt @@ -17,8 +17,6 @@ set(OLIVE_SOURCES ${OLIVE_SOURCES} codec/ffmpeg/avframeptr.h - codec/ffmpeg/ffmpegcommon.h - codec/ffmpeg/ffmpegcommon.cpp codec/ffmpeg/ffmpegdecoder.h codec/ffmpeg/ffmpegdecoder.cpp codec/ffmpeg/ffmpegencoder.h diff --git a/app/codec/ffmpeg/ffmpegcommon.cpp b/app/codec/ffmpeg/ffmpegcommon.cpp deleted file mode 100644 index cdc2554e1..000000000 --- a/app/codec/ffmpeg/ffmpegcommon.cpp +++ /dev/null @@ -1,125 +0,0 @@ -/*** - - Olive - Non-Linear Video Editor - Copyright (C) 2019 Olive Team - - This program is free software: you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program. If not, see . - -***/ - -#include "ffmpegcommon.h" - -OLIVE_NAMESPACE_ENTER - -AVPixelFormat FFmpegCommon::GetCompatiblePixelFormat(const AVPixelFormat &pix_fmt) -{ - AVPixelFormat possible_pix_fmts[] = { - AV_PIX_FMT_RGBA, - AV_PIX_FMT_RGBA64, - AV_PIX_FMT_NONE - }; - - return avcodec_find_best_pix_fmt_of_list(possible_pix_fmts, - pix_fmt, - 1, - nullptr); -} - -SampleFormat::Format FFmpegCommon::GetNativeSampleFormat(const AVSampleFormat &smp_fmt) -{ - switch (smp_fmt) { - case AV_SAMPLE_FMT_U8: - return SampleFormat::SAMPLE_FMT_U8; - case AV_SAMPLE_FMT_S16: - return SampleFormat::SAMPLE_FMT_S16; - case AV_SAMPLE_FMT_S32: - return SampleFormat::SAMPLE_FMT_S32; - case AV_SAMPLE_FMT_S64: - return SampleFormat::SAMPLE_FMT_S64; - case AV_SAMPLE_FMT_FLT: - return SampleFormat::SAMPLE_FMT_FLT; - case AV_SAMPLE_FMT_DBL: - return SampleFormat::SAMPLE_FMT_DBL; - case AV_SAMPLE_FMT_U8P : - case AV_SAMPLE_FMT_S16P: - case AV_SAMPLE_FMT_S32P: - case AV_SAMPLE_FMT_S64P: - case AV_SAMPLE_FMT_FLTP: - case AV_SAMPLE_FMT_DBLP: - case AV_SAMPLE_FMT_NONE: - case AV_SAMPLE_FMT_NB: - break; - } - - return SampleFormat::SAMPLE_FMT_INVALID; -} - -AVSampleFormat FFmpegCommon::GetFFmpegSampleFormat(const SampleFormat::Format &smp_fmt) -{ - switch (smp_fmt) { - case SampleFormat::SAMPLE_FMT_U8: - return AV_SAMPLE_FMT_U8; - case SampleFormat::SAMPLE_FMT_S16: - return AV_SAMPLE_FMT_S16; - case SampleFormat::SAMPLE_FMT_S32: - return AV_SAMPLE_FMT_S32; - case SampleFormat::SAMPLE_FMT_S64: - return AV_SAMPLE_FMT_S64; - case SampleFormat::SAMPLE_FMT_FLT: - return AV_SAMPLE_FMT_FLT; - case SampleFormat::SAMPLE_FMT_DBL: - return AV_SAMPLE_FMT_DBL; - case SampleFormat::SAMPLE_FMT_INVALID: - case SampleFormat::SAMPLE_FMT_COUNT: - break; - } - - return AV_SAMPLE_FMT_NONE; -} - -AVPixelFormat FFmpegCommon::GetFFmpegPixelFormat(const PixelFormat::Format &pix_fmt) -{ - switch (pix_fmt) { - case PixelFormat::PIX_FMT_RGBA8: - return AV_PIX_FMT_RGBA; - case PixelFormat::PIX_FMT_RGBA16U: - return AV_PIX_FMT_RGBA64; - case PixelFormat::PIX_FMT_RGBA16F: - case PixelFormat::PIX_FMT_RGBA32F: - case PixelFormat::PIX_FMT_INVALID: - case PixelFormat::PIX_FMT_COUNT: - break; - } - - return AV_PIX_FMT_NONE; -} - -PixelFormat::Format FFmpegCommon::GetCompatiblePixelFormat(const PixelFormat::Format &pix_fmt) -{ - switch (pix_fmt) { - case PixelFormat::PIX_FMT_RGBA8: - return PixelFormat::PIX_FMT_RGBA8; - case PixelFormat::PIX_FMT_RGBA16U: - case PixelFormat::PIX_FMT_RGBA16F: - case PixelFormat::PIX_FMT_RGBA32F: - return PixelFormat::PIX_FMT_RGBA16U; - case PixelFormat::PIX_FMT_INVALID: - case PixelFormat::PIX_FMT_COUNT: - break; - } - - return PixelFormat::PIX_FMT_INVALID; -} - -OLIVE_NAMESPACE_EXIT diff --git a/app/codec/ffmpeg/ffmpegdecoder.cpp b/app/codec/ffmpeg/ffmpegdecoder.cpp index ac4e402b7..cdab55a67 100644 --- a/app/codec/ffmpeg/ffmpegdecoder.cpp +++ b/app/codec/ffmpeg/ffmpegdecoder.cpp @@ -38,13 +38,12 @@ extern "C" { #include "codec/waveinput.h" #include "common/define.h" +#include "common/ffmpegutils.h" #include "common/filefunctions.h" #include "common/functiontimer.h" #include "common/timecodefunctions.h" -#include "ffmpegcommon.h" #include "render/framehashcache.h" #include "render/diskmanager.h" -#include "render/pixelformat.h" OLIVE_NAMESPACE_ENTER @@ -73,13 +72,17 @@ bool FFmpegDecoder::OpenInternal() if (stream()->type() == Stream::kVideo) { // Get an Olive compatible AVPixelFormat - ideal_pix_fmt_ = FFmpegCommon::GetCompatiblePixelFormat(static_cast(s->codecpar->format)); + ideal_pix_fmt_ = FFmpegUtils::GetCompatiblePixelFormat(static_cast(s->codecpar->format)); // Determine which Olive native pixel format we retrieved // Note that FFmpeg doesn't support float formats native_pix_fmt_ = GetNativePixelFormat(ideal_pix_fmt_); + native_channel_count_ = GetNativeChannelCount(ideal_pix_fmt_); - if (native_pix_fmt_ == PixelFormat::PIX_FMT_INVALID) { + qDebug() << "Set channel count to:" << native_channel_count_; + + if (native_pix_fmt_ == VideoParams::kFormatInvalid + || native_channel_count_ == 0) { qDebug() << "Failed to find valid native pixel format for" << ideal_pix_fmt_; return false; } @@ -124,6 +127,7 @@ FramePtr FFmpegDecoder::RetrieveStillImage(const rational &timecode, const int & output_frame->set_video_params(VideoParams(frame->width, frame->height, native_pix_fmt_, + native_channel_count_, std::static_pointer_cast(stream())->pixel_aspect_ratio(), std::static_pointer_cast(stream())->interlacing(), divider)); @@ -172,7 +176,7 @@ FramePtr FFmpegDecoder::RetrieveVideoInternal(const rational &timecode, const in ClearFrameCache(); // Set new frame pool parameters - pool_.SetParameters(divided_width, divided_height, native_pix_fmt_); + pool_.SetParameters(divided_width, divided_height, native_pix_fmt_, native_channel_count_); } // Retrieve frame @@ -184,6 +188,7 @@ FramePtr FFmpegDecoder::RetrieveVideoInternal(const rational &timecode, const in copy->set_video_params(VideoParams(vs->width(), vs->height(), native_pix_fmt_, + native_channel_count_, std::static_pointer_cast(stream())->pixel_aspect_ratio(), std::static_pointer_cast(stream())->interlacing(), divider)); @@ -328,10 +333,13 @@ FootagePtr FFmpegDecoder::Probe(const QString& filename, const QAtomicInt* cance video_stream->set_width(avstream->codecpar->width); video_stream->set_height(avstream->codecpar->height); - video_stream->set_format(GetNativePixelFormat(FFmpegCommon::GetCompatiblePixelFormat(static_cast(avstream->codecpar->format)))); video_stream->set_interlacing(interlacing); video_stream->set_pixel_aspect_ratio(pixel_aspect_ratio); + AVPixelFormat compatible_pix_fmt = FFmpegUtils::GetCompatiblePixelFormat(static_cast(avstream->codecpar->format)); + video_stream->set_format(GetNativePixelFormat(compatible_pix_fmt)); + video_stream->set_channel_count(GetNativeChannelCount(compatible_pix_fmt)); + str = video_stream; } else { @@ -460,7 +468,7 @@ bool FFmpegDecoder::ConformAudioInternal(const QString &filename, const AudioPar // Create resampling context SwrContext* resampler = swr_alloc_set_opts(nullptr, params.channel_layout(), - FFmpegCommon::GetFFmpegSampleFormat(params.format()), + FFmpegUtils::GetFFmpegSampleFormat(params.format()), params.sample_rate(), channel_layout, static_cast(instance_.avstream()->codecpar->format), @@ -542,15 +550,31 @@ bool FFmpegDecoder::ConformAudioInternal(const QString &filename, const AudioPar return success; } -PixelFormat::Format FFmpegDecoder::GetNativePixelFormat(AVPixelFormat pix_fmt) +VideoParams::Format FFmpegDecoder::GetNativePixelFormat(AVPixelFormat pix_fmt) { switch (pix_fmt) { + case AV_PIX_FMT_RGB24: case AV_PIX_FMT_RGBA: - return PixelFormat::PIX_FMT_RGBA8; + return VideoParams::kFormatUnsigned8; + case AV_PIX_FMT_RGB48: case AV_PIX_FMT_RGBA64: - return PixelFormat::PIX_FMT_RGBA16U; + return VideoParams::kFormatUnsigned16; default: - return PixelFormat::PIX_FMT_INVALID; + return VideoParams::kFormatInvalid; + } +} + +int FFmpegDecoder::GetNativeChannelCount(AVPixelFormat pix_fmt) +{ + switch (pix_fmt) { + case AV_PIX_FMT_RGB24: + case AV_PIX_FMT_RGB48: + return VideoParams::kRGBChannelCount; + case AV_PIX_FMT_RGBA: + case AV_PIX_FMT_RGBA64: + return VideoParams::kRGBAChannelCount; + default: + return 0; } } @@ -729,7 +753,7 @@ FFmpegFramePool::ElementPtr FFmpegDecoder::RetrieveFrame(const int64_t& target_t // Store in queue, converting to native format uint8_t* destination_data = cached->data(); - int destination_linesize = Frame::generate_linesize_bytes(VideoParams::GetScaledDimension(instance_.avstream()->codecpar->width, divider), native_pix_fmt_); + int destination_linesize = Frame::generate_linesize_bytes(VideoParams::GetScaledDimension(instance_.avstream()->codecpar->width, divider), native_pix_fmt_, native_channel_count_); FFmpegBufferToNativeBuffer(working_frame->data, working_frame->linesize, &destination_data, &destination_linesize); // Set timestamp so this frame can be identified later diff --git a/app/codec/ffmpeg/ffmpegdecoder.h b/app/codec/ffmpeg/ffmpegdecoder.h index b74aa5bde..1f820d746 100644 --- a/app/codec/ffmpeg/ffmpegdecoder.h +++ b/app/codec/ffmpeg/ffmpegdecoder.h @@ -32,7 +32,6 @@ extern "C" { #include #include -#include "audio/sampleformat.h" #include "avframeptr.h" #include "codec/decoder.h" #include "codec/waveoutput.h" @@ -126,7 +125,8 @@ private: FramePtr RetrieveStillImage(const rational& timecode, const int& divider); - static PixelFormat::Format GetNativePixelFormat(AVPixelFormat pix_fmt); + static VideoParams::Format GetNativePixelFormat(AVPixelFormat pix_fmt); + static int GetNativeChannelCount(AVPixelFormat pix_fmt); static uint64_t ValidateChannelLayout(AVStream *stream); @@ -143,7 +143,8 @@ private: SwsContext* scale_ctx_; int scale_divider_; AVPixelFormat ideal_pix_fmt_; - PixelFormat::Format native_pix_fmt_; + VideoParams::Format native_pix_fmt_; + int native_channel_count_; FFmpegFramePool pool_; diff --git a/app/codec/ffmpeg/ffmpegencoder.cpp b/app/codec/ffmpeg/ffmpegencoder.cpp index c31ac6b5a..3e95937db 100644 --- a/app/codec/ffmpeg/ffmpegencoder.cpp +++ b/app/codec/ffmpeg/ffmpegencoder.cpp @@ -26,8 +26,7 @@ extern "C" { #include -#include "ffmpegcommon.h" -#include "render/pixelformat.h" +#include "common/ffmpegutils.h" OLIVE_NAMESPACE_ENTER @@ -36,7 +35,8 @@ FFmpegEncoder::FFmpegEncoder(const EncodingParams ¶ms) : fmt_ctx_(nullptr), video_stream_(nullptr), video_codec_ctx_(nullptr), - video_scale_ctx_(nullptr), + video_alpha_scale_ctx_(nullptr), + video_noalpha_scale_ctx_(nullptr), audio_stream_(nullptr), audio_codec_ctx_(nullptr), audio_resample_ctx_(nullptr), @@ -72,29 +72,49 @@ bool FFmpegEncoder::Open() } // This is the format we will expect frames received in Write() to be in - PixelFormat::Format native_pixel_fmt = params().video_params().format(); + VideoParams::Format native_pixel_fmt = params().video_params().format(); // This is the format we will need to convert the frame to for swscale to understand it - video_conversion_fmt_ = FFmpegCommon::GetCompatiblePixelFormat(native_pixel_fmt); + video_conversion_fmt_ = FFmpegUtils::GetCompatiblePixelFormat(native_pixel_fmt); // This is the equivalent pixel format above as an AVPixelFormat that swscale can understand - AVPixelFormat src_pix_fmt = FFmpegCommon::GetFFmpegPixelFormat(video_conversion_fmt_); + AVPixelFormat src_alpha_pix_fmt = FFmpegUtils::GetFFmpegPixelFormat(video_conversion_fmt_, + VideoParams::kRGBAChannelCount); + + AVPixelFormat src_noalpha_pix_fmt = FFmpegUtils::GetFFmpegPixelFormat(video_conversion_fmt_, + VideoParams::kRGBChannelCount); + + if (src_alpha_pix_fmt == AV_PIX_FMT_NONE || src_noalpha_pix_fmt == AV_PIX_FMT_NONE) { + Error(QStringLiteral("Failed to find suitable pixel format for this buffer")); + return false; + } // This is the pixel format the encoder wants to encode to AVPixelFormat encoder_pix_fmt = video_codec_ctx_->pix_fmt; // Set up a scaling context - if the native pixel format is not equal to the encoder's, we'll need to convert it // before encoding. Even if we don't, this may be useful for converting between linesizes, etc. - video_scale_ctx_ = sws_getContext(params().video_params().width(), - params().video_params().height(), - src_pix_fmt, - params().video_params().width(), - params().video_params().height(), - encoder_pix_fmt, - 0, - nullptr, - nullptr, - nullptr); + video_alpha_scale_ctx_ = sws_getContext(params().video_params().width(), + params().video_params().height(), + src_alpha_pix_fmt, + params().video_params().width(), + params().video_params().height(), + encoder_pix_fmt, + 0, + nullptr, + nullptr, + nullptr); + + video_noalpha_scale_ctx_ = sws_getContext(params().video_params().width(), + params().video_params().height(), + src_noalpha_pix_fmt, + params().video_params().width(), + params().video_params().height(), + encoder_pix_fmt, + 0, + nullptr, + nullptr, + nullptr); } // Initialize an audio stream if it's enabled @@ -157,19 +177,22 @@ bool FFmpegEncoder::WriteFrame(FramePtr frame, rational time) // We may need to convert this frame to a frame that swscale will understand if (frame->format() != video_conversion_fmt_) { - frame = PixelFormat::ConvertPixelFormat(frame, video_conversion_fmt_); + frame = frame->convert(video_conversion_fmt_); } // Use swscale context to convert formats/linesizes input_data = frame->const_data(); input_linesize = frame->linesize_bytes(); - error_code = sws_scale(video_scale_ctx_, + + error_code = sws_scale((frame->channel_count() == VideoParams::kRGBAChannelCount) ? video_alpha_scale_ctx_ : video_noalpha_scale_ctx_, reinterpret_cast(&input_data), &input_linesize, 0, frame->height(), encoded_frame->data, encoded_frame->linesize); + + if (error_code < 0) { FFmpegError("Failed to scale frame", error_code); goto fail; @@ -208,7 +231,7 @@ void FFmpegEncoder::WriteAudio(AudioParams pcm_info, QIODevice* file) audio_codec_ctx_->sample_fmt, audio_codec_ctx_->sample_rate, static_cast(pcm_info.channel_layout()), - FFmpegCommon::GetFFmpegSampleFormat(pcm_info.format()), + FFmpegUtils::GetFFmpegSampleFormat(pcm_info.format()), pcm_info.sample_rate(), 0, nullptr); @@ -300,9 +323,14 @@ void FFmpegEncoder::Close() open_ = false; } - if (video_scale_ctx_) { - sws_freeContext(video_scale_ctx_); - video_scale_ctx_ = nullptr; + if (video_alpha_scale_ctx_) { + sws_freeContext(video_alpha_scale_ctx_); + video_alpha_scale_ctx_ = nullptr; + } + + if (video_noalpha_scale_ctx_) { + sws_freeContext(video_noalpha_scale_ctx_); + video_noalpha_scale_ctx_ = nullptr; } if (video_codec_ctx_) { diff --git a/app/codec/ffmpeg/ffmpegencoder.h b/app/codec/ffmpeg/ffmpegencoder.h index e42d8137a..6b28fb62f 100644 --- a/app/codec/ffmpeg/ffmpegencoder.h +++ b/app/codec/ffmpeg/ffmpegencoder.h @@ -47,7 +47,7 @@ public: virtual void Close() override; - virtual PixelFormat::Format GetDesiredPixelFormat() const override + virtual VideoParams::Format GetDesiredPixelFormat() const override { return video_conversion_fmt_; } @@ -85,8 +85,9 @@ private: AVStream* video_stream_; AVCodecContext* video_codec_ctx_; - SwsContext* video_scale_ctx_; - PixelFormat::Format video_conversion_fmt_; + SwsContext* video_alpha_scale_ctx_; + SwsContext* video_noalpha_scale_ctx_; + VideoParams::Format video_conversion_fmt_; AVStream* audio_stream_; AVCodecContext* audio_codec_ctx_; diff --git a/app/codec/ffmpeg/ffmpegframepool.cpp b/app/codec/ffmpeg/ffmpegframepool.cpp index ac114ba12..520f5d0ac 100644 --- a/app/codec/ffmpeg/ffmpegframepool.cpp +++ b/app/codec/ffmpeg/ffmpegframepool.cpp @@ -28,22 +28,24 @@ FFmpegFramePool::FFmpegFramePool(int element_count) : MemoryPool(element_count), width_(0), height_(0), - format_(PixelFormat::PIX_FMT_INVALID) + format_(VideoParams::kFormatInvalid), + channel_count_(0) { } -void FFmpegFramePool::SetParameters(int width, int height, PixelFormat::Format format) +void FFmpegFramePool::SetParameters(int width, int height, VideoParams::Format format, int channel_count) { Clear(); width_ = width; height_ = height; format_ = format; + channel_count_ = channel_count; } size_t FFmpegFramePool::GetElementSize() { - return Frame::generate_linesize_bytes(width_, format_) * height_; + return Frame::generate_linesize_bytes(width_, format_, channel_count_) * height_; } OLIVE_NAMESPACE_EXIT diff --git a/app/codec/ffmpeg/ffmpegframepool.h b/app/codec/ffmpeg/ffmpegframepool.h index 8a72bb61e..f97a948d0 100644 --- a/app/codec/ffmpeg/ffmpegframepool.h +++ b/app/codec/ffmpeg/ffmpegframepool.h @@ -22,7 +22,6 @@ #define FFMPEGFRAMEPOOL_H #include "common/memorypool.h" -#include "render/pixelformat.h" #include "render/videoparams.h" OLIVE_NAMESPACE_ENTER @@ -32,7 +31,7 @@ class FFmpegFramePool : public MemoryPool public: FFmpegFramePool(int element_count); - void SetParameters(int width, int height, PixelFormat::Format format); + void SetParameters(int width, int height, VideoParams::Format format, int channel_count); const int& width() const { @@ -52,7 +51,9 @@ private: int height_; - PixelFormat::Format format_; + VideoParams::Format format_; + + int channel_count_; }; diff --git a/app/codec/frame.cpp b/app/codec/frame.cpp index 9abdac922..7d474a1c5 100644 --- a/app/codec/frame.cpp +++ b/app/codec/frame.cpp @@ -20,10 +20,13 @@ #include "frame.h" +#include #include #include #include +#include "common/oiioutils.h" + OLIVE_NAMESPACE_ENTER Frame::Frame() : @@ -45,14 +48,14 @@ void Frame::set_video_params(const VideoParams ¶ms) { params_ = params; - linesize_ = generate_linesize_bytes(width(), params_.format()); - linesize_pixels_ = linesize_ / PixelFormat::BytesPerPixel(params_.format()); + linesize_ = generate_linesize_bytes(width(), params_.format(), params_.channel_count()); + linesize_pixels_ = linesize_ / params_.GetBytesPerPixel(); } -int Frame::generate_linesize_bytes(int width, PixelFormat::Format format) +int Frame::generate_linesize_bytes(int width, VideoParams::Format format, int channel_count) { // Align to 32 bytes (not sure if this is necessary?) - return PixelFormat::BytesPerPixel(format) * ((width + 31) & ~31); + return VideoParams::GetBytesPerPixel(format, channel_count) * ((width + 31) & ~31); } Color Frame::get_pixel(int x, int y) const @@ -61,9 +64,9 @@ Color Frame::get_pixel(int x, int y) const return Color(); } - int byte_offset = y * linesize_bytes() + x * PixelFormat::BytesPerPixel(video_params().format()); + int byte_offset = y * linesize_bytes() + x * video_params().GetBytesPerPixel(); - return Color(data_.data() + byte_offset, video_params().format()); + return Color(data_.data() + byte_offset, video_params().format(), video_params().channel_count()); } bool Frame::contains_pixel(int x, int y) const @@ -77,9 +80,9 @@ void Frame::set_pixel(int x, int y, const Color &c) return; } - int byte_offset = y * linesize_bytes() + x * PixelFormat::BytesPerPixel(video_params().format()); + int byte_offset = y * linesize_bytes() + x * video_params().GetBytesPerPixel(); - c.toData(data_.data() + byte_offset, video_params().format()); + c.toData(data_.data() + byte_offset, video_params().format(), video_params().channel_count()); } bool Frame::allocate() @@ -90,9 +93,40 @@ bool Frame::allocate() return false; } - data_.resize(PixelFormat::GetBufferSize(params_.format(), linesize_, height())); + data_.resize(VideoParams::GetBufferSize(linesize_, height(), params_.format(), params_.channel_count())); return true; } +FramePtr Frame::convert(VideoParams::Format format) const +{ + // Create new params with destination format + VideoParams params = params_; + params.set_format(format); + + // Create new frame + FramePtr converted = Frame::Create(); + converted->set_video_params(params); + converted->set_timestamp(timestamp_); + converted->allocate(); + + // Do the conversion through OIIO for convenience + OIIO::ImageBuf src(OIIO::ImageSpec(width(), height(), + channel_count(), + OIIOUtils::GetOIIOBaseTypeFromFormat(this->format()))); + + OIIOUtils::FrameToBuffer(this, &src); + + OIIO::ImageBuf dst(OIIO::ImageSpec(converted->width(), converted->height(), + channel_count(), + OIIOUtils::GetOIIOBaseTypeFromFormat(format))); + + if (dst.copy_pixels(src)) { + OIIOUtils::BufferToFrame(&dst, converted.get()); + return converted; + } else { + return nullptr; + } +} + OLIVE_NAMESPACE_EXIT diff --git a/app/codec/frame.h b/app/codec/frame.h index 8c89902b9..29fbdaac1 100644 --- a/app/codec/frame.h +++ b/app/codec/frame.h @@ -26,7 +26,6 @@ #include "common/rational.h" #include "render/color.h" -#include "render/pixelformat.h" #include "render/videoparams.h" OLIVE_NAMESPACE_ENTER @@ -47,7 +46,7 @@ public: const VideoParams& video_params() const; void set_video_params(const VideoParams& params); - static int generate_linesize_bytes(int width, PixelFormat::Format format); + static int generate_linesize_bytes(int width, VideoParams::Format format, int channel_count); int linesize_pixels() const { @@ -69,11 +68,16 @@ public: return params_.effective_height(); } - PixelFormat::Format format() const + VideoParams::Format format() const { return params_.format(); } + int channel_count() const + { + return params_.channel_count(); + } + Color get_pixel(int x, int y) const; bool contains_pixel(int x, int y) const; void set_pixel(int x, int y, const Color& c); @@ -144,6 +148,8 @@ public: return data_.size(); } + FramePtr convert(VideoParams::Format format) const; + private: VideoParams params_; diff --git a/app/codec/oiio/CMakeLists.txt b/app/codec/oiio/CMakeLists.txt index 4843b25b1..201fd3ee7 100644 --- a/app/codec/oiio/CMakeLists.txt +++ b/app/codec/oiio/CMakeLists.txt @@ -16,8 +16,6 @@ set(OLIVE_SOURCES ${OLIVE_SOURCES} - codec/oiio/oiiocommon.cpp - codec/oiio/oiiocommon.h codec/oiio/oiiodecoder.cpp codec/oiio/oiiodecoder.h PARENT_SCOPE diff --git a/app/codec/oiio/oiiocommon.h b/app/codec/oiio/oiiocommon.h deleted file mode 100644 index aeccc2e0d..000000000 --- a/app/codec/oiio/oiiocommon.h +++ /dev/null @@ -1,47 +0,0 @@ -/*** - - Olive - Non-Linear Video Editor - Copyright (C) 2019 Olive Team - - This program is free software: you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program. If not, see . - -***/ - -#ifndef OIIOCOMMON_H -#define OIIOCOMMON_H - -#include -#include - -#include "codec/frame.h" -#include "render/pixelformat.h" - -OLIVE_NAMESPACE_ENTER - -class OIIOCommon -{ -public: - static void FrameToBuffer(FramePtr frame, OIIO::ImageBuf* buf); - - static void BufferToFrame(OIIO::ImageBuf* buf, FramePtr frame); - - static PixelFormat::Format GetFormatFromOIIOBasetype(const OIIO::ImageSpec& spec); - - static rational GetPixelAspectRatioFromOIIO(const OIIO::ImageSpec& spec); - -}; - -OLIVE_NAMESPACE_EXIT - -#endif // OIIOCOMMON_H diff --git a/app/codec/oiio/oiiodecoder.cpp b/app/codec/oiio/oiiodecoder.cpp index 1728c04d2..392951240 100644 --- a/app/codec/oiio/oiiodecoder.cpp +++ b/app/codec/oiio/oiiodecoder.cpp @@ -27,9 +27,9 @@ #include #include "common/define.h" +#include "common/oiioutils.h" #include "config/config.h" #include "core.h" -#include "oiiocommon.h" OLIVE_NAMESPACE_ENTER @@ -81,8 +81,9 @@ FootagePtr OIIODecoder::Probe(const QString& filename, const QAtomicInt* cancell image_stream->set_width(in->spec().width); image_stream->set_height(in->spec().height); - image_stream->set_format(OIIOCommon::GetFormatFromOIIOBasetype(in->spec())); - image_stream->set_pixel_aspect_ratio(OIIOCommon::GetPixelAspectRatioFromOIIO(in->spec())); + image_stream->set_format(OIIOUtils::GetFormatFromOIIOBasetype(static_cast(in->spec().format.basetype))); + image_stream->set_channel_count(in->spec().nchannels); + image_stream->set_pixel_aspect_ratio(OIIOUtils::GetPixelAspectRatioFromOIIO(in->spec())); image_stream->set_video_type(VideoStream::kVideoTypeStill); // Images will always have just one stream @@ -149,14 +150,15 @@ FramePtr OIIODecoder::RetrieveVideoInternal(const rational &timecode, const int& frame->set_video_params(VideoParams(buffer_->spec().width, buffer_->spec().height, pix_fmt_, - OIIOCommon::GetPixelAspectRatioFromOIIO(buffer_->spec()), + channel_count_, + OIIOUtils::GetPixelAspectRatioFromOIIO(buffer_->spec()), VideoParams::kInterlaceNone, // FIXME: Does OIIO deinterlace for us? divider)); frame->allocate(); if (divider == 1) { - OIIOCommon::BufferToFrame(buffer_, frame); + OIIOUtils::BufferToFrame(buffer_, frame.get()); } else { @@ -167,7 +169,7 @@ FramePtr OIIODecoder::RetrieveVideoInternal(const rational &timecode, const int& qWarning() << "OIIO resize failed"; } - OIIOCommon::BufferToFrame(&dst, frame); + OIIOUtils::BufferToFrame(&dst, frame.get()); } @@ -215,18 +217,23 @@ bool OIIODecoder::OpenImageHandler(const QString &fn) // Check if we can work with this pixel format const OIIO::ImageSpec& spec = image_->spec(); - //is_rgba_ = (spec.nchannels == kRGBAChannels); + // Store channel count + channel_count_ = spec.nchannels; // We use RGBA frames because that tends to be the native format of GPUs - pix_fmt_ = OIIOCommon::GetFormatFromOIIOBasetype(spec); + pix_fmt_ = OIIOUtils::GetFormatFromOIIOBasetype(static_cast(spec.format.basetype)); - if (pix_fmt_ == PixelFormat::PIX_FMT_INVALID) { + if (pix_fmt_ == VideoParams::kFormatInvalid) { qWarning() << "Failed to convert OIIO::ImageDesc to native pixel format"; return false; } - // FIXME: Many OIIO pixel formats are not handled here - OIIO::TypeDesc type = PixelFormat::GetOIIOTypeDesc(pix_fmt_); + OIIO::TypeDesc::BASETYPE type = OIIOUtils::GetOIIOBaseTypeFromFormat(pix_fmt_); + + if (type == OIIO::TypeDesc::UNKNOWN) { + qCritical() << "Failed to determine appropriate OIIO basetype from native format"; + return false; + } #if OIIO_VERSION < 20100 buffer_ = new OIIO::ImageBuf(OIIO::ImageSpec(spec.width, spec.height, spec.nchannels, type)); diff --git a/app/codec/oiio/oiiodecoder.h b/app/codec/oiio/oiiodecoder.h index 820057d3e..f4b7e96d9 100644 --- a/app/codec/oiio/oiiodecoder.h +++ b/app/codec/oiio/oiiodecoder.h @@ -25,7 +25,6 @@ #include #include "codec/decoder.h" -#include "render/pixelformat.h" OLIVE_NAMESPACE_ENTER @@ -63,9 +62,9 @@ private: int64_t last_sequence_index_; - PixelFormat::Format pix_fmt_; + VideoParams::Format pix_fmt_; - //bool is_rgba_; + int channel_count_; OIIO::ImageBuf* buffer_; diff --git a/app/codec/waveinput.cpp b/app/codec/waveinput.cpp index 275bea1f2..06fd5f2b6 100644 --- a/app/codec/waveinput.cpp +++ b/app/codec/waveinput.cpp @@ -108,27 +108,27 @@ bool WaveInput::open() uint16_t bits_per_sample; data_stream >> bits_per_sample; - SampleFormat::Format format; + AudioParams::Format format; switch (bits_per_sample) { case 8: - format = SampleFormat::SAMPLE_FMT_U8; + format = AudioParams::kFormatUnsigned8; break; case 16: - format = SampleFormat::SAMPLE_FMT_S16; + format = AudioParams::kFormatSigned16; break; case 32: if (data_is_float) { - format = SampleFormat::SAMPLE_FMT_FLT; + format = AudioParams::kFormatFloat32; } else { - format = SampleFormat::SAMPLE_FMT_S32; + format = AudioParams::kFormatSigned32; } break; case 64: if (data_is_float) { - format = SampleFormat::SAMPLE_FMT_DBL; + format = AudioParams::kFormatFloat64; } else { - format = SampleFormat::SAMPLE_FMT_S64; + format = AudioParams::kFormatSigned64; } break; default: diff --git a/app/codec/waveoutput.cpp b/app/codec/waveoutput.cpp index 844b3ad8f..648b8c4a8 100644 --- a/app/codec/waveoutput.cpp +++ b/app/codec/waveoutput.cpp @@ -20,6 +20,8 @@ #include "waveoutput.h" +#include "render/audioparams.h" + OLIVE_NAMESPACE_ENTER const int16_t kWAVIntegerFormat = 1; @@ -60,18 +62,18 @@ bool WaveOutput::open() // Type of format switch (params_.format()) { - case SampleFormat::SAMPLE_FMT_U8: - case SampleFormat::SAMPLE_FMT_S16: - case SampleFormat::SAMPLE_FMT_S32: - case SampleFormat::SAMPLE_FMT_S64: + case AudioParams::kFormatUnsigned8: + case AudioParams::kFormatSigned16: + case AudioParams::kFormatSigned32: + case AudioParams::kFormatSigned64: write_int(&file_, kWAVIntegerFormat); break; - case SampleFormat::SAMPLE_FMT_FLT: - case SampleFormat::SAMPLE_FMT_DBL: + case AudioParams::kFormatFloat32: + case AudioParams::kFormatFloat64: write_int(&file_, kWAVFloatFormat); break; - case SampleFormat::SAMPLE_FMT_INVALID: - case SampleFormat::SAMPLE_FMT_COUNT: + case AudioParams::kFormatInvalid: + case AudioParams::kFormatCount: qWarning() << "Invalid sample format for WAVE audio"; file_.close(); return false; diff --git a/app/codec/waveoutput.h b/app/codec/waveoutput.h index a42f103e0..450fe38bc 100644 --- a/app/codec/waveoutput.h +++ b/app/codec/waveoutput.h @@ -24,7 +24,6 @@ #include #include -#include "audio/sampleformat.h" #include "render/audioparams.h" OLIVE_NAMESPACE_ENTER diff --git a/app/common/CMakeLists.txt b/app/common/CMakeLists.txt index 553af7017..06963187b 100644 --- a/app/common/CMakeLists.txt +++ b/app/common/CMakeLists.txt @@ -16,44 +16,49 @@ set(OLIVE_SOURCES ${OLIVE_SOURCES} - common/bezier.h common/bezier.cpp + common/bezier.h common/cancelableobject.h common/channellayout.h common/clamp.h - common/commandlineparser.h common/commandlineparser.cpp - common/crashpadinterface.h + common/commandlineparser.h common/crashpadinterface.cpp + common/crashpadinterface.h common/crashpadutils.h - common/debug.h common/debug.cpp + common/debug.h common/define.h - common/filefunctions.h + common/ffmpegutils.cpp + common/ffmpegutils.h common/filefunctions.cpp - common/flipmodifiers.h + common/filefunctions.h common/flipmodifiers.cpp + common/flipmodifiers.h common/functiontimer.h common/lerp.h - common/memorypool.h common/memorypool.cpp + common/memorypool.h + common/ocioutils.cpp common/ocioutils.h - common/qtutils.h + common/oiioutils.cpp + common/oiioutils.h common/qtutils.cpp + common/qtutils.h common/range.h - common/ratiodialog.h common/ratiodialog.cpp + common/ratiodialog.h common/rational.h common/rational.cpp common/threadsafemap.h - common/threadedobject.h common/threadedobject.cpp - common/timecodefunctions.h + common/threadedobject.h common/timecodefunctions.cpp - common/timerange.h + common/timecodefunctions.h common/timerange.cpp + common/timerange.h common/tohex.h - common/xmlutils.h common/xmlutils.cpp + common/xmlutils.h PARENT_SCOPE ) diff --git a/app/common/define.h b/app/common/define.h index aa968fcf7..0a29394a0 100644 --- a/app/common/define.h +++ b/app/common/define.h @@ -29,10 +29,6 @@ OLIVE_NAMESPACE_ENTER -const int kHSVChannels = 3; -const int kRGBChannels = 3; -const int kRGBAChannels = 4; - /// The minimum size an icon in ProjectExplorer can be const int kProjectIconSizeMinimum = 16; diff --git a/app/common/ffmpegutils.cpp b/app/common/ffmpegutils.cpp new file mode 100644 index 000000000..9453bd851 --- /dev/null +++ b/app/common/ffmpegutils.cpp @@ -0,0 +1,141 @@ +/*** + + Olive - Non-Linear Video Editor + Copyright (C) 2019 Olive Team + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . + +***/ + +#include "common/ffmpegutils.h" + +OLIVE_NAMESPACE_ENTER + +AVPixelFormat FFmpegUtils::GetCompatiblePixelFormat(const AVPixelFormat &pix_fmt) +{ + AVPixelFormat possible_pix_fmts[] = { + AV_PIX_FMT_RGB24, + AV_PIX_FMT_RGBA, + AV_PIX_FMT_RGB48, + AV_PIX_FMT_RGBA64, + AV_PIX_FMT_NONE + }; + + return avcodec_find_best_pix_fmt_of_list(possible_pix_fmts, + pix_fmt, + 1, + nullptr); +} + +AudioParams::Format FFmpegUtils::GetNativeSampleFormat(const AVSampleFormat &smp_fmt) +{ + switch (smp_fmt) { + case AV_SAMPLE_FMT_U8: + return AudioParams::kFormatUnsigned8; + case AV_SAMPLE_FMT_S16: + return AudioParams::kFormatSigned16; + case AV_SAMPLE_FMT_S32: + return AudioParams::kFormatSigned32; + case AV_SAMPLE_FMT_S64: + return AudioParams::kFormatSigned64; + case AV_SAMPLE_FMT_FLT: + return AudioParams::kFormatFloat32; + case AV_SAMPLE_FMT_DBL: + return AudioParams::kFormatFloat64; + case AV_SAMPLE_FMT_U8P : + case AV_SAMPLE_FMT_S16P: + case AV_SAMPLE_FMT_S32P: + case AV_SAMPLE_FMT_S64P: + case AV_SAMPLE_FMT_FLTP: + case AV_SAMPLE_FMT_DBLP: + case AV_SAMPLE_FMT_NONE: + case AV_SAMPLE_FMT_NB: + break; + } + + return AudioParams::kFormatInvalid; +} + +AVSampleFormat FFmpegUtils::GetFFmpegSampleFormat(const AudioParams::Format &smp_fmt) +{ + switch (smp_fmt) { + case AudioParams::kFormatUnsigned8: + return AV_SAMPLE_FMT_U8; + case AudioParams::kFormatSigned16: + return AV_SAMPLE_FMT_S16; + case AudioParams::kFormatSigned32: + return AV_SAMPLE_FMT_S32; + case AudioParams::kFormatSigned64: + return AV_SAMPLE_FMT_S64; + case AudioParams::kFormatFloat32: + return AV_SAMPLE_FMT_FLT; + case AudioParams::kFormatFloat64: + return AV_SAMPLE_FMT_DBL; + case AudioParams::kFormatInvalid: + case AudioParams::kFormatCount: + break; + } + + return AV_SAMPLE_FMT_NONE; +} + +AVPixelFormat FFmpegUtils::GetFFmpegPixelFormat(const VideoParams::Format &pix_fmt, int channel_layout) +{ + if (channel_layout == VideoParams::kRGBChannelCount) { + switch (pix_fmt) { + case VideoParams::kFormatUnsigned8: + return AV_PIX_FMT_RGB24; + case VideoParams::kFormatUnsigned16: + return AV_PIX_FMT_RGB48; + case VideoParams::kFormatFloat16: + case VideoParams::kFormatFloat32: + case VideoParams::kFormatInvalid: + case VideoParams::kFormatCount: + break; + } + } else if (channel_layout == VideoParams::kRGBAChannelCount) { + switch (pix_fmt) { + case VideoParams::kFormatUnsigned8: + return AV_PIX_FMT_RGBA; + case VideoParams::kFormatUnsigned16: + return AV_PIX_FMT_RGBA64; + case VideoParams::kFormatFloat16: + case VideoParams::kFormatFloat32: + case VideoParams::kFormatInvalid: + case VideoParams::kFormatCount: + break; + } + } + + return AV_PIX_FMT_NONE; +} + +VideoParams::Format FFmpegUtils::GetCompatiblePixelFormat(const VideoParams::Format &pix_fmt) +{ + switch (pix_fmt) { + case VideoParams::kFormatUnsigned8: + return VideoParams::kFormatUnsigned8; + case VideoParams::kFormatUnsigned16: + case VideoParams::kFormatFloat16: + case VideoParams::kFormatFloat32: + return VideoParams::kFormatUnsigned16; + case VideoParams::kFormatInvalid: + case VideoParams::kFormatCount: + break; + } + + return VideoParams::kFormatInvalid; +} + +OLIVE_NAMESPACE_EXIT diff --git a/app/codec/ffmpeg/ffmpegcommon.h b/app/common/ffmpegutils.h similarity index 77% rename from app/codec/ffmpeg/ffmpegcommon.h rename to app/common/ffmpegutils.h index 106452fad..6e9fb002a 100644 --- a/app/codec/ffmpeg/ffmpegcommon.h +++ b/app/common/ffmpegutils.h @@ -25,12 +25,12 @@ extern "C" { #include } -#include "audio/sampleformat.h" -#include "render/pixelformat.h" +#include "render/audioparams.h" +#include "render/videoparams.h" OLIVE_NAMESPACE_ENTER -class FFmpegCommon { +class FFmpegUtils { public: /** * @brief Returns an AVPixelFormat that can be used to convert a frame to a data type Olive supports with minimal data loss @@ -40,22 +40,22 @@ public: /** * @brief Returns a native pixel format that can be used to convert from a native frame to an AVFrame with minimal data loss */ - static PixelFormat::Format GetCompatiblePixelFormat(const PixelFormat::Format& pix_fmt); + static VideoParams::Format GetCompatiblePixelFormat(const VideoParams::Format& pix_fmt); /** * @brief Returns an FFmpeg pixel format for a given native pixel format */ - static AVPixelFormat GetFFmpegPixelFormat(const PixelFormat::Format& pix_fmt); + static AVPixelFormat GetFFmpegPixelFormat(const VideoParams::Format& pix_fmt, int channel_layout); /** * @brief Returns a native sample format type for a given AVSampleFormat */ - static SampleFormat::Format GetNativeSampleFormat(const AVSampleFormat& smp_fmt); + static AudioParams::Format GetNativeSampleFormat(const AVSampleFormat& smp_fmt); /** * @brief Returns an FFmpeg sample format type for a given native type */ - static AVSampleFormat GetFFmpegSampleFormat(const SampleFormat::Format &smp_fmt); + static AVSampleFormat GetFFmpegSampleFormat(const AudioParams::Format &smp_fmt); }; OLIVE_NAMESPACE_EXIT diff --git a/app/audio/sampleformat.h b/app/common/ocioutils.cpp similarity index 57% rename from app/audio/sampleformat.h rename to app/common/ocioutils.cpp index 1261d04a1..c5f182450 100644 --- a/app/audio/sampleformat.h +++ b/app/common/ocioutils.cpp @@ -18,39 +18,30 @@ ***/ -#ifndef SAMPLEFORMAT_H -#define SAMPLEFORMAT_H - -#include - -#include "common/define.h" +#include "ocioutils.h" OLIVE_NAMESPACE_ENTER -class SampleFormat +OCIO::BitDepth OCIOUtils::GetOCIOBitDepthFromPixelFormat(VideoParams::Format format) { -public: - SampleFormat() = default; + switch (format) { + case VideoParams::kFormatUnsigned8: + return OCIO::BIT_DEPTH_UINT8; + case VideoParams::kFormatUnsigned16: + return OCIO::BIT_DEPTH_UINT16; + break; + case VideoParams::kFormatFloat16: + return OCIO::BIT_DEPTH_F16; + break; + case VideoParams::kFormatFloat32: + return OCIO::BIT_DEPTH_F32; + break; + case VideoParams::kFormatInvalid: + case VideoParams::kFormatCount: + break; + } - enum Format { - SAMPLE_FMT_INVALID = -1, - - SAMPLE_FMT_U8, - SAMPLE_FMT_S16, - SAMPLE_FMT_S32, - SAMPLE_FMT_S64, - SAMPLE_FMT_FLT, - SAMPLE_FMT_DBL, - - SAMPLE_FMT_COUNT - }; - - static const Format kInternalFormat; - - static QString GetSampleFormatName(const Format& f); - -}; + return OCIO::BIT_DEPTH_UNKNOWN; +} OLIVE_NAMESPACE_EXIT - -#endif // SAMPLEFORMAT_H diff --git a/app/common/ocioutils.h b/app/common/ocioutils.h index a290a1e50..edbaa9fef 100644 --- a/app/common/ocioutils.h +++ b/app/common/ocioutils.h @@ -24,4 +24,16 @@ #include namespace OCIO = OpenColorIO_v2_0dev; +#include "render/videoparams.h" + +OLIVE_NAMESPACE_ENTER + +class OCIOUtils +{ +public: + static OCIO::BitDepth GetOCIOBitDepthFromPixelFormat(VideoParams::Format format); +}; + +OLIVE_NAMESPACE_EXIT + #endif // OCIOUTILS_H diff --git a/app/codec/oiio/oiiocommon.cpp b/app/common/oiioutils.cpp similarity index 68% rename from app/codec/oiio/oiiocommon.cpp rename to app/common/oiioutils.cpp index f51f82aa2..8381ba904 100644 --- a/app/codec/oiio/oiiocommon.cpp +++ b/app/common/oiioutils.cpp @@ -18,11 +18,11 @@ ***/ -#include "oiiocommon.h" +#include "oiioutils.h" OLIVE_NAMESPACE_ENTER -void OIIOCommon::FrameToBuffer(FramePtr frame, OIIO::ImageBuf *buf) +void OIIOUtils::FrameToBuffer(const Frame* frame, OIIO::ImageBuf *buf) { #if OIIO_VERSION < 20112 // @@ -45,13 +45,13 @@ void OIIOCommon::FrameToBuffer(FramePtr frame, OIIO::ImageBuf *buf) #else buf->set_pixels(OIIO::ROI(), buf->spec().format, - frame->data(), + frame->const_data(), OIIO::AutoStride, frame->linesize_bytes()); #endif } -void OIIOCommon::BufferToFrame(OIIO::ImageBuf *buf, FramePtr frame) +void OIIOUtils::BufferToFrame(OIIO::ImageBuf *buf, Frame* frame) { #if OIIO_VERSION < 20112 // @@ -79,24 +79,42 @@ void OIIOCommon::BufferToFrame(OIIO::ImageBuf *buf, FramePtr frame) #endif } -PixelFormat::Format OIIOCommon::GetFormatFromOIIOBasetype(const OIIO::ImageSpec& spec) -{ - if (spec.format == OIIO::TypeDesc::UINT8) { - return PixelFormat::PIX_FMT_RGBA8; - } else if (spec.format == OIIO::TypeDesc::UINT16) { - return PixelFormat::PIX_FMT_RGBA16U; - } else if (spec.format == OIIO::TypeDesc::HALF) { - return PixelFormat::PIX_FMT_RGBA16F; - } else if (spec.format == OIIO::TypeDesc::FLOAT) { - return PixelFormat::PIX_FMT_RGBA32F; - } else { - return PixelFormat::PIX_FMT_INVALID; - } -} - -rational OIIOCommon::GetPixelAspectRatioFromOIIO(const OIIO::ImageSpec &spec) +rational OIIOUtils::GetPixelAspectRatioFromOIIO(const OIIO::ImageSpec &spec) { return rational::fromDouble(spec.get_float_attribute("PixelAspectRatio", 1)); } +VideoParams::Format OIIOUtils::GetFormatFromOIIOBasetype(OIIO::TypeDesc::BASETYPE type) +{ + switch (type) { + case OIIO::TypeDesc::UNKNOWN: + case OIIO::TypeDesc::NONE: + break; + + case OIIO::TypeDesc::INT8: + case OIIO::TypeDesc::INT16: + case OIIO::TypeDesc::INT32: + case OIIO::TypeDesc::UINT32: + case OIIO::TypeDesc::INT64: + case OIIO::TypeDesc::UINT64: + case OIIO::TypeDesc::STRING: + case OIIO::TypeDesc::PTR: + case OIIO::TypeDesc::LASTBASE: + case OIIO::TypeDesc::DOUBLE: + qDebug() << "Tried to use unknown OIIO base type"; + break; + + case OIIO::TypeDesc::UINT8: + return VideoParams::kFormatUnsigned8; + case OIIO::TypeDesc::UINT16: + return VideoParams::kFormatUnsigned16; + case OIIO::TypeDesc::HALF: + return VideoParams::kFormatFloat16; + case OIIO::TypeDesc::FLOAT: + return VideoParams::kFormatFloat32; + } + + return VideoParams::kFormatInvalid; +} + OLIVE_NAMESPACE_EXIT diff --git a/app/common/oiioutils.h b/app/common/oiioutils.h new file mode 100644 index 000000000..a9dca5baa --- /dev/null +++ b/app/common/oiioutils.h @@ -0,0 +1,65 @@ +/*** + + Olive - Non-Linear Video Editor + Copyright (C) 2019 Olive Team + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . + +***/ + +#ifndef OIIOUTILS_H +#define OIIOUTILS_H + +#include +#include + +#include "codec/frame.h" +#include "render/videoparams.h" + +OLIVE_NAMESPACE_ENTER + +class OIIOUtils { +public: + static OIIO::TypeDesc::BASETYPE GetOIIOBaseTypeFromFormat(VideoParams::Format format) + { + switch (format) { + case VideoParams::kFormatUnsigned8: + return OIIO::TypeDesc::UINT8; + case VideoParams::kFormatUnsigned16: + return OIIO::TypeDesc::UINT16; + case VideoParams::kFormatFloat16: + return OIIO::TypeDesc::HALF; + case VideoParams::kFormatFloat32: + return OIIO::TypeDesc::FLOAT; + case VideoParams::kFormatInvalid: + case VideoParams::kFormatCount: + break; + } + + return OIIO::TypeDesc::UNKNOWN; + } + + static void FrameToBuffer(const Frame *frame, OIIO::ImageBuf* buf); + + static void BufferToFrame(OIIO::ImageBuf* buf, Frame* frame); + + static VideoParams::Format GetFormatFromOIIOBasetype(OIIO::TypeDesc::BASETYPE type); + + static rational GetPixelAspectRatioFromOIIO(const OIIO::ImageSpec& spec); + +}; + +OLIVE_NAMESPACE_EXIT + +#endif // OIIOUTILS_H diff --git a/app/config/config.cpp b/app/config/config.cpp index 2feb40578..3c818f084 100644 --- a/app/config/config.cpp +++ b/app/config/config.cpp @@ -116,11 +116,10 @@ void Config::SetDefaults() SetEntryInternal(QStringLiteral("DefaultSequenceInterlacing"), NodeParam::kInt, VideoParams::kInterlaceNone); SetEntryInternal(QStringLiteral("DefaultSequenceAudioFrequency"), NodeParam::kInt, 48000); SetEntryInternal(QStringLiteral("DefaultSequenceAudioLayout"), NodeParam::kInt, QVariant::fromValue(static_cast(AV_CH_LAYOUT_STEREO))); - SetEntryInternal(QStringLiteral("DefaultSequencePreviewFormat"), NodeParam::kInt, PixelFormat::PIX_FMT_RGBA16F); // Online/offline settings - SetEntryInternal(QStringLiteral("OnlinePixelFormat"), NodeParam::kInt, PixelFormat::PIX_FMT_RGBA32F); - SetEntryInternal(QStringLiteral("OfflinePixelFormat"), NodeParam::kInt, PixelFormat::PIX_FMT_RGBA16F); + SetEntryInternal(QStringLiteral("OnlinePixelFormat"), NodeParam::kInt, VideoParams::kFormatFloat32); + SetEntryInternal(QStringLiteral("OfflinePixelFormat"), NodeParam::kInt, VideoParams::kFormatFloat16); } void Config::Load() diff --git a/app/core.cpp b/app/core.cpp index b60591b88..5a7f179bf 100644 --- a/app/core.cpp +++ b/app/core.cpp @@ -51,7 +51,6 @@ #include "panel/viewer/viewer.h" #include "render/colormanager.h" #include "render/diskmanager.h" -#include "render/pixelformat.h" #include "render/rendermanager.h" #ifdef USE_OTIO #include "task/project/loadotio/loadotio.h" @@ -189,8 +188,6 @@ void Core::Stop() DiskManager::DestroyInstance(); - PixelFormat::DestroyInstance(); - NodeFactory::Destroy(); delete main_window_; @@ -646,9 +643,6 @@ void Core::StartGUI(bool full_screen) // Initialize disk service DiskManager::CreateInstance(); - // Initialize pixel service - PixelFormat::CreateInstance(); - // Connect the PanelFocusManager to the application's focus change signal connect(qApp, &QApplication::focusChanged, diff --git a/app/dialog/export/export.cpp b/app/dialog/export/export.cpp index c14aff1f3..ccc3df207 100644 --- a/app/dialog/export/export.cpp +++ b/app/dialog/export/export.cpp @@ -34,7 +34,6 @@ #include "dialog/task/task.h" #include "project/item/sequence/sequence.h" #include "project/project.h" -#include "render/pixelformat.h" #include "ui/icons/icons.h" OLIVE_NAMESPACE_ENTER @@ -179,7 +178,7 @@ ExportDialog::ExportDialog(ViewerOutput *viewer_node, QWidget *parent) : video_tab_->height_slider()->SetDefaultValue(viewer_node_->video_params().height()); video_tab_->frame_rate_combobox()->SetFrameRate(viewer_node_->video_params().time_base().flipped()); video_tab_->pixel_aspect_combobox()->SetPixelAspectRatio(viewer_node_->video_params().pixel_aspect_ratio()); - video_tab_->pixel_format_field()->SetPixelFormat(PixelFormat::instance()->GetConfiguredFormatForMode(RenderMode::kOnline)); + video_tab_->pixel_format_field()->SetPixelFormat(static_cast(Config::Current()["OnlinePixelFormat"].toInt())); video_tab_->interlaced_combobox()->SetInterlaceMode(viewer_node_->video_params().interlacing()); audio_tab_->sample_rate_combobox()->SetSampleRate(viewer_node_->audio_params().sample_rate()); audio_tab_->channel_layout_combobox()->SetChannelLayout(viewer_node_->audio_params().channel_layout()); @@ -432,13 +431,14 @@ ExportParams ExportDialog::GenerateParams() const static_cast(video_tab_->height_slider()->GetValue()), video_tab_->frame_rate_combobox()->GetFrameRate().flipped(), video_tab_->pixel_format_field()->GetPixelFormat(), + VideoParams::kInternalChannelCount, video_tab_->pixel_aspect_combobox()->GetPixelAspectRatio(), video_tab_->interlaced_combobox()->GetInterlaceMode(), 1); AudioParams audio_render_params(audio_tab_->sample_rate_combobox()->currentData().toInt(), audio_tab_->channel_layout_combobox()->GetChannelLayout(), - SampleFormat::kInternalFormat); + AudioParams::kInternalFormat); ExportParams params; params.SetFilename(filename_edit_->text()); diff --git a/app/dialog/sequence/sequence.cpp b/app/dialog/sequence/sequence.cpp index 3006c2b73..0df85621e 100644 --- a/app/dialog/sequence/sequence.cpp +++ b/app/dialog/sequence/sequence.cpp @@ -107,13 +107,14 @@ void SequenceDialog::accept() parameter_tab_->GetSelectedVideoHeight(), parameter_tab_->GetSelectedVideoFrameRate().flipped(), parameter_tab_->GetSelectedPreviewFormat(), + VideoParams::kInternalChannelCount, parameter_tab_->GetSelectedVideoPixelAspect(), parameter_tab_->GetSelectedVideoInterlacingMode(), parameter_tab_->GetSelectedPreviewResolution()); AudioParams audio_params = AudioParams(parameter_tab_->GetSelectedAudioSampleRate(), parameter_tab_->GetSelectedAudioChannelLayout(), - SampleFormat::kInternalFormat); + AudioParams::kInternalFormat); if (make_undoable_) { diff --git a/app/dialog/sequence/sequencedialogparametertab.cpp b/app/dialog/sequence/sequencedialogparametertab.cpp index cd744eefc..326df8b11 100644 --- a/app/dialog/sequence/sequencedialogparametertab.cpp +++ b/app/dialog/sequence/sequencedialogparametertab.cpp @@ -133,7 +133,8 @@ void SequenceDialogParameterTab::UpdatePreviewResolutionLabel() { VideoParams test_param(video_width_field_->GetValue(), video_height_field_->GetValue(), - PixelFormat::PIX_FMT_INVALID, + VideoParams::kFormatInvalid, + VideoParams::kInternalChannelCount, rational(1), VideoParams::kInterlaceNone, preview_resolution_field_->currentData().toInt()); diff --git a/app/dialog/sequence/sequencedialogparametertab.h b/app/dialog/sequence/sequencedialogparametertab.h index 794abe505..d2dabdea1 100644 --- a/app/dialog/sequence/sequencedialogparametertab.h +++ b/app/dialog/sequence/sequencedialogparametertab.h @@ -58,7 +58,7 @@ public: return preview_resolution_field_->GetDivider(); } - PixelFormat::Format GetSelectedPreviewFormat() const + VideoParams::Format GetSelectedPreviewFormat() const { return preview_format_field_->GetPixelFormat(); } diff --git a/app/dialog/sequence/sequencedialogpresettab.cpp b/app/dialog/sequence/sequencedialogpresettab.cpp index 18c9419db..1f25a29fb 100644 --- a/app/dialog/sequence/sequencedialogpresettab.cpp +++ b/app/dialog/sequence/sequencedialogpresettab.cpp @@ -30,6 +30,7 @@ #include #include "common/filefunctions.h" +#include "config/config.h" #include "node/input.h" #include "render/videoparams.h" #include "ui/icons/icons.h" @@ -41,8 +42,6 @@ const int kDataIsPreset = Qt::UserRole; const int kDataPresetIsCustomRole = Qt::UserRole + 1; const int kDataPresetDataRole = Qt::UserRole + 2; -const PixelFormat::Format kDefaultPreviewFormat = PixelFormat::PIX_FMT_RGBA16F; - SequenceDialogPresetTab::SequenceDialogPresetTab(QWidget* parent) : QWidget(parent), PresetManager(this, QStringLiteral("sequencepresets")) @@ -100,6 +99,7 @@ QTreeWidgetItem* SequenceDialogPresetTab::CreateFolder(const QString &name) QTreeWidgetItem *SequenceDialogPresetTab::CreateHDPresetFolder(const QString &name, int width, int height, int divider) { + VideoParams::Format default_format = static_cast(Config::Current()["OfflinePixelFormat"].toInt()); QTreeWidgetItem* parent = CreateFolder(name); AddStandardItem(parent, SequencePreset::Create(tr("%1 23.976 FPS").arg(name), width, @@ -110,7 +110,7 @@ QTreeWidgetItem *SequenceDialogPresetTab::CreateHDPresetFolder(const QString &na 48000, AV_CH_LAYOUT_STEREO, divider, - kDefaultPreviewFormat)); + default_format)); AddStandardItem(parent, SequencePreset::Create(tr("%1 25 FPS").arg(name), width, height, @@ -120,7 +120,7 @@ QTreeWidgetItem *SequenceDialogPresetTab::CreateHDPresetFolder(const QString &na 48000, AV_CH_LAYOUT_STEREO, divider, - kDefaultPreviewFormat)); + default_format)); AddStandardItem(parent, SequencePreset::Create(tr("%1 29.97 FPS").arg(name), width, height, @@ -130,7 +130,7 @@ QTreeWidgetItem *SequenceDialogPresetTab::CreateHDPresetFolder(const QString &na 48000, AV_CH_LAYOUT_STEREO, divider, - kDefaultPreviewFormat)); + default_format)); AddStandardItem(parent, SequencePreset::Create(tr("%1 50 FPS").arg(name), width, height, @@ -140,7 +140,7 @@ QTreeWidgetItem *SequenceDialogPresetTab::CreateHDPresetFolder(const QString &na 48000, AV_CH_LAYOUT_STEREO, divider, - kDefaultPreviewFormat)); + default_format)); AddStandardItem(parent, SequencePreset::Create(tr("%1 59.94 FPS").arg(name), width, height, @@ -150,12 +150,13 @@ QTreeWidgetItem *SequenceDialogPresetTab::CreateHDPresetFolder(const QString &na 48000, AV_CH_LAYOUT_STEREO, divider, - kDefaultPreviewFormat)); + default_format)); return parent; } QTreeWidgetItem *SequenceDialogPresetTab::CreateSDPresetFolder(const QString &name, int width, int height, const rational& frame_rate, const rational &standard_par, const rational &wide_par, int divider) { + VideoParams::Format default_format = static_cast(Config::Current()["OfflinePixelFormat"].toInt()); QTreeWidgetItem* parent = CreateFolder(name); preset_tree_->addTopLevelItem(parent); AddStandardItem(parent, SequencePreset::Create(tr("%1 Standard").arg(name), @@ -167,7 +168,7 @@ QTreeWidgetItem *SequenceDialogPresetTab::CreateSDPresetFolder(const QString &na 48000, AV_CH_LAYOUT_STEREO, divider, - kDefaultPreviewFormat)); + default_format)); AddStandardItem(parent, SequencePreset::Create(tr("%1 Widescreen").arg(name), width, height, @@ -177,7 +178,7 @@ QTreeWidgetItem *SequenceDialogPresetTab::CreateSDPresetFolder(const QString &na 48000, AV_CH_LAYOUT_STEREO, divider, - kDefaultPreviewFormat)); + default_format)); return parent; } diff --git a/app/dialog/sequence/sequencepreset.h b/app/dialog/sequence/sequencepreset.h index 6b134b8f1..59db546fd 100644 --- a/app/dialog/sequence/sequencepreset.h +++ b/app/dialog/sequence/sequencepreset.h @@ -26,7 +26,6 @@ #include "common/rational.h" #include "common/xmlutils.h" #include "dialog/sequence/presetmanager.h" -#include "render/pixelformat.h" #include "render/videoparams.h" OLIVE_NAMESPACE_ENTER @@ -44,7 +43,7 @@ public: int sample_rate, uint64_t channel_layout, int preview_divider, - PixelFormat::Format preview_format) : + VideoParams::Format preview_format) : width_(width), height_(height), frame_rate_(frame_rate), @@ -67,7 +66,7 @@ public: int sample_rate, uint64_t channel_layout, int preview_divider, - PixelFormat::Format preview_format) + VideoParams::Format preview_format) { return std::make_shared(name, width, height, frame_rate, pixel_aspect, interlacing, sample_rate, channel_layout, @@ -96,7 +95,7 @@ public: } else if (reader->name() == QStringLiteral("divider")) { preview_divider_ = reader->readElementText().toInt(); } else if (reader->name() == QStringLiteral("format")) { - preview_format_ = static_cast(reader->readElementText().toInt()); + preview_format_ = static_cast(reader->readElementText().toInt()); } else { reader->skipCurrentElement(); } @@ -157,7 +156,7 @@ public: return preview_divider_; } - PixelFormat::Format preview_format() const + VideoParams::Format preview_format() const { return preview_format_; } @@ -171,7 +170,7 @@ private: int sample_rate_; uint64_t channel_layout_; int preview_divider_; - PixelFormat::Format preview_format_; + VideoParams::Format preview_format_; }; diff --git a/app/node/input/media/video/video.cpp b/app/node/input/media/video/video.cpp index c02aeaf39..5507bc12c 100644 --- a/app/node/input/media/video/video.cpp +++ b/app/node/input/media/video/video.cpp @@ -27,7 +27,6 @@ #include "codec/ffmpeg/ffmpegdecoder.h" #include "core.h" #include "project/item/footage/footage.h" -#include "render/pixelformat.h" OLIVE_NAMESPACE_ENTER @@ -38,7 +37,7 @@ Node *VideoInput::copy() const Stream::Type VideoInput::type() const { - return Stream::kVideo; + return Stream::kVideo; } QString VideoInput::Name() const diff --git a/app/project/item/footage/videostream.cpp b/app/project/item/footage/videostream.cpp index d96f319c7..9a0094e4f 100644 --- a/app/project/item/footage/videostream.cpp +++ b/app/project/item/footage/videostream.cpp @@ -104,7 +104,9 @@ void VideoStream::LoadCustomParameters(QXmlStreamReader *reader) } else if (reader->name() == QStringLiteral("type")) { set_video_type(static_cast(reader->readElementText().toInt())); } else if (reader->name() == QStringLiteral("format")) { - set_format(static_cast(reader->readElementText().toInt())); + set_format(static_cast(reader->readElementText().toInt())); + } else if (reader->name() == QStringLiteral("channels")) { + set_channel_count(reader->readElementText().toInt()); } else if (reader->name() == QStringLiteral("pixelaspect")) { set_pixel_aspect_ratio(rational::fromString(reader->readElementText())); } else if (reader->name() == QStringLiteral("framerate")) { @@ -126,6 +128,7 @@ void VideoStream::SaveCustomParameters(QXmlStreamWriter *writer) const writer->writeTextElement(QStringLiteral("interlacing"), QString::number(interlacing_)); writer->writeTextElement(QStringLiteral("type"), QString::number(video_type_)); writer->writeTextElement(QStringLiteral("format"), QString::number(format_)); + writer->writeTextElement(QStringLiteral("channels"), QString::number(channel_count_)); writer->writeTextElement(QStringLiteral("pixelaspect"), pixel_aspect_ratio_.toString()); writer->writeTextElement(QStringLiteral("framerate"), frame_rate_.toString()); writer->writeTextElement(QStringLiteral("starttime"), QString::number(start_time_)); diff --git a/app/project/item/footage/videostream.h b/app/project/item/footage/videostream.h index aa91707a2..59fb8956c 100644 --- a/app/project/item/footage/videostream.h +++ b/app/project/item/footage/videostream.h @@ -21,7 +21,6 @@ #ifndef VIDEOSTREAM_H #define VIDEOSTREAM_H -#include "render/pixelformat.h" #include "render/videoparams.h" #include "stream.h" @@ -74,16 +73,26 @@ public: height_ = height; } - const PixelFormat::Format& format() const + const VideoParams::Format& format() const { return format_; } - void set_format(const PixelFormat::Format& format) + void set_format(const VideoParams::Format& format) { format_ = format; } + int channel_count() const + { + return channel_count_; + } + + void set_channel_count(int c) + { + channel_count_ = c; + } + bool premultiplied_alpha() const; void set_premultiplied_alpha(bool e); @@ -153,7 +162,9 @@ private: VideoType video_type_; - PixelFormat::Format format_; + VideoParams::Format format_; + + int channel_count_; rational pixel_aspect_ratio_; diff --git a/app/project/item/sequence/sequence.cpp b/app/project/item/sequence/sequence.cpp index 91042e555..8b7c4d534 100644 --- a/app/project/item/sequence/sequence.cpp +++ b/app/project/item/sequence/sequence.cpp @@ -70,7 +70,7 @@ void Sequence::Load(QXmlStreamReader *reader, XMLNodeData& xml_node_data, const int video_width = 0, video_height = 0, preview_div = 1; rational video_timebase, video_pixel_aspect; VideoParams::Interlacing video_interlacing = VideoParams::kInterlaceNone; - PixelFormat::Format preview_format = PixelFormat::PIX_FMT_INVALID; + VideoParams::Format preview_format = VideoParams::kFormatInvalid; while (XMLReadNextStartElement(reader)) { if (cancelled && *cancelled) { @@ -86,7 +86,7 @@ void Sequence::Load(QXmlStreamReader *reader, XMLNodeData& xml_node_data, const } else if (reader->name() == QStringLiteral("divider")) { preview_div = reader->readElementText().toInt(); } else if (reader->name() == QStringLiteral("format")) { - preview_format = static_cast(reader->readElementText().toInt()); + preview_format = static_cast(reader->readElementText().toInt()); } else if (reader->name() == QStringLiteral("pixelaspect")) { video_pixel_aspect = rational::fromString(reader->readElementText()); } else if (reader->name() == QStringLiteral("interlacing")) { @@ -97,11 +97,12 @@ void Sequence::Load(QXmlStreamReader *reader, XMLNodeData& xml_node_data, const } set_video_params(VideoParams(video_width, video_height, video_timebase, preview_format, - video_pixel_aspect, video_interlacing, preview_div)); + VideoParams::kInternalChannelCount, video_pixel_aspect, + video_interlacing, preview_div)); } else if (reader->name() == QStringLiteral("audio")) { int rate = 0; uint64_t layout = 0; - SampleFormat::Format format = SampleFormat::SAMPLE_FMT_INVALID; + AudioParams::Format format = AudioParams::kFormatInvalid; while (XMLReadNextStartElement(reader)) { if (reader->name() == QStringLiteral("rate")) { @@ -109,7 +110,7 @@ void Sequence::Load(QXmlStreamReader *reader, XMLNodeData& xml_node_data, const } else if (reader->name() == QStringLiteral("layout")) { layout = reader->readElementText().toULongLong(); } else if (reader->name() == QStringLiteral("format")) { - format = static_cast(reader->readElementText().toInt()); + format = static_cast(reader->readElementText().toInt()); } else { reader->skipCurrentElement(); } @@ -268,13 +269,14 @@ void Sequence::set_default_parameters() set_video_params(VideoParams(width, height, Config::Current()["DefaultSequenceFrameRate"].value(), - static_cast(Config::Current()["DefaultSequencePreviewFormat"].toInt()), + static_cast(Config::Current()["OfflinePixelFormat"].toInt()), + VideoParams::kInternalChannelCount, Config::Current()["DefaultSequencePixelAspect"].value(), Config::Current()["DefaultSequenceInterlacing"].value(), VideoParams::generate_auto_divider(width, height))); set_audio_params(AudioParams(Config::Current()["DefaultSequenceAudioFrequency"].toInt(), Config::Current()["DefaultSequenceAudioLayout"].toULongLong(), - SampleFormat::kInternalFormat)); + AudioParams::kInternalFormat)); } void Sequence::set_parameters_from_footage(const QList footage) @@ -310,7 +312,8 @@ void Sequence::set_parameters_from_footage(const QList footage) set_video_params(VideoParams(vs->width(), vs->height(), using_timebase, - static_cast(Config::Current()["DefaultSequencePreviewFormat"].toInt()), + static_cast(Config::Current()["OfflinePixelFormat"].toInt()), + VideoParams::kInternalChannelCount, vs->pixel_aspect_ratio(), vs->interlacing(), VideoParams::generate_auto_divider(vs->width(), vs->height()))); @@ -320,7 +323,7 @@ void Sequence::set_parameters_from_footage(const QList footage) case Stream::kAudio: if (!found_audio_params) { AudioStream* as = static_cast(s.get()); - set_audio_params(AudioParams(as->sample_rate(), as->channel_layout(), SampleFormat::kInternalFormat)); + set_audio_params(AudioParams(as->sample_rate(), as->channel_layout(), AudioParams::kInternalFormat)); found_audio_params = true; } break; diff --git a/app/render/CMakeLists.txt b/app/render/CMakeLists.txt index abb4bda59..7f0bae3c7 100644 --- a/app/render/CMakeLists.txt +++ b/app/render/CMakeLists.txt @@ -37,8 +37,6 @@ set(OLIVE_SOURCES render/framehashcache.h render/managedcolor.cpp render/managedcolor.h - render/pixelformat.cpp - render/pixelformat.h render/playbackcache.cpp render/playbackcache.h render/previewautocacher.cpp diff --git a/app/render/audioparams.cpp b/app/render/audioparams.cpp index 9fb1ec2e1..5ea10389e 100644 --- a/app/render/audioparams.cpp +++ b/app/render/audioparams.cpp @@ -49,6 +49,8 @@ const QVector AudioParams::kSupportedChannelLayouts = { AV_CH_LAYOUT_7POINT1 }; +const AudioParams::Format AudioParams::kInternalFormat = AudioParams::kFormatFloat32; + qint64 AudioParams::time_to_bytes(const double &time) const { Q_ASSERT(is_valid()); @@ -68,6 +70,26 @@ bool AudioParams::operator!=(const AudioParams &other) const return !(*this == other); } +QAudioFormat::SampleType AudioParams::GetQtSampleType(AudioParams::Format format) +{ + switch (format) { + case kFormatUnsigned8: + return QAudioFormat::UnSignedInt; + case kFormatSigned16: + case kFormatSigned32: + case kFormatSigned64: + return QAudioFormat::SignedInt; + case kFormatFloat32: + case kFormatFloat64: + return QAudioFormat::Float; + case kFormatInvalid: + case kFormatCount: + break; + } + + return QAudioFormat::Unknown; +} + qint64 AudioParams::time_to_bytes(const rational &time) const { return time_to_bytes(time.toDouble()); @@ -119,18 +141,18 @@ int AudioParams::channel_count() const int AudioParams::bytes_per_sample_per_channel() const { switch (format_) { - case SampleFormat::SAMPLE_FMT_U8: + case kFormatUnsigned8: return 1; - case SampleFormat::SAMPLE_FMT_S16: + case kFormatSigned16: return 2; - case SampleFormat::SAMPLE_FMT_S32: - case SampleFormat::SAMPLE_FMT_FLT: + case kFormatSigned32: + case kFormatFloat32: return 4; - case SampleFormat::SAMPLE_FMT_DBL: - case SampleFormat::SAMPLE_FMT_S64: + case kFormatSigned64: + case kFormatFloat64: return 8; - case SampleFormat::SAMPLE_FMT_INVALID: - case SampleFormat::SAMPLE_FMT_COUNT: + case kFormatInvalid: + case kFormatCount: break; } @@ -146,8 +168,8 @@ bool AudioParams::is_valid() const { return (sample_rate() > 0 && channel_layout() > 0 - && format_ != SampleFormat::SAMPLE_FMT_INVALID - && format_ != SampleFormat::SAMPLE_FMT_COUNT); + && format_ > kFormatInvalid + && format_ < kFormatCount); } QString AudioParams::SampleRateToString(const int &sample_rate) diff --git a/app/render/audioparams.h b/app/render/audioparams.h index 521218e0e..db9c0aa86 100644 --- a/app/render/audioparams.h +++ b/app/render/audioparams.h @@ -21,23 +21,51 @@ #ifndef AUDIOPARAMS_H #define AUDIOPARAMS_H +#include #include -#include "audio/sampleformat.h" #include "common/rational.h" OLIVE_NAMESPACE_ENTER class AudioParams { public: + enum Format { + /// Invalid + kFormatInvalid = -1, + + /// 8-bit unsigned integer + kFormatUnsigned8, + + /// 16-bit signed integer + kFormatSigned16, + + /// 32-bit signed integer + kFormatSigned32, + + /// 64-bit signed integer + kFormatSigned64, + + /// 32-bit float + kFormatFloat32, + + /// 64-bit float + kFormatFloat64, + + /// Total format count + kFormatCount + }; + + static const Format kInternalFormat; + AudioParams() : sample_rate_(0), channel_layout_(0), - format_(SampleFormat::SAMPLE_FMT_INVALID) + format_(kFormatInvalid) { } - AudioParams(const int& sample_rate, const uint64_t& channel_layout, const SampleFormat::Format& format) : + AudioParams(const int& sample_rate, const uint64_t& channel_layout, const Format& format) : sample_rate_(sample_rate), channel_layout_(channel_layout), format_(format) @@ -59,7 +87,7 @@ public: return rational(1, sample_rate()); } - const SampleFormat::Format &format() const + const Format &format() const { return format_; } @@ -80,6 +108,8 @@ public: bool operator==(const AudioParams& other) const; bool operator!=(const AudioParams& other) const; + static QAudioFormat::SampleType GetQtSampleType(Format format); + static const QVector kSupportedChannelLayouts; static const QVector kSupportedSampleRates; @@ -98,7 +128,7 @@ private: uint64_t channel_layout_; - SampleFormat::Format format_; + Format format_; }; diff --git a/app/render/color.cpp b/app/render/color.cpp index 67151413e..55181d83f 100644 --- a/app/render/color.cpp +++ b/app/render/color.cpp @@ -20,7 +20,10 @@ #include "color.h" +#include + #include "common/clamp.h" +#include "common/oiioutils.h" OLIVE_NAMESPACE_ENTER @@ -65,9 +68,9 @@ Color Color::fromHsv(const double &h, const double &s, const double &v) return Color(Rs + m, Gs + m, Bs + m); } -Color::Color(const char *data, const PixelFormat::Format &format) +Color::Color(const char *data, const VideoParams::Format &format, int ch_layout) { - *this = fromData(data, format); + *this = fromData(data, format, ch_layout); } Color::Color(const QColor &c) @@ -194,24 +197,24 @@ double Color::lightness() const return l; } -void Color::toData(char *data, const PixelFormat::Format &format) const +void Color::toData(char *data, const VideoParams::Format &format, int ch_layout) const { - OIIO::convert_types(OIIO::TypeDesc::DOUBLE, - data_, - PixelFormat::GetOIIOTypeDesc(format), - data, - kRGBAChannels); + OIIO::convert_pixel_values(OIIO::TypeDesc::DOUBLE, + data_, + OIIOUtils::GetOIIOBaseTypeFromFormat(format), + data, + ch_layout); } -Color Color::fromData(const char *data, const PixelFormat::Format &format) +Color Color::fromData(const char *data, const VideoParams::Format &format, int ch_layout) { Color c; - OIIO::convert_types(PixelFormat::GetOIIOTypeDesc(format), - data, - OIIO::TypeDesc::DOUBLE, - c.data_, - kRGBAChannels); + OIIO::convert_pixel_values(OIIOUtils::GetOIIOBaseTypeFromFormat(format), + data, + OIIO::TypeDesc::DOUBLE, + c.data_, + ch_layout); return c; } @@ -236,7 +239,7 @@ double Color::GetRoughLuminance() const const Color &Color::operator+=(const Color &rhs) { - for (int i=0;i #include "common/define.h" -#include "render/pixelformat.h" +#include "render/videoparams.h" OLIVE_NAMESPACE_ENTER @@ -37,7 +37,7 @@ class Color public: Color() { - for (int i=0;iwidth() * f->height() * kRGBAChannels; - - switch (static_cast(f->format())) { - case PixelFormat::PIX_FMT_INVALID: - case PixelFormat::PIX_FMT_COUNT: - qWarning() << "Alpha association functions received an invalid pixel format"; - break; - case PixelFormat::PIX_FMT_RGBA8: - case PixelFormat::PIX_FMT_RGBA16U: - qWarning() << "Alpha association functions only works on float-based pixel formats at this time"; - break; - case PixelFormat::PIX_FMT_RGBA16F: - { - AssociateAlphaInternal(action, reinterpret_cast(f->data()), pixel_count); - break; - } - case PixelFormat::PIX_FMT_RGBA32F: - { - AssociateAlphaInternal(action, reinterpret_cast(f->data()), pixel_count); - break; - } - } -} - -template -void ColorManager::AssociateAlphaInternal(ColorManager::AlphaAction action, T *data, int pix_count) -{ - for (int i=0;i 0) { - for (int j=0;j - static void AssociateAlphaInternal(AlphaAction action, T* data, int pix_count); - QString config_filename_; QString default_input_color_space_; diff --git a/app/render/colorprocessor.cpp b/app/render/colorprocessor.cpp index 6ea08ff41..cc249c977 100644 --- a/app/render/colorprocessor.cpp +++ b/app/render/colorprocessor.cpp @@ -21,6 +21,7 @@ #include "colorprocessor.h" #include "common/define.h" +#include "common/ocioutils.h" #include "colormanager.h" OLIVE_NAMESPACE_ENTER @@ -77,7 +78,7 @@ ColorProcessor::ColorProcessor(ColorManager *config, const QString &input, const void ColorProcessor::ConvertFrame(Frame *f) { - OCIO::BitDepth ocio_bit_depth = PixelFormat::GetOCIOBitDepthFromPixelFormat(f->format()); + OCIO::BitDepth ocio_bit_depth = OCIOUtils::GetOCIOBitDepthFromPixelFormat(f->format()); if (ocio_bit_depth == OCIO::BIT_DEPTH_UNKNOWN) { qCritical() << "Tried to color convert frame with no format"; @@ -87,7 +88,7 @@ void ColorProcessor::ConvertFrame(Frame *f) OCIO::PackedImageDesc img(f->data(), f->width(), f->height(), - kRGBAChannels, + VideoParams::kRGBAChannelCount, ocio_bit_depth, OCIO::AutoStride, OCIO::AutoStride, diff --git a/app/render/framehashcache.cpp b/app/render/framehashcache.cpp index d555d2a38..d88e407f2 100644 --- a/app/render/framehashcache.cpp +++ b/app/render/framehashcache.cpp @@ -243,24 +243,27 @@ FramePtr FrameHashCache::LoadCacheFrame(const QString &fn) int height = dw.max.y - dw.min.y + 1; bool has_alpha = file.header().channels().findChannel("A"); - PixelFormat::Format image_format; + VideoParams::Format image_format; if (pix_type == Imf::HALF) { - image_format = PixelFormat::PIX_FMT_RGBA16F; + image_format = VideoParams::kFormatFloat16; } else { - image_format = PixelFormat::PIX_FMT_RGBA32F; + image_format = VideoParams::kFormatFloat32; } + int channel_count = has_alpha ? VideoParams::kRGBAChannelCount : VideoParams::kRGBChannelCount; + frame = Frame::Create(); frame->set_video_params(VideoParams(width, height, image_format, + channel_count, rational::fromDouble(file.header().pixelAspectRatio()))); frame->allocate(); - int bpc = PixelFormat::BytesPerChannel(image_format); + int bpc = VideoParams::GetBytesPerChannel(image_format); - size_t xs = kRGBAChannels * bpc; + size_t xs = channel_count * bpc; size_t ys = frame->linesize_bytes(); Imf::FrameBuffer framebuffer; @@ -398,12 +401,15 @@ QString FrameHashCache::CachePathName(const QString &cache_path, const QByteArra bool FrameHashCache::SaveCacheFrame(const QString &filename, char *data, const VideoParams &vparam, int linesize_bytes) const { - Q_ASSERT(PixelFormat::FormatIsFloat(vparam.format())); + if (!VideoParams::FormatIsFloat(vparam.format())) { + qCritical() << "Tried to cache frame with non-float pixel format"; + return false; + } // Floating point types are stored in EXR Imf::PixelType pix_type; - if (vparam.format() == PixelFormat::PIX_FMT_RGBA16F) { + if (vparam.format() == VideoParams::kFormatFloat16) { pix_type = Imf::HALF; } else { pix_type = Imf::FLOAT; @@ -414,7 +420,9 @@ bool FrameHashCache::SaveCacheFrame(const QString &filename, char *data, const V header.channels().insert("R", Imf::Channel(pix_type)); header.channels().insert("G", Imf::Channel(pix_type)); header.channels().insert("B", Imf::Channel(pix_type)); - header.channels().insert("A", Imf::Channel(pix_type)); + if (vparam.channel_count() == VideoParams::kRGBAChannelCount) { + header.channels().insert("A", Imf::Channel(pix_type)); + } header.compression() = Imf::DWAA_COMPRESSION; header.insert("dwaCompressionLevel", Imf::FloatAttribute(200.0f)); @@ -422,16 +430,18 @@ bool FrameHashCache::SaveCacheFrame(const QString &filename, char *data, const V Imf::OutputFile out(filename.toUtf8(), header, 0); - int bpc = PixelFormat::BytesPerChannel(vparam.format()); + int bpc = VideoParams::GetBytesPerChannel(vparam.format()); - size_t xs = kRGBAChannels * bpc; + size_t xs = vparam.channel_count() * bpc; size_t ys = linesize_bytes; Imf::FrameBuffer framebuffer; framebuffer.insert("R", Imf::Slice(pix_type, data, xs, ys)); framebuffer.insert("G", Imf::Slice(pix_type, data + bpc, xs, ys)); framebuffer.insert("B", Imf::Slice(pix_type, data + 2*bpc, xs, ys)); - framebuffer.insert("A", Imf::Slice(pix_type, data + 3*bpc, xs, ys)); + if (vparam.channel_count() == VideoParams::kRGBAChannelCount) { + framebuffer.insert("A", Imf::Slice(pix_type, data + 3*bpc, xs, ys)); + } out.setFrameBuffer(framebuffer); out.writePixels(vparam.effective_height()); diff --git a/app/render/framehashcache.h b/app/render/framehashcache.h index 1d8360043..17009dabf 100644 --- a/app/render/framehashcache.h +++ b/app/render/framehashcache.h @@ -25,7 +25,7 @@ #include "common/rational.h" #include "common/timerange.h" -#include "render/pixelformat.h" +#include "codec/frame.h" #include "render/playbackcache.h" #include "render/videoparams.h" diff --git a/app/render/managedcolor.cpp b/app/render/managedcolor.cpp index f4d86e197..042478cf2 100644 --- a/app/render/managedcolor.cpp +++ b/app/render/managedcolor.cpp @@ -26,13 +26,13 @@ ManagedColor::ManagedColor() { } -ManagedColor::ManagedColor(const float &r, const float &g, const float &b, const float &a) : +ManagedColor::ManagedColor(const double &r, const double &g, const double &b, const double &a) : Color(r, g, b, a) { } -ManagedColor::ManagedColor(const char *data, const PixelFormat::Format &format) : - Color(data, format) +ManagedColor::ManagedColor(const char *data, const VideoParams::Format &format, int channel_layout) : + Color(data, format, channel_layout) { } diff --git a/app/render/managedcolor.h b/app/render/managedcolor.h index c214f57b4..707218903 100644 --- a/app/render/managedcolor.h +++ b/app/render/managedcolor.h @@ -30,8 +30,8 @@ class ManagedColor : public Color { public: ManagedColor(); - ManagedColor(const float& r, const float& g, const float& b, const float& a = 1.0f); - ManagedColor(const char *data, const PixelFormat::Format &format); + ManagedColor(const double& r, const double& g, const double& b, const double& a = 1.0); + ManagedColor(const char *data, const VideoParams::Format &format, int channel_layout); ManagedColor(const Color& c); const QString& color_input() const; diff --git a/app/render/opengl/openglrenderer.cpp b/app/render/opengl/openglrenderer.cpp index e6e304099..8020affe9 100644 --- a/app/render/opengl/openglrenderer.cpp +++ b/app/render/opengl/openglrenderer.cpp @@ -21,7 +21,7 @@ #include "openglrenderer.h" #include -#include +#include OLIVE_NAMESPACE_ENTER @@ -128,7 +128,7 @@ void OpenGLRenderer::ClearDestination(double r, double g, double b, double a) functions_->glClear(GL_COLOR_BUFFER_BIT); } -QVariant OpenGLRenderer::CreateNativeTexture2D(int width, int height, PixelFormat::Format format, Texture::ChannelFormat channel_format, const void *data, int linesize) +QVariant OpenGLRenderer::CreateNativeTexture2D(int width, int height, VideoParams::Format format, int channel_count, const void *data, int linesize) { GLuint texture; functions_->glGenTextures(1, &texture); @@ -140,8 +140,8 @@ QVariant OpenGLRenderer::CreateNativeTexture2D(int width, int height, PixelForma functions_->glBindTexture(GL_TEXTURE_2D, texture); - functions_->glTexImage2D(GL_TEXTURE_2D, 0, GetInternalFormat(format, channel_format), - width, height, 0, GetPixelFormat(channel_format), + functions_->glTexImage2D(GL_TEXTURE_2D, 0, GetInternalFormat(format, channel_count), + width, height, 0, GetPixelFormat(channel_count), GetPixelType(format), data); functions_->glPixelStorei(GL_UNPACK_ROW_LENGTH, 0); @@ -151,7 +151,7 @@ QVariant OpenGLRenderer::CreateNativeTexture2D(int width, int height, PixelForma return texture; } -QVariant OpenGLRenderer::CreateNativeTexture3D(int width, int height, int depth, PixelFormat::Format format, Texture::ChannelFormat channel_format, const void *data, int linesize) +QVariant OpenGLRenderer::CreateNativeTexture3D(int width, int height, int depth, VideoParams::Format format, int channel_count, const void *data, int linesize) { GLuint texture; functions_->glGenTextures(1, &texture); @@ -163,8 +163,8 @@ QVariant OpenGLRenderer::CreateNativeTexture3D(int width, int height, int depth, functions_->glBindTexture(GL_TEXTURE_3D, texture); - context_->extraFunctions()->glTexImage3D(GL_TEXTURE_3D, 0, GetInternalFormat(format, channel_format), - width, height, depth, 0, GetPixelFormat(channel_format), + context_->extraFunctions()->glTexImage3D(GL_TEXTURE_3D, 0, GetInternalFormat(format, channel_count), + width, height, depth, 0, GetPixelFormat(channel_count), GetPixelType(format), data); functions_->glPixelStorei(GL_UNPACK_ROW_LENGTH, 0); @@ -241,7 +241,7 @@ void OpenGLRenderer::UploadToTexture(Texture *texture, const void *data, int lin functions_->glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, p.effective_width(), p.effective_height(), - GL_RGBA, GetPixelType(p.format()), + GetPixelFormat(p.channel_count()), GetPixelType(p.format()), data); functions_->glPixelStorei(GL_UNPACK_ROW_LENGTH, 0); @@ -264,7 +264,7 @@ void OpenGLRenderer::DownloadFromTexture(Texture* texture, void *data, int lines 0, p.width(), p.height(), - GL_RGBA, + GetPixelFormat(p.channel_count()), GetPixelType(p.format()), data); @@ -360,7 +360,7 @@ void OpenGLRenderer::Blit(QVariant s, ShaderJob job, Texture *destination, Video GLuint tex_id = texture ? texture->id().value() : 0; textures_to_bind.append({texture, job.GetInterpolation(it.key())}); - if (texture && texture->has_meaningful_alpha()) { + if (texture && texture->channel_count() == VideoParams::kRGBAChannelCount) { input_textures_have_alpha = true; } @@ -440,6 +440,13 @@ void OpenGLRenderer::Blit(QVariant s, ShaderJob job, Texture *destination, Video destination_params.effective_width(), destination_params.effective_height()); + // Set whether our destination texture needs an alpha channel + if (input_textures_have_alpha || job.GetAlphaChannelRequired()) { + destination_params.set_channel_count(VideoParams::kRGBAChannelCount); + } else { + destination_params.set_channel_count(VideoParams::kRGBChannelCount); + } + // Bind vertex array object QOpenGLVertexArrayObject vao_; vao_.create(); @@ -533,9 +540,6 @@ void OpenGLRenderer::Blit(QVariant s, ShaderJob job, Texture *destination, Video if (destination) { // Reset framebuffer to default if we were drawing to a texture DetachTextureAsDestination(); - - // Set metadata for whether this texture has a meaningful alpha channel - destination->set_has_meaningful_alpha((input_textures_have_alpha || job.GetAlphaChannelRequired())); } // Release any textures we bound before @@ -555,58 +559,97 @@ void OpenGLRenderer::Blit(QVariant s, ShaderJob job, Texture *destination, Video vao_.destroy(); } -GLint OpenGLRenderer::GetInternalFormat(PixelFormat::Format format, bool with_alpha) +GLint OpenGLRenderer::GetInternalFormat(VideoParams::Format format, int channel_layout) { switch (format) { - case PixelFormat::PIX_FMT_RGBA8: - return with_alpha ? GL_RGBA8 : GL_RGB8; - case PixelFormat::PIX_FMT_RGBA16U: - return with_alpha ? GL_RGBA16 : GL_RGB16; - case PixelFormat::PIX_FMT_RGBA16F: - return with_alpha ? GL_RGBA16F : GL_RGB16F; - case PixelFormat::PIX_FMT_RGBA32F: - return with_alpha ? GL_RGBA32F : GL_RGB32F; - - case PixelFormat::PIX_FMT_INVALID: - case PixelFormat::PIX_FMT_COUNT: + case VideoParams::kFormatUnsigned8: + switch (channel_layout) { + case 1: + return GL_R8; + case 2: + return GL_RG8; + case 3: + return GL_RGB8; + case 4: + return GL_RGBA8; + } + break; + case VideoParams::kFormatUnsigned16: + switch (channel_layout) { + case 1: + return GL_R16; + case 2: + return GL_RG16; + case 3: + return GL_RGB16; + case 4: + return GL_RGBA16; + } + break; + case VideoParams::kFormatFloat16: + switch (channel_layout) { + case 1: + return GL_R16F; + case 2: + return GL_RG16F; + case 3: + return GL_RGB16F; + case 4: + return GL_RGBA16F; + } + break; + case VideoParams::kFormatFloat32: + switch (channel_layout) { + case 1: + return GL_R32F; + case 2: + return GL_RG32F; + case 3: + return GL_RGB32F; + case 4: + return GL_RGBA32F; + } + break; + case VideoParams::kFormatInvalid: + case VideoParams::kFormatCount: break; } return GL_INVALID_VALUE; } -GLenum OpenGLRenderer::GetPixelType(PixelFormat::Format format) +GLenum OpenGLRenderer::GetPixelType(VideoParams::Format format) { switch (format) { - case PixelFormat::PIX_FMT_RGBA8: + case VideoParams::kFormatUnsigned8: return GL_UNSIGNED_BYTE; - case PixelFormat::PIX_FMT_RGBA16U: + case VideoParams::kFormatUnsigned16: return GL_UNSIGNED_SHORT; - case PixelFormat::PIX_FMT_RGBA16F: + case VideoParams::kFormatFloat16: return GL_HALF_FLOAT; - case PixelFormat::PIX_FMT_RGBA32F: + case VideoParams::kFormatFloat32: return GL_FLOAT; - case PixelFormat::PIX_FMT_INVALID: - case PixelFormat::PIX_FMT_COUNT: + case VideoParams::kFormatInvalid: + case VideoParams::kFormatCount: break; } return GL_INVALID_VALUE; } -GLenum OpenGLRenderer::GetPixelFormat(Texture::ChannelFormat format) +GLenum OpenGLRenderer::GetPixelFormat(int channel_count) { - switch (format) { - case Texture::kRGBA: - return GL_RGBA; - case Texture::kRGB: - return GL_RGB; - case Texture::kRedOnly: + switch (channel_count) { + case 1: return GL_RED; + case 3: + return GL_RGB; + case 4: + return GL_RGBA; + default: + return GL_INVALID_VALUE; } - - return GL_INVALID_ENUM; } void OpenGLRenderer::PrepareInputTexture(GLenum target, Texture::Interpolation interp) diff --git a/app/render/opengl/openglrenderer.h b/app/render/opengl/openglrenderer.h index ce1f5d795..d212a111a 100644 --- a/app/render/opengl/openglrenderer.h +++ b/app/render/opengl/openglrenderer.h @@ -51,8 +51,8 @@ public slots: virtual void ClearDestination(double r = 0.0, double g = 0.0, double b = 0.0, double a = 0.0) override; - virtual QVariant CreateNativeTexture2D(int width, int height, OLIVE_NAMESPACE::PixelFormat::Format format, OLIVE_NAMESPACE::Texture::ChannelFormat channel_format, const void* data = nullptr, int linesize = 0) override; - virtual QVariant CreateNativeTexture3D(int width, int height, int depth, OLIVE_NAMESPACE::PixelFormat::Format format, OLIVE_NAMESPACE::Texture::ChannelFormat channel_format, const void* data = nullptr, int linesize = 0) override; + virtual QVariant CreateNativeTexture2D(int width, int height, OLIVE_NAMESPACE::VideoParams::Format format, int channel_count, const void* data = nullptr, int linesize = 0) override; + virtual QVariant CreateNativeTexture3D(int width, int height, int depth, OLIVE_NAMESPACE::VideoParams::Format format, int channel_count, const void* data = nullptr, int linesize = 0) override; virtual void DestroyNativeTexture(QVariant texture) override; @@ -71,11 +71,11 @@ protected slots: OLIVE_NAMESPACE::VideoParams destination_params) override; private: - static GLint GetInternalFormat(PixelFormat::Format format, bool with_alpha); + static GLint GetInternalFormat(VideoParams::Format format, int channel_layout); - static GLenum GetPixelType(PixelFormat::Format format); + static GLenum GetPixelType(VideoParams::Format format); - static GLenum GetPixelFormat(Texture::ChannelFormat format); + static GLenum GetPixelFormat(int channel_count); void AttachTextureAsDestination(OLIVE_NAMESPACE::Texture* texture); diff --git a/app/render/pixelformat.cpp b/app/render/pixelformat.cpp deleted file mode 100644 index 92c0ebd46..000000000 --- a/app/render/pixelformat.cpp +++ /dev/null @@ -1,230 +0,0 @@ -/*** - - Olive - Non-Linear Video Editor - Copyright (C) 2019 Olive Team - - This program is free software: you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program. If not, see . - -***/ - -#include "pixelformat.h" - -#include "OpenImageIO/imagebuf.h" -#include -#include -#include - -#include "codec/oiio/oiiocommon.h" -#include "common/define.h" -#include "core.h" - -OLIVE_NAMESPACE_ENTER - -bool PixelFormat::FormatIsFloat(const PixelFormat::Format &format) -{ - switch (format) { - case PixelFormat::PIX_FMT_RGBA16F: - case PixelFormat::PIX_FMT_RGBA32F: - return true; - - case PixelFormat::PIX_FMT_RGBA8: - case PixelFormat::PIX_FMT_RGBA16U: - case PixelFormat::PIX_FMT_INVALID: - case PixelFormat::PIX_FMT_COUNT: - break; - } - - return false; -} - -OIIO::TypeDesc::BASETYPE PixelFormat::GetOIIOTypeDesc(const PixelFormat::Format &format) -{ - switch (format) { - case PixelFormat::PIX_FMT_RGBA8: - return OIIO::TypeDesc::UINT8; - case PixelFormat::PIX_FMT_RGBA16U: - return OIIO::TypeDesc::UINT16; - case PixelFormat::PIX_FMT_RGBA16F: - return OIIO::TypeDesc::HALF; - case PixelFormat::PIX_FMT_RGBA32F: - return OIIO::TypeDesc::FLOAT; - case PixelFormat::PIX_FMT_INVALID: - case PixelFormat::PIX_FMT_COUNT: - break; - } - - return OIIO::TypeDesc::UNKNOWN; -} - -QString PixelFormat::GetName(const PixelFormat::Format &format) -{ - switch (format) { - case PixelFormat::PIX_FMT_RGBA8: - return tr("8-bit"); - case PixelFormat::PIX_FMT_RGBA16U: - return tr("16-bit Integer"); - case PixelFormat::PIX_FMT_RGBA16F: - return tr("Half-Float (16-bit)"); - case PixelFormat::PIX_FMT_RGBA32F: - return tr("Full-Float (32-bit)"); - case PixelFormat::PIX_FMT_INVALID: - case PixelFormat::PIX_FMT_COUNT: - break; - } - - return tr("Unknown (%1)").arg(format); -} - -OCIO::BitDepth PixelFormat::GetOCIOBitDepthFromPixelFormat(PixelFormat::Format format) -{ - switch (format) { - case PixelFormat::PIX_FMT_RGBA8: - return OCIO::BIT_DEPTH_UINT8; - case PixelFormat::PIX_FMT_RGBA16U: - return OCIO::BIT_DEPTH_UINT16; - break; - case PixelFormat::PIX_FMT_RGBA16F: - return OCIO::BIT_DEPTH_F16; - break; - case PixelFormat::PIX_FMT_RGBA32F: - return OCIO::BIT_DEPTH_F32; - break; - case PixelFormat::PIX_FMT_INVALID: - case PixelFormat::PIX_FMT_COUNT: - break; - } - - return OCIO::BIT_DEPTH_UNKNOWN; -} - -PixelFormat* PixelFormat::instance_ = nullptr; - -void PixelFormat::CreateInstance() -{ - instance_ = new PixelFormat(); -} - -void PixelFormat::DestroyInstance() -{ - delete instance_; -} - -PixelFormat *PixelFormat::instance() -{ - return instance_; -} - -PixelFormat::Format PixelFormat::GetConfiguredFormatForMode(RenderMode::Mode mode) -{ - return static_cast( - Core::GetPreferenceForRenderMode(mode, QStringLiteral("PixelFormat")).toInt()); -} - -void PixelFormat::SetConfiguredFormatForMode(RenderMode::Mode mode, PixelFormat::Format format) -{ - if (format != GetConfiguredFormatForMode(mode)) { - Core::SetPreferenceForRenderMode(mode, QStringLiteral("PixelFormat"), format); - - emit FormatChanged(); - } -} - -PixelFormat::Format PixelFormat::OIIOFormatToOliveFormat(OIIO::TypeDesc desc) -{ - if (desc == OIIO::TypeDesc::UINT8) { - return PixelFormat::PIX_FMT_RGBA8; - } else if (desc == OIIO::TypeDesc::UINT16) { - return PixelFormat::PIX_FMT_RGBA16U; - } else if (desc == OIIO::TypeDesc::HALF) { - return PixelFormat::PIX_FMT_RGBA16F; - } else if (desc == OIIO::TypeDesc::FLOAT) { - return PixelFormat::PIX_FMT_RGBA32F; - } - - return PixelFormat::PIX_FMT_INVALID; -} - -int PixelFormat::GetBufferSize(const PixelFormat::Format &format, const int &width, const int &height) -{ - return BytesPerPixel(format) * width * height; -} - -int PixelFormat::BytesPerPixel(const PixelFormat::Format &format) -{ - return BytesPerChannel(format) * kRGBAChannels; -} - -int PixelFormat::BytesPerChannel(const PixelFormat::Format &format) -{ - switch (format) { - case PixelFormat::PIX_FMT_RGBA8: - return 1; - case PixelFormat::PIX_FMT_RGBA16U: - case PixelFormat::PIX_FMT_RGBA16F: - return 2; - case PixelFormat::PIX_FMT_RGBA32F: - return 4; - case PixelFormat::PIX_FMT_INVALID: - case PixelFormat::PIX_FMT_COUNT: - break; - } - - qFatal("Invalid pixel format requested"); - - // qFatal will abort so we won't get here, but this suppresses compiler warnings - return 0; -} - -FramePtr PixelFormat::ConvertPixelFormat(FramePtr frame, const PixelFormat::Format &dest_format) -{ - if (frame->format() == dest_format) { - return frame; - } - - // Create a destination frame with the same parameters - FramePtr converted = Frame::Create(); - converted->set_video_params(VideoParams(frame->video_params().width(), - frame->video_params().height(), - dest_format)); - converted->set_timestamp(frame->timestamp()); - converted->allocate(); - - // Do the conversion through OIIO - create a buffer for the source image - OIIO::ImageBuf src(OIIO::ImageSpec(frame->width(), - frame->height(), - kRGBAChannels, - GetOIIOTypeDesc(frame->format()))); - - // Set the pixels (this is necessary as opposed to an OIIO buffer wrapper since Frame has - // linesizes) - OIIOCommon::FrameToBuffer(frame, &src); - - // Create a destination OIIO buffer with our destination format - OIIO::ImageBuf dst(OIIO::ImageSpec(converted->width(), - converted->height(), - kRGBAChannels, - GetOIIOTypeDesc(converted->format()))); - - if (dst.copy_pixels(src)) { - - // Convert our buffer back to a frame - OIIOCommon::BufferToFrame(&dst, converted); - - return converted; - } else { - return nullptr; - } -} - -OLIVE_NAMESPACE_EXIT diff --git a/app/render/pixelformat.h b/app/render/pixelformat.h deleted file mode 100644 index c60027c93..000000000 --- a/app/render/pixelformat.h +++ /dev/null @@ -1,134 +0,0 @@ -/*** - - Olive - Non-Linear Video Editor - Copyright (C) 2019 Olive Team - - This program is free software: you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program. If not, see . - -***/ - -#ifndef BITDEPTHS_H -#define BITDEPTHS_H - -#include -#include -#include -#include - -#include "common/ocioutils.h" -#include "render/rendermodes.h" - -OLIVE_NAMESPACE_ENTER - -class Frame; -using FramePtr = std::shared_ptr; - -class PixelFormat : public QObject -{ - Q_OBJECT -public: - /** - * @brief Olive's internal supported pixel formats. - */ - enum Format { - PIX_FMT_INVALID = -1, - - PIX_FMT_RGBA8, - PIX_FMT_RGBA16U, - PIX_FMT_RGBA16F, - PIX_FMT_RGBA32F, - - PIX_FMT_COUNT - }; - - static void CreateInstance(); - static void DestroyInstance(); - static PixelFormat* instance(); - - /** - * @brief Returns the configured pixel format for a given mode - */ - Format GetConfiguredFormatForMode(RenderMode::Mode mode); - void SetConfiguredFormatForMode(RenderMode::Mode mode, PixelFormat::Format format); - - static Format OIIOFormatToOliveFormat(OIIO::TypeDesc desc); - - /** - * @brief Returns the minimum buffer size (in bytes) necessary for a given format, width, and height. - * - * @param format - * - * The format of the data the buffer should contain. Must be a member of the olive::PixelFormat enum. - * - * @param width - * - * The width (in pixels) of the buffer. - * - * @param height - * - * The height (in pixels) of the buffer. - */ - static int GetBufferSize(const Format &format, const int& width, const int& height); - - /** - * @brief Returns the number of bytes per pixel for a certain format - * - * Different formats use different sizes of data for pixels. Use this function to determine how many bytes a pixel - * requires for a certain format. The number of bytes will always be a multiple of 4 since all formats use RGBA and - * are at least 1 bpc. - */ - static int BytesPerPixel(const Format &format); - - /** - * @brief Returns the number of bytes per channel for a certain format - */ - static int BytesPerChannel(const Format& format); - - /** - * @brief Convert a frame to a pixel format - * - * If the frame's pixel format == the destination format, this just returns `frame`. - */ - static FramePtr ConvertPixelFormat(FramePtr frame, const Format &dest_format); - - /** - * @brief Simple convenience function returning whether a pixel format is float-based or integer-based - */ - static bool FormatIsFloat(const Format& format); - - /** - * @brief Get corresponding OpenImageIO TypeDesc for a given pixel format - */ - static OIIO::TypeDesc::BASETYPE GetOIIOTypeDesc(const Format& format); - - /** - * @brief Get format name - */ - static QString GetName(const Format& format); - - static OCIO::BitDepth GetOCIOBitDepthFromPixelFormat(PixelFormat::Format format); - -signals: - void FormatChanged(); - -private: - PixelFormat() = default; - - static PixelFormat* instance_; - -}; - -OLIVE_NAMESPACE_EXIT - -#endif // BITDEPTHS_H diff --git a/app/render/renderer.cpp b/app/render/renderer.cpp index 83107935b..e3aad5fd4 100644 --- a/app/render/renderer.cpp +++ b/app/render/renderer.cpp @@ -32,16 +32,16 @@ Renderer::Renderer(QObject *parent) : } -TexturePtr Renderer::CreateTexture(const VideoParams ¶ms, Texture::Type type, Texture::ChannelFormat channel_format, const void *data, int linesize) +TexturePtr Renderer::CreateTexture(const VideoParams ¶ms, Texture::Type type, const void *data, int linesize) { QVariant v; if (type == Texture::k3D) { v = CreateNativeTexture3D(params.effective_width(), params.effective_height(), - params.effective_depth(), params.format(), channel_format, data, linesize); + params.effective_depth(), params.format(), params.channel_count(), data, linesize); } else { v = CreateNativeTexture2D(params.effective_width(), params.effective_height(), params.format(), - channel_format, data, linesize); + params.channel_count(), data, linesize); } if (v.isNull()) { @@ -53,7 +53,7 @@ TexturePtr Renderer::CreateTexture(const VideoParams ¶ms, Texture::Type type TexturePtr Renderer::CreateTexture(const VideoParams ¶ms, const void *data, int linesize) { - return CreateTexture(params, Texture::k2D, Texture::kRGBA, data, linesize); + return CreateTexture(params, Texture::k2D, data, linesize); } void Renderer::BlitColorManaged(ColorProcessorPtr color_processor, TexturePtr source, bool source_is_premultiplied, Texture *destination, const QMatrix4x4 &matrix) @@ -104,6 +104,7 @@ bool Renderer::GetColorContext(ColorProcessorPtr color_processor, Renderer::Colo "uniform int ove_maintex_alpha;\n" "\n" "// Macros defining `ove_maintex_alpha` state\n" + "// Matches `AlphaAssociated` C++ enum\n" "#define ALPHA_NONE 0\n" "#define ALPHA_UNASSOC 1\n" "#define ALPHA_ASSOC 2\n" @@ -185,8 +186,8 @@ bool Renderer::GetColorContext(ColorProcessorPtr color_processor, Renderer::Colo } // Allocate 3D LUT - color_ctx.lut3d_textures[i].texture = CreateTexture(VideoParams(edge_len, edge_len, edge_len, PixelFormat::PIX_FMT_RGBA32F), - Texture::k3D, Texture::kRGB, values); + color_ctx.lut3d_textures[i].texture = CreateTexture(VideoParams(edge_len, edge_len, edge_len, VideoParams::kFormatFloat32, VideoParams::kRGBChannelCount), + Texture::k3D, values); color_ctx.lut3d_textures[i].name = sampler_name; color_ctx.lut3d_textures[i].interpolation = (interpolation == OCIO::INTERP_NEAREST) ? Texture::kNearest : Texture::kLinear; } @@ -216,9 +217,8 @@ bool Renderer::GetColorContext(ColorProcessorPtr color_processor, Renderer::Colo } // Allocate 1D LUT - color_ctx.lut1d_textures[i].texture = CreateTexture(VideoParams(width, height, PixelFormat::PIX_FMT_RGBA32F), + color_ctx.lut1d_textures[i].texture = CreateTexture(VideoParams(width, height, VideoParams::kFormatFloat32, (channel == OCIO::GpuShaderDesc::TEXTURE_RED_CHANNEL) ? 1 : VideoParams::kRGBChannelCount), Texture::k2D, - (channel == OCIO::GpuShaderDesc::TEXTURE_RED_CHANNEL) ? Texture::kRedOnly : Texture::kRGB, values); color_ctx.lut1d_textures[i].name = sampler_name; color_ctx.lut1d_textures[i].interpolation = (interpolation == OCIO::INTERP_NEAREST) ? Texture::kNearest : Texture::kLinear; @@ -244,6 +244,21 @@ void Renderer::BlitColorManagedInternal(ColorProcessorPtr color_processor, Textu job.InsertValue(QStringLiteral("ove_maintex"), ShaderValue(QVariant::fromValue(source), NodeParam::kTexture)); job.InsertValue(QStringLiteral("ove_mvpmat"), ShaderValue(matrix, NodeParam::kMatrix)); + AlphaAssociated associated; + if (source->channel_count() == VideoParams::kRGBAChannelCount) { + if (source_is_premultiplied) { + // De-assoc/re-assoc required for color management + associated = kAlphaAssociated; + } else { + // Just assoc at the end + associated = kAlphaUnassociated; + } + } else { + // No assoc/deassoc required + associated = kAlphaNone; + } + job.InsertValue(QStringLiteral("ove_maintex_alpha"), ShaderValue(associated, NodeParam::kInt)); + foreach (const ColorContext::LUT& l, color_ctx.lut3d_textures) { job.InsertValue(l.name, ShaderValue(QVariant::fromValue(l.texture), NodeParam::kTexture)); job.SetInterpolation(l.name, l.interpolation); diff --git a/app/render/renderer.h b/app/render/renderer.h index fdea3da57..99bcf6374 100644 --- a/app/render/renderer.h +++ b/app/render/renderer.h @@ -43,7 +43,7 @@ public: virtual bool Init() = 0; - TexturePtr CreateTexture(const VideoParams& params, Texture::Type type, Texture::ChannelFormat channel_format, const void* data = nullptr, int linesize = 0); + TexturePtr CreateTexture(const VideoParams& params, Texture::Type type, const void* data = nullptr, int linesize = 0); TexturePtr CreateTexture(const VideoParams& params, const void *data = nullptr, int linesize = 0); void BlitToTexture(QVariant shader, @@ -72,8 +72,8 @@ public slots: virtual void ClearDestination(double r = 0.0, double g = 0.0, double b = 0.0, double a = 0.0) = 0; - virtual QVariant CreateNativeTexture2D(int width, int height, OLIVE_NAMESPACE::PixelFormat::Format format, OLIVE_NAMESPACE::Texture::ChannelFormat channel_format, const void* data = nullptr, int linesize = 0) = 0; - virtual QVariant CreateNativeTexture3D(int width, int height, int depth, OLIVE_NAMESPACE::PixelFormat::Format format, OLIVE_NAMESPACE::Texture::ChannelFormat channel_format, const void* data = nullptr, int linesize = 0) = 0; + virtual QVariant CreateNativeTexture2D(int width, int height, OLIVE_NAMESPACE::VideoParams::Format format, int channel_count, const void* data = nullptr, int linesize = 0) = 0; + virtual QVariant CreateNativeTexture3D(int width, int height, int depth, OLIVE_NAMESPACE::VideoParams::Format format, int channel_count, const void* data = nullptr, int linesize = 0) = 0; virtual void DestroyNativeTexture(QVariant texture) = 0; @@ -105,6 +105,12 @@ private: }; + enum AlphaAssociated { + kAlphaNone, + kAlphaUnassociated, + kAlphaAssociated + }; + bool GetColorContext(ColorProcessorPtr color_processor, ColorContext* ctx); void BlitColorManagedInternal(ColorProcessorPtr color_processor, TexturePtr source, diff --git a/app/render/rendererthreadwrapper.cpp b/app/render/rendererthreadwrapper.cpp index 2024fd377..483304575 100644 --- a/app/render/rendererthreadwrapper.cpp +++ b/app/render/rendererthreadwrapper.cpp @@ -76,7 +76,7 @@ void RendererThreadWrapper::ClearDestination(double r, double g, double b, doubl Q_ARG(double, a)); } -QVariant RendererThreadWrapper::CreateNativeTexture2D(int width, int height, PixelFormat::Format format, OLIVE_NAMESPACE::Texture::ChannelFormat channel_format, const void *data, int linesize) +QVariant RendererThreadWrapper::CreateNativeTexture2D(int width, int height, VideoParams::Format format, int channel_count, const void *data, int linesize) { QVariant v; @@ -84,15 +84,15 @@ QVariant RendererThreadWrapper::CreateNativeTexture2D(int width, int height, Pix Q_RETURN_ARG(QVariant, v), Q_ARG(int, width), Q_ARG(int, height), - OLIVE_NS_ARG(PixelFormat::Format, format), - OLIVE_NS_ARG(Texture::ChannelFormat, channel_format), + OLIVE_NS_ARG(VideoParams::Format, format), + Q_ARG(int, channel_count), Q_ARG(const void*, data), Q_ARG(int, linesize)); return v; } -QVariant RendererThreadWrapper::CreateNativeTexture3D(int width, int height, int depth, PixelFormat::Format format, Texture::ChannelFormat channel_format, const void *data, int linesize) +QVariant RendererThreadWrapper::CreateNativeTexture3D(int width, int height, int depth, VideoParams::Format format, int channel_count, const void *data, int linesize) { QVariant v; @@ -101,8 +101,8 @@ QVariant RendererThreadWrapper::CreateNativeTexture3D(int width, int height, int Q_ARG(int, width), Q_ARG(int, height), Q_ARG(int, depth), - OLIVE_NS_ARG(PixelFormat::Format, format), - OLIVE_NS_ARG(Texture::ChannelFormat, channel_format), + OLIVE_NS_ARG(VideoParams::Format, format), + Q_ARG(int, channel_count), Q_ARG(const void*, data), Q_ARG(int, linesize)); diff --git a/app/render/rendererthreadwrapper.h b/app/render/rendererthreadwrapper.h index a3b9e5cda..1c682161a 100644 --- a/app/render/rendererthreadwrapper.h +++ b/app/render/rendererthreadwrapper.h @@ -47,8 +47,8 @@ public slots: virtual void ClearDestination(double r = 0.0, double g = 0.0, double b = 0.0, double a = 0.0) override; - virtual QVariant CreateNativeTexture2D(int width, int height, OLIVE_NAMESPACE::PixelFormat::Format format, OLIVE_NAMESPACE::Texture::ChannelFormat channel_format, const void* data = nullptr, int linesize = 0) override; - virtual QVariant CreateNativeTexture3D(int width, int height, int depth, OLIVE_NAMESPACE::PixelFormat::Format format, OLIVE_NAMESPACE::Texture::ChannelFormat channel_format, const void* data = nullptr, int linesize = 0) override; + virtual QVariant CreateNativeTexture2D(int width, int height, OLIVE_NAMESPACE::VideoParams::Format format, int channel_count, const void* data = nullptr, int linesize = 0) override; + virtual QVariant CreateNativeTexture3D(int width, int height, int depth, OLIVE_NAMESPACE::VideoParams::Format format, int channel_count, const void* data = nullptr, int linesize = 0) override; virtual void DestroyNativeTexture(QVariant texture) override; diff --git a/app/render/rendermanager.cpp b/app/render/rendermanager.cpp index 2f6401a06..ba84737b0 100644 --- a/app/render/rendermanager.cpp +++ b/app/render/rendermanager.cpp @@ -86,11 +86,11 @@ QByteArray RenderManager::Hash(const Node *n, const VideoParams ¶ms, const r // Embed video parameters into this hash int width = params.effective_width(); int height = params.effective_height(); - PixelFormat::Format format = params.format(); + VideoParams::Format format = params.format(); hasher.addData(reinterpret_cast(&width), sizeof(int)); hasher.addData(reinterpret_cast(&height), sizeof(int)); - hasher.addData(reinterpret_cast(&format), sizeof(PixelFormat::Format)); + hasher.addData(reinterpret_cast(&format), sizeof(VideoParams::Format)); if (n) { n->Hash(hasher, time); @@ -111,7 +111,7 @@ RenderTicketPtr RenderManager::RenderFrame(ViewerOutput* viewer, ColorManager* c viewer->audio_params(), QSize(0, 0), QMatrix4x4(), - PixelFormat::PIX_FMT_INVALID, + VideoParams::kFormatInvalid, nullptr, cache, prioritize); @@ -121,7 +121,7 @@ RenderTicketPtr RenderManager::RenderFrame(ViewerOutput* viewer, ColorManager* c const rational& time, RenderMode::Mode mode, const VideoParams &video_params, const AudioParams &audio_params, const QSize& force_size, - const QMatrix4x4& force_matrix, PixelFormat::Format force_format, + const QMatrix4x4& force_matrix, VideoParams::Format force_format, ColorProcessorPtr force_color_output, FrameHashCache* cache, bool prioritize) { diff --git a/app/render/rendermanager.h b/app/render/rendermanager.h index 702356023..06b23c59d 100644 --- a/app/render/rendermanager.h +++ b/app/render/rendermanager.h @@ -87,7 +87,7 @@ public: const rational& time, RenderMode::Mode mode, const VideoParams& video_params, const AudioParams& audio_params, const QSize& force_size, - const QMatrix4x4& force_matrix, PixelFormat::Format force_format, + const QMatrix4x4& force_matrix, VideoParams::Format force_format, ColorProcessorPtr force_color_output, FrameHashCache* cache = nullptr, bool prioritize = false); diff --git a/app/render/renderprocessor.cpp b/app/render/renderprocessor.cpp index a9bdca01a..d3c0480e8 100644 --- a/app/render/renderprocessor.cpp +++ b/app/render/renderprocessor.cpp @@ -67,11 +67,15 @@ void RenderProcessor::Run() frame_params.set_height(frame_size.height()); } - PixelFormat::Format frame_format = static_cast(ticket_->property("format").toInt()); - if (frame_format != PixelFormat::PIX_FMT_INVALID) { + VideoParams::Format frame_format = static_cast(ticket_->property("format").toInt()); + if (frame_format != VideoParams::kFormatInvalid) { frame_params.set_format(frame_format); } + if (texture) { + frame_params.set_channel_count(texture->channel_count()); + } + FramePtr frame = Frame::Create(); frame->set_timestamp(time); frame->set_video_params(frame_params); @@ -448,9 +452,14 @@ QVariant RenderProcessor::ProcessFrameGeneration(const Node *node, const Generat { FramePtr frame = Frame::Create(); - const VideoParams& video_params = ticket_->property("vparam").value(); + VideoParams frame_params = ticket_->property("vparam").value(); + if (job.GetAlphaChannelRequired()) { + frame_params.set_channel_count(VideoParams::kRGBAChannelCount); + } else { + frame_params.set_channel_count(VideoParams::kRGBChannelCount); + } - frame->set_video_params(video_params); + frame->set_video_params(frame_params); frame->allocate(); node->GenerateFrame(frame, job); @@ -459,8 +468,6 @@ QVariant RenderProcessor::ProcessFrameGeneration(const Node *node, const Generat frame->data(), frame->linesize_pixels()); - texture->set_has_meaningful_alpha(job.GetAlphaChannelRequired()); - return QVariant::fromValue(texture); } diff --git a/app/render/texture.h b/app/render/texture.h index abf4e7e2e..4aaf01f62 100644 --- a/app/render/texture.h +++ b/app/render/texture.h @@ -41,19 +41,12 @@ public: kMipmappedLinear }; - enum ChannelFormat { - kRGBA, - kRGB, - kRedOnly - }; - static const Interpolation kDefaultInterpolation; Texture(Renderer* renderer, const QVariant& native, const VideoParams& param, Type type) : renderer_(renderer), params_(param), id_(native), - meaningful_alpha_(true), type_(type) { } @@ -82,11 +75,16 @@ public: return params_.height(); } - PixelFormat::Format format() const + VideoParams::Format format() const { return params_.format(); } + int channel_count() const + { + return params_.channel_count(); + } + int divider() const { return params_.divider(); @@ -97,16 +95,6 @@ public: return params_.pixel_aspect_ratio(); } - bool has_meaningful_alpha() const - { - return meaningful_alpha_; - } - - void set_has_meaningful_alpha(bool e) - { - meaningful_alpha_ = e; - } - Type type() const { return type_; @@ -119,8 +107,6 @@ private: QVariant id_; - bool meaningful_alpha_; - Type type_; }; diff --git a/app/render/videoparams.cpp b/app/render/videoparams.cpp index c9609701e..e7c500f6f 100644 --- a/app/render/videoparams.cpp +++ b/app/render/videoparams.cpp @@ -24,7 +24,9 @@ #include "core.h" -OLIVE_NAMESPACE_ENTER +OLIVE_NAMESPACE_ENTER; + +const int VideoParams::kInternalChannelCount = kRGBAChannelCount; const rational VideoParams::kPixelAspectSquare(1); const rational VideoParams::kPixelAspectNTSCStandard(8, 9); @@ -63,16 +65,18 @@ VideoParams::VideoParams() : width_(0), height_(0), depth_(0), - format_(PixelFormat::PIX_FMT_INVALID), + format_(kFormatInvalid), + channel_count_(0), interlacing_(Interlacing::kInterlaceNone) { } -VideoParams::VideoParams(const int &width, const int &height, const PixelFormat::Format &format, const rational& pixel_aspect_ratio, const Interlacing &interlacing, const int& divider) : +VideoParams::VideoParams(int width, int height, Format format, int nb_channels, const rational& pixel_aspect_ratio, Interlacing interlacing, int divider) : width_(width), height_(height), depth_(0), format_(format), + channel_count_(nb_channels), pixel_aspect_ratio_(pixel_aspect_ratio), interlacing_(interlacing), divider_(divider) @@ -81,11 +85,12 @@ VideoParams::VideoParams(const int &width, const int &height, const PixelFormat: validate_pixel_aspect_ratio(); } -VideoParams::VideoParams(const int &width, const int &height, const int &depth, const PixelFormat::Format &format, const rational &pixel_aspect_ratio, const VideoParams::Interlacing &interlacing, const int ÷r) : +VideoParams::VideoParams(int width, int height, int depth, Format format, int nb_channels, const rational &pixel_aspect_ratio, VideoParams::Interlacing interlacing, int divider) : width_(width), height_(height), depth_(depth), format_(format), + channel_count_(nb_channels), pixel_aspect_ratio_(pixel_aspect_ratio), interlacing_(interlacing), divider_(divider) @@ -94,12 +99,13 @@ VideoParams::VideoParams(const int &width, const int &height, const int &depth, validate_pixel_aspect_ratio(); } -VideoParams::VideoParams(const int &width, const int &height, const rational &time_base, const PixelFormat::Format &format, const rational& pixel_aspect_ratio, const Interlacing &interlacing, const int ÷r) : +VideoParams::VideoParams(int width, int height, const rational &time_base, Format format, int nb_channels, const rational& pixel_aspect_ratio, Interlacing interlacing, int divider) : width_(width), height_(height), depth_(0), time_base_(time_base), format_(format), + channel_count_(nb_channels), pixel_aspect_ratio_(pixel_aspect_ratio), interlacing_(interlacing), divider_(divider) @@ -159,6 +165,64 @@ bool VideoParams::operator!=(const VideoParams &rhs) const return !(*this == rhs); } +int VideoParams::GetBytesPerChannel(VideoParams::Format format) +{ + switch (format) { + case kFormatInvalid: + case kFormatCount: + break; + case kFormatUnsigned8: + return 1; + case kFormatUnsigned16: + case kFormatFloat16: + return 2; + case kFormatFloat32: + return 4; + } + + return 0; +} + +int VideoParams::GetBytesPerPixel(VideoParams::Format format, int channels) +{ + return GetBytesPerChannel(format) * channels; +} + +bool VideoParams::FormatIsFloat(VideoParams::Format format) +{ + switch (format) { + case kFormatFloat16: + case kFormatFloat32: + return true; + case kFormatUnsigned8: + case kFormatUnsigned16: + case kFormatInvalid: + case kFormatCount: + break; + } + + return false; +} + +QString VideoParams::GetFormatName(VideoParams::Format format) +{ + switch (format) { + case kFormatUnsigned8: + return QCoreApplication::translate("VideoParams", "8-bit"); + case kFormatUnsigned16: + return QCoreApplication::translate("VideoParams", "16-bit Integer"); + case kFormatFloat16: + return QCoreApplication::translate("VideoParams", "Half-Float (16-bit)"); + case kFormatFloat32: + return QCoreApplication::translate("VideoParams", "Full-Float (32-bit)"); + case kFormatInvalid: + case kFormatCount: + break; + } + + return QCoreApplication::translate("VideoParams", "Unknown (0x%1)").arg(format, 0, 16); +} + void VideoParams::calculate_effective_size() { effective_width_ = GetScaledDimension(width(), divider_); @@ -178,8 +242,8 @@ bool VideoParams::is_valid() const return (width() > 0 && height() > 0 && !pixel_aspect_ratio_.isNull() - && format_ != PixelFormat::PIX_FMT_INVALID - && format_ != PixelFormat::PIX_FMT_COUNT); + && format_ > kFormatInvalid && format_ < kFormatCount + && channel_count_ > 0); } QString VideoParams::FrameRateToString(const rational &frame_rate) diff --git a/app/render/videoparams.h b/app/render/videoparams.h index 3d7102e9f..7cd4ef7c1 100644 --- a/app/render/videoparams.h +++ b/app/render/videoparams.h @@ -22,13 +22,35 @@ #define VIDEOPARAMS_H #include "common/rational.h" -#include "pixelformat.h" #include "rendermodes.h" OLIVE_NAMESPACE_ENTER class VideoParams { public: + enum Format { + /// Invalid or no format + kFormatInvalid = -1, + + /// 8-bit unsigned integer + kFormatUnsigned8, + + /// 16-bit unsigned integer + kFormatUnsigned16, + + /// 16-bit half float + kFormatFloat16, + + /// 32-bit full float + kFormatFloat32, + + /// 64-bit double float - disabled since very, very few libs support 64-bit buffers + //kFormatFloat64, + + /// Total format count + kFormatCount + }; + enum Interlacing { kInterlaceNone, kInterlacedTopFirst, @@ -36,16 +58,17 @@ public: }; VideoParams(); - VideoParams(const int& width, const int& height, const PixelFormat::Format& format, + VideoParams(int width, int height, Format format, int nb_channels, const rational& pixel_aspect_ratio = 1, - const Interlacing& interlacing = kInterlaceNone, const int& divider = 1); - VideoParams(const int& width, const int& height, const int& depth, - const PixelFormat::Format& format, + Interlacing interlacing = kInterlaceNone, int divider = 1); + VideoParams(int width, int height, int depth, + Format format, int nb_channels, const rational& pixel_aspect_ratio = 1, - const Interlacing& interlacing = kInterlaceNone, const int& divider = 1); - VideoParams(const int& width, const int& height, const rational& time_base, - const PixelFormat::Format& format, const rational& pixel_aspect_ratio = 1, - const Interlacing& interlacing = kInterlaceNone, const int& divider = 1); + Interlacing interlacing = kInterlaceNone, int divider = 1); + VideoParams(int width, int height, const rational& time_base, + Format format, int nb_channels, + const rational& pixel_aspect_ratio = 1, + Interlacing interlacing = kInterlaceNone, int divider = 1); int width() const { @@ -116,16 +139,26 @@ public: return effective_depth_; } - PixelFormat::Format format() const + Format format() const { return format_; } - void set_format(PixelFormat::Format f) + void set_format(Format f) { format_ = f; } + int channel_count() const + { + return channel_count_; + } + + void set_channel_count(int c) + { + channel_count_ = c; + } + const rational& pixel_aspect_ratio() const { return pixel_aspect_ratio_; @@ -154,6 +187,33 @@ public: bool operator==(const VideoParams& rhs) const; bool operator!=(const VideoParams& rhs) const; + static int GetBytesPerChannel(Format format); + int GetBytesPerChannel() const + { + return GetBytesPerChannel(format_); + } + + static int GetBytesPerPixel(Format format, int channels); + int GetBytesPerPixel() const + { + return GetBytesPerPixel(format_, channel_count_); + } + + static int GetBufferSize(int width, int height, Format format, int channels) + { + return width * height * GetBytesPerPixel(format, channels); + } + int GetBufferSize() const + { + return GetBufferSize(width_, height_, format_, channel_count_); + } + + static bool FormatIsFloat(Format format); + + static QString GetFormatName(Format format); + + static const int kInternalChannelCount; + static const rational kPixelAspectSquare; static const rational kPixelAspectNTSCStandard; static const rational kPixelAspectNTSCWidescreen; @@ -165,6 +225,10 @@ public: static const QVector kStandardPixelAspects; static const QVector kSupportedDividers; + static const int kHSVChannelCount = 3; + static const int kRGBChannelCount = 3; + static const int kRGBAChannelCount = 4; + /** * @brief Convert rational frame rate (i.e. flipped timebase) to a user-friendly string */ @@ -185,7 +249,9 @@ private: int depth_; rational time_base_; - PixelFormat::Format format_; + Format format_; + + int channel_count_; rational pixel_aspect_ratio_; diff --git a/app/task/export/export.cpp b/app/task/export/export.cpp index e7e53b0a1..1f5d4df38 100644 --- a/app/task/export/export.cpp +++ b/app/task/export/export.cpp @@ -170,18 +170,6 @@ void ExportTask::FrameDownloaded(FramePtr f, const QByteArray &hash, const QVect } } -void FrameColorConvert(ColorProcessorPtr processor, FramePtr frame) -{ - // Color conversion must be done with unassociated alpha, and the pipeline is always associated - ColorManager::DisassociateAlpha(frame); - - // Convert color space - processor->ConvertFrame(frame); - - // Re-associate alpha - ColorManager::ReassociateAlpha(frame); -} - void ExportTask::AudioDownloaded(const TimeRange &range, SampleBufferPtr samples, qint64 job_time) { Q_UNUSED(job_time) diff --git a/app/task/render/render.cpp b/app/task/render/render.cpp index 6b90dd1e4..65821d777 100644 --- a/app/task/render/render.cpp +++ b/app/task/render/render.cpp @@ -42,7 +42,7 @@ bool RenderTask::Render(ColorManager* manager, const TimeRangeList &audio_range, RenderMode::Mode mode, FrameHashCache* cache, const QSize &force_size, - const QMatrix4x4 &force_matrix, PixelFormat::Format force_format, + const QMatrix4x4 &force_matrix, VideoParams::Format force_format, ColorProcessorPtr force_color_output) { // Run watchers in another thread so they can accept signals even while this thread is blocked diff --git a/app/task/render/render.h b/app/task/render/render.h index 9f8c1ea17..428e4e243 100644 --- a/app/task/render/render.h +++ b/app/task/render/render.h @@ -44,7 +44,7 @@ protected: const TimeRangeList &audio_range, RenderMode::Mode mode, FrameHashCache *cache, const QSize& force_size = QSize(0, 0), const QMatrix4x4& force_matrix = QMatrix4x4(), - PixelFormat::Format force_format = PixelFormat::PIX_FMT_INVALID, + VideoParams::Format force_format = VideoParams::kFormatInvalid, ColorProcessorPtr force_color_output = nullptr); virtual void DownloadFrame(QThread* thread, FramePtr frame, const QByteArray &hash); diff --git a/app/widget/manageddisplay/manageddisplay.h b/app/widget/manageddisplay/manageddisplay.h index 86f82113a..dc10913dd 100644 --- a/app/widget/manageddisplay/manageddisplay.h +++ b/app/widget/manageddisplay/manageddisplay.h @@ -21,6 +21,7 @@ #ifndef MANAGEDDISPLAYOBJECT_H #define MANAGEDDISPLAYOBJECT_H +#include #include #include "render/colormanager.h" diff --git a/app/widget/nodetableview/nodetabletraverser.cpp b/app/widget/nodetableview/nodetabletraverser.cpp index 156409224..69df8e142 100644 --- a/app/widget/nodetableview/nodetabletraverser.cpp +++ b/app/widget/nodetableview/nodetabletraverser.cpp @@ -30,6 +30,7 @@ QVariant NodeTableTraverser::ProcessVideoFootage(StreamPtr stream, const rationa video_stream->height(), video_stream->timebase(), video_stream->format(), + video_stream->channel_count(), video_stream->pixel_aspect_ratio())); } @@ -39,7 +40,7 @@ QVariant NodeTableTraverser::ProcessAudioFootage(StreamPtr stream, const TimeRan return QVariant::fromValue(AudioParams(audio_stream->sample_rate(), audio_stream->channel_layout(), - SampleFormat::kInternalFormat)); + AudioParams::kInternalFormat)); } OLIVE_NAMESPACE_EXIT diff --git a/app/widget/nodetableview/nodetableview.cpp b/app/widget/nodetableview/nodetableview.cpp index 722ff0a96..4f5116b7f 100644 --- a/app/widget/nodetableview/nodetableview.cpp +++ b/app/widget/nodetableview/nodetableview.cpp @@ -145,7 +145,7 @@ void NodeTableView::SetTime(const rational &time) case NodeParam::kTexture: { // NodeTableTraverser puts video params in here - for (int k=0;ksetItemWidget(sub_item, 2 + k, new QCheckBox()); } break; diff --git a/app/widget/scope/histogram/histogram.cpp b/app/widget/scope/histogram/histogram.cpp index 87def5cc3..f292ccc29 100644 --- a/app/widget/scope/histogram/histogram.cpp +++ b/app/widget/scope/histogram/histogram.cpp @@ -80,7 +80,9 @@ void HistogramScope::DrawScope(TexturePtr managed_tex, QVariant pipeline) if (!texture_row_sums_ || texture_row_sums_->width() != this->width() || texture_row_sums_->height() != this->height()) { - texture_row_sums_ = renderer()->CreateTexture(VideoParams(width(), height(), managed_tex->format())); + texture_row_sums_ = renderer()->CreateTexture(VideoParams(width(), height(), + managed_tex->format(), + managed_tex->channel_count())); } // Draw managed texture to a sums texture diff --git a/app/widget/scope/scopebase/scopebase.cpp b/app/widget/scope/scopebase/scopebase.cpp index 9cf864a24..ebeb1c7a7 100644 --- a/app/widget/scope/scopebase/scopebase.cpp +++ b/app/widget/scope/scopebase/scopebase.cpp @@ -20,6 +20,8 @@ #include "scopebase.h" +#include "config/config.h" + OLIVE_NAMESPACE_ENTER ScopeBase::ScopeBase(QWidget* parent) : @@ -54,7 +56,9 @@ void ScopeBase::DrawScope(TexturePtr managed_tex, QVariant pipeline) job.InsertValue(QStringLiteral("ove_maintex"), ShaderValue(QVariant::fromValue(managed_tex), NodeParam::kTexture)); - renderer()->Blit(pipeline, job, VideoParams(width(), height(), PixelFormat::PIX_FMT_RGBA16F)); + renderer()->Blit(pipeline, job, VideoParams(width(), height(), + static_cast(Config::Current()["OfflinePixelFormat"].toInt()), + VideoParams::kInternalChannelCount)); } void ScopeBase::UploadTextureFromBuffer() diff --git a/app/widget/scope/waveform/waveform.cpp b/app/widget/scope/waveform/waveform.cpp index 9abd47458..ac4964624 100644 --- a/app/widget/scope/waveform/waveform.cpp +++ b/app/widget/scope/waveform/waveform.cpp @@ -28,6 +28,7 @@ #include #include "common/qtutils.h" +#include "config/config.h" #include "node/node.h" OLIVE_NAMESPACE_ENTER @@ -74,7 +75,9 @@ void WaveformScope::DrawScope(TexturePtr managed_tex, QVariant pipeline) job.InsertValue(QStringLiteral("ove_maintex"), ShaderValue(QVariant::fromValue(managed_tex), NodeParam::kTexture)); - renderer()->Blit(pipeline, job, VideoParams(width(), height(), PixelFormat::PIX_FMT_RGBA16F)); + renderer()->Blit(pipeline, job, VideoParams(width(), height(), + static_cast(Config::Current()["OfflinePixelFormat"].toInt()), + VideoParams::kInternalChannelCount)); float waveform_dim_x = ceil((width() - 1.0) * waveform_scale); float waveform_dim_y = ceil((height() - 1.0) * waveform_scale); diff --git a/app/widget/standardcombos/pixelformatcombobox.h b/app/widget/standardcombos/pixelformatcombobox.h index 88ad74f29..7fc29dc94 100644 --- a/app/widget/standardcombos/pixelformatcombobox.h +++ b/app/widget/standardcombos/pixelformatcombobox.h @@ -23,7 +23,7 @@ #include -#include "render/pixelformat.h" +#include "render/videoparams.h" OLIVE_NAMESPACE_ENTER @@ -35,21 +35,21 @@ public: QComboBox(parent) { // Set up preview formats - for (int i=0;i(i); + for (int i=0;i(i); - if (!float_only || PixelFormat::FormatIsFloat(pix_fmt)) { - this->addItem(PixelFormat::GetName(pix_fmt), pix_fmt); + if (!float_only || VideoParams::FormatIsFloat(pix_fmt)) { + this->addItem(VideoParams::GetFormatName(pix_fmt), pix_fmt); } } } - PixelFormat::Format GetPixelFormat() const + VideoParams::Format GetPixelFormat() const { - return static_cast(this->currentData().toInt()); + return static_cast(this->currentData().toInt()); } - void SetPixelFormat(PixelFormat::Format fmt) + void SetPixelFormat(VideoParams::Format fmt) { for (int i=0; icount(); i++) { if (this->itemData(i).toInt() == fmt) { diff --git a/app/widget/timelinewidget/tool/import.cpp b/app/widget/timelinewidget/tool/import.cpp index a2c77b7d4..a1552839e 100644 --- a/app/widget/timelinewidget/tool/import.cpp +++ b/app/widget/timelinewidget/tool/import.cpp @@ -397,8 +397,8 @@ void ImportTool::DropGhosts(bool insert) QVector block_items(parent()->GetGhostItems().size()); - // Check if we're inserting - if (insert) { + // Check if we're inserting (only valid if we're not creating this sequence ourselves) + if (insert && !open_sequence) { InsertGapsAtGhostDestination(command); } diff --git a/app/widget/viewer/viewer.cpp b/app/widget/viewer/viewer.cpp index ed83de293..d2b584722 100644 --- a/app/widget/viewer/viewer.cpp +++ b/app/widget/viewer/viewer.cpp @@ -37,7 +37,6 @@ #include "config/config.h" #include "project/item/sequence/sequence.h" #include "project/project.h" -#include "render/pixelformat.h" #include "render/rendermanager.h" #include "task/taskmanager.h" #include "widget/menu/menu.h" @@ -113,9 +112,6 @@ ViewerWidget::ViewerWidget(QWidget *parent) : connect(waveform_view_, &AudioWaveformView::TimeChanged, this, &ViewerWidget::TimeChangedFromWaveform); connect(waveform_view_, &AudioWaveformView::customContextMenuRequested, this, &ViewerWidget::ShowContextMenu); - // Ensures renderer is updated if the global pixel format is changed - connect(PixelFormat::instance(), &PixelFormat::FormatChanged, this, &ViewerWidget::UpdateRendererVideoParameters); - connect(&playback_backup_timer_, &QTimer::timeout, this, &ViewerWidget::PlaybackTimerUpdate); SetAutoMaxScrollBar(true); @@ -616,11 +612,6 @@ void ViewerWidget::RequestNextFrameForQueue() watcher->SetTicket(GetFrame(next_time, false)); } -PixelFormat::Format ViewerWidget::GetCurrentPixelFormat() const -{ - return PixelFormat::instance()->GetConfiguredFormatForMode(RenderMode::kOffline); -} - RenderTicketPtr ViewerWidget::GetFrame(const rational &t, bool clear_render_queue) { QByteArray cached_hash = GetConnectedNode()->video_frame_cache()->GetHash(t); diff --git a/app/widget/viewer/viewer.h b/app/widget/viewer/viewer.h index 887f92b06..838dc4f4f 100644 --- a/app/widget/viewer/viewer.h +++ b/app/widget/viewer/viewer.h @@ -191,8 +191,6 @@ private: void RequestNextFrameForQueue(); - PixelFormat::Format GetCurrentPixelFormat() const; - RenderTicketPtr GetFrame(const rational& t, bool clear_render_queue); void FinishPlayPreprocess(); diff --git a/app/widget/viewer/viewerdisplay.cpp b/app/widget/viewer/viewerdisplay.cpp index 84e9487bf..68fe1d505 100644 --- a/app/widget/viewer/viewerdisplay.cpp +++ b/app/widget/viewer/viewerdisplay.cpp @@ -31,9 +31,9 @@ #include "common/define.h" #include "common/functiontimer.h" -#include "gizmotraverser.h" -#include "render/pixelformat.h" +#include "config/config.h" #include "core.h" +#include "gizmotraverser.h" OLIVE_NAMESPACE_ENTER @@ -105,7 +105,8 @@ void ViewerDisplayWidget::SetImage(FramePtr in_buffer) if (!texture_ || texture_->width() != in_buffer->width() || texture_->height() != in_buffer->height() - || texture_->format() != in_buffer->format()) { + || texture_->format() != in_buffer->format() + || texture_->channel_count() != in_buffer->channel_count()) { texture_ = renderer()->CreateTexture(in_buffer->video_params(), in_buffer->data(), in_buffer->linesize_pixels()); } else { texture_->Upload(in_buffer->data(), in_buffer->linesize_pixels()); @@ -299,7 +300,7 @@ void ViewerDisplayWidget::OnPaint() // Draw texture through color transform renderer()->BlitColorManaged(color_service(), texture_, true, - VideoParams(width(), height(), PixelFormat::PIX_FMT_RGBA16F), + VideoParams(width(), height(), static_cast(Config::Current()["OfflinePixelFormat"].toInt()), VideoParams::kInternalChannelCount), GetCompleteMatrixFlippedYTranslation()); }