FFmpeg
slice.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 
21 #include "swscale_internal.h"
22 
23 static void free_lines(SwsSlice *s)
24 {
25  int i;
26  for (i = 0; i < 2; ++i) {
27  int n = s->plane[i].available_lines;
28  int j;
29  for (j = 0; j < n; ++j) {
30  av_freep(&s->plane[i].line[j]);
31  if (s->is_ring)
32  s->plane[i].line[j+n] = NULL;
33  }
34  }
35 
36  for (i = 0; i < 4; ++i)
37  memset(s->plane[i].line, 0, sizeof(uint8_t*) * s->plane[i].available_lines * (s->is_ring ? 3 : 1));
38  s->should_free_lines = 0;
39 }
40 
41 /*
42  slice lines contains extra bytes for vectorial code thus @size
43  is the allocated memory size and @width is the number of pixels
44 */
45 static int alloc_lines(SwsSlice *s, int size, int width)
46 {
47  int i;
48  int idx[2] = {3, 2};
49 
50  s->should_free_lines = 1;
51  s->width = width;
52 
53  for (i = 0; i < 2; ++i) {
54  int n = s->plane[i].available_lines;
55  int j;
56  int ii = idx[i];
57 
58  av_assert0(n == s->plane[ii].available_lines);
59  for (j = 0; j < n; ++j) {
60  // chroma plane line U and V are expected to be contiguous in memory
61  // by mmx vertical scaler code
62  s->plane[i].line[j] = av_malloc(size * 2 + 32);
63  if (!s->plane[i].line[j]) {
64  free_lines(s);
65  return AVERROR(ENOMEM);
66  }
67  s->plane[ii].line[j] = s->plane[i].line[j] + size + 16;
68  if (s->is_ring) {
69  s->plane[i].line[j+n] = s->plane[i].line[j];
70  s->plane[ii].line[j+n] = s->plane[ii].line[j];
71  }
72  }
73  }
74 
75  return 0;
76 }
77 
78 static int alloc_slice(SwsSlice *s, enum AVPixelFormat fmt, int lumLines, int chrLines, int h_sub_sample, int v_sub_sample, int ring)
79 {
80  int i;
81  int size[4] = { lumLines,
82  chrLines,
83  chrLines,
84  lumLines };
85 
86  s->h_chr_sub_sample = h_sub_sample;
87  s->v_chr_sub_sample = v_sub_sample;
88  s->fmt = fmt;
89  s->is_ring = ring;
90  s->should_free_lines = 0;
91 
92  for (i = 0; i < 4; ++i) {
93  int n = size[i] * ( ring == 0 ? 1 : 3);
94  s->plane[i].line = av_mallocz_array(sizeof(uint8_t*), n);
95  if (!s->plane[i].line)
96  return AVERROR(ENOMEM);
97 
98  s->plane[i].tmp = ring ? s->plane[i].line + size[i] * 2 : NULL;
99  s->plane[i].available_lines = size[i];
100  s->plane[i].sliceY = 0;
101  s->plane[i].sliceH = 0;
102  }
103  return 0;
104 }
105 
106 static void free_slice(SwsSlice *s)
107 {
108  int i;
109  if (s) {
110  if (s->should_free_lines)
111  free_lines(s);
112  for (i = 0; i < 4; ++i) {
113  av_freep(&s->plane[i].line);
114  s->plane[i].tmp = NULL;
115  }
116  }
117 }
118 
119 int ff_rotate_slice(SwsSlice *s, int lum, int chr)
120 {
121  int i;
122  if (lum) {
123  for (i = 0; i < 4; i+=3) {
124  int n = s->plane[i].available_lines;
125  int l = lum - s->plane[i].sliceY;
126 
127  if (l >= n * 2) {
128  s->plane[i].sliceY += n;
129  s->plane[i].sliceH -= n;
130  }
131  }
132  }
133  if (chr) {
134  for (i = 1; i < 3; ++i) {
135  int n = s->plane[i].available_lines;
136  int l = chr - s->plane[i].sliceY;
137 
138  if (l >= n * 2) {
139  s->plane[i].sliceY += n;
140  s->plane[i].sliceH -= n;
141  }
142  }
143  }
144  return 0;
145 }
146 
147 int ff_init_slice_from_src(SwsSlice * s, uint8_t *src[4], int stride[4], int srcW, int lumY, int lumH, int chrY, int chrH, int relative)
148 {
149  int i = 0;
150 
151  const int start[4] = {lumY,
152  chrY,
153  chrY,
154  lumY};
155 
156  const int end[4] = {lumY +lumH,
157  chrY + chrH,
158  chrY + chrH,
159  lumY + lumH};
160 
161  uint8_t *const src_[4] = {src[0] + (relative ? 0 : start[0]) * stride[0],
162  src[1] + (relative ? 0 : start[1]) * stride[1],
163  src[2] + (relative ? 0 : start[2]) * stride[2],
164  src[3] + (relative ? 0 : start[3]) * stride[3]};
165 
166  s->width = srcW;
167 
168  for (i = 0; i < 4; ++i) {
169  int j;
170  int first = s->plane[i].sliceY;
171  int n = s->plane[i].available_lines;
172  int lines = end[i] - start[i];
173  int tot_lines = end[i] - first;
174 
175  if (start[i] >= first && n >= tot_lines) {
176  s->plane[i].sliceH = FFMAX(tot_lines, s->plane[i].sliceH);
177  for (j = 0; j < lines; j+= 1)
178  s->plane[i].line[start[i] - first + j] = src_[i] + j * stride[i];
179  } else {
180  s->plane[i].sliceY = start[i];
181  lines = lines > n ? n : lines;
182  s->plane[i].sliceH = lines;
183  for (j = 0; j < lines; j+= 1)
184  s->plane[i].line[j] = src_[i] + j * stride[i];
185  }
186 
187  }
188 
189  return 0;
190 }
191 
192 static void fill_ones(SwsSlice *s, int n, int bpc)
193 {
194  int i, j, k, size, end;
195 
196  for (i = 0; i < 4; ++i) {
197  size = s->plane[i].available_lines;
198  for (j = 0; j < size; ++j) {
199  if (bpc == 16) {
200  end = (n>>1) + 1;
201  for (k = 0; k < end; ++k)
202  ((int32_t*)(s->plane[i].line[j]))[k] = 1<<18;
203  } else if (bpc == 32) {
204  end = (n>>2) + 1;
205  for (k = 0; k < end; ++k)
206  ((int64_t*)(s->plane[i].line[j]))[k] = 1LL<<34;
207  } else {
208  end = n + 1;
209  for (k = 0; k < end; ++k)
210  ((int16_t*)(s->plane[i].line[j]))[k] = 1<<14;
211  }
212  }
213  }
214 }
215 
216 /*
217  Calculates the minimum ring buffer size, it should be able to store vFilterSize
218  more n lines where n is the max difference between each adjacent slice which
219  outputs a line.
220  The n lines are needed only when there is not enough src lines to output a single
221  dst line, then we should buffer these lines to process them on the next call to scale.
222 */
223 static void get_min_buffer_size(SwsContext *c, int *out_lum_size, int *out_chr_size)
224 {
225  int lumY;
226  int dstH = c->dstH;
227  int chrDstH = c->chrDstH;
228  int *lumFilterPos = c->vLumFilterPos;
229  int *chrFilterPos = c->vChrFilterPos;
230  int lumFilterSize = c->vLumFilterSize;
231  int chrFilterSize = c->vChrFilterSize;
232  int chrSubSample = c->chrSrcVSubSample;
233 
234  *out_lum_size = lumFilterSize;
235  *out_chr_size = chrFilterSize;
236 
237  for (lumY = 0; lumY < dstH; lumY++) {
238  int chrY = (int64_t)lumY * chrDstH / dstH;
239  int nextSlice = FFMAX(lumFilterPos[lumY] + lumFilterSize - 1,
240  ((chrFilterPos[chrY] + chrFilterSize - 1)
241  << chrSubSample));
242 
243  nextSlice >>= chrSubSample;
244  nextSlice <<= chrSubSample;
245  (*out_lum_size) = FFMAX((*out_lum_size), nextSlice - lumFilterPos[lumY]);
246  (*out_chr_size) = FFMAX((*out_chr_size), (nextSlice >> chrSubSample) - chrFilterPos[chrY]);
247  }
248 }
249 
250 
251 
253 {
254  int i;
255  int index;
256  int num_ydesc;
257  int num_cdesc;
258  int num_vdesc = isPlanarYUV(c->dstFormat) && !isGray(c->dstFormat) ? 2 : 1;
259  int need_lum_conv = c->lumToYV12 || c->readLumPlanar || c->alpToYV12 || c->readAlpPlanar;
260  int need_chr_conv = c->chrToYV12 || c->readChrPlanar;
261  int need_gamma = c->is_internal_gamma;
262  int srcIdx, dstIdx;
263  int dst_stride = FFALIGN(c->dstW * sizeof(int16_t) + 66, 16);
264 
265  uint32_t * pal = usePal(c->srcFormat) ? c->pal_yuv : (uint32_t*)c->input_rgb2yuv_table;
266  int res = 0;
267 
268  int lumBufSize;
269  int chrBufSize;
270 
271  get_min_buffer_size(c, &lumBufSize, &chrBufSize);
272  lumBufSize = FFMAX(lumBufSize, c->vLumFilterSize + MAX_LINES_AHEAD);
273  chrBufSize = FFMAX(chrBufSize, c->vChrFilterSize + MAX_LINES_AHEAD);
274 
275  if (c->dstBpc == 16)
276  dst_stride <<= 1;
277 
278  if (c->dstBpc == 32)
279  dst_stride <<= 2;
280 
281  num_ydesc = need_lum_conv ? 2 : 1;
282  num_cdesc = need_chr_conv ? 2 : 1;
283 
284  c->numSlice = FFMAX(num_ydesc, num_cdesc) + 2;
285  c->numDesc = num_ydesc + num_cdesc + num_vdesc + (need_gamma ? 2 : 0);
286  c->descIndex[0] = num_ydesc + (need_gamma ? 1 : 0);
287  c->descIndex[1] = num_ydesc + num_cdesc + (need_gamma ? 1 : 0);
288 
289 
290 
292  if (!c->desc)
293  return AVERROR(ENOMEM);
294  c->slice = av_mallocz_array(sizeof(SwsSlice), c->numSlice);
295 
296 
297  res = alloc_slice(&c->slice[0], c->srcFormat, c->srcH, c->chrSrcH, c->chrSrcHSubSample, c->chrSrcVSubSample, 0);
298  if (res < 0) goto cleanup;
299  for (i = 1; i < c->numSlice-2; ++i) {
300  res = alloc_slice(&c->slice[i], c->srcFormat, lumBufSize, chrBufSize, c->chrSrcHSubSample, c->chrSrcVSubSample, 0);
301  if (res < 0) goto cleanup;
302  res = alloc_lines(&c->slice[i], FFALIGN(c->srcW*2+78, 16), c->srcW);
303  if (res < 0) goto cleanup;
304  }
305  // horizontal scaler output
306  res = alloc_slice(&c->slice[i], c->srcFormat, lumBufSize, chrBufSize, c->chrDstHSubSample, c->chrDstVSubSample, 1);
307  if (res < 0) goto cleanup;
308  res = alloc_lines(&c->slice[i], dst_stride, c->dstW);
309  if (res < 0) goto cleanup;
310 
311  fill_ones(&c->slice[i], dst_stride>>1, c->dstBpc);
312 
313  // vertical scaler output
314  ++i;
315  res = alloc_slice(&c->slice[i], c->dstFormat, c->dstH, c->chrDstH, c->chrDstHSubSample, c->chrDstVSubSample, 0);
316  if (res < 0) goto cleanup;
317 
318  index = 0;
319  srcIdx = 0;
320  dstIdx = 1;
321 
322  if (need_gamma) {
323  res = ff_init_gamma_convert(c->desc + index, c->slice + srcIdx, c->inv_gamma);
324  if (res < 0) goto cleanup;
325  ++index;
326  }
327 
328  if (need_lum_conv) {
329  res = ff_init_desc_fmt_convert(&c->desc[index], &c->slice[srcIdx], &c->slice[dstIdx], pal);
330  if (res < 0) goto cleanup;
331  c->desc[index].alpha = c->needAlpha;
332  ++index;
333  srcIdx = dstIdx;
334  }
335 
336 
337  dstIdx = FFMAX(num_ydesc, num_cdesc);
338  res = ff_init_desc_hscale(&c->desc[index], &c->slice[srcIdx], &c->slice[dstIdx], c->hLumFilter, c->hLumFilterPos, c->hLumFilterSize, c->lumXInc);
339  if (res < 0) goto cleanup;
340  c->desc[index].alpha = c->needAlpha;
341 
342 
343  ++index;
344  {
345  srcIdx = 0;
346  dstIdx = 1;
347  if (need_chr_conv) {
348  res = ff_init_desc_cfmt_convert(&c->desc[index], &c->slice[srcIdx], &c->slice[dstIdx], pal);
349  if (res < 0) goto cleanup;
350  ++index;
351  srcIdx = dstIdx;
352  }
353 
354  dstIdx = FFMAX(num_ydesc, num_cdesc);
355  if (c->needs_hcscale)
356  res = ff_init_desc_chscale(&c->desc[index], &c->slice[srcIdx], &c->slice[dstIdx], c->hChrFilter, c->hChrFilterPos, c->hChrFilterSize, c->chrXInc);
357  else
358  res = ff_init_desc_no_chr(&c->desc[index], &c->slice[srcIdx], &c->slice[dstIdx]);
359  if (res < 0) goto cleanup;
360  }
361 
362  ++index;
363  {
364  srcIdx = c->numSlice - 2;
365  dstIdx = c->numSlice - 1;
366  res = ff_init_vscale(c, c->desc + index, c->slice + srcIdx, c->slice + dstIdx);
367  if (res < 0) goto cleanup;
368  }
369 
370  ++index;
371  if (need_gamma) {
372  res = ff_init_gamma_convert(c->desc + index, c->slice + dstIdx, c->gamma);
373  if (res < 0) goto cleanup;
374  }
375 
376  return 0;
377 
378 cleanup:
379  ff_free_filters(c);
380  return res;
381 }
382 
384 {
385  int i;
386  if (c->desc) {
387  for (i = 0; i < c->numDesc; ++i)
388  av_freep(&c->desc[i].instance);
389  av_freep(&c->desc);
390  }
391 
392  if (c->slice) {
393  for (i = 0; i < c->numSlice; ++i)
394  free_slice(&c->slice[i]);
395  av_freep(&c->slice);
396  }
397  return 0;
398 }
int ff_init_gamma_convert(SwsFilterDescriptor *desc, SwsSlice *src, uint16_t *table)
initializes gamma conversion descriptor
Definition: gamma.c:58
#define NULL
Definition: coverity.c:32
int ff_init_desc_fmt_convert(SwsFilterDescriptor *desc, SwsSlice *src, SwsSlice *dst, uint32_t *pal)
initializes lum pixel format conversion descriptor
Definition: hscale.c:127
int chrSrcH
Height of source chroma planes.
int ff_free_filters(SwsContext *c)
Definition: slice.c:383
int ff_init_slice_from_src(SwsSlice *s, uint8_t *src[4], int stride[4], int srcW, int lumY, int lumH, int chrY, int chrH, int relative)
Definition: slice.c:147
int h_chr_sub_sample
horizontal chroma subsampling factor
Struct which holds all necessary data for processing a slice.
void(* chrToYV12)(uint8_t *dstU, uint8_t *dstV, const uint8_t *src1, const uint8_t *src2, const uint8_t *src3, int width, uint32_t *pal)
Unscaled conversion of chroma planes to YV12 for horizontal scaler.
void(* alpToYV12)(uint8_t *dst, const uint8_t *src, const uint8_t *src2, const uint8_t *src3, int width, uint32_t *pal)
Unscaled conversion of alpha plane to YV12 for horizontal scaler.
static void free_lines(SwsSlice *s)
Definition: slice.c:23
int srcH
Height of source luma/alpha planes.
int ff_rotate_slice(SwsSlice *s, int lum, int chr)
Definition: slice.c:119
#define av_assert0(cond)
assert() equivalent, that is always enabled.
Definition: avassert.h:37
static void get_min_buffer_size(SwsContext *c, int *out_lum_size, int *out_chr_size)
Definition: slice.c:223
int chrDstVSubSample
Binary logarithm of vertical subsampling factor between luma/alpha and chroma planes in destination i...
uint8_t
#define av_malloc(s)
uint8_t ** line
line buffer
int alpha
Flag for processing alpha channel.
int vChrFilterSize
Vertical filter size for chroma pixels.
static av_cold int end(AVCodecContext *avctx)
Definition: avrndec.c:90
Undefined Behavior In the C some operations are like signed integer dereferencing freed accessing outside allocated Undefined Behavior must not occur in a C it is not safe even if the output of undefined operations is unused The unsafety may seem nit picking but Optimizing compilers have in fact optimized code on the assumption that no undefined Behavior occurs Optimizing code based on wrong assumptions can and has in some cases lead to effects beyond the output of computations The signed integer overflow problem in speed critical code Code which is highly optimized and works with signed integers sometimes has the problem that often the output of the computation does not c
Definition: undefined.txt:32
int v_chr_sub_sample
vertical chroma subsampling factor
trying all byte sequences megabyte in length and selecting the best looking sequence will yield cases to try But first
enum AVPixelFormat dstFormat
Destination pixel format.
ptrdiff_t size
Definition: opengl_enc.c:100
uint16_t * inv_gamma
#define FFALIGN(x, a)
Definition: macros.h:48
int ff_init_desc_no_chr(SwsFilterDescriptor *desc, SwsSlice *src, SwsSlice *dst)
Definition: hscale.c:281
int chrSrcHSubSample
Binary logarithm of horizontal subsampling factor between luma/alpha and chroma planes in source imag...
int32_t * vChrFilterPos
Array of vertical filter starting positions for each dst[i] for chroma planes.
int dstH
Height of destination luma/alpha planes.
#define src
Definition: vp8dsp.c:254
int ff_init_desc_cfmt_convert(SwsFilterDescriptor *desc, SwsSlice *src, SwsSlice *dst, uint32_t *pal)
initializes chr pixel format conversion descriptor
Definition: hscale.c:235
#define i(width, name, range_min, range_max)
Definition: cbs_h2645.c:269
int32_t * hChrFilterPos
Array of horizontal filter starting positions for each dst[i] for chroma planes.
int hLumFilterSize
Horizontal filter size for luma/alpha pixels.
static int alloc_lines(SwsSlice *s, int size, int width)
Definition: slice.c:45
int ff_init_vscale(SwsContext *c, SwsFilterDescriptor *desc, SwsSlice *src, SwsSlice *dst)
initializes vertical scaling descriptors
Definition: vscale.c:213
#define FFMAX(a, b)
Definition: common.h:94
SwsPlane plane[MAX_SLICE_PLANES]
color planes
static int alloc_slice(SwsSlice *s, enum AVPixelFormat fmt, int lumLines, int chrLines, int h_sub_sample, int v_sub_sample, int ring)
Definition: slice.c:78
int32_t * hLumFilterPos
Array of horizontal filter starting positions for each dst[i] for luma/alpha planes.
int hChrFilterSize
Horizontal filter size for chroma pixels.
int sliceH
number of lines
int ff_init_desc_hscale(SwsFilterDescriptor *desc, SwsSlice *src, SwsSlice *dst, uint16_t *filter, int *filter_pos, int filter_size, int xInc)
initializes lum horizontal scaling descriptor
Definition: hscale.c:144
static double lum(void *priv, double x, double y, int plane)
Definition: vf_fftfilt.c:95
#define width
void(* readChrPlanar)(uint8_t *dstU, uint8_t *dstV, const uint8_t *src[4], int width, int32_t *rgb2yuv)
static void fill_ones(SwsSlice *s, int n, int bpc)
Definition: slice.c:192
int32_t
int ff_init_desc_chscale(SwsFilterDescriptor *desc, SwsSlice *src, SwsSlice *dst, uint16_t *filter, int *filter_pos, int filter_size, int xInc)
initializes chr horizontal scaling descriptor
Definition: hscale.c:250
#define s(width, name)
Definition: cbs_vp9.c:257
int available_lines
max number of lines that can be hold by this plane
struct SwsFilterDescriptor * desc
int dstW
Width of destination luma/alpha planes.
int needs_hcscale
Set if there are chroma planes to be converted.
int32_t * vLumFilterPos
Array of vertical filter starting positions for each dst[i] for luma/alpha planes.
#define isGray(x)
Definition: swscale.c:40
int should_free_lines
flag to identify if there are dynamic allocated lines
int is_ring
flag to identify if this slice is a ring buffer
void(* readAlpPlanar)(uint8_t *dst, const uint8_t *src[4], int width, int32_t *rgb2yuv)
int width
Slice line width.
int chrDstH
Height of destination chroma planes.
Struct which defines a slice of an image to be scaled or an output for a scaled slice.
struct SwsSlice * slice
int index
Definition: gxfenc.c:89
int vLumFilterSize
Vertical filter size for luma/alpha pixels.
static av_always_inline int isPlanarYUV(enum AVPixelFormat pix_fmt)
static void free_slice(SwsSlice *s)
Definition: slice.c:106
void * instance
Filter instance data.
int ff_init_filters(SwsContext *c)
Definition: slice.c:252
int16_t * hLumFilter
Array of horizontal filter coefficients for luma/alpha planes.
GLint GLenum GLboolean GLsizei stride
Definition: opengl_enc.c:104
enum AVPixelFormat srcFormat
Source pixel format.
enum AVPixelFormat fmt
planes pixel format
void(* readLumPlanar)(uint8_t *dst, const uint8_t *src[4], int width, int32_t *rgb2yuv)
Functions to read planar input, such as planar RGB, and convert internally to Y/UV/A.
uint16_t * gamma
uint8_t ** tmp
Tmp line buffer used by mmx code.
#define MAX_LINES_AHEAD
void(* lumToYV12)(uint8_t *dst, const uint8_t *src, const uint8_t *src2, const uint8_t *src3, int width, uint32_t *pal)
Unscaled conversion of luma plane to YV12 for horizontal scaler.
int32_t input_rgb2yuv_table[16+40 *4]
#define av_freep(p)
static av_always_inline int usePal(enum AVPixelFormat pix_fmt)
int16_t * hChrFilter
Array of horizontal filter coefficients for chroma planes.
int sliceY
index of first line
Filter the word “frame” indicates either a video frame or a group of audio as stored in an AVFrame structure Format for each input and each output the list of supported formats For video that means pixel format For audio that means channel sample they are references to shared objects When the negotiation mechanism computes the intersection of the formats supported at each end of a all references to both lists are replaced with a reference to the intersection And when a single format is eventually chosen for a link amongst the remaining all references to the list are updated That means that if a filter requires that its input and output have the same format amongst a supported all it has to do is use a reference to the same list of formats query_formats can leave some formats unset and return AVERROR(EAGAIN) to cause the negotiation mechanism toagain later.That can be used by filters with complex requirements to use the format negotiated on one link to set the formats supported on another.Frame references ownership and permissions
int chrDstHSubSample
Binary logarithm of horizontal subsampling factor between luma/alpha and chroma planes in destination...
int srcW
Width of source luma/alpha planes.
int chrSrcVSubSample
Binary logarithm of vertical subsampling factor between luma/alpha and chroma planes in source image...
AVPixelFormat
Pixel format.
Definition: pixfmt.h:64
uint32_t pal_yuv[256]
static av_cold void cleanup(FlashSV2Context *s)
Definition: flashsv2enc.c:127
void * av_mallocz_array(size_t nmemb, size_t size)
Definition: mem.c:190