FFmpeg  4.4.5
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 
24 typedef struct EPXContext {
25  const AVClass *class;
26 
27  int n;
28 
29  int (*epx_slice)(AVFilterContext *ctx, void *arg, int jobnr, int nb_jobs);
30 } EPXContext;
31 
32 typedef struct ThreadData {
33  AVFrame *in, *out;
34 } ThreadData;
35 
36 #define OFFSET(x) offsetof(EPXContext, x)
37 #define FLAGS AV_OPT_FLAG_FILTERING_PARAM|AV_OPT_FLAG_VIDEO_PARAM
38 static const AVOption epx_options[] = {
39  { "n", "set scale factor", OFFSET(n), AV_OPT_TYPE_INT, {.i64 = 3}, 2, 3, .flags = FLAGS },
40  { NULL }
41 };
42 
44 
45 static int epx2_slice(AVFilterContext *ctx, void *arg, int jobnr, int nb_jobs)
46 {
47  ThreadData *td = arg;
48  const AVFrame *in = td->in;
49  AVFrame *out = td->out;
50  const int slice_start = (in->height * jobnr ) / nb_jobs;
51  const int slice_end = (in->height * (jobnr+1)) / nb_jobs;
52 
53  for (int p = 0; p < 1; p++) {
54  const int width = in->width;
55  const int height = in->height;
56  const int src_linesize = in->linesize[p] / 4;
57  const int dst_linesize = out->linesize[p] / 4;
58  const uint32_t *src = (const uint32_t *)in->data[p];
59  uint32_t *dst = (uint32_t *)out->data[p];
60  const uint32_t *src_line[3];
61 
62  src_line[0] = src + src_linesize * FFMAX(slice_start - 1, 0);
63  src_line[1] = src + src_linesize * slice_start;
64  src_line[2] = src + src_linesize * FFMIN(slice_start + 1, height-1);
65 
66  for (int y = slice_start; y < slice_end; y++) {
67  uint32_t *dst_line[2];
68 
69  dst_line[0] = dst + dst_linesize*2*y;
70  dst_line[1] = dst + dst_linesize*(2*y+1);
71 
72  for (int x = 0; x < width; x++) {
73  uint32_t E0, E1, E2, E3;
74  uint32_t B, D, E, F, H;
75 
76  B = src_line[0][x];
77  D = src_line[1][FFMAX(x-1, 0)];
78  E = src_line[1][x];
79  F = src_line[1][FFMIN(x+1, width - 1)];
80  H = src_line[2][x];
81 
82  if (B != H && D != F) {
83  E0 = D == B ? D : E;
84  E1 = B == F ? F : E;
85  E2 = D == H ? D : E;
86  E3 = H == F ? F : E;
87  } else {
88  E0 = E;
89  E1 = E;
90  E2 = E;
91  E3 = E;
92  }
93 
94  dst_line[0][x*2] = E0;
95  dst_line[0][x*2+1] = E1;
96  dst_line[1][x*2] = E2;
97  dst_line[1][x*2+1] = E3;
98  }
99 
100  src_line[0] = src_line[1];
101  src_line[1] = src_line[2];
102  src_line[2] = src_line[1];
103 
104  if (y < height - 1)
105  src_line[2] += src_linesize;
106  }
107  }
108 
109  return 0;
110 }
111 
112 static int epx3_slice(AVFilterContext *ctx, void *arg, int jobnr, int nb_jobs)
113 {
114  ThreadData *td = arg;
115  const AVFrame *in = td->in;
116  AVFrame *out = td->out;
117  const int slice_start = (in->height * jobnr ) / nb_jobs;
118  const int slice_end = (in->height * (jobnr+1)) / nb_jobs;
119 
120  for (int p = 0; p < 1; p++) {
121  const int width = in->width;
122  const int height = in->height;
123  const int src_linesize = in->linesize[p] / 4;
124  const int dst_linesize = out->linesize[p] / 4;
125  const uint32_t *src = (const uint32_t *)in->data[p];
126  uint32_t *dst = (uint32_t *)out->data[p];
127  const uint32_t *src_line[3];
128 
129  src_line[0] = src + src_linesize * FFMAX(slice_start - 1, 0);
130  src_line[1] = src + src_linesize * slice_start;
131  src_line[2] = src + src_linesize * FFMIN(slice_start + 1, height-1);
132 
133  for (int y = slice_start; y < slice_end; y++) {
134  uint32_t *dst_line[3];
135 
136  dst_line[0] = dst + dst_linesize*3*y;
137  dst_line[1] = dst + dst_linesize*(3*y+1);
138  dst_line[2] = dst + dst_linesize*(3*y+2);
139 
140  for (int x = 0; x < width; x++) {
141  uint32_t E0, E1, E2, E3, E4, E5, E6, E7, E8;
142  uint32_t A, B, C, D, E, F, G, H, I;
143 
144  A = src_line[0][FFMAX(x-1, 0)];
145  B = src_line[0][x];
146  C = src_line[0][FFMIN(x+1, width - 1)];
147  D = src_line[1][FFMAX(x-1, 0)];
148  E = src_line[1][x];
149  F = src_line[1][FFMIN(x+1, width - 1)];
150  G = src_line[2][FFMAX(x-1, 0)];
151  H = src_line[2][x];
152  I = src_line[2][FFMIN(x+1, width - 1)];
153 
154  if (B != H && D != F) {
155  E0 = D == B ? D : E;
156  E1 = (D == B && E != C) || (B == F && E != A) ? B : E;
157  E2 = B == F ? F : E;
158  E3 = (D == B && E != G) || (D == H && E != A) ? D : E;
159  E4 = E;
160  E5 = (B == F && E != I) || (H == F && E != C) ? F : E;
161  E6 = D == H ? D : E;
162  E7 = (D == H && E != I) || (H == F && E != G) ? H : E;
163  E8 = H == F ? F : E;
164  } else {
165  E0 = E;
166  E1 = E;
167  E2 = E;
168  E3 = E;
169  E4 = E;
170  E5 = E;
171  E6 = E;
172  E7 = E;
173  E8 = E;
174  }
175 
176  dst_line[0][x*3] = E0;
177  dst_line[0][x*3+1] = E1;
178  dst_line[0][x*3+2] = E2;
179  dst_line[1][x*3] = E3;
180  dst_line[1][x*3+1] = E4;
181  dst_line[1][x*3+2] = E5;
182  dst_line[2][x*3] = E6;
183  dst_line[2][x*3+1] = E7;
184  dst_line[2][x*3+2] = E8;
185  }
186 
187  src_line[0] = src_line[1];
188  src_line[1] = src_line[2];
189  src_line[2] = src_line[1];
190 
191  if (y < height - 1)
192  src_line[2] += src_linesize;
193  }
194  }
195 
196  return 0;
197 }
198 
199 static int config_output(AVFilterLink *outlink)
200 {
201  AVFilterContext *ctx = outlink->src;
202  EPXContext *s = ctx->priv;
203  AVFilterLink *inlink = ctx->inputs[0];
204  const AVPixFmtDescriptor *desc;
205 
206  desc = av_pix_fmt_desc_get(outlink->format);
207  if (!desc)
208  return AVERROR_BUG;
209 
210  outlink->w = inlink->w * s->n;
211  outlink->h = inlink->h * s->n;
212 
213  switch (s->n) {
214  case 2:
215  s->epx_slice = epx2_slice;
216  break;
217  case 3:
218  s->epx_slice = epx3_slice;
219  break;
220  }
221 
222  return 0;
223 }
224 
226 {
227  static const enum AVPixelFormat pix_fmts[] = {
230  };
231 
233  if (!fmts_list)
234  return AVERROR(ENOMEM);
235  return ff_set_common_formats(ctx, fmts_list);
236 }
237 
238 static int filter_frame(AVFilterLink *inlink, AVFrame *in)
239 {
240  AVFilterContext *ctx = inlink->dst;
241  AVFilterLink *outlink = ctx->outputs[0];
242  EPXContext *s = ctx->priv;
243  ThreadData td;
244 
245  AVFrame *out = ff_get_video_buffer(outlink, outlink->w, outlink->h);
246  if (!out) {
247  av_frame_free(&in);
248  return AVERROR(ENOMEM);
249  }
250 
252 
253  td.in = in, td.out = out;
254  ctx->internal->execute(ctx, s->epx_slice, &td, NULL, FFMIN(inlink->h, ff_filter_get_nb_threads(ctx)));
255 
256  av_frame_free(&in);
257  return ff_filter_frame(outlink, out);
258 }
259 
260 static const AVFilterPad inputs[] = {
261  {
262  .name = "default",
263  .type = AVMEDIA_TYPE_VIDEO,
264  .filter_frame = filter_frame,
265  },
266  { NULL }
267 };
268 
269 static const AVFilterPad outputs[] = {
270  {
271  .name = "default",
272  .type = AVMEDIA_TYPE_VIDEO,
273  .config_props = config_output,
274  },
275  { NULL }
276 };
277 
279  .name = "epx",
280  .description = NULL_IF_CONFIG_SMALL("Scale the input using EPX algorithm."),
281  .inputs = inputs,
282  .outputs = outputs,
283  .query_formats = query_formats,
284  .priv_size = sizeof(EPXContext),
285  .priv_class = &epx_class,
287 };
#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
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:27
int(* epx_slice)(AVFilterContext *ctx, void *arg, int jobnr, int nb_jobs)
Definition: vf_epx.c:29
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:112
static int epx2_slice(AVFilterContext *ctx, void *arg, int jobnr, int nb_jobs)
Definition: vf_epx.c:45
AVFilter ff_vf_epx
Definition: vf_epx.c:278
static int query_formats(AVFilterContext *ctx)
Definition: vf_epx.c:225
AVFILTER_DEFINE_CLASS(epx)
#define FLAGS
Definition: vf_epx.c:37
static const AVFilterPad inputs[]
Definition: vf_epx.c:260
static const AVFilterPad outputs[]
Definition: vf_epx.c:269
static int filter_frame(AVFilterLink *inlink, AVFrame *in)
Definition: vf_epx.c:238
#define OFFSET(x)
Definition: vf_epx.c:36
static int config_output(AVFilterLink *outlink)
Definition: vf_epx.c:199
static const AVOption epx_options[]
Definition: vf_epx.c:38
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