From 500a8490b22f71668b2638308cbace278144c312 Mon Sep 17 00:00:00 2001 From: Fredrik Mellbin Date: Fri, 5 Apr 2024 18:08:40 +0200 Subject: [PATCH] Have secondary useful width and height adapted to a multiple of the subsampling --- src/avisynth.cpp | 4 ++-- src/vapoursynth.cpp | 8 ++++---- src/videosource.cpp | 23 ++++++++++++++++------- src/videosource.h | 8 ++++++++ 4 files changed, 30 insertions(+), 13 deletions(-) diff --git a/src/avisynth.cpp b/src/avisynth.cpp index 0fd8738..beb60ab 100644 --- a/src/avisynth.cpp +++ b/src/avisynth.cpp @@ -138,8 +138,8 @@ class AvisynthVideoSource : public IClip { VI.image_type |= VideoInfo::IT_FIELDBASED; VI.image_type |= VP.TFF ? VideoInfo::IT_TFF : VideoInfo::IT_BFF; - VI.width = VP.Width; - VI.height = VP.Height; + VI.width = VP.SSModWidth; + VI.height = VP.SSModHeight; VI.num_frames = vsh::int64ToIntS(VP.NumFrames); VI.SetFPS(VP.FPS.Num, VP.FPS.Den); diff --git a/src/vapoursynth.cpp b/src/vapoursynth.cpp index a352fc6..1434e14 100644 --- a/src/vapoursynth.cpp +++ b/src/vapoursynth.cpp @@ -81,7 +81,7 @@ static const VSFrame *VS_CC BestVideoSourceGetFrame(int n, int ActivationReason, VSVideoFormat AlphaFormat = {}; vsapi->queryVideoFormat(&AlphaFormat, cfGray, VideoFormat.sampleType, VideoFormat.bitsPerSample, 0, 0, Core); - Dst = vsapi->newVideoFrame(&VideoFormat, Src->Width, Src->Height, nullptr, Core); + Dst = vsapi->newVideoFrame(&VideoFormat, Src->SSModWidth, Src->SSModHeight, nullptr, Core); uint8_t *DstPtrs[3] = {}; ptrdiff_t DstStride[3] = {}; @@ -92,7 +92,7 @@ static const VSFrame *VS_CC BestVideoSourceGetFrame(int n, int ActivationReason, ptrdiff_t AlphaStride = 0; if (Src->VF.Alpha) { - AlphaDst = vsapi->newVideoFrame(&AlphaFormat, Src->Width, Src->Height, nullptr, Core); + AlphaDst = vsapi->newVideoFrame(&AlphaFormat, Src->SSModWidth, Src->SSModHeight, nullptr, Core); AlphaStride = vsapi->getStride(AlphaDst, 0); vsapi->mapSetInt(vsapi->getFramePropertiesRW(AlphaDst), "_ColorRange", 0, maAppend); } @@ -202,8 +202,8 @@ static void VS_CC CreateBestVideoSource(const VSMap *In, VSMap *Out, void *, VSC const VideoProperties &VP = D->V->GetVideoProperties(); if (VP.VF.ColorFamily == 0 || !vsapi->queryVideoFormat(&D->VI.format, VP.VF.ColorFamily, VP.VF.Float, VP.VF.Bits, VP.VF.SubSamplingW, VP.VF.SubSamplingH, Core)) throw BestSourceException("Unsupported video format from decoder (probably less than 8 bit or palette)"); - D->VI.width = VP.Width; - D->VI.height = VP.Height; + D->VI.width = VP.SSModWidth; + D->VI.height = VP.SSModHeight; if (VariableFormat) D->VI = {}; D->VI.numFrames = vsh::int64ToIntS(VP.NumFrames); diff --git a/src/videosource.cpp b/src/videosource.cpp index 3ef9c49..15e9893 100644 --- a/src/videosource.cpp +++ b/src/videosource.cpp @@ -284,11 +284,13 @@ void LWVideoDecoder::GetVideoProperties(VideoProperties &VP) { if (!PropFrame) return; + VP.VF.Set(av_pix_fmt_desc_get(static_cast(PropFrame->format))); VP.FieldBased = !!(PropFrame->flags & AV_FRAME_FLAG_INTERLACED); VP.TFF = !!(PropFrame->flags & AV_FRAME_FLAG_TOP_FIELD_FIRST); VP.Width = CodecContext->width; VP.Height = CodecContext->height; - VP.VF.Set(av_pix_fmt_desc_get(static_cast(PropFrame->format))); + VP.SSModWidth = VP.Width - (VP.Width % (1 << VP.VF.SubSamplingW)); + VP.SSModHeight = VP.Height - (VP.Height % (1 << VP.VF.SubSamplingH)); VP.FPS = CodecContext->framerate; // Set the framerate from the container if the codec framerate is invalid @@ -466,6 +468,8 @@ BestVideoFrame::BestVideoFrame(AVFrame *F) { PTS = Frame->pts; Width = Frame->width; Height = Frame->height; + SSModWidth = Width - (Width % (1 << VF.SubSamplingW)); + SSModHeight = Height - (Height % (1 << VF.SubSamplingH)); Duration = Frame->duration; KeyFrame = !!(Frame->flags & AV_FRAME_FLAG_KEY); PictType = av_get_picture_type_char(Frame->pict_type); @@ -582,6 +586,11 @@ bool BestVideoFrame::ExportAsPlanar(uint8_t **Dsts, ptrdiff_t *Stride, uint8_t * if (VF.ColorFamily == 0) return false; auto Desc = av_pix_fmt_desc_get(static_cast(Frame->format)); + + // Keep it simple until someone complains + int SourceWidth = SSModWidth; + int SourceHeight = SSModHeight; + if (IsRealPlanar(Desc)) { size_t BytesPerSample = 0; @@ -600,8 +609,8 @@ bool BestVideoFrame::ExportAsPlanar(uint8_t **Dsts, ptrdiff_t *Stride, uint8_t * int NumBasePlanes = (VF.ColorFamily == 1 ? 1 : 3); for (int Plane = 0; Plane < NumBasePlanes; Plane++) { - int PlaneW = Frame->width; - int PlaneH = Frame->height; + int PlaneW = SourceWidth; + int PlaneH = SourceHeight; if (Plane > 0) { PlaneW >>= Desc->log2_chroma_w; PlaneH >>= Desc->log2_chroma_h; @@ -619,16 +628,16 @@ bool BestVideoFrame::ExportAsPlanar(uint8_t **Dsts, ptrdiff_t *Stride, uint8_t * if (HasAlpha(Desc) && AlphaDst) { const uint8_t *Src = Frame->data[3]; uint8_t *Dst = AlphaDst; - for (int h = 0; h < Frame->height; h++) { - memcpy(Dst, Src, BytesPerSample * Frame->width); + for (int h = 0; h < SourceHeight; h++) { + memcpy(Dst, Src, BytesPerSample * SourceWidth); Src += Frame->linesize[3]; Dst += AlphaStride; } } } else { p2p_buffer_param Buf = {}; - Buf.height = Frame->height; - Buf.width = Frame->width; + Buf.height = SourceHeight; + Buf.width = SourceWidth; switch (Frame->format) { case AV_PIX_FMT_YUYV422: diff --git a/src/videosource.h b/src/videosource.h index 31b6cc7..8a88b85 100644 --- a/src/videosource.h +++ b/src/videosource.h @@ -63,6 +63,10 @@ struct VideoProperties { int Width; int Height; + /* Height and width but largest possible size where it's a multiple of the subsampling */ + int SSModWidth; + int SSModHeight; + bool FieldBased; bool TFF; @@ -140,6 +144,10 @@ class BestVideoFrame { int Width; int Height; + /* Height and width but largest possible size where it's a multiple of the subsampling */ + int SSModWidth; + int SSModHeight; + int64_t PTS; int64_t Duration; int Matrix;