FFmpeg
 All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros Groups Pages
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 static int lum_planar_vscale(SwsContext *c, SwsFilterDescriptor *desc, int sliceY, int sliceH)
23 {
24  VScalerContext *inst = desc->instance;
25  int dstW = desc->dst->width;
26 
27  int first = FFMAX(1-inst->filter_size, inst->filter_pos[sliceY]);
28  int sp = first - desc->src->plane[0].sliceY;
29  int dp = sliceY - desc->dst->plane[0].sliceY;
30  uint8_t **src = desc->src->plane[0].line + sp;
31  uint8_t **dst = desc->dst->plane[0].line + dp;
32  uint16_t *filter = inst->filter[0] + (inst->isMMX ? 0 : sliceY * inst->filter_size);
33 
34  if (inst->filter_size == 1)
35  ((yuv2planar1_fn)inst->pfn)((const int16_t*)src[0], dst[0], dstW, c->lumDither8, 0);
36  else
37  ((yuv2planarX_fn)inst->pfn)(filter, inst->filter_size, (const int16_t**)src, dst[0], dstW, c->lumDither8, 0);
38 
39  if (desc->alpha) {
40  int sp = first - desc->src->plane[3].sliceY;
41  int dp = sliceY - desc->dst->plane[3].sliceY;
42  uint8_t **src = desc->src->plane[3].line + sp;
43  uint8_t **dst = desc->dst->plane[3].line + dp;
44  uint16_t *filter = inst->filter[1] + (inst->isMMX ? 0 : sliceY * inst->filter_size);
45 
46  if (inst->filter_size == 1)
47  ((yuv2planar1_fn)inst->pfn)((const int16_t*)src[0], dst[0], dstW, c->lumDither8, 0);
48  else
49  ((yuv2planarX_fn)inst->pfn)(filter, inst->filter_size, (const int16_t**)src, dst[0], dstW, c->lumDither8, 0);
50  }
51 
52  return 1;
53 }
54 
55 static int chr_planar_vscale(SwsContext *c, SwsFilterDescriptor *desc, int sliceY, int sliceH)
56 {
57  const int chrSkipMask = (1 << desc->dst->v_chr_sub_sample) - 1;
58  if (sliceY & chrSkipMask)
59  return 0;
60  else {
61  VScalerContext *inst = desc->instance;
62  int dstW = FF_CEIL_RSHIFT(desc->dst->width, desc->dst->h_chr_sub_sample);
63  int chrSliceY = sliceY >> desc->dst->v_chr_sub_sample;
64 
65  int first = FFMAX(1-inst->filter_size, inst->filter_pos[chrSliceY]);
66  int sp1 = first - desc->src->plane[1].sliceY;
67  int sp2 = first - desc->src->plane[2].sliceY;
68  int dp1 = chrSliceY - desc->dst->plane[1].sliceY;
69  int dp2 = chrSliceY - desc->dst->plane[2].sliceY;
70  uint8_t **src1 = desc->src->plane[1].line + sp1;
71  uint8_t **src2 = desc->src->plane[2].line + sp2;
72  uint8_t **dst1 = desc->dst->plane[1].line + dp1;
73  uint8_t **dst2 = desc->dst->plane[2].line + dp2;
74  uint16_t *filter = inst->filter[0] + (inst->isMMX ? 0 : chrSliceY * inst->filter_size);
75 
76  if (c->yuv2nv12cX) {
77  ((yuv2interleavedX_fn)inst->pfn)(c, filter, inst->filter_size, (const int16_t**)src1, (const int16_t**)src2, dst1[0], dstW);
78  } else if (inst->filter_size == 1) {
79  ((yuv2planar1_fn)inst->pfn)((const int16_t*)src1[0], dst1[0], dstW, c->chrDither8, 0);
80  ((yuv2planar1_fn)inst->pfn)((const int16_t*)src2[0], dst2[0], dstW, c->chrDither8, 3);
81  } else {
82  ((yuv2planarX_fn)inst->pfn)(filter, inst->filter_size, (const int16_t**)src1, dst1[0], dstW, c->chrDither8, 0);
83  ((yuv2planarX_fn)inst->pfn)(filter, inst->filter_size, (const int16_t**)src2, dst2[0], dstW, c->chrDither8, inst->isMMX ? (c->uv_offx2 >> 1) : 3);
84  }
85  }
86 
87  return 1;
88 }
89 
90 static int packed_vscale(SwsContext *c, SwsFilterDescriptor *desc, int sliceY, int sliceH)
91 {
92  VScalerContext *inst = desc->instance;
93  int dstW = desc->dst->width;
94  int chrSliceY = sliceY >> desc->dst->v_chr_sub_sample;
95 
96  int lum_fsize = inst[0].filter_size;
97  int chr_fsize = inst[1].filter_size;
98  uint16_t *lum_filter = inst[0].filter[0];
99  uint16_t *chr_filter = inst[1].filter[0];
100 
101  int firstLum = FFMAX(1-lum_fsize, inst[0].filter_pos[chrSliceY]);
102  int firstChr = FFMAX(1-chr_fsize, inst[1].filter_pos[chrSliceY]);
103 
104  int sp0 = firstLum - desc->src->plane[0].sliceY;
105  int sp1 = firstChr - desc->src->plane[1].sliceY;
106  int sp2 = firstChr - desc->src->plane[2].sliceY;
107  int sp3 = firstLum - desc->src->plane[3].sliceY;
108  int dp = sliceY - desc->dst->plane[0].sliceY;
109  uint8_t **src0 = desc->src->plane[0].line + sp0;
110  uint8_t **src1 = desc->src->plane[1].line + sp1;
111  uint8_t **src2 = desc->src->plane[2].line + sp2;
112  uint8_t **src3 = desc->alpha ? desc->src->plane[3].line + sp3 : NULL;
113  uint8_t **dst = desc->dst->plane[0].line + dp;
114 
115 
116  if (c->yuv2packed1 && lum_fsize == 1 && chr_fsize <= 2) { // unscaled RGB
117  int chrAlpha = chr_fsize == 1 ? 0 : chr_filter[2 * sliceY + 1];
118  ((yuv2packed1_fn)inst->pfn)(c, (const int16_t*)*src0, (const int16_t**)src1, (const int16_t**)src2, (const int16_t*)(desc->alpha ? *src3 : NULL), *dst, dstW, chrAlpha, sliceY);
119  } else if (c->yuv2packed2 && lum_fsize == 2 && chr_fsize == 2) { // bilinear upscale RGB
120  int lumAlpha = lum_filter[2 * sliceY + 1];
121  int chrAlpha = chr_filter[2 * sliceY + 1];
122  c->lumMmxFilter[2] =
123  c->lumMmxFilter[3] = lum_filter[2 * sliceY] * 0x10001;
124  c->chrMmxFilter[2] =
125  c->chrMmxFilter[3] = chr_filter[2 * chrSliceY] * 0x10001;
126  ((yuv2packed2_fn)inst->pfn)(c, (const int16_t**)src0, (const int16_t**)src1, (const int16_t**)src2, (const int16_t**)src3,
127  *dst, dstW, lumAlpha, chrAlpha, sliceY);
128  } else { // general RGB
129  ((yuv2packedX_fn)inst->pfn)(c, lum_filter + sliceY * lum_fsize,
130  (const int16_t**)src0, lum_fsize, chr_filter + sliceY * chr_fsize,
131  (const int16_t**)src1, (const int16_t**)src2, chr_fsize, (const int16_t**)src3, *dst, dstW, sliceY);
132  }
133  return 1;
134 }
135 
136 static int any_vscale(SwsContext *c, SwsFilterDescriptor *desc, int sliceY, int sliceH)
137 {
138  VScalerContext *inst = desc->instance;
139  int dstW = desc->dst->width;
140  int chrSliceY = sliceY >> desc->dst->v_chr_sub_sample;
141 
142  int lum_fsize = inst[0].filter_size;
143  int chr_fsize = inst[1].filter_size;
144  uint16_t *lum_filter = inst[0].filter[0];
145  uint16_t *chr_filter = inst[1].filter[0];
146 
147  int firstLum = FFMAX(1-lum_fsize, inst[0].filter_pos[chrSliceY]);
148  int firstChr = FFMAX(1-chr_fsize, inst[1].filter_pos[chrSliceY]);
149 
150  int sp0 = firstLum - desc->src->plane[0].sliceY;
151  int sp1 = firstChr - desc->src->plane[1].sliceY;
152  int sp2 = firstChr - desc->src->plane[2].sliceY;
153  int sp3 = firstLum - desc->src->plane[3].sliceY;
154  int dp0 = sliceY - desc->dst->plane[0].sliceY;
155  int dp1 = chrSliceY - desc->dst->plane[1].sliceY;
156  int dp2 = chrSliceY - desc->dst->plane[2].sliceY;
157  int dp3 = sliceY - desc->dst->plane[3].sliceY;
158 
159  uint8_t **src0 = desc->src->plane[0].line + sp0;
160  uint8_t **src1 = desc->src->plane[1].line + sp1;
161  uint8_t **src2 = desc->src->plane[2].line + sp2;
162  uint8_t **src3 = desc->alpha ? desc->src->plane[3].line + sp3 : NULL;
163  uint8_t *dst[4] = { desc->dst->plane[0].line[dp0],
164  desc->dst->plane[1].line[dp1],
165  desc->dst->plane[2].line[dp2],
166  desc->alpha ? desc->dst->plane[3].line[dp3] : NULL };
167 
168  av_assert1(!c->yuv2packed1 && !c->yuv2packed2);
169  ((yuv2anyX_fn)inst->pfn)(c, lum_filter + sliceY * lum_fsize,
170  (const int16_t**)src0, lum_fsize, chr_filter + sliceY * chr_fsize,
171  (const int16_t**)src1, (const int16_t**)src2, chr_fsize, (const int16_t**)src3, dst, dstW, sliceY);
172 
173  return 1;
174 
175 }
176 
178 {
179  VScalerContext *lumCtx = NULL;
180  VScalerContext *chrCtx = NULL;
181 
182  if (isPlanarYUV(c->dstFormat) || (isGray(c->dstFormat) && !isALPHA(c->dstFormat))) {
183  lumCtx = av_mallocz(sizeof(VScalerContext));
184  if (!lumCtx)
185  return AVERROR(ENOMEM);
186 
187 
188  desc[0].process = lum_planar_vscale;
189  desc[0].instance = lumCtx;
190  desc[0].src = src;
191  desc[0].dst = dst;
192  desc[0].alpha = c->alpPixBuf != 0;
193 
194  if (!isGray(c->dstFormat)) {
195  chrCtx = av_mallocz(sizeof(VScalerContext));
196  if (!chrCtx)
197  return AVERROR(ENOMEM);
198  desc[1].process = chr_planar_vscale;
199  desc[1].instance = chrCtx;
200  desc[1].src = src;
201  desc[1].dst = dst;
202  }
203  } else {
204  lumCtx = av_mallocz_array(sizeof(VScalerContext), 2);
205  if (!lumCtx)
206  return AVERROR(ENOMEM);
207  chrCtx = &lumCtx[1];
208 
209  desc[0].process = c->yuv2packedX ? packed_vscale : any_vscale;
210  desc[0].instance = lumCtx;
211  desc[0].src = src;
212  desc[0].dst = dst;
213  desc[0].alpha = c->alpPixBuf != 0;
214  }
215 
218  return 0;
219 }
220 
222  yuv2planar1_fn yuv2plane1,
223  yuv2planarX_fn yuv2planeX,
224  yuv2interleavedX_fn yuv2nv12cX,
225  yuv2packed1_fn yuv2packed1,
226  yuv2packed2_fn yuv2packed2,
227  yuv2packedX_fn yuv2packedX,
228  yuv2anyX_fn yuv2anyX, int use_mmx)
229 {
230  VScalerContext *lumCtx = NULL;
231  VScalerContext *chrCtx = NULL;
232  int idx = c->numDesc - (c->is_internal_gamma ? 2 : 1);
233 
234  if (isPlanarYUV(c->dstFormat) || (isGray(c->dstFormat) && !isALPHA(c->dstFormat))) {
235  if (!isGray(c->dstFormat)) {
236  chrCtx = c->desc[idx].instance;
237 
238  chrCtx->filter[0] = use_mmx ? (int16_t*)c->chrMmxFilter : c->vChrFilter;
239  chrCtx->filter_size = c->vChrFilterSize;
240  chrCtx->filter_pos = c->vChrFilterPos;
241  chrCtx->isMMX = use_mmx;
242 
243  --idx;
244  if (yuv2nv12cX) chrCtx->pfn = yuv2nv12cX;
245  else if (c->vChrFilterSize == 1) chrCtx->pfn = yuv2plane1;
246  else chrCtx->pfn = yuv2planeX;
247  }
248 
249  lumCtx = c->desc[idx].instance;
250 
251  lumCtx->filter[0] = use_mmx ? (int16_t*)c->lumMmxFilter : c->vLumFilter;
252  lumCtx->filter[1] = use_mmx ? (int16_t*)c->alpMmxFilter : c->vLumFilter;
253  lumCtx->filter_size = c->vLumFilterSize;
254  lumCtx->filter_pos = c->vLumFilterPos;
255  lumCtx->isMMX = use_mmx;
256 
257  if (c->vLumFilterSize == 1) lumCtx->pfn = yuv2plane1;
258  else lumCtx->pfn = yuv2planeX;
259 
260  } else {
261  lumCtx = c->desc[idx].instance;
262  chrCtx = &lumCtx[1];
263 
264  lumCtx->filter[0] = c->vLumFilter;
265  lumCtx->filter_size = c->vLumFilterSize;
266  lumCtx->filter_pos = c->vLumFilterPos;
267 
268  chrCtx->filter[0] = c->vChrFilter;
269  chrCtx->filter_size = c->vChrFilterSize;
270  chrCtx->filter_pos = c->vChrFilterPos;
271 
272  lumCtx->isMMX = use_mmx;
273  chrCtx->isMMX = use_mmx;
274 
275  if (yuv2packedX) {
276  if (c->yuv2packed1 && c->vLumFilterSize == 1 && c->vChrFilterSize <= 2)
277  lumCtx->pfn = yuv2packed1;
278  else if (c->yuv2packed2 && c->vLumFilterSize == 2 && c->vChrFilterSize == 2)
279  lumCtx->pfn = yuv2packed2;
280  else
281  lumCtx->pfn = yuv2packedX;
282  } else
283  lumCtx->pfn = yuv2anyX;
284  }
285 }
286 
287 
int16_t ** alpPixBuf
Ring buffer for scaled horizontal alpha plane lines to be fed to the vertical scaler.
#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:221
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:177
uint16_t * filter[2]
const uint8_t * lumDither8
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 ...
uint8_t
static int any_vscale(SwsContext *c, SwsFilterDescriptor *desc, int sliceY, int sliceH)
Definition: vscale.c:136
uint8_t ** line
line buffer
int alpha
Flag for processing alpha channel.
int vChrFilterSize
Vertical filter size for chroma pixels.
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...
int v_chr_sub_sample
vertical chroma subsampling factor
SwsSlice * dst
Output slice.
#define sp
Definition: regdef.h:63
int(* process)(SwsContext *c, struct SwsFilterDescriptor *desc, int sliceY, int sliceH)
Function for processing input slice sliceH lines starting from line sliceY.
enum AVPixelFormat dstFormat
Destination pixel format.
#define isALPHA(x)
Definition: swscale-test.c:49
yuv2packedX_fn yuv2packedX
int32_t * vChrFilterPos
Array of vertical filter starting positions for each dst[i] for chroma planes.
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...
yuv2anyX_fn yuv2anyX
#define AVERROR(e)
Definition: error.h:43
yuv2packed1_fn yuv2packed1
#define FFMAX(a, b)
Definition: common.h:79
SwsPlane plane[MAX_SLICE_PLANES]
color planes
int32_t alpMmxFilter[4 *MAX_FILTER_SIZE]
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 (...
ptrdiff_t uv_offx2
offset (in bytes) between u and v planes
#define av_assert1(cond)
assert() equivalent, that does not lie in speed critical code.
Definition: avassert.h:53
yuv2planar1_fn yuv2plane1
yuv2interleavedX_fn yuv2nv12cX
#define FF_CEIL_RSHIFT(a, b)
Definition: common.h:57
struct SwsFilterDescriptor * desc
int32_t * vLumFilterPos
Array of vertical filter starting positions for each dst[i] for luma/alpha planes.
static int lum_planar_vscale(SwsContext *c, SwsFilterDescriptor *desc, int sliceY, int sliceH)
Definition: vscale.c:22
int32_t lumMmxFilter[4 *MAX_FILTER_SIZE]
static int packed_vscale(SwsContext *c, SwsFilterDescriptor *desc, int sliceY, int sliceH)
Definition: vscale.c:90
#define src1
Definition: h264pred.c:139
AVS_Value src
Definition: avisynth_c.h:482
int width
Slice line width.
yuv2planarX_fn yuv2planeX
Struct which defines a slice of an image to be scaled or a output for a scaled slice.
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.
#define isGray(x)
Definition: swscale-test.c:38
const uint8_t * chrDither8
yuv2packed2_fn yuv2packed2
static void filter(MpegAudioContext *s, int ch, const short *samples, int incr)
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...
if(ret< 0)
Definition: vf_mcdeint.c:280
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...
static double c[64]
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...
int32_t chrMmxFilter[4 *MAX_FILTER_SIZE]
static void * av_mallocz_array(size_t nmemb, size_t size)
Definition: mem.h:228
int16_t * vLumFilter
Array of vertical filter coefficients for luma/alpha planes.
SwsSlice * src
Source slice.
int sliceY
index of first line
void * av_mallocz(size_t size)
Allocate a block of size bytes with alignment suitable for all memory accesses (including vectors if ...
Definition: mem.c:252
static int chr_planar_vscale(SwsContext *c, SwsFilterDescriptor *desc, int sliceY, int sliceH)
Definition: vscale.c:55