From ba94ea51cd22fa260fcd5742f153f2b016ab9d9e Mon Sep 17 00:00:00 2001 From: itsmattkc Date: Sat, 11 Jan 2020 00:06:12 +1100 Subject: [PATCH] read and utilize the aspect ratio metadata from video files --- app/codec/ffmpeg/ffmpegdecoder.cpp | 13 ++++++++++ app/codec/ffmpeg/ffmpegdecoder.h | 2 ++ app/codec/frame.cpp | 29 +++++++++++++++------- app/codec/frame.h | 26 +++++++++---------- app/render/backend/opengl/openglworker.cpp | 27 +++++++++++++++++++- 5 files changed, 74 insertions(+), 23 deletions(-) diff --git a/app/codec/ffmpeg/ffmpegdecoder.cpp b/app/codec/ffmpeg/ffmpegdecoder.cpp index 68e84b207..abca161ca 100644 --- a/app/codec/ffmpeg/ffmpegdecoder.cpp +++ b/app/codec/ffmpeg/ffmpegdecoder.cpp @@ -143,6 +143,18 @@ bool FFmpegDecoder::Open() // We should never get here, but just in case... qFatal("Invalid output format"); } + + // Determine sample aspect ratio + AVRational sar = av_guess_sample_aspect_ratio(fmt_ctx_, avstream_, nullptr); + + // Use it to determine the display aspect ratio + // I'll be honest, I'm not entirely sure how this works or what it does. This code is the DAR code from ffprobe + // and seems to retrieve the DAR accurately. + av_reduce(&display_aspect_ratio_.num, + &display_aspect_ratio_.den, + avstream_->codecpar->width * sar.num, + avstream_->codecpar->height * sar.den, + 1024*1024); } // All allocation succeeded so we set the state to open @@ -180,6 +192,7 @@ FramePtr FFmpegDecoder::RetrieveVideo(const rational &timecode) frame_container->set_height(avstream_->codecpar->height); frame_container->set_format(native_pix_fmt_); frame_container->set_timestamp(Timecode::timestamp_to_time(target_ts, avstream_->time_base)); + frame_container->set_aspect_ratio(display_aspect_ratio_); frame_container->allocate(); memcpy(frame_container->data(), frame_loader.constData(), frame_loader.size()); diff --git a/app/codec/ffmpeg/ffmpegdecoder.h b/app/codec/ffmpeg/ffmpegdecoder.h index 8520062f8..1546a558b 100644 --- a/app/codec/ffmpeg/ffmpegdecoder.h +++ b/app/codec/ffmpeg/ffmpegdecoder.h @@ -147,6 +147,8 @@ private: AVPixelFormat ideal_pix_fmt_; PixelFormat::Format native_pix_fmt_; + AVRational display_aspect_ratio_; + QVector frame_index_; }; diff --git a/app/codec/frame.cpp b/app/codec/frame.cpp index 0d25dad35..3f94958d2 100644 --- a/app/codec/frame.cpp +++ b/app/codec/frame.cpp @@ -30,7 +30,8 @@ Frame::Frame() : height_(0), format_(PixelFormat::PIX_FMT_INVALID), sample_count_(0), - timestamp_(0) + timestamp_(0), + aspect_ratio_(1) { } @@ -39,7 +40,7 @@ FramePtr Frame::Create() return std::make_shared(); } -const int &Frame::width() +const int &Frame::width() const { return width_; } @@ -49,7 +50,7 @@ void Frame::set_width(const int &width) width_ = width; } -const int &Frame::height() +const int &Frame::height() const { return height_; } @@ -59,7 +60,17 @@ void Frame::set_height(const int &height) height_ = height; } -const AudioRenderingParams &Frame::audio_params() +const rational &Frame::aspect_ratio() const +{ + return aspect_ratio_; +} + +void Frame::set_aspect_ratio(const rational &aspect_ratio) +{ + aspect_ratio_ = aspect_ratio; +} + +const AudioRenderingParams &Frame::audio_params() const { return audio_params_; } @@ -69,7 +80,7 @@ void Frame::set_audio_params(const AudioRenderingParams ¶ms) audio_params_ = params; } -const rational &Frame::timestamp() +const rational &Frame::timestamp() const { return timestamp_; } @@ -89,7 +100,7 @@ void Frame::set_native_timestamp(const int64_t ×tamp) native_timestamp_ = timestamp; }*/ -const PixelFormat::Format &Frame::format() +const PixelFormat::Format &Frame::format() const { return format_; } @@ -99,12 +110,12 @@ void Frame::set_format(const PixelFormat::Format &format) format_ = format; } -QByteArray Frame::ToByteArray() +QByteArray Frame::ToByteArray() const { return data_; } -const int &Frame::sample_count() +const int &Frame::sample_count() const { return sample_count_; } @@ -119,7 +130,7 @@ char *Frame::data() return data_.data(); } -const char *Frame::const_data() +const char *Frame::const_data() const { return data_.constData(); } diff --git a/app/codec/frame.h b/app/codec/frame.h index e173a8cf9..6663854dd 100644 --- a/app/codec/frame.h +++ b/app/codec/frame.h @@ -33,15 +33,10 @@ using FramePtr = std::shared_ptr; /** * @brief Video frame data or audio sample data from a Decoder - * - * Abstraction from AVFrame. Currently a simple AVFrame wrapper. - * - * This class does not support copying at this time. */ class Frame { public: - /// Normal constructor Frame(); static FramePtr Create(); @@ -49,19 +44,22 @@ public: /** * @brief Get frame's width in pixels */ - const int& width(); + const int& width() const; void set_width(const int& width); /** * @brief Get frame's height in pixels */ - const int& height(); + const int& height() const; void set_height(const int& height); - const AudioRenderingParams& audio_params(); + const rational& aspect_ratio() const; + void set_aspect_ratio(const rational& aspect_ratio); + + const AudioRenderingParams& audio_params() const; void set_audio_params(const AudioRenderingParams& params); - const int &sample_count(); + const int &sample_count() const; void set_sample_count(const int &sample_count); /** @@ -69,7 +67,7 @@ public: * * This timestamp is always a rational that will equate to the time in seconds. */ - const rational& timestamp(); + const rational& timestamp() const; void set_timestamp(const rational& timestamp); /*const int64_t& native_timestamp(); @@ -82,7 +80,7 @@ public: * * Currently this will either be an olive::PixelFormat (video) or an olive::SampleFormat (audio). */ - const PixelFormat::Format& format(); + const PixelFormat::Format& format() const; void set_format(const PixelFormat::Format& format); /** @@ -90,7 +88,7 @@ public: * * Will always do a deep copy. If you want to affect the data directly, use data() instead. */ - QByteArray ToByteArray(); + QByteArray ToByteArray() const; /** * @brief Get the data buffer of this frame @@ -100,7 +98,7 @@ public: /** * @brief Get the const data buffer of this frame */ - const char* const_data(); + const char* const_data() const; /** * @brief Allocate memory buffer to store data based on parameters @@ -138,6 +136,8 @@ private: rational timestamp_; + rational aspect_ratio_; + }; Q_DECLARE_METATYPE(FramePtr) diff --git a/app/render/backend/opengl/openglworker.cpp b/app/render/backend/opengl/openglworker.cpp index bc6c06a85..1137485dc 100644 --- a/app/render/backend/opengl/openglworker.cpp +++ b/app/render/backend/opengl/openglworker.cpp @@ -101,6 +101,31 @@ void OpenGLWorker::FrameToValue(StreamPtr stream, FramePtr frame, NodeValueTable color_processor->Enable(ctx_, video_stream->premultiplied_alpha()); } + // Check frame aspect ratio + rational literal_ar(frame->width(), frame->height()); + + if (literal_ar != frame->aspect_ratio()) { + qDebug() << "NON EQUAL ASPECT RATIO, adjusting!"; + + int new_width = frame->width(); + int new_height = frame->height(); + + // Scale the frame in a way that does not reduce the resolution + if (frame->aspect_ratio() > literal_ar) { + // Make wider + new_width = qRound(static_cast(new_width) * frame->aspect_ratio().toDouble() / literal_ar.toDouble()); + } else { + // Make taller + new_height = qRound(static_cast(new_height) * literal_ar.toDouble() / frame->aspect_ratio().toDouble()); + } + + footage_params = VideoRenderingParams(new_width, + new_height, + footage_params.time_base(), + footage_params.format(), + footage_params.mode()); + } + // Create destination texture OpenGLTextureCache::ReferencePtr associated_tex_ref = texture_cache_->Get(ctx_, footage_params); @@ -109,7 +134,7 @@ void OpenGLWorker::FrameToValue(StreamPtr stream, FramePtr frame, NodeValueTable footage_tex_ref->texture()->Bind(); // Set viewport for texture size - functions_->glViewport(0, 0, footage_tex_ref->texture()->width(), footage_tex_ref->texture()->height()); + functions_->glViewport(0, 0, associated_tex_ref->texture()->width(), associated_tex_ref->texture()->height()); // Blit old texture to new texture through OCIO shader color_processor->ProcessOpenGL();