FFmpeg  4.0
vscale.c
Go to the documentation of this file.
1 /*
2  * Copyright (C) 2015 Pedro Arthur <bygrandao@gmail.com>
3  *
4  * This file is part of FFmpeg.
5  *
6  * FFmpeg is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU Lesser General Public
8  * License as published by the Free Software Foundation; either
9  * version 2.1 of the License, or (at your option) any later version.
10  *
11  * FFmpeg is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14  * Lesser General Public License for more details.
15  *
16  * You should have received a copy of the GNU Lesser General Public
17  * License along with FFmpeg; if not, write to the Free Software
18  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
19  */
20 #include "swscale_internal.h"
21 
22 typedef struct VScalerContext
23 {
24  uint16_t *filter[2];
27  int isMMX;
28  void *pfn;
31 
32 
33 static int lum_planar_vscale(SwsContext *c, SwsFilterDescriptor *desc, int sliceY, int sliceH)
34 {
35  VScalerContext *inst = desc->instance;
36  int dstW = desc->dst->width;
37 
38  int first = FFMAX(1-inst->filter_size, inst->filter_pos[sliceY]);
39  int sp = first - desc->src->plane[0].sliceY;
40  int dp = sliceY - desc->dst->plane[0].sliceY;
41  uint8_t **src = desc->src->plane[0].line + sp;
42  uint8_t **dst = desc->dst->plane[0].line + dp;
43  uint16_t *filter = inst->filter[0] + (inst->isMMX ? 0 : sliceY * inst->filter_size);
44 
45  if (inst->filter_size == 1)
46  ((yuv2planar1_fn)inst->pfn)((const int16_t*)src[0], dst[0], dstW, c->lumDither8, 0);
47  else
48  ((yuv2planarX_fn)inst->pfn)(filter, inst->filter_size, (const int16_t**)src, dst[0], dstW, c->lumDither8, 0);
49 
50  if (desc->alpha) {
51  int sp = first - desc->src->plane[3].sliceY;
52  int dp = sliceY - desc->dst->plane[3].sliceY;
53  uint8_t **src = desc->src->plane[3].line + sp;
54  uint8_t **dst = desc->dst->plane[3].line + dp;
55  uint16_t *filter = inst->filter[1] + (inst->isMMX ? 0 : sliceY * inst->filter_size);
56 
57  if (inst->filter_size == 1)
58  ((yuv2planar1_fn)inst->pfn)((const int16_t*)src[0], dst[0], dstW, c->lumDither8, 0);
59  else
60  ((yuv2planarX_fn)inst->pfn)(filter, inst->filter_size, (const int16_t**)src, dst[0], dstW, c->lumDither8, 0);
61  }
62 
63  return 1;
64 }
65 
66 static int chr_planar_vscale(SwsContext *c, SwsFilterDescriptor *desc, int sliceY, int sliceH)
67 {
68  const int chrSkipMask = (1 << desc->dst->v_chr_sub_sample) - 1;
69  if (sliceY & chrSkipMask)
70  return 0;
71  else {
72  VScalerContext *inst = desc->instance;
73  int dstW = AV_CEIL_RSHIFT(desc->dst->width, desc->dst->h_chr_sub_sample);
74  int chrSliceY = sliceY >> desc->dst->v_chr_sub_sample;
75 
76  int first = FFMAX(1-inst->filter_size, inst->filter_pos[chrSliceY]);
77  int sp1 = first - desc->src->plane[1].sliceY;
78  int sp2 = first - desc->src->plane[2].sliceY;
79  int dp1 = chrSliceY - desc->dst->plane[1].sliceY;
80  int dp2 = chrSliceY - desc->dst->plane[2].sliceY;
81  uint8_t **src1 = desc->src->plane[1].line + sp1;
82  uint8_t **src2 = desc->src->plane[2].line + sp2;
83  uint8_t **dst1 = desc->dst->plane[1].line + dp1;
84  uint8_t **dst2 = desc->dst->plane[2].line + dp2;
85  uint16_t *filter = inst->filter[0] + (inst->isMMX ? 0 : chrSliceY * inst->filter_size);
86 
87  if (c->yuv2nv12cX) {
88  ((yuv2interleavedX_fn)inst->pfn)(c, filter, inst->filter_size, (const int16_t**)src1, (const int16_t**)src2, dst1[0], dstW);
89  } else if (inst->filter_size == 1) {
90  ((yuv2planar1_fn)inst->pfn)((const int16_t*)src1[0], dst1[0], dstW, c->chrDither8, 0);
91  ((yuv2planar1_fn)inst->pfn)((const int16_t*)src2[0], dst2[0], dstW, c->chrDither8, 3);
92  } else {
93  ((yuv2planarX_fn)inst->pfn)(filter, inst->filter_size, (const int16_t**)src1, dst1[0], dstW, c->chrDither8, 0);
94  ((yuv2planarX_fn)inst->pfn)(filter, inst->filter_size, (const int16_t**)src2, dst2[0], dstW, c->chrDither8, inst->isMMX ? (c->uv_offx2 >> 1) : 3);
95  }
96  }
97 
98  return 1;
99 }
100 
101 static int packed_vscale(SwsContext *c, SwsFilterDescriptor *desc, int sliceY, int sliceH)
102 {
103  VScalerContext *inst = desc->instance;
104  int dstW = desc->dst->width;
105  int chrSliceY = sliceY >> desc->dst->v_chr_sub_sample;
106 
107  int lum_fsize = inst[0].filter_size;
108  int chr_fsize = inst[1].filter_size;
109  uint16_t *lum_filter = inst[0].filter[0];
110  uint16_t *chr_filter = inst[1].filter[0];
111 
112  int firstLum = FFMAX(1-lum_fsize, inst[0].filter_pos[ sliceY]);
113  int firstChr = FFMAX(1-chr_fsize, inst[1].filter_pos[chrSliceY]);
114 
115  int sp0 = firstLum - desc->src->plane[0].sliceY;
116  int sp1 = firstChr - desc->src->plane[1].sliceY;
117  int sp2 = firstChr - desc->src->plane[2].sliceY;
118  int sp3 = firstLum - desc->src->plane[3].sliceY;
119  int dp = sliceY - desc->dst->plane[0].sliceY;
120  uint8_t **src0 = desc->src->plane[0].line + sp0;
121  uint8_t **src1 = desc->src->plane[1].line + sp1;
122  uint8_t **src2 = desc->src->plane[2].line + sp2;
123  uint8_t **src3 = desc->alpha ? desc->src->plane[3].line + sp3 : NULL;
124  uint8_t **dst = desc->dst->plane[0].line + dp;
125 
126 
127  if (c->yuv2packed1 && lum_fsize == 1 && chr_fsize == 1) { // unscaled RGB
128  ((yuv2packed1_fn)inst->pfn)(c, (const int16_t*)*src0, (const int16_t**)src1, (const int16_t**)src2,
129  (const int16_t*)(desc->alpha ? *src3 : NULL), *dst, dstW, 0, sliceY);
130  } else if (c->yuv2packed1 && lum_fsize == 1 && chr_fsize == 2 &&
131  chr_filter[2 * chrSliceY + 1] + chr_filter[2 * chrSliceY] == 4096 &&
132  chr_filter[2 * chrSliceY + 1] <= 4096U) { // unscaled RGB
133  int chrAlpha = chr_filter[2 * chrSliceY + 1];
134  ((yuv2packed1_fn)inst->pfn)(c, (const int16_t*)*src0, (const int16_t**)src1, (const int16_t**)src2,
135  (const int16_t*)(desc->alpha ? *src3 : NULL), *dst, dstW, chrAlpha, sliceY);
136  } else if (c->yuv2packed2 && lum_fsize == 2 && chr_fsize == 2 &&
137  lum_filter[2 * sliceY + 1] + lum_filter[2 * sliceY] == 4096 &&
138  lum_filter[2 * sliceY + 1] <= 4096U &&
139  chr_filter[2 * chrSliceY + 1] + chr_filter[2 * chrSliceY] == 4096 &&
140  chr_filter[2 * chrSliceY + 1] <= 4096U
141  ) { // bilinear upscale RGB
142  int lumAlpha = lum_filter[2 * sliceY + 1];
143  int chrAlpha = chr_filter[2 * chrSliceY + 1];
144  c->lumMmxFilter[2] =
145  c->lumMmxFilter[3] = lum_filter[2 * sliceY] * 0x10001;
146  c->chrMmxFilter[2] =
147  c->chrMmxFilter[3] = chr_filter[2 * chrSliceY] * 0x10001;
148  ((yuv2packed2_fn)inst->pfn)(c, (const int16_t**)src0, (const int16_t**)src1, (const int16_t**)src2, (const int16_t**)src3,
149  *dst, dstW, lumAlpha, chrAlpha, sliceY);
150  } else { // general RGB
151  if ((c->yuv2packed1 && lum_fsize == 1 && chr_fsize == 2) ||
152  (c->yuv2packed2 && lum_fsize == 2 && chr_fsize == 2)) {
154  av_log(c, AV_LOG_INFO, "Optimized 2 tap filter code cannot be used\n");
156  }
157 
158  inst->yuv2packedX(c, lum_filter + sliceY * lum_fsize,
159  (const int16_t**)src0, lum_fsize, chr_filter + chrSliceY * chr_fsize,
160  (const int16_t**)src1, (const int16_t**)src2, chr_fsize, (const int16_t**)src3, *dst, dstW, sliceY);
161  }
162  return 1;
163 }
164 
165 static int any_vscale(SwsContext *c, SwsFilterDescriptor *desc, int sliceY, int sliceH)
166 {
167  VScalerContext *inst = desc->instance;
168  int dstW = desc->dst->width;
169  int chrSliceY = sliceY >> desc->dst->v_chr_sub_sample;
170 
171  int lum_fsize = inst[0].filter_size;
172  int chr_fsize = inst[1].filter_size;
173  uint16_t *lum_filter = inst[0].filter[0];
174  uint16_t *chr_filter = inst[1].filter[0];
175 
176  int firstLum = FFMAX(1-lum_fsize, inst[0].filter_pos[ sliceY]);
177  int firstChr = FFMAX(1-chr_fsize, inst[1].filter_pos[chrSliceY]);
178 
179  int sp0 = firstLum - desc->src->plane[0].sliceY;
180  int sp1 = firstChr - desc->src->plane[1].sliceY;
181  int sp2 = firstChr - desc->src->plane[2].sliceY;
182  int sp3 = firstLum - desc->src->plane[3].sliceY;
183  int dp0 = sliceY - desc->dst->plane[0].sliceY;
184  int dp1 = chrSliceY - desc->dst->plane[1].sliceY;
185  int dp2 = chrSliceY - desc->dst->plane[2].sliceY;
186  int dp3 = sliceY - desc->dst->plane[3].sliceY;
187 
188  uint8_t **src0 = desc->src->plane[0].line + sp0;
189  uint8_t **src1 = desc->src->plane[1].line + sp1;
190  uint8_t **src2 = desc->src->plane[2].line + sp2;
191  uint8_t **src3 = desc->alpha ? desc->src->plane[3].line + sp3 : NULL;
192  uint8_t *dst[4] = { desc->dst->plane[0].line[dp0],
193  desc->dst->plane[1].line[dp1],
194  desc->dst->plane[2].line[dp2],
195  desc->alpha ? desc->dst->plane[3].line[dp3] : NULL };
196 
197  av_assert1(!c->yuv2packed1 && !c->yuv2packed2);
198  ((yuv2anyX_fn)inst->pfn)(c, lum_filter + sliceY * lum_fsize,
199  (const int16_t**)src0, lum_fsize, chr_filter + sliceY * chr_fsize,
200  (const int16_t**)src1, (const int16_t**)src2, chr_fsize, (const int16_t**)src3, dst, dstW, sliceY);
201 
202  return 1;
203 
204 }
205 
207 {
208  VScalerContext *lumCtx = NULL;
209  VScalerContext *chrCtx = NULL;
210 
211  if (isPlanarYUV(c->dstFormat) || (isGray(c->dstFormat) && !isALPHA(c->dstFormat))) {
212  lumCtx = av_mallocz(sizeof(VScalerContext));
213  if (!lumCtx)
214  return AVERROR(ENOMEM);
215 
216 
217  desc[0].process = lum_planar_vscale;
218  desc[0].instance = lumCtx;
219  desc[0].src = src;
220  desc[0].dst = dst;
221  desc[0].alpha = c->needAlpha;
222 
223  if (!isGray(c->dstFormat)) {
224  chrCtx = av_mallocz(sizeof(VScalerContext));
225  if (!chrCtx)
226  return AVERROR(ENOMEM);
227  desc[1].process = chr_planar_vscale;
228  desc[1].instance = chrCtx;
229  desc[1].src = src;
230  desc[1].dst = dst;
231  }
232  } else {
233  lumCtx = av_mallocz_array(sizeof(VScalerContext), 2);
234  if (!lumCtx)
235  return AVERROR(ENOMEM);
236  chrCtx = &lumCtx[1];
237 
238  desc[0].process = c->yuv2packedX ? packed_vscale : any_vscale;
239  desc[0].instance = lumCtx;
240  desc[0].src = src;
241  desc[0].dst = dst;
242  desc[0].alpha = c->needAlpha;
243  }
244 
247  return 0;
248 }
249 
251  yuv2planar1_fn yuv2plane1,
252  yuv2planarX_fn yuv2planeX,
253  yuv2interleavedX_fn yuv2nv12cX,
254  yuv2packed1_fn yuv2packed1,
255  yuv2packed2_fn yuv2packed2,
257  yuv2anyX_fn yuv2anyX, int use_mmx)
258 {
259  VScalerContext *lumCtx = NULL;
260  VScalerContext *chrCtx = NULL;
261  int idx = c->numDesc - (c->is_internal_gamma ? 2 : 1); //FIXME avoid hardcoding indexes
262 
263  if (isPlanarYUV(c->dstFormat) || (isGray(c->dstFormat) && !isALPHA(c->dstFormat))) {
264  if (!isGray(c->dstFormat)) {
265  chrCtx = c->desc[idx].instance;
266 
267  chrCtx->filter[0] = use_mmx ? (int16_t*)c->chrMmxFilter : c->vChrFilter;
268  chrCtx->filter_size = c->vChrFilterSize;
269  chrCtx->filter_pos = c->vChrFilterPos;
270  chrCtx->isMMX = use_mmx;
271 
272  --idx;
273  if (yuv2nv12cX) chrCtx->pfn = yuv2nv12cX;
274  else if (c->vChrFilterSize == 1) chrCtx->pfn = yuv2plane1;
275  else chrCtx->pfn = yuv2planeX;
276  }
277 
278  lumCtx = c->desc[idx].instance;
279 
280  lumCtx->filter[0] = use_mmx ? (int16_t*)c->lumMmxFilter : c->vLumFilter;
281  lumCtx->filter[1] = use_mmx ? (int16_t*)c->alpMmxFilter : c->vLumFilter;
282  lumCtx->filter_size = c->vLumFilterSize;
283  lumCtx->filter_pos = c->vLumFilterPos;
284  lumCtx->isMMX = use_mmx;
285 
286  if (c->vLumFilterSize == 1) lumCtx->pfn = yuv2plane1;
287  else lumCtx->pfn = yuv2planeX;
288 
289  } else {
290  lumCtx = c->desc[idx].instance;
291  chrCtx = &lumCtx[1];
292 
293  lumCtx->filter[0] = c->vLumFilter;
294  lumCtx->filter_size = c->vLumFilterSize;
295  lumCtx->filter_pos = c->vLumFilterPos;
296 
297  chrCtx->filter[0] = c->vChrFilter;
298  chrCtx->filter_size = c->vChrFilterSize;
299  chrCtx->filter_pos = c->vChrFilterPos;
300 
301  lumCtx->isMMX = use_mmx;
302  chrCtx->isMMX = use_mmx;
303 
304  if (yuv2packedX) {
305  if (c->yuv2packed1 && c->vLumFilterSize == 1 && c->vChrFilterSize <= 2)
306  lumCtx->pfn = yuv2packed1;
307  else if (c->yuv2packed2 && c->vLumFilterSize == 2 && c->vChrFilterSize == 2)
308  lumCtx->pfn = yuv2packed2;
309  lumCtx->yuv2packedX = yuv2packedX;
310  } else
311  lumCtx->pfn = yuv2anyX;
312  }
313 }
314 
315 
#define NULL
Definition: coverity.c:32
void ff_init_vscale_pfn(SwsContext *c, yuv2planar1_fn yuv2plane1, yuv2planarX_fn yuv2planeX, yuv2interleavedX_fn yuv2nv12cX, yuv2packed1_fn yuv2packed1, yuv2packed2_fn yuv2packed2, yuv2packedX_fn yuv2packedX, yuv2anyX_fn yuv2anyX, int use_mmx)
setup vertical scaler functions
Definition: vscale.c:250
const char * desc
Definition: nvenc.c:65
int h_chr_sub_sample
horizontal chroma subsampling factor
Struct which holds all necessary data for processing a slice.
int ff_init_vscale(SwsContext *c, SwsFilterDescriptor *desc, SwsSlice *src, SwsSlice *dst)
initializes vertical scaling descriptors
Definition: vscale.c:206
uint16_t * filter[2]
Definition: vscale.c:24
const uint8_t * lumDither8
#define src
Definition: vp8dsp.c:254
uint8_t
static int any_vscale(SwsContext *c, SwsFilterDescriptor *desc, int sliceY, int sliceH)
Definition: vscale.c:165
uint8_t ** line
line buffer
int alpha
Flag for processing alpha channel.
int vChrFilterSize
Vertical filter size for chroma pixels.
int v_chr_sub_sample
vertical chroma subsampling factor
SwsSlice * dst
Output slice.
void(* yuv2planar1_fn)(const int16_t *src, uint8_t *dest, int dstW, const uint8_t *dither, int offset)
Write one line of horizontally scaled data to planar output without any additional vertical scaling (...
#define sp
Definition: regdef.h:63
enum AVPixelFormat dstFormat
Destination pixel format.
#define isALPHA(x)
Definition: swscale.c:51
#define av_log(a,...)
yuv2packedX_fn yuv2packedX
int32_t * vChrFilterPos
Array of vertical filter starting positions for each dst[i] for chroma planes.
#define U(x)
Definition: vp56_arith.h:37
yuv2anyX_fn yuv2anyX
#define AVERROR(e)
Definition: error.h:43
yuv2packed1_fn yuv2packed1
void * av_mallocz(size_t size)
Allocate a memory block with alignment suitable for all memory accesses (including vectors if availab...
Definition: mem.c:236
#define FFMAX(a, b)
Definition: common.h:94
SwsPlane plane[MAX_SLICE_PLANES]
color planes
int32_t alpMmxFilter[4 *MAX_FILTER_SIZE]
ptrdiff_t uv_offx2
offset (in bytes) between u and v planes
void * pfn
Definition: vscale.c:28
#define av_assert1(cond)
assert() equivalent, that does not lie in speed critical code.
Definition: avassert.h:53
yuv2planar1_fn yuv2plane1
yuv2interleavedX_fn yuv2nv12cX
int32_t
struct SwsFilterDescriptor * desc
if(ret< 0)
Definition: vf_mcdeint.c:279
int32_t * vLumFilterPos
Array of vertical filter starting positions for each dst[i] for luma/alpha planes.
#define isGray(x)
Definition: swscale.c:40
static int lum_planar_vscale(SwsContext *c, SwsFilterDescriptor *desc, int sliceY, int sliceH)
Definition: vscale.c:33
int32_t lumMmxFilter[4 *MAX_FILTER_SIZE]
static int packed_vscale(SwsContext *c, SwsFilterDescriptor *desc, int sliceY, int sliceH)
Definition: vscale.c:101
#define src1
Definition: h264pred.c:139
#define AV_LOG_INFO
Standard information.
Definition: log.h:187
int width
Slice line width.
void(* yuv2packedX_fn)(struct SwsContext *c, const int16_t *lumFilter, const int16_t **lumSrc, int lumFilterSize, const int16_t *chrFilter, const int16_t **chrUSrc, const int16_t **chrVSrc, int chrFilterSize, const int16_t **alpSrc, uint8_t *dest, int dstW, int y)
Write one line of horizontally scaled Y/U/V/A to packed-pixel YUV/RGB output by doing multi-point ver...
int(* process)(SwsContext *c, struct SwsFilterDescriptor *desc, int sliceY, int sliceH)
Function for processing input slice sliceH lines starting from line sliceY.
yuv2planarX_fn yuv2planeX
int warned_unuseable_bilinear
void(* yuv2packed1_fn)(struct SwsContext *c, const int16_t *lumSrc, const int16_t *chrUSrc[2], const int16_t *chrVSrc[2], const int16_t *alpSrc, uint8_t *dest, int dstW, int uvalpha, int y)
Write one line of horizontally scaled Y/U/V/A to packed-pixel YUV/RGB output without any additional v...
Struct which defines a slice of an image to be scaled or an output for a scaled slice.
int32_t * filter_pos
Definition: vscale.c:25
void(* yuv2planarX_fn)(const int16_t *filter, int filterSize, const int16_t **src, uint8_t *dest, int dstW, const uint8_t *dither, int offset)
Write one line of horizontally scaled data to planar output with multi-point vertical scaling between...
int vLumFilterSize
Vertical filter size for luma/alpha pixels.
#define src0
Definition: h264pred.c:138
static av_always_inline int isPlanarYUV(enum AVPixelFormat pix_fmt)
int16_t * vChrFilter
Array of vertical filter coefficients for chroma planes.
void * instance
Filter instance data.
const uint8_t * chrDither8
yuv2packed2_fn yuv2packed2
static double c[64]
void(* yuv2packed2_fn)(struct SwsContext *c, const int16_t *lumSrc[2], const int16_t *chrUSrc[2], const int16_t *chrVSrc[2], const int16_t *alpSrc[2], uint8_t *dest, int dstW, int yalpha, int uvalpha, int y)
Write one line of horizontally scaled Y/U/V/A to packed-pixel YUV/RGB output by doing bilinear scalin...
int32_t chrMmxFilter[4 *MAX_FILTER_SIZE]
yuv2packedX_fn yuv2packedX
Definition: vscale.c:29
void(* yuv2interleavedX_fn)(struct SwsContext *c, const int16_t *chrFilter, int chrFilterSize, const int16_t **chrUSrc, const int16_t **chrVSrc, uint8_t *dest, int dstW)
Write one line of horizontally scaled chroma to interleaved output with multi-point vertical scaling ...
void(* yuv2anyX_fn)(struct SwsContext *c, const int16_t *lumFilter, const int16_t **lumSrc, int lumFilterSize, const int16_t *chrFilter, const int16_t **chrUSrc, const int16_t **chrVSrc, int chrFilterSize, const int16_t **alpSrc, uint8_t **dest, int dstW, int y)
Write one line of horizontally scaled Y/U/V/A to YUV/RGB output by doing multi-point vertical scaling...
int16_t * vLumFilter
Array of vertical filter coefficients for luma/alpha planes.
SwsSlice * src
Source slice.
int sliceY
index of first line
int filter_size
Definition: vscale.c:26
static int chr_planar_vscale(SwsContext *c, SwsFilterDescriptor *desc, int sliceY, int sliceH)
Definition: vscale.c:66
void * av_mallocz_array(size_t nmemb, size_t size)
Allocate a memory block for an array with av_mallocz().
Definition: mem.c:191
#define AV_CEIL_RSHIFT(a, b)
Definition: common.h:58