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 is16bit)
193 {
194  int i;
195  for (i = 0; i < 4; ++i) {
196  int j;
197  int size = s->plane[i].available_lines;
198  for (j = 0; j < size; ++j) {
199  int k;
200  int end = is16bit ? n>>1: n;
201  // fill also one extra element
202  end += 1;
203  if (is16bit)
204  for (k = 0; k < end; ++k)
205  ((int32_t*)(s->plane[i].line[j]))[k] = 1<<18;
206  else
207  for (k = 0; k < end; ++k)
208  ((int16_t*)(s->plane[i].line[j]))[k] = 1<<14;
209  }
210  }
211 }
212 
213 /*
214  Calculates the minimum ring buffer size, it should be able to store vFilterSize
215  more n lines where n is the max difference between each adjacent slice which
216  outputs a line.
217  The n lines are needed only when there is not enough src lines to output a single
218  dst line, then we should buffer these lines to process them on the next call to scale.
219 */
220 static void get_min_buffer_size(SwsContext *c, int *out_lum_size, int *out_chr_size)
221 {
222  int lumY;
223  int dstH = c->dstH;
224  int chrDstH = c->chrDstH;
225  int *lumFilterPos = c->vLumFilterPos;
226  int *chrFilterPos = c->vChrFilterPos;
227  int lumFilterSize = c->vLumFilterSize;
228  int chrFilterSize = c->vChrFilterSize;
229  int chrSubSample = c->chrSrcVSubSample;
230 
231  *out_lum_size = lumFilterSize;
232  *out_chr_size = chrFilterSize;
233 
234  for (lumY = 0; lumY < dstH; lumY++) {
235  int chrY = (int64_t)lumY * chrDstH / dstH;
236  int nextSlice = FFMAX(lumFilterPos[lumY] + lumFilterSize - 1,
237  ((chrFilterPos[chrY] + chrFilterSize - 1)
238  << chrSubSample));
239 
240  nextSlice >>= chrSubSample;
241  nextSlice <<= chrSubSample;
242  (*out_lum_size) = FFMAX((*out_lum_size), nextSlice - lumFilterPos[lumY]);
243  (*out_chr_size) = FFMAX((*out_chr_size), (nextSlice >> chrSubSample) - chrFilterPos[chrY]);
244  }
245 }
246 
247 
248 
250 {
251  int i;
252  int index;
253  int num_ydesc;
254  int num_cdesc;
255  int num_vdesc = isPlanarYUV(c->dstFormat) && !isGray(c->dstFormat) ? 2 : 1;
256  int need_lum_conv = c->lumToYV12 || c->readLumPlanar || c->alpToYV12 || c->readAlpPlanar;
257  int need_chr_conv = c->chrToYV12 || c->readChrPlanar;
258  int need_gamma = c->is_internal_gamma;
259  int srcIdx, dstIdx;
260  int dst_stride = FFALIGN(c->dstW * sizeof(int16_t) + 66, 16);
261 
262  uint32_t * pal = usePal(c->srcFormat) ? c->pal_yuv : (uint32_t*)c->input_rgb2yuv_table;
263  int res = 0;
264 
265  int lumBufSize;
266  int chrBufSize;
267 
268  get_min_buffer_size(c, &lumBufSize, &chrBufSize);
269  lumBufSize = FFMAX(lumBufSize, c->vLumFilterSize + MAX_LINES_AHEAD);
270  chrBufSize = FFMAX(chrBufSize, c->vChrFilterSize + MAX_LINES_AHEAD);
271 
272  if (c->dstBpc == 16)
273  dst_stride <<= 1;
274 
275  num_ydesc = need_lum_conv ? 2 : 1;
276  num_cdesc = need_chr_conv ? 2 : 1;
277 
278  c->numSlice = FFMAX(num_ydesc, num_cdesc) + 2;
279  c->numDesc = num_ydesc + num_cdesc + num_vdesc + (need_gamma ? 2 : 0);
280  c->descIndex[0] = num_ydesc + (need_gamma ? 1 : 0);
281  c->descIndex[1] = num_ydesc + num_cdesc + (need_gamma ? 1 : 0);
282 
283 
284 
285  c->desc = av_mallocz_array(sizeof(SwsFilterDescriptor), c->numDesc);
286  if (!c->desc)
287  return AVERROR(ENOMEM);
288  c->slice = av_mallocz_array(sizeof(SwsSlice), c->numSlice);
289  if (!c->slice) {
290  res = AVERROR(ENOMEM);
291  goto cleanup;
292  }
293 
294  res = alloc_slice(&c->slice[0], c->srcFormat, c->srcH, c->chrSrcH, c->chrSrcHSubSample, c->chrSrcVSubSample, 0);
295  if (res < 0) goto cleanup;
296  for (i = 1; i < c->numSlice-2; ++i) {
297  res = alloc_slice(&c->slice[i], c->srcFormat, lumBufSize, chrBufSize, c->chrSrcHSubSample, c->chrSrcVSubSample, 0);
298  if (res < 0) goto cleanup;
299  res = alloc_lines(&c->slice[i], FFALIGN(c->srcW*2+78, 16), c->srcW);
300  if (res < 0) goto cleanup;
301  }
302  // horizontal scaler output
303  res = alloc_slice(&c->slice[i], c->srcFormat, lumBufSize, chrBufSize, c->chrDstHSubSample, c->chrDstVSubSample, 1);
304  if (res < 0) goto cleanup;
305  res = alloc_lines(&c->slice[i], dst_stride, c->dstW);
306  if (res < 0) goto cleanup;
307 
308  fill_ones(&c->slice[i], dst_stride>>1, c->dstBpc == 16);
309 
310  // vertical scaler output
311  ++i;
312  res = alloc_slice(&c->slice[i], c->dstFormat, c->dstH, c->chrDstH, c->chrDstHSubSample, c->chrDstVSubSample, 0);
313  if (res < 0) goto cleanup;
314 
315  index = 0;
316  srcIdx = 0;
317  dstIdx = 1;
318 
319  if (need_gamma) {
320  res = ff_init_gamma_convert(c->desc + index, c->slice + srcIdx, c->inv_gamma);
321  if (res < 0) goto cleanup;
322  ++index;
323  }
324 
325  if (need_lum_conv) {
326  res = ff_init_desc_fmt_convert(&c->desc[index], &c->slice[srcIdx], &c->slice[dstIdx], pal);
327  if (res < 0) goto cleanup;
328  c->desc[index].alpha = c->needAlpha;
329  ++index;
330  srcIdx = dstIdx;
331  }
332 
333 
334  dstIdx = FFMAX(num_ydesc, num_cdesc);
335  res = ff_init_desc_hscale(&c->desc[index], &c->slice[srcIdx], &c->slice[dstIdx], c->hLumFilter, c->hLumFilterPos, c->hLumFilterSize, c->lumXInc);
336  if (res < 0) goto cleanup;
337  c->desc[index].alpha = c->needAlpha;
338 
339 
340  ++index;
341  {
342  srcIdx = 0;
343  dstIdx = 1;
344  if (need_chr_conv) {
345  res = ff_init_desc_cfmt_convert(&c->desc[index], &c->slice[srcIdx], &c->slice[dstIdx], pal);
346  if (res < 0) goto cleanup;
347  ++index;
348  srcIdx = dstIdx;
349  }
350 
351  dstIdx = FFMAX(num_ydesc, num_cdesc);
352  if (c->needs_hcscale)
353  res = ff_init_desc_chscale(&c->desc[index], &c->slice[srcIdx], &c->slice[dstIdx], c->hChrFilter, c->hChrFilterPos, c->hChrFilterSize, c->chrXInc);
354  else
355  res = ff_init_desc_no_chr(&c->desc[index], &c->slice[srcIdx], &c->slice[dstIdx]);
356  if (res < 0) goto cleanup;
357  }
358 
359  ++index;
360  {
361  srcIdx = c->numSlice - 2;
362  dstIdx = c->numSlice - 1;
363  res = ff_init_vscale(c, c->desc + index, c->slice + srcIdx, c->slice + dstIdx);
364  if (res < 0) goto cleanup;
365  }
366 
367  ++index;
368  if (need_gamma) {
369  res = ff_init_gamma_convert(c->desc + index, c->slice + dstIdx, c->gamma);
370  if (res < 0) goto cleanup;
371  }
372 
373  return 0;
374 
375 cleanup:
377  return res;
378 }
379 
381 {
382  int i;
383  if (c->desc) {
384  for (i = 0; i < c->numDesc; ++i)
385  av_freep(&c->desc[i].instance);
386  av_freep(&c->desc);
387  }
388 
389  if (c->slice) {
390  for (i = 0; i < c->numSlice; ++i)
391  free_slice(&c->slice[i]);
392  av_freep(&c->slice);
393  }
394  return 0;
395 }
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
stride
int stride
Definition: mace.c:144
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
isPlanarYUV
static av_always_inline int isPlanarYUV(enum AVPixelFormat pix_fmt)
Definition: swscale_internal.h:674
n
int n
Definition: avisynth_c.h:760
get_min_buffer_size
static void get_min_buffer_size(SwsContext *c, int *out_lum_size, int *out_chr_size)
Definition: slice.c:220
ff_rotate_slice
int ff_rotate_slice(SwsSlice *s, int lum, int chr)
Definition: slice.c:119
end
static av_cold int end(AVCodecContext *avctx)
Definition: avrndec.c:90
fill_ones
static void fill_ones(SwsSlice *s, int n, int is16bit)
Definition: slice.c:192
cleanup
static av_cold void cleanup(FlashSV2Context *s)
Definition: flashsv2enc.c:127
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
SwsFilterDescriptor
Struct which holds all necessary data for processing a slice.
Definition: swscale_internal.h:958
isGray
#define isGray(x)
Definition: swscale.c:40
av_mallocz_array
void * av_mallocz_array(size_t nmemb, size_t size)
Definition: mem.c:191
av_malloc
#define av_malloc(s)
Definition: tableprint_vlc.h:31
ff_init_desc_no_chr
int ff_init_desc_no_chr(SwsFilterDescriptor *desc, SwsSlice *src, SwsSlice *dst)
Definition: hscale.c:281
fmt
const char * fmt
Definition: avisynth_c.h:861
start
void INT64 start
Definition: avisynth_c.h:767
src
#define src
Definition: vp8dsp.c:254
ff_init_filters
int ff_init_filters(SwsContext *c)
Definition: slice.c:249
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:257
av_assert0
#define av_assert0(cond)
assert() equivalent, that is always enabled.
Definition: avassert.h:37
int32_t
int32_t
Definition: audio_convert.c:194
NULL
#define NULL
Definition: coverity.c:32
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:816
FFMAX
#define FFMAX(a, b)
Definition: common.h:94
size
int size
Definition: twinvq_data.h:11134
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:259
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:380
swscale_internal.h
uint8_t
uint8_t
Definition: audio_convert.c:194
SwsSlice
Struct which defines a slice of an image to be scaled or an output for a scaled slice.
Definition: swscale_internal.h:943
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_vscale
int ff_init_vscale(SwsContext *c, SwsFilterDescriptor *desc, SwsSlice *src, SwsSlice *dst)
initializes vertical scaling descriptors
Definition: vscale.c:206
FFALIGN
#define FFALIGN(x, a)
Definition: macros.h:48
lum
static double lum(void *priv, double x, double y, int plane)
Definition: vf_fftfilt.c:95
av_freep
#define av_freep(p)
Definition: tableprint_vlc.h:35
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
SwsContext
Definition: swscale_internal.h:280
MAX_LINES_AHEAD
#define MAX_LINES_AHEAD
Definition: swscale_internal.h:1014