From 930848e07ab5b2356ad2fea7210352703b456530 Mon Sep 17 00:00:00 2001 From: itsmattkc <34096995+itsmattkc@users.noreply.github.com> Date: Sun, 29 May 2022 18:33:35 -0700 Subject: [PATCH 1/3] decoder: make texture inside decoder --- app/codec/decoder.cpp | 14 +++++++------- app/codec/decoder.h | 8 +++++--- app/codec/ffmpeg/ffmpegdecoder.cpp | 16 +++++++++------- app/codec/ffmpeg/ffmpegdecoder.h | 2 +- app/codec/oiio/oiiodecoder.cpp | 7 +++---- app/codec/oiio/oiiodecoder.h | 2 +- app/common/ffmpegutils.cpp | 21 ++++++++++++--------- app/common/ffmpegutils.h | 2 +- app/render/renderprocessor.cpp | 8 +++----- 9 files changed, 42 insertions(+), 38 deletions(-) diff --git a/app/codec/decoder.cpp b/app/codec/decoder.cpp index 9fa9765fb..9da151b7c 100644 --- a/app/codec/decoder.cpp +++ b/app/codec/decoder.cpp @@ -86,7 +86,7 @@ bool Decoder::Open(const CodecStream &stream) } } -bool Decoder::RetrieveVideo(TexturePtr destination, const rational &timecode, const RetrieveVideoParams ÷r, const QAtomicInt *cancelled) +TexturePtr Decoder::RetrieveVideo(Renderer *renderer, const rational &timecode, const RetrieveVideoParams ÷r, const QAtomicInt *cancelled) { QMutexLocker locker(&mutex_); @@ -94,19 +94,19 @@ bool Decoder::RetrieveVideo(TexturePtr destination, const rational &timecode, co if (!stream_.IsValid()) { qCritical() << "Can't retrieve video on a closed decoder"; - return false; + return nullptr; } if (!SupportsVideo()) { qCritical() << "Decoder doesn't support video"; - return false; + return nullptr; } if (cancelled && *cancelled) { - return false; + return nullptr; } - return RetrieveVideoInternal(destination, timecode, divider, cancelled); + return RetrieveVideoInternal(renderer, timecode, divider, cancelled); } Decoder::RetrieveAudioStatus Decoder::RetrieveAudio(SampleBuffer &dest, const TimeRange &range, const AudioParams ¶ms, const QString& cache_path, Footage::LoopMode loop_mode, RenderMode::Mode mode) @@ -264,12 +264,12 @@ int64_t Decoder::GetImageSequenceIndex(const QString &filename) return number_only.toLongLong(); } -bool Decoder::RetrieveVideoInternal(TexturePtr destination, const rational &timecode, const RetrieveVideoParams ÷r, const QAtomicInt *cancelled) +TexturePtr Decoder::RetrieveVideoInternal(Renderer *renderer, const rational &timecode, const RetrieveVideoParams ÷r, const QAtomicInt *cancelled) { Q_UNUSED(timecode) Q_UNUSED(divider) Q_UNUSED(cancelled) - return false; + return nullptr; } bool Decoder::ConformAudioInternal(const QVector &filenames, const AudioParams ¶ms, const QAtomicInt* cancelled) diff --git a/app/codec/decoder.h b/app/codec/decoder.h index ad778eafb..061378be0 100644 --- a/app/codec/decoder.h +++ b/app/codec/decoder.h @@ -150,9 +150,11 @@ public: RetrieveVideoParams() { divider = 1; + maximum_format = VideoParams::kFormatInvalid; } int divider; + VideoParams::Format maximum_format; void reset() { @@ -161,7 +163,7 @@ public: bool operator==(const RetrieveVideoParams& rhs) const { - return divider == rhs.divider; + return divider == rhs.divider && maximum_format == rhs.maximum_format; } bool operator!=(const RetrieveVideoParams& rhs) const @@ -180,7 +182,7 @@ public: * * This function is thread safe and can only run while the decoder is open. \see Open() */ - bool RetrieveVideo(TexturePtr destination, const rational& timecode, const RetrieveVideoParams& divider, const QAtomicInt *cancelled = nullptr); + TexturePtr RetrieveVideo(Renderer *renderer, const rational& timecode, const RetrieveVideoParams& params, const QAtomicInt *cancelled = nullptr); enum RetrieveAudioStatus { kInvalid = -1, @@ -275,7 +277,7 @@ protected: * Sub-classes must override this function IF they support video. Function is already mutexed * so sub-classes don't need to worry about thread safety. */ - virtual bool RetrieveVideoInternal(TexturePtr destination, const rational& timecode, const RetrieveVideoParams& divider, const QAtomicInt *cancelled); + virtual TexturePtr RetrieveVideoInternal(Renderer *renderer, const rational& timecode, const RetrieveVideoParams& params, const QAtomicInt *cancelled); virtual bool ConformAudioInternal(const QVector& filenames, const AudioParams ¶ms, const QAtomicInt* cancelled); diff --git a/app/codec/ffmpeg/ffmpegdecoder.cpp b/app/codec/ffmpeg/ffmpegdecoder.cpp index 29af60cd6..81ef1a306 100644 --- a/app/codec/ffmpeg/ffmpegdecoder.cpp +++ b/app/codec/ffmpeg/ffmpegdecoder.cpp @@ -47,6 +47,7 @@ extern "C" { #include "common/timecodefunctions.h" #include "render/framehashcache.h" #include "render/diskmanager.h" +#include "render/renderer.h" #include "render/subtitleparams.h" namespace olive { @@ -138,18 +139,18 @@ bool FFmpegDecoder::OpenInternal() return output_frame; }*/ -bool FFmpegDecoder::RetrieveVideoInternal(TexturePtr destination, const rational &timecode, const RetrieveVideoParams ¶ms, const QAtomicInt *cancelled) +TexturePtr FFmpegDecoder::RetrieveVideoInternal(Renderer *renderer, const rational &timecode, const RetrieveVideoParams ¶ms, const QAtomicInt *cancelled) { if (AVFramePtr f = RetrieveFrame(timecode, cancelled)) { if (InitScaler(f.get(), params)) { int r; r = av_buffersrc_add_frame_flags(buffersrc_ctx_, f.get(), AV_BUFFERSRC_FLAG_KEEP_REF); if (r < 0) { - return false; + return nullptr; } r = av_buffersink_get_frame(buffersink_ctx_, working_frame_); if (r < 0) { - return false; + return nullptr; } VideoParams vp(instance_.avstream()->codecpar->width, @@ -160,14 +161,15 @@ bool FFmpegDecoder::RetrieveVideoInternal(TexturePtr destination, const rational VideoParams::kInterlaceNone, params.divider); - destination->Upload(working_frame_->data[0], working_frame_->linesize[0] / vp.GetBytesPerPixel()); + TexturePtr tex = renderer->CreateTexture(vp, working_frame_->data[0], working_frame_->linesize[0] / vp.GetBytesPerPixel()); av_frame_unref(working_frame_); - return true; + + return tex; } } - return false; + return nullptr; } void FFmpegDecoder::CloseInternal() @@ -798,7 +800,7 @@ bool FFmpegDecoder::InitScaler(AVFrame *input, const RetrieveVideoParams& params } // Get an Olive compatible AVPixelFormat - AVPixelFormat ideal_pix_fmt = FFmpegUtils::GetCompatiblePixelFormat(static_cast(input_fmt_)); + AVPixelFormat ideal_pix_fmt = FFmpegUtils::GetCompatiblePixelFormat(static_cast(input_fmt_), params.maximum_format); // Determine which Olive native pixel format we retrieved // Note that FFmpeg doesn't support float formats diff --git a/app/codec/ffmpeg/ffmpegdecoder.h b/app/codec/ffmpeg/ffmpegdecoder.h index 017eb86ea..c8d92a9b6 100644 --- a/app/codec/ffmpeg/ffmpegdecoder.h +++ b/app/codec/ffmpeg/ffmpegdecoder.h @@ -68,7 +68,7 @@ public: protected: virtual bool OpenInternal() override; - virtual bool RetrieveVideoInternal(TexturePtr destination, const rational& timecode, const RetrieveVideoParams& params, const QAtomicInt *cancelled) override; + virtual TexturePtr RetrieveVideoInternal(Renderer *renderer, const rational& timecode, const RetrieveVideoParams& params, const QAtomicInt *cancelled) override; virtual bool ConformAudioInternal(const QVector& filenames, const AudioParams ¶ms, const QAtomicInt* cancelled) override; virtual void CloseInternal() override; diff --git a/app/codec/oiio/oiiodecoder.cpp b/app/codec/oiio/oiiodecoder.cpp index 1d98bae6c..9eea81d18 100644 --- a/app/codec/oiio/oiiodecoder.cpp +++ b/app/codec/oiio/oiiodecoder.cpp @@ -29,6 +29,7 @@ #include "common/oiioutils.h" #include "config/config.h" #include "core.h" +#include "render/renderer.h" namespace olive { @@ -115,7 +116,7 @@ bool OIIODecoder::OpenInternal() return OpenImageHandler(stream().filename(), stream().stream()); } -bool OIIODecoder::RetrieveVideoInternal(TexturePtr destination, const rational &timecode, const RetrieveVideoParams ¶ms, const QAtomicInt *cancelled) +TexturePtr OIIODecoder::RetrieveVideoInternal(Renderer *renderer, const rational &timecode, const RetrieveVideoParams ¶ms, const QAtomicInt *cancelled) { Q_UNUSED(timecode) Q_UNUSED(cancelled) @@ -152,9 +153,7 @@ bool OIIODecoder::RetrieveVideoInternal(TexturePtr destination, const rational & } } - destination->Upload(buffer_.data(), buffer_.linesize_pixels()); - - return true; + return renderer->CreateTexture(vp, buffer_.data(), buffer_.linesize_pixels()); } void OIIODecoder::CloseInternal() diff --git a/app/codec/oiio/oiiodecoder.h b/app/codec/oiio/oiiodecoder.h index 3d863da4e..5233678af 100644 --- a/app/codec/oiio/oiiodecoder.h +++ b/app/codec/oiio/oiiodecoder.h @@ -44,7 +44,7 @@ public: protected: virtual bool OpenInternal() override; - virtual bool RetrieveVideoInternal(TexturePtr destination, const rational& timecode, const RetrieveVideoParams& params, const QAtomicInt *cancelled) override; + virtual TexturePtr RetrieveVideoInternal(Renderer *renderer, const rational& timecode, const RetrieveVideoParams& params, const QAtomicInt *cancelled) override; virtual void CloseInternal() override; private: diff --git a/app/common/ffmpegutils.cpp b/app/common/ffmpegutils.cpp index 411f0a115..94a314f3a 100644 --- a/app/common/ffmpegutils.cpp +++ b/app/common/ffmpegutils.cpp @@ -22,17 +22,20 @@ namespace olive { -AVPixelFormat FFmpegUtils::GetCompatiblePixelFormat(const AVPixelFormat &pix_fmt) +AVPixelFormat FFmpegUtils::GetCompatiblePixelFormat(const AVPixelFormat &pix_fmt, VideoParams::Format maximum) { - AVPixelFormat possible_pix_fmts[] = { - // RGBA formats only because GPUs always upconvert to RGBA, so if it's RGB, that adds extra - // conversion overhead - AV_PIX_FMT_RGBA, - AV_PIX_FMT_RGBA64, - AV_PIX_FMT_NONE - }; + std::vector possible_pix_fmts(3); - return avcodec_find_best_pix_fmt_of_list(possible_pix_fmts, + possible_pix_fmts[0] = AV_PIX_FMT_RGBA; + + if (maximum == VideoParams::kFormatUnsigned8) { + possible_pix_fmts[1] = AV_PIX_FMT_NONE; + } else { + possible_pix_fmts[1] = AV_PIX_FMT_RGBA64; + possible_pix_fmts[2] = AV_PIX_FMT_NONE; + } + + return avcodec_find_best_pix_fmt_of_list(possible_pix_fmts.data(), pix_fmt, 1, nullptr); diff --git a/app/common/ffmpegutils.h b/app/common/ffmpegutils.h index 9fa58582a..cc74d8c48 100644 --- a/app/common/ffmpegutils.h +++ b/app/common/ffmpegutils.h @@ -36,7 +36,7 @@ public: /** * @brief Returns an AVPixelFormat that can be used to convert a frame to a data type Olive supports with minimal data loss */ - static AVPixelFormat GetCompatiblePixelFormat(const AVPixelFormat& pix_fmt); + static AVPixelFormat GetCompatiblePixelFormat(const AVPixelFormat& pix_fmt, VideoParams::Format maximum = VideoParams::kFormatInvalid); /** * @brief Returns a native pixel format that can be used to convert from a native frame to an AVFrame with minimal data loss diff --git a/app/render/renderprocessor.cpp b/app/render/renderprocessor.cpp index 475491a77..37e11a66a 100644 --- a/app/render/renderprocessor.cpp +++ b/app/render/renderprocessor.cpp @@ -452,17 +452,15 @@ void RenderProcessor::ProcessVideoFootage(TexturePtr destination, const FootageJ if (decoder) { Decoder::RetrieveVideoParams p; p.divider = stream.video_params().divider(); + p.maximum_format = destination->format(); if (!IsCancelled()) { - VideoParams tex_params = stream.video_params(); if (tex_params.is_valid()) { - TexturePtr unmanaged_texture = render_ctx_->CreateTexture(tex_params); + TexturePtr unmanaged_texture = decoder->RetrieveVideo(render_ctx_, (stream_data.video_type() == VideoParams::kVideoTypeVideo) ? input_time : Decoder::kAnyTimecode, p, GetCancelPointer()); - bool frame = decoder->RetrieveVideo(unmanaged_texture, (stream_data.video_type() == VideoParams::kVideoTypeVideo) ? input_time : Decoder::kAnyTimecode, p, GetCancelPointer()); - - if (frame) { + if (unmanaged_texture) { // We convert to our rendering pixel format, since that will always be float-based which // is necessary for correct color conversion ColorProcessorPtr processor = ColorProcessor::Create(color_manager, From d28202a2dbbf86d4eceef536898cf114f6551a41 Mon Sep 17 00:00:00 2001 From: itsmattkc <34096995+itsmattkc@users.noreply.github.com> Date: Mon, 30 May 2022 15:34:38 -0700 Subject: [PATCH 2/3] render: convert yuv to rgb on gpu Huge performance improvement --- app/codec/ffmpeg/ffmpegdecoder.cpp | 112 +++++++++++++++++++++++++---- app/shaders/yuv2rgb.frag | 35 +++++++++ 2 files changed, 135 insertions(+), 12 deletions(-) create mode 100644 app/shaders/yuv2rgb.frag diff --git a/app/codec/ffmpeg/ffmpegdecoder.cpp b/app/codec/ffmpeg/ffmpegdecoder.cpp index 81ef1a306..12d669d5c 100644 --- a/app/codec/ffmpeg/ffmpegdecoder.cpp +++ b/app/codec/ffmpeg/ffmpegdecoder.cpp @@ -52,6 +52,8 @@ extern "C" { namespace olive { +QVariant Yuv2RgbShader; + FFmpegDecoder::FFmpegDecoder() : filter_graph_(nullptr), buffersrc_ctx_(nullptr), @@ -143,16 +145,6 @@ TexturePtr FFmpegDecoder::RetrieveVideoInternal(Renderer *renderer, const ration { if (AVFramePtr f = RetrieveFrame(timecode, cancelled)) { if (InitScaler(f.get(), params)) { - int r; - r = av_buffersrc_add_frame_flags(buffersrc_ctx_, f.get(), AV_BUFFERSRC_FLAG_KEEP_REF); - if (r < 0) { - return nullptr; - } - r = av_buffersink_get_frame(buffersink_ctx_, working_frame_); - if (r < 0) { - return nullptr; - } - VideoParams vp(instance_.avstream()->codecpar->width, instance_.avstream()->codecpar->height, native_pix_fmt_, @@ -161,9 +153,105 @@ TexturePtr FFmpegDecoder::RetrieveVideoInternal(Renderer *renderer, const ration VideoParams::kInterlaceNone, params.divider); - TexturePtr tex = renderer->CreateTexture(vp, working_frame_->data[0], working_frame_->linesize[0] / vp.GetBytesPerPixel()); + QElapsedTimer t; + t.start(); - av_frame_unref(working_frame_); + TexturePtr tex = nullptr; + const bool hwscale = true; + + // Attempt to use GLSL shader for faster YUV to RGB conversion + if (hwscale) { + AVPixelFormat src_fmt = AVPixelFormat(f.get()->format); + if (src_fmt == AV_PIX_FMT_YUV420P + || src_fmt == AV_PIX_FMT_YUV422P + || src_fmt == AV_PIX_FMT_YUV444P + || src_fmt == AV_PIX_FMT_YUV420P10LE + || src_fmt == AV_PIX_FMT_YUV422P10LE + || src_fmt == AV_PIX_FMT_YUV444P10LE + || src_fmt == AV_PIX_FMT_YUV420P12LE + || src_fmt == AV_PIX_FMT_YUV422P12LE + || src_fmt == AV_PIX_FMT_YUV444P12LE) { + if (Yuv2RgbShader.isNull()) { + // Compile shader + Yuv2RgbShader = renderer->CreateNativeShader(ShaderCode(FileFunctions::ReadFileAsString(QStringLiteral(":/shaders/yuv2rgb.frag")))); + } + + if (!Yuv2RgbShader.isNull()) { + int px_size; + int bits_per_pixel; + switch (src_fmt) { + case AV_PIX_FMT_YUV420P: + case AV_PIX_FMT_YUV422P: + case AV_PIX_FMT_YUV444P: + default: + px_size = 1; + bits_per_pixel = 8; + break; + case AV_PIX_FMT_YUV420P10LE: + case AV_PIX_FMT_YUV422P10LE: + case AV_PIX_FMT_YUV444P10LE: + px_size = 2; + bits_per_pixel = 10; + break; + case AV_PIX_FMT_YUV420P12LE: + case AV_PIX_FMT_YUV422P12LE: + case AV_PIX_FMT_YUV444P12LE: + px_size = 2; + bits_per_pixel = 12; + break; + } + + VideoParams plane_params = vp; + plane_params.set_channel_count(1); + plane_params.set_divider(1); + TexturePtr y_plane = renderer->CreateTexture(plane_params, f->data[0], f->linesize[0] / px_size); + + if (src_fmt == AV_PIX_FMT_YUV420P + || src_fmt == AV_PIX_FMT_YUV422P + || src_fmt == AV_PIX_FMT_YUV420P10LE + || src_fmt == AV_PIX_FMT_YUV422P10LE + || src_fmt == AV_PIX_FMT_YUV420P12LE + || src_fmt == AV_PIX_FMT_YUV422P12LE) { + plane_params.set_width(plane_params.width()/2); + } + + if (src_fmt == AV_PIX_FMT_YUV420P + || src_fmt == AV_PIX_FMT_YUV420P10LE + || src_fmt == AV_PIX_FMT_YUV420P12LE) { + plane_params.set_height(plane_params.height()/2); + } + + TexturePtr u_plane = renderer->CreateTexture(plane_params, f->data[1], f->linesize[1] / px_size); + TexturePtr v_plane = renderer->CreateTexture(plane_params, f->data[2], f->linesize[2] / px_size); + + ShaderJob job; + job.Insert(QStringLiteral("y_channel"), NodeValue(NodeValue::kTexture, QVariant::fromValue(y_plane))); + job.Insert(QStringLiteral("u_channel"), NodeValue(NodeValue::kTexture, QVariant::fromValue(u_plane))); + job.Insert(QStringLiteral("v_channel"), NodeValue(NodeValue::kTexture, QVariant::fromValue(v_plane))); + job.Insert(QStringLiteral("bits_per_pixel"), NodeValue(NodeValue::kInt, bits_per_pixel)); + + tex = renderer->CreateTexture(vp); + renderer->BlitToTexture(Yuv2RgbShader, job, tex.get(), false); + } + } + } + + if (!tex) { + // Fallback to software pixel format conversion + int r; + r = av_buffersrc_add_frame_flags(buffersrc_ctx_, f.get(), AV_BUFFERSRC_FLAG_KEEP_REF); + if (r < 0) { + return nullptr; + } + r = av_buffersink_get_frame(buffersink_ctx_, working_frame_); + if (r < 0) { + return nullptr; + } + + tex = renderer->CreateTexture(vp, working_frame_->data[0], working_frame_->linesize[0] / vp.GetBytesPerPixel()); + + av_frame_unref(working_frame_); + } return tex; } diff --git a/app/shaders/yuv2rgb.frag b/app/shaders/yuv2rgb.frag new file mode 100644 index 000000000..62c73e149 --- /dev/null +++ b/app/shaders/yuv2rgb.frag @@ -0,0 +1,35 @@ +uniform sampler2D y_channel; +uniform sampler2D u_channel; +uniform sampler2D v_channel; + +uniform int bits_per_pixel; + +in vec2 ove_texcoord; +out vec4 frag_color; + +void main() { + vec4 rgba; + + vec3 yuv; + + yuv.r = texture(y_channel, ove_texcoord).r; + yuv.g = texture(u_channel, ove_texcoord).r; + yuv.b = texture(v_channel, ove_texcoord).r; + + if (bits_per_pixel == 10) { + yuv *= 64.0; + } else if (bits_per_pixel == 12) { + yuv *= 16.0; + } + + yuv.r = 1.1643 * (yuv.r - 0.0625); + yuv.g = yuv.g - 0.5; + yuv.b = yuv.b - 0.5; + + rgba.r = yuv.r + 1.5958 * yuv.b; + rgba.g = yuv.r - 0.39173 * yuv.g - 0.81290 * yuv.b; + rgba.b = yuv.r + 2.017 * yuv.g; + rgba.a = 1.0; + + frag_color = rgba; +} From 156b6adf996a50e102965c243bd4b47bbf47a3ea Mon Sep 17 00:00:00 2001 From: itsmattkc <34096995+itsmattkc@users.noreply.github.com> Date: Mon, 30 May 2022 15:41:05 -0700 Subject: [PATCH 3/3] decoder: ensure correct format is used for planes --- app/codec/ffmpeg/ffmpegdecoder.cpp | 20 ++++++++++++-------- app/codec/ffmpeg/ffmpegdecoder.h | 3 ++- 2 files changed, 14 insertions(+), 9 deletions(-) diff --git a/app/codec/ffmpeg/ffmpegdecoder.cpp b/app/codec/ffmpeg/ffmpegdecoder.cpp index 12d669d5c..0e8a51ef2 100644 --- a/app/codec/ffmpeg/ffmpegdecoder.cpp +++ b/app/codec/ffmpeg/ffmpegdecoder.cpp @@ -59,7 +59,8 @@ FFmpegDecoder::FFmpegDecoder() : buffersrc_ctx_(nullptr), buffersink_ctx_(nullptr), input_fmt_(AV_PIX_FMT_NONE), - native_pix_fmt_(VideoParams::kFormatInvalid), + native_internal_pix_fmt_(VideoParams::kFormatInvalid), + native_output_pix_fmt_(VideoParams::kFormatInvalid), working_frame_(nullptr), working_packet_(nullptr), is_working_(false), @@ -147,15 +148,12 @@ TexturePtr FFmpegDecoder::RetrieveVideoInternal(Renderer *renderer, const ration if (InitScaler(f.get(), params)) { VideoParams vp(instance_.avstream()->codecpar->width, instance_.avstream()->codecpar->height, - native_pix_fmt_, + native_output_pix_fmt_, native_channel_count_, av_guess_sample_aspect_ratio(instance_.fmt_ctx(), instance_.avstream(), nullptr), VideoParams::kInterlaceNone, params.divider); - QElapsedTimer t; - t.start(); - TexturePtr tex = nullptr; const bool hwscale = true; @@ -204,6 +202,7 @@ TexturePtr FFmpegDecoder::RetrieveVideoInternal(Renderer *renderer, const ration VideoParams plane_params = vp; plane_params.set_channel_count(1); plane_params.set_divider(1); + plane_params.set_format(native_internal_pix_fmt_); TexturePtr y_plane = renderer->CreateTexture(plane_params, f->data[0], f->linesize[0] / px_size); if (src_fmt == AV_PIX_FMT_YUV420P @@ -278,7 +277,8 @@ void FFmpegDecoder::CloseInternal() instance_.Close(); input_fmt_ = AV_PIX_FMT_NONE; - native_pix_fmt_ = VideoParams::kFormatInvalid; + native_internal_pix_fmt_ = VideoParams::kFormatInvalid; + native_output_pix_fmt_ = VideoParams::kFormatInvalid; } QString FFmpegDecoder::id() const @@ -892,10 +892,14 @@ bool FFmpegDecoder::InitScaler(AVFrame *input, const RetrieveVideoParams& params // Determine which Olive native pixel format we retrieved // Note that FFmpeg doesn't support float formats - native_pix_fmt_ = GetNativePixelFormat(ideal_pix_fmt); + native_output_pix_fmt_ = GetNativePixelFormat(ideal_pix_fmt); native_channel_count_ = GetNativeChannelCount(ideal_pix_fmt); - if (native_pix_fmt_ == VideoParams::kFormatInvalid + AVPixelFormat ideal_internal_pix_fmt = FFmpegUtils::GetCompatiblePixelFormat(static_cast(input_fmt_)); + native_internal_pix_fmt_ = GetNativePixelFormat(ideal_internal_pix_fmt); + + if (native_output_pix_fmt_ == VideoParams::kFormatInvalid + || native_internal_pix_fmt_ == VideoParams::kFormatInvalid || native_channel_count_ == 0) { qCritical() << "Failed to find valid native pixel format for" << ideal_pix_fmt; return false; diff --git a/app/codec/ffmpeg/ffmpegdecoder.h b/app/codec/ffmpeg/ffmpegdecoder.h index c8d92a9b6..80c46fb1f 100644 --- a/app/codec/ffmpeg/ffmpegdecoder.h +++ b/app/codec/ffmpeg/ffmpegdecoder.h @@ -160,7 +160,8 @@ private: AVFilterContext* buffersrc_ctx_; AVFilterContext* buffersink_ctx_; AVPixelFormat input_fmt_; - VideoParams::Format native_pix_fmt_; + VideoParams::Format native_internal_pix_fmt_; + VideoParams::Format native_output_pix_fmt_; int native_channel_count_; AVFrame *working_frame_;