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_calloc(n, sizeof(*s->plane[i].line));
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  s->width = srcW;
162 
163  for (i = 0; i < 4 && src[i] != NULL; ++i) {
164  uint8_t *const src_i = src[i] + (relative ? 0 : start[i]) * stride[i];
165  int j;
166  int first = s->plane[i].sliceY;
167  int n = s->plane[i].available_lines;
168  int lines = end[i] - start[i];
169  int tot_lines = end[i] - first;
170 
171  if (start[i] >= first && n >= tot_lines) {
172  s->plane[i].sliceH = FFMAX(tot_lines, s->plane[i].sliceH);
173  for (j = 0; j < lines; j+= 1)
174  s->plane[i].line[start[i] - first + j] = src_i + j * stride[i];
175  } else {
176  s->plane[i].sliceY = start[i];
177  lines = lines > n ? n : lines;
178  s->plane[i].sliceH = lines;
179  for (j = 0; j < lines; j+= 1)
180  s->plane[i].line[j] = src_i + j * stride[i];
181  }
182 
183  }
184 
185  return 0;
186 }
187 
188 static void fill_ones(SwsSlice *s, int n, int bpc)
189 {
190  int i, j, k, size, end;
191 
192  for (i = 0; i < 4; ++i) {
193  size = s->plane[i].available_lines;
194  for (j = 0; j < size; ++j) {
195  if (bpc == 16) {
196  end = (n>>1) + 1;
197  for (k = 0; k < end; ++k)
198  ((int32_t*)(s->plane[i].line[j]))[k] = 1<<18;
199  } else if (bpc == 32) {
200  end = (n>>2) + 1;
201  for (k = 0; k < end; ++k)
202  ((int64_t*)(s->plane[i].line[j]))[k] = 1LL<<34;
203  } else {
204  end = n + 1;
205  for (k = 0; k < end; ++k)
206  ((int16_t*)(s->plane[i].line[j]))[k] = 1<<14;
207  }
208  }
209  }
210 }
211 
212 /*
213  Calculates the minimum ring buffer size, it should be able to store vFilterSize
214  more n lines where n is the max difference between each adjacent slice which
215  outputs a line.
216  The n lines are needed only when there is not enough src lines to output a single
217  dst line, then we should buffer these lines to process them on the next call to scale.
218 */
219 static void get_min_buffer_size(SwsContext *c, int *out_lum_size, int *out_chr_size)
220 {
221  int lumY;
222  int dstH = c->dstH;
223  int chrDstH = c->chrDstH;
224  int *lumFilterPos = c->vLumFilterPos;
225  int *chrFilterPos = c->vChrFilterPos;
226  int lumFilterSize = c->vLumFilterSize;
227  int chrFilterSize = c->vChrFilterSize;
228  int chrSubSample = c->chrSrcVSubSample;
229 
230  *out_lum_size = lumFilterSize;
231  *out_chr_size = chrFilterSize;
232 
233  for (lumY = 0; lumY < dstH; lumY++) {
234  int chrY = (int64_t)lumY * chrDstH / dstH;
235  int nextSlice = FFMAX(lumFilterPos[lumY] + lumFilterSize - 1,
236  ((chrFilterPos[chrY] + chrFilterSize - 1)
237  << chrSubSample));
238 
239  nextSlice >>= chrSubSample;
240  nextSlice <<= chrSubSample;
241  (*out_lum_size) = FFMAX((*out_lum_size), nextSlice - lumFilterPos[lumY]);
242  (*out_chr_size) = FFMAX((*out_chr_size), (nextSlice >> chrSubSample) - chrFilterPos[chrY]);
243  }
244 }
245 
246 
247 
249 {
250  int i;
251  int index;
252  int num_ydesc;
253  int num_cdesc;
254  int num_vdesc = isPlanarYUV(c->dstFormat) && !isGray(c->dstFormat) ? 2 : 1;
255  int need_lum_conv = c->lumToYV12 || c->readLumPlanar || c->alpToYV12 || c->readAlpPlanar;
256  int need_chr_conv = c->chrToYV12 || c->readChrPlanar;
257  int need_gamma = c->is_internal_gamma;
258  int srcIdx, dstIdx;
259  int dst_stride = FFALIGN(c->dstW * sizeof(int16_t) + 66, 16);
260 
261  uint32_t * pal = usePal(c->srcFormat) ? c->pal_yuv : (uint32_t*)c->input_rgb2yuv_table;
262  int res = 0;
263 
264  int lumBufSize;
265  int chrBufSize;
266 
267  get_min_buffer_size(c, &lumBufSize, &chrBufSize);
268  lumBufSize = FFMAX(lumBufSize, c->vLumFilterSize + MAX_LINES_AHEAD);
269  chrBufSize = FFMAX(chrBufSize, c->vChrFilterSize + MAX_LINES_AHEAD);
270 
271  if (c->dstBpc == 16)
272  dst_stride <<= 1;
273 
274  if (c->dstBpc == 32)
275  dst_stride <<= 2;
276 
277  num_ydesc = need_lum_conv ? 2 : 1;
278  num_cdesc = need_chr_conv ? 2 : 1;
279 
280  c->numSlice = FFMAX(num_ydesc, num_cdesc) + 2;
281  c->numDesc = num_ydesc + num_cdesc + num_vdesc + (need_gamma ? 2 : 0);
282  c->descIndex[0] = num_ydesc + (need_gamma ? 1 : 0);
283  c->descIndex[1] = num_ydesc + num_cdesc + (need_gamma ? 1 : 0);
284 
285  if (isFloat16(c->srcFormat)) {
286  c->h2f_tables = av_malloc(sizeof(*c->h2f_tables));
287  if (!c->h2f_tables)
288  return AVERROR(ENOMEM);
289  ff_init_half2float_tables(c->h2f_tables);
290  c->input_opaque = c->h2f_tables;
291  }
292 
293  c->desc = av_calloc(c->numDesc, sizeof(*c->desc));
294  if (!c->desc)
295  return AVERROR(ENOMEM);
296  c->slice = av_calloc(c->numSlice, sizeof(*c->slice));
297  if (!c->slice) {
298  res = AVERROR(ENOMEM);
299  goto cleanup;
300  }
301 
302  res = alloc_slice(&c->slice[0], c->srcFormat, c->srcH, c->chrSrcH, c->chrSrcHSubSample, c->chrSrcVSubSample, 0);
303  if (res < 0) goto cleanup;
304  for (i = 1; i < c->numSlice-2; ++i) {
305  res = alloc_slice(&c->slice[i], c->srcFormat, lumBufSize, chrBufSize, c->chrSrcHSubSample, c->chrSrcVSubSample, 0);
306  if (res < 0) goto cleanup;
307  res = alloc_lines(&c->slice[i], FFALIGN(c->srcW*2+78, 16), c->srcW);
308  if (res < 0) goto cleanup;
309  }
310  // horizontal scaler output
311  res = alloc_slice(&c->slice[i], c->srcFormat, lumBufSize, chrBufSize, c->chrDstHSubSample, c->chrDstVSubSample, 1);
312  if (res < 0) goto cleanup;
313  res = alloc_lines(&c->slice[i], dst_stride, c->dstW);
314  if (res < 0) goto cleanup;
315 
316  fill_ones(&c->slice[i], dst_stride>>1, c->dstBpc);
317 
318  // vertical scaler output
319  ++i;
320  res = alloc_slice(&c->slice[i], c->dstFormat, c->dstH, c->chrDstH, c->chrDstHSubSample, c->chrDstVSubSample, 0);
321  if (res < 0) goto cleanup;
322 
323  index = 0;
324  srcIdx = 0;
325  dstIdx = 1;
326 
327  if (need_gamma) {
328  res = ff_init_gamma_convert(c->desc + index, c->slice + srcIdx, c->inv_gamma);
329  if (res < 0) goto cleanup;
330  ++index;
331  }
332 
333  if (need_lum_conv) {
334  res = ff_init_desc_fmt_convert(&c->desc[index], &c->slice[srcIdx], &c->slice[dstIdx], pal);
335  if (res < 0) goto cleanup;
336  c->desc[index].alpha = c->needAlpha;
337  ++index;
338  srcIdx = dstIdx;
339  }
340 
341 
342  dstIdx = FFMAX(num_ydesc, num_cdesc);
343  res = ff_init_desc_hscale(&c->desc[index], &c->slice[srcIdx], &c->slice[dstIdx], c->hLumFilter, c->hLumFilterPos, c->hLumFilterSize, c->lumXInc);
344  if (res < 0) goto cleanup;
345  c->desc[index].alpha = c->needAlpha;
346 
347 
348  ++index;
349  {
350  srcIdx = 0;
351  dstIdx = 1;
352  if (need_chr_conv) {
353  res = ff_init_desc_cfmt_convert(&c->desc[index], &c->slice[srcIdx], &c->slice[dstIdx], pal);
354  if (res < 0) goto cleanup;
355  ++index;
356  srcIdx = dstIdx;
357  }
358 
359  dstIdx = FFMAX(num_ydesc, num_cdesc);
360  if (c->needs_hcscale)
361  res = ff_init_desc_chscale(&c->desc[index], &c->slice[srcIdx], &c->slice[dstIdx], c->hChrFilter, c->hChrFilterPos, c->hChrFilterSize, c->chrXInc);
362  else
363  res = ff_init_desc_no_chr(&c->desc[index], &c->slice[srcIdx], &c->slice[dstIdx]);
364  if (res < 0) goto cleanup;
365  }
366 
367  ++index;
368  {
369  srcIdx = c->numSlice - 2;
370  dstIdx = c->numSlice - 1;
371  res = ff_init_vscale(c, c->desc + index, c->slice + srcIdx, c->slice + dstIdx);
372  if (res < 0) goto cleanup;
373  }
374 
375  ++index;
376  if (need_gamma) {
377  res = ff_init_gamma_convert(c->desc + index, c->slice + dstIdx, c->gamma);
378  if (res < 0) goto cleanup;
379  }
380 
381  return 0;
382 
383 cleanup:
385  return res;
386 }
387 
389 {
390  int i;
391  if (c->desc) {
392  for (i = 0; i < c->numDesc; ++i)
393  av_freep(&c->desc[i].instance);
394  av_freep(&c->desc);
395  }
396 
397  if (c->slice) {
398  for (i = 0; i < c->numSlice; ++i)
399  free_slice(&c->slice[i]);
400  av_freep(&c->slice);
401  }
402  av_freep(&c->h2f_tables);
403  return 0;
404 }
ff_init_desc_cfmt_convert
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
AVPixelFormat
AVPixelFormat
Pixel format.
Definition: pixfmt.h:64
AVERROR
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
fill_ones
static void fill_ones(SwsSlice *s, int n, int bpc)
Definition: slice.c:188
get_min_buffer_size
static void get_min_buffer_size(SwsContext *c, int *out_lum_size, int *out_chr_size)
Definition: slice.c:219
ff_rotate_slice
int ff_rotate_slice(SwsSlice *s, int lum, int chr)
Definition: slice.c:119
cleanup
static av_cold void cleanup(FlashSV2Context *s)
Definition: flashsv2enc.c:130
ff_init_desc_hscale
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
isGray
#define isGray(x)
Definition: swscale.c:40
FFMAX
#define FFMAX(a, b)
Definition: macros.h:47
av_malloc
#define av_malloc(s)
Definition: tableprint_vlc.h:30
ff_init_desc_no_chr
int ff_init_desc_no_chr(SwsFilterDescriptor *desc, SwsSlice *src, SwsSlice *dst)
Definition: hscale.c:281
ff_init_filters
int ff_init_filters(SwsContext *c)
Definition: slice.c:248
first
trying all byte sequences megabyte in length and selecting the best looking sequence will yield cases to try But first
Definition: rate_distortion.txt:12
width
#define width
s
#define s(width, name)
Definition: cbs_vp9.c:198
av_assert0
#define av_assert0(cond)
assert() equivalent, that is always enabled.
Definition: avassert.h:40
NULL
#define NULL
Definition: coverity.c:32
isFloat16
static av_always_inline int isFloat16(enum AVPixelFormat pix_fmt)
Definition: swscale_internal.h:847
ff_init_desc_chscale
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
index
int index
Definition: gxfenc.c:89
c
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
free_lines
static void free_lines(SwsSlice *s)
Definition: slice.c:23
alloc_lines
static int alloc_lines(SwsSlice *s, int size, int width)
Definition: slice.c:45
usePal
static av_always_inline int usePal(enum AVPixelFormat pix_fmt)
Definition: swscale_internal.h:894
size
int size
Definition: twinvq_data.h:10344
free_slice
static void free_slice(SwsSlice *s)
Definition: slice.c:106
alloc_slice
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
i
#define i(width, name, range_min, range_max)
Definition: cbs_h2645.c:255
ff_init_gamma_convert
int ff_init_gamma_convert(SwsFilterDescriptor *desc, SwsSlice *src, uint16_t *table)
initializes gamma conversion descriptor
Definition: gamma.c:58
ff_free_filters
int ff_free_filters(SwsContext *c)
Definition: slice.c:388
swscale_internal.h
SwsSlice
Struct which defines a slice of an image to be scaled or an output for a scaled slice.
Definition: swscale_internal.h:1085
av_calloc
void * av_calloc(size_t nmemb, size_t size)
Definition: mem.c:262
stride
#define stride
Definition: h264pred_template.c:537
ff_init_slice_from_src
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
ff_init_half2float_tables
void ff_init_half2float_tables(Half2FloatTables *t)
Definition: half2float.c:39
isPlanarYUV
static av_always_inline int isPlanarYUV(enum AVPixelFormat pix_fmt)
Definition: vf_dnn_processing.c:154
ff_init_vscale
int ff_init_vscale(SwsContext *c, SwsFilterDescriptor *desc, SwsSlice *src, SwsSlice *dst)
initializes vertical scaling descriptors
Definition: vscale.c:213
FFALIGN
#define FFALIGN(x, a)
Definition: macros.h:78
lum
static double lum(void *priv, double x, double y, int plane)
Definition: vf_fftfilt.c:107
av_freep
#define av_freep(p)
Definition: tableprint_vlc.h:34
src
INIT_CLIP pixel * src
Definition: h264pred_template.c:418
ff_init_desc_fmt_convert
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
int32_t
int32_t
Definition: audioconvert.c:56
SwsContext
Definition: swscale_internal.h:299
MAX_LINES_AHEAD
#define MAX_LINES_AHEAD
Definition: swscale_internal.h:1159