FFmpeg  4.4.8
vf_epx.c
Go to the documentation of this file.
1 /*
2  * This file is part of FFmpeg.
3  *
4  * FFmpeg is free software; you can redistribute it and/or
5  * modify it under the terms of the GNU Lesser General Public
6  * License as published by the Free Software Foundation; either
7  * version 2.1 of the License, or (at your option) any later version.
8  *
9  * FFmpeg is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12  * Lesser General Public License for more details.
13  *
14  * You should have received a copy of the GNU Lesser General Public
15  * License along with FFmpeg; if not, write to the Free Software
16  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
17  */
18 
19 #include "libavutil/opt.h"
20 #include "libavutil/avassert.h"
21 #include "libavutil/pixdesc.h"
22 #include "internal.h"
23 #include "filters.h"
24 
25 typedef struct EPXContext {
26  const AVClass *class;
27 
28  int n;
29 
30  int (*epx_slice)(AVFilterContext *ctx, void *arg, int jobnr, int nb_jobs);
31 } EPXContext;
32 
33 typedef struct ThreadData {
34  AVFrame *in, *out;
35 } ThreadData;
36 
37 #define OFFSET(x) offsetof(EPXContext, x)
38 #define FLAGS AV_OPT_FLAG_FILTERING_PARAM|AV_OPT_FLAG_VIDEO_PARAM
39 static const AVOption epx_options[] = {
40  { "n", "set scale factor", OFFSET(n), AV_OPT_TYPE_INT, {.i64 = 3}, 2, 3, .flags = FLAGS },
41  { NULL }
42 };
43 
45 
46 static int epx2_slice(AVFilterContext *ctx, void *arg, int jobnr, int nb_jobs)
47 {
48  ThreadData *td = arg;
49  const AVFrame *in = td->in;
50  AVFrame *out = td->out;
51  const int slice_start = ff_slice_pos(in->height, jobnr, nb_jobs);
52  const int slice_end = ff_slice_pos(in->height, jobnr + 1, nb_jobs);
53 
54  for (int p = 0; p < 1; p++) {
55  const int width = in->width;
56  const int height = in->height;
57  const int src_linesize = in->linesize[p] / 4;
58  const int dst_linesize = out->linesize[p] / 4;
59  const uint32_t *src = (const uint32_t *)in->data[p];
60  uint32_t *dst = (uint32_t *)out->data[p];
61  const uint32_t *src_line[3];
62 
63  src_line[0] = src + src_linesize * FFMAX(slice_start - 1, 0);
64  src_line[1] = src + src_linesize * slice_start;
65  src_line[2] = src + src_linesize * FFMIN(slice_start + 1, height-1);
66 
67  for (int y = slice_start; y < slice_end; y++) {
68  uint32_t *dst_line[2];
69 
70  dst_line[0] = dst + dst_linesize*2*y;
71  dst_line[1] = dst + dst_linesize*(2*y+1);
72 
73  for (int x = 0; x < width; x++) {
74  uint32_t E0, E1, E2, E3;
75  uint32_t B, D, E, F, H;
76 
77  B = src_line[0][x];
78  D = src_line[1][FFMAX(x-1, 0)];
79  E = src_line[1][x];
80  F = src_line[1][FFMIN(x+1, width - 1)];
81  H = src_line[2][x];
82 
83  if (B != H && D != F) {
84  E0 = D == B ? D : E;
85  E1 = B == F ? F : E;
86  E2 = D == H ? D : E;
87  E3 = H == F ? F : E;
88  } else {
89  E0 = E;
90  E1 = E;
91  E2 = E;
92  E3 = E;
93  }
94 
95  dst_line[0][x*2] = E0;
96  dst_line[0][x*2+1] = E1;
97  dst_line[1][x*2] = E2;
98  dst_line[1][x*2+1] = E3;
99  }
100 
101  src_line[0] = src_line[1];
102  src_line[1] = src_line[2];
103  src_line[2] = src_line[1];
104 
105  if (y < height - 1)
106  src_line[2] += src_linesize;
107  }
108  }
109 
110  return 0;
111 }
112 
113 static int epx3_slice(AVFilterContext *ctx, void *arg, int jobnr, int nb_jobs)
114 {
115  ThreadData *td = arg;
116  const AVFrame *in = td->in;
117  AVFrame *out = td->out;
118  const int slice_start = ff_slice_pos(in->height, jobnr, nb_jobs);
119  const int slice_end = ff_slice_pos(in->height, jobnr + 1, nb_jobs);
120 
121  for (int p = 0; p < 1; p++) {
122  const int width = in->width;
123  const int height = in->height;
124  const int src_linesize = in->linesize[p] / 4;
125  const int dst_linesize = out->linesize[p] / 4;
126  const uint32_t *src = (const uint32_t *)in->data[p];
127  uint32_t *dst = (uint32_t *)out->data[p];
128  const uint32_t *src_line[3];
129 
130  src_line[0] = src + src_linesize * FFMAX(slice_start - 1, 0);
131  src_line[1] = src + src_linesize * slice_start;
132  src_line[2] = src + src_linesize * FFMIN(slice_start + 1, height-1);
133 
134  for (int y = slice_start; y < slice_end; y++) {
135  uint32_t *dst_line[3];
136 
137  dst_line[0] = dst + dst_linesize*3*y;
138  dst_line[1] = dst + dst_linesize*(3*y+1);
139  dst_line[2] = dst + dst_linesize*(3*y+2);
140 
141  for (int x = 0; x < width; x++) {
142  uint32_t E0, E1, E2, E3, E4, E5, E6, E7, E8;
143  uint32_t A, B, C, D, E, F, G, H, I;
144 
145  A = src_line[0][FFMAX(x-1, 0)];
146  B = src_line[0][x];
147  C = src_line[0][FFMIN(x+1, width - 1)];
148  D = src_line[1][FFMAX(x-1, 0)];
149  E = src_line[1][x];
150  F = src_line[1][FFMIN(x+1, width - 1)];
151  G = src_line[2][FFMAX(x-1, 0)];
152  H = src_line[2][x];
153  I = src_line[2][FFMIN(x+1, width - 1)];
154 
155  if (B != H && D != F) {
156  E0 = D == B ? D : E;
157  E1 = (D == B && E != C) || (B == F && E != A) ? B : E;
158  E2 = B == F ? F : E;
159  E3 = (D == B && E != G) || (D == H && E != A) ? D : E;
160  E4 = E;
161  E5 = (B == F && E != I) || (H == F && E != C) ? F : E;
162  E6 = D == H ? D : E;
163  E7 = (D == H && E != I) || (H == F && E != G) ? H : E;
164  E8 = H == F ? F : E;
165  } else {
166  E0 = E;
167  E1 = E;
168  E2 = E;
169  E3 = E;
170  E4 = E;
171  E5 = E;
172  E6 = E;
173  E7 = E;
174  E8 = E;
175  }
176 
177  dst_line[0][x*3] = E0;
178  dst_line[0][x*3+1] = E1;
179  dst_line[0][x*3+2] = E2;
180  dst_line[1][x*3] = E3;
181  dst_line[1][x*3+1] = E4;
182  dst_line[1][x*3+2] = E5;
183  dst_line[2][x*3] = E6;
184  dst_line[2][x*3+1] = E7;
185  dst_line[2][x*3+2] = E8;
186  }
187 
188  src_line[0] = src_line[1];
189  src_line[1] = src_line[2];
190  src_line[2] = src_line[1];
191 
192  if (y < height - 1)
193  src_line[2] += src_linesize;
194  }
195  }
196 
197  return 0;
198 }
199 
200 static int config_output(AVFilterLink *outlink)
201 {
202  AVFilterContext *ctx = outlink->src;
203  EPXContext *s = ctx->priv;
204  AVFilterLink *inlink = ctx->inputs[0];
205  const AVPixFmtDescriptor *desc;
206 
207  desc = av_pix_fmt_desc_get(outlink->format);
208  if (!desc)
209  return AVERROR_BUG;
210 
211  outlink->w = inlink->w * s->n;
212  outlink->h = inlink->h * s->n;
213 
214  switch (s->n) {
215  case 2:
216  s->epx_slice = epx2_slice;
217  break;
218  case 3:
219  s->epx_slice = epx3_slice;
220  break;
221  }
222 
223  return 0;
224 }
225 
227 {
228  static const enum AVPixelFormat pix_fmts[] = {
231  };
232 
234  if (!fmts_list)
235  return AVERROR(ENOMEM);
236  return ff_set_common_formats(ctx, fmts_list);
237 }
238 
239 static int filter_frame(AVFilterLink *inlink, AVFrame *in)
240 {
241  AVFilterContext *ctx = inlink->dst;
242  AVFilterLink *outlink = ctx->outputs[0];
243  EPXContext *s = ctx->priv;
244  ThreadData td;
245 
246  AVFrame *out = ff_get_video_buffer(outlink, outlink->w, outlink->h);
247  if (!out) {
248  av_frame_free(&in);
249  return AVERROR(ENOMEM);
250  }
251 
253 
254  td.in = in, td.out = out;
255  ctx->internal->execute(ctx, s->epx_slice, &td, NULL, FFMIN(inlink->h, ff_filter_get_nb_threads(ctx)));
256 
257  av_frame_free(&in);
258  return ff_filter_frame(outlink, out);
259 }
260 
261 static const AVFilterPad inputs[] = {
262  {
263  .name = "default",
264  .type = AVMEDIA_TYPE_VIDEO,
265  .filter_frame = filter_frame,
266  },
267  { NULL }
268 };
269 
270 static const AVFilterPad outputs[] = {
271  {
272  .name = "default",
273  .type = AVMEDIA_TYPE_VIDEO,
274  .config_props = config_output,
275  },
276  { NULL }
277 };
278 
280  .name = "epx",
281  .description = NULL_IF_CONFIG_SMALL("Scale the input using EPX algorithm."),
282  .inputs = inputs,
283  .outputs = outputs,
284  .query_formats = query_formats,
285  .priv_size = sizeof(EPXContext),
286  .priv_class = &epx_class,
288 };
#define A(x)
Definition: vp56_arith.h:28
uint8_t pi<< 24) CONV_FUNC_GROUP(AV_SAMPLE_FMT_FLT, float, AV_SAMPLE_FMT_U8, uint8_t,(*(const uint8_t *) pi - 0x80) *(1.0f/(1<< 7))) CONV_FUNC_GROUP(AV_SAMPLE_FMT_DBL, double, AV_SAMPLE_FMT_U8, uint8_t,(*(const uint8_t *) pi - 0x80) *(1.0/(1<< 7))) CONV_FUNC_GROUP(AV_SAMPLE_FMT_U8, uint8_t, AV_SAMPLE_FMT_S16, int16_t,(*(const int16_t *) pi >> 8)+0x80) CONV_FUNC_GROUP(AV_SAMPLE_FMT_FLT, float, AV_SAMPLE_FMT_S16, int16_t, *(const int16_t *) pi *(1.0f/(1<< 15))) CONV_FUNC_GROUP(AV_SAMPLE_FMT_DBL, double, AV_SAMPLE_FMT_S16, int16_t, *(const int16_t *) pi *(1.0/(1<< 15))) CONV_FUNC_GROUP(AV_SAMPLE_FMT_U8, uint8_t, AV_SAMPLE_FMT_S32, int32_t,(*(const int32_t *) pi >> 24)+0x80) CONV_FUNC_GROUP(AV_SAMPLE_FMT_FLT, float, AV_SAMPLE_FMT_S32, int32_t, *(const int32_t *) pi *(1.0f/(1U<< 31))) CONV_FUNC_GROUP(AV_SAMPLE_FMT_DBL, double, AV_SAMPLE_FMT_S32, int32_t, *(const int32_t *) pi *(1.0/(1U<< 31))) CONV_FUNC_GROUP(AV_SAMPLE_FMT_U8, uint8_t, AV_SAMPLE_FMT_FLT, float, av_clip_uint8(lrintf(*(const float *) pi *(1<< 7))+0x80)) CONV_FUNC_GROUP(AV_SAMPLE_FMT_S16, int16_t, AV_SAMPLE_FMT_FLT, float, av_clip_int16(lrintf(*(const float *) pi *(1<< 15)))) CONV_FUNC_GROUP(AV_SAMPLE_FMT_S32, int32_t, AV_SAMPLE_FMT_FLT, float, av_clipl_int32(llrintf(*(const float *) pi *(1U<< 31)))) CONV_FUNC_GROUP(AV_SAMPLE_FMT_U8, uint8_t, AV_SAMPLE_FMT_DBL, double, av_clip_uint8(lrint(*(const double *) pi *(1<< 7))+0x80)) CONV_FUNC_GROUP(AV_SAMPLE_FMT_S16, int16_t, AV_SAMPLE_FMT_DBL, double, av_clip_int16(lrint(*(const double *) pi *(1<< 15)))) CONV_FUNC_GROUP(AV_SAMPLE_FMT_S32, int32_t, AV_SAMPLE_FMT_DBL, double, av_clipl_int32(llrint(*(const double *) pi *(1U<< 31)))) #define SET_CONV_FUNC_GROUP(ofmt, ifmt) static void set_generic_function(AudioConvert *ac) { } void ff_audio_convert_free(AudioConvert **ac) { if(! *ac) return;ff_dither_free(&(*ac) ->dc);av_freep(ac);} AudioConvert *ff_audio_convert_alloc(AVAudioResampleContext *avr, enum AVSampleFormat out_fmt, enum AVSampleFormat in_fmt, int channels, int sample_rate, int apply_map) { AudioConvert *ac;int in_planar, out_planar;ac=av_mallocz(sizeof(*ac));if(!ac) return NULL;ac->avr=avr;ac->out_fmt=out_fmt;ac->in_fmt=in_fmt;ac->channels=channels;ac->apply_map=apply_map;if(avr->dither_method !=AV_RESAMPLE_DITHER_NONE &&av_get_packed_sample_fmt(out_fmt)==AV_SAMPLE_FMT_S16 &&av_get_bytes_per_sample(in_fmt) > 2) { ac->dc=ff_dither_alloc(avr, out_fmt, in_fmt, channels, sample_rate, apply_map);if(!ac->dc) { av_free(ac);return NULL;} return ac;} in_planar=ff_sample_fmt_is_planar(in_fmt, channels);out_planar=ff_sample_fmt_is_planar(out_fmt, channels);if(in_planar==out_planar) { ac->func_type=CONV_FUNC_TYPE_FLAT;ac->planes=in_planar ? ac->channels :1;} else if(in_planar) ac->func_type=CONV_FUNC_TYPE_INTERLEAVE;else ac->func_type=CONV_FUNC_TYPE_DEINTERLEAVE;set_generic_function(ac);if(ARCH_AARCH64) ff_audio_convert_init_aarch64(ac);if(ARCH_ARM) ff_audio_convert_init_arm(ac);if(ARCH_X86) ff_audio_convert_init_x86(ac);return ac;} int ff_audio_convert(AudioConvert *ac, AudioData *out, AudioData *in) { int use_generic=1;int len=in->nb_samples;int p;if(ac->dc) { av_log(ac->avr, AV_LOG_TRACE, "%d samples - audio_convert: %s to %s (dithered)\n", len, av_get_sample_fmt_name(ac->in_fmt), av_get_sample_fmt_name(ac->out_fmt));return ff_convert_dither(ac-> in
simple assert() macros that are a bit more flexible than ISO C assert().
#define E
Definition: avdct.c:32
int ff_filter_frame(AVFilterLink *link, AVFrame *frame)
Send a frame of data to the next filter.
Definition: avfilter.c:1096
int ff_filter_get_nb_threads(AVFilterContext *ctx)
Get number of threads for current filter instance.
Definition: avfilter.c:802
#define flags(name, subs,...)
Definition: cbs_av1.c:572
#define s(width, name)
Definition: cbs_vp9.c:257
#define FFMIN(a, b)
Definition: common.h:105
#define FFMAX(a, b)
Definition: common.h:103
#define NULL
Definition: coverity.c:32
#define F(x)
int
static int ff_slice_pos(int total, int jobnr, int nb_jobs)
Compute the boundary index for a slice when work of size total is split into nb_jobs slices.
Definition: filters.h:271
int ff_set_common_formats(AVFilterContext *ctx, AVFilterFormats *formats)
A helper for query_formats() which sets all links to the same list of formats.
Definition: formats.c:587
AVFilterFormats * ff_make_format_list(const int *fmts)
Create a list of supported formats.
Definition: formats.c:286
@ AV_OPT_TYPE_INT
Definition: opt.h:225
#define AVFILTER_FLAG_SLICE_THREADS
The filter supports multithreading by splitting frames into multiple parts and processing them concur...
Definition: avfilter.h:117
#define AVERROR_BUG
Internal bug, also see AVERROR_BUG2.
Definition: error.h:50
#define AVERROR(e)
Definition: error.h:43
void av_frame_free(AVFrame **frame)
Free the frame and any dynamically allocated objects in it, e.g.
Definition: frame.c:203
int av_frame_copy_props(AVFrame *dst, const AVFrame *src)
Copy only "metadata" fields from src to dst.
Definition: frame.c:658
@ AVMEDIA_TYPE_VIDEO
Definition: avutil.h:201
#define B
Definition: huffyuvdsp.h:32
#define G
Definition: huffyuvdsp.h:33
#define E4(a, b)
Definition: indeo3data.h:251
#define E2(a, b)
Expand a pair of delta values (a,b) into two/four delta entries.
Definition: indeo3data.h:250
#define C
const char * arg
Definition: jacosubdec.c:66
common internal API header
#define NULL_IF_CONFIG_SMALL(x)
Return NULL if CONFIG_SMALL is true, otherwise the argument without modification.
Definition: internal.h:117
static enum AVPixelFormat pix_fmts[]
Definition: libkvazaar.c:309
const char * desc
Definition: libsvtav1.c:79
#define E1(x)
Definition: mem_internal.h:103
static int slice_end(AVCodecContext *avctx, AVFrame *pict)
Handle slice ends.
Definition: mpeg12dec.c:2033
AVOptions.
const AVPixFmtDescriptor * av_pix_fmt_desc_get(enum AVPixelFormat pix_fmt)
Definition: pixdesc.c:2573
AVPixelFormat
Pixel format.
Definition: pixfmt.h:64
@ AV_PIX_FMT_NONE
Definition: pixfmt.h:65
@ AV_PIX_FMT_ARGB
packed ARGB 8:8:8:8, 32bpp, ARGBARGB...
Definition: pixfmt.h:92
@ AV_PIX_FMT_BGRA
packed BGRA 8:8:8:8, 32bpp, BGRABGRA...
Definition: pixfmt.h:95
@ AV_PIX_FMT_ABGR
packed ABGR 8:8:8:8, 32bpp, ABGRABGR...
Definition: pixfmt.h:94
@ AV_PIX_FMT_RGBA
packed RGBA 8:8:8:8, 32bpp, RGBARGBA...
Definition: pixfmt.h:93
#define td
Definition: regdef.h:70
D(D(float, sse)
Definition: rematrix_init.c:28
Describe the class of an AVClass context structure.
Definition: log.h:67
An instance of a filter.
Definition: avfilter.h:341
A list of supported formats for one end of a filter link.
Definition: formats.h:65
A filter pad used for either input or output.
Definition: internal.h:54
const char * name
Pad name.
Definition: internal.h:60
Filter definition.
Definition: avfilter.h:145
const char * name
Filter name.
Definition: avfilter.h:149
AVFormatInternal * internal
An opaque field for libavformat internal usage.
Definition: avformat.h:1699
This structure describes decoded (raw) audio or video data.
Definition: frame.h:318
AVOption.
Definition: opt.h:248
Descriptor that unambiguously describes how the bits of a pixel are stored in the up to 4 data planes...
Definition: pixdesc.h:81
int n
Definition: vf_epx.c:28
int(* epx_slice)(AVFilterContext *ctx, void *arg, int jobnr, int nb_jobs)
Definition: vf_epx.c:30
Used for passing data between threads.
Definition: dsddec.c:67
AVFrame * out
Definition: af_adeclick.c:502
AVFrame * in
Definition: af_adenorm.c:223
#define src
Definition: vp8dsp.c:255
FILE * out
Definition: movenc.c:54
AVFormatContext * ctx
Definition: movenc.c:48
#define height
#define width
@ H
Definition: vf_addroi.c:26
static int epx3_slice(AVFilterContext *ctx, void *arg, int jobnr, int nb_jobs)
Definition: vf_epx.c:113
static int epx2_slice(AVFilterContext *ctx, void *arg, int jobnr, int nb_jobs)
Definition: vf_epx.c:46
AVFilter ff_vf_epx
Definition: vf_epx.c:279
static int query_formats(AVFilterContext *ctx)
Definition: vf_epx.c:226
AVFILTER_DEFINE_CLASS(epx)
#define FLAGS
Definition: vf_epx.c:38
static const AVFilterPad inputs[]
Definition: vf_epx.c:261
static const AVFilterPad outputs[]
Definition: vf_epx.c:270
static int filter_frame(AVFilterLink *inlink, AVFrame *in)
Definition: vf_epx.c:239
#define OFFSET(x)
Definition: vf_epx.c:37
static int config_output(AVFilterLink *outlink)
Definition: vf_epx.c:200
static const AVOption epx_options[]
Definition: vf_epx.c:39
AVFrame * ff_get_video_buffer(AVFilterLink *link, int w, int h)
Request a picture buffer with a specific set of permissions.
Definition: video.c:104