Signed-off-by: Paul B Mahol <onemda@gmail.com>
Paul B Mahol authored on 2013/07/08 21:42:53... | ... |
@@ -2221,6 +2221,7 @@ owdenoise_filter_deps="gpl" |
2221 | 2221 |
pan_filter_deps="swresample" |
2222 | 2222 |
phase_filter_deps="gpl" |
2223 | 2223 |
pp_filter_deps="gpl postproc" |
2224 |
+pullup_filter_deps="gpl" |
|
2224 | 2225 |
removelogo_filter_deps="avcodec avformat swscale" |
2225 | 2226 |
sab_filter_deps="gpl swscale" |
2226 | 2227 |
scale_filter_deps="swscale" |
... | ... |
@@ -6184,6 +6184,59 @@ On this example the input file being processed is compared with the |
6184 | 6184 |
reference file @file{ref_movie.mpg}. The PSNR of each individual frame |
6185 | 6185 |
is stored in @file{stats.log}. |
6186 | 6186 |
|
6187 |
+@section pullup |
|
6188 |
+ |
|
6189 |
+Pulldown reversal (inverse telecine) filter, capable of handling mixed |
|
6190 |
+hard-telecine, 24000/1001 fps progressive, and 30000/1001 fps progressive |
|
6191 |
+content. |
|
6192 |
+ |
|
6193 |
+The pullup filter is designed to take advantage of future context in making |
|
6194 |
+its decisions. This filter is stateless in the sense that it does not lock |
|
6195 |
+onto a pattern to follow, but it instead looks forward to the following |
|
6196 |
+fields in order to identify matches and rebuild progressive frames. |
|
6197 |
+ |
|
6198 |
+The filter accepts the following options: |
|
6199 |
+ |
|
6200 |
+@table @option |
|
6201 |
+@item jl |
|
6202 |
+@item jr |
|
6203 |
+@item jt |
|
6204 |
+@item jb |
|
6205 |
+These options set the amount of "junk" to ignore at the left, right, top, and |
|
6206 |
+bottom of the image, respectively. Left and right are in units of 8 pixels, |
|
6207 |
+while top and bottom are in units of 2 lines. |
|
6208 |
+The default is 8 pixels on each side. |
|
6209 |
+ |
|
6210 |
+@item sb |
|
6211 |
+Set the strict breaks. Setting this option to 1 will reduce the chances of |
|
6212 |
+filter generating an occasional mismatched frame, but it may also cause an |
|
6213 |
+excessive number of frames to be dropped during high motion sequences. |
|
6214 |
+Conversely, setting it to -1 will make filter match fields more easily. |
|
6215 |
+This may help processing of video where there is slight blurring between |
|
6216 |
+the fields, but may also cause there to be interlaced frames in the output. |
|
6217 |
+Default value is @code{0}. |
|
6218 |
+ |
|
6219 |
+@item mp |
|
6220 |
+Set the metric plane to use. It accepts the following values: |
|
6221 |
+@table @samp |
|
6222 |
+@item l |
|
6223 |
+Use luma plane. |
|
6224 |
+ |
|
6225 |
+@item u |
|
6226 |
+Use chroma blue plane. |
|
6227 |
+ |
|
6228 |
+@item v |
|
6229 |
+Use chroma red plane. |
|
6230 |
+@end table |
|
6231 |
+ |
|
6232 |
+This option may be set to use chroma plane instead of the default luma plane |
|
6233 |
+for doing filter's computations. This may improve accuracy on very clean |
|
6234 |
+source material, but more likely will decrease accuracy, especially if there |
|
6235 |
+is chroma noise (rainbow effect) or any grayscale video. |
|
6236 |
+The main purpose of setting @option{mp} to a chroma plane is to reduce CPU |
|
6237 |
+load and make pullup usable in realtime on slow machines. |
|
6238 |
+@end table |
|
6239 |
+ |
|
6187 | 6240 |
@section removelogo |
6188 | 6241 |
|
6189 | 6242 |
Suppress a TV station logo, using an image file to determine which |
... | ... |
@@ -173,6 +173,7 @@ OBJS-$(CONFIG_PHASE_FILTER) += vf_phase.o |
173 | 173 |
OBJS-$(CONFIG_PIXDESCTEST_FILTER) += vf_pixdesctest.o |
174 | 174 |
OBJS-$(CONFIG_PP_FILTER) += vf_pp.o |
175 | 175 |
OBJS-$(CONFIG_PSNR_FILTER) += vf_psnr.o dualinput.o |
176 |
+OBJS-$(CONFIG_PULLUP_FILTER) += vf_pullup.o |
|
176 | 177 |
OBJS-$(CONFIG_REMOVELOGO_FILTER) += bbox.o lswsutils.o lavfutils.o vf_removelogo.o |
177 | 178 |
OBJS-$(CONFIG_ROTATE_FILTER) += vf_rotate.o |
178 | 179 |
OBJS-$(CONFIG_SEPARATEFIELDS_FILTER) += vf_separatefields.o |
... | ... |
@@ -168,6 +168,7 @@ void avfilter_register_all(void) |
168 | 168 |
REGISTER_FILTER(PIXDESCTEST, pixdesctest, vf); |
169 | 169 |
REGISTER_FILTER(PP, pp, vf); |
170 | 170 |
REGISTER_FILTER(PSNR, psnr, vf); |
171 |
+ REGISTER_FILTER(PULLUP, pullup, vf); |
|
171 | 172 |
REGISTER_FILTER(REMOVELOGO, removelogo, vf); |
172 | 173 |
REGISTER_FILTER(ROTATE, rotate, vf); |
173 | 174 |
REGISTER_FILTER(SAB, sab, vf); |
... | ... |
@@ -30,7 +30,7 @@ |
30 | 30 |
#include "libavutil/avutil.h" |
31 | 31 |
|
32 | 32 |
#define LIBAVFILTER_VERSION_MAJOR 3 |
33 |
-#define LIBAVFILTER_VERSION_MINOR 85 |
|
33 |
+#define LIBAVFILTER_VERSION_MINOR 86 |
|
34 | 34 |
#define LIBAVFILTER_VERSION_MICRO 100 |
35 | 35 |
|
36 | 36 |
#define LIBAVFILTER_VERSION_INT AV_VERSION_INT(LIBAVFILTER_VERSION_MAJOR, \ |
37 | 37 |
new file mode 100644 |
... | ... |
@@ -0,0 +1,762 @@ |
0 |
+/* |
|
1 |
+ * Copyright (c) 2003 Rich Felker |
|
2 |
+ * |
|
3 |
+ * This file is part of FFmpeg. |
|
4 |
+ * |
|
5 |
+ * FFmpeg is free software; you can redistribute it and/or |
|
6 |
+ * modify it under the terms of the GNU General Public |
|
7 |
+ * License as published by the Free Software Foundation; either |
|
8 |
+ * version 2 of the License, or (at your option) any later version. |
|
9 |
+ * |
|
10 |
+ * FFmpeg is distributed in the hope that it will be useful, |
|
11 |
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of |
|
12 |
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
|
13 |
+ * GNU General Public License for more details. |
|
14 |
+ * |
|
15 |
+ * You should have received a copy of the GNU General Public License along |
|
16 |
+ * with FFmpeg; if not, write to the Free Software |
|
17 |
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA |
|
18 |
+ */ |
|
19 |
+ |
|
20 |
+#include "libavutil/avassert.h" |
|
21 |
+#include "libavutil/imgutils.h" |
|
22 |
+#include "libavutil/opt.h" |
|
23 |
+#include "libavutil/pixdesc.h" |
|
24 |
+#include "avfilter.h" |
|
25 |
+#include "formats.h" |
|
26 |
+#include "internal.h" |
|
27 |
+#include "video.h" |
|
28 |
+#include "vf_pullup.h" |
|
29 |
+ |
|
30 |
+#define F_HAVE_BREAKS 1 |
|
31 |
+#define F_HAVE_AFFINITY 2 |
|
32 |
+ |
|
33 |
+#define BREAK_LEFT 1 |
|
34 |
+#define BREAK_RIGHT 2 |
|
35 |
+ |
|
36 |
+#define OFFSET(x) offsetof(PullupContext, x) |
|
37 |
+#define FLAGS AV_OPT_FLAG_VIDEO_PARAM|AV_OPT_FLAG_FILTERING_PARAM |
|
38 |
+ |
|
39 |
+static const AVOption pullup_options[] = { |
|
40 |
+ { "jl", "set left junk size", OFFSET(junk_left), AV_OPT_TYPE_INT, {.i64=1}, 0, INT_MAX, FLAGS }, |
|
41 |
+ { "jr", "set right junk size", OFFSET(junk_right), AV_OPT_TYPE_INT, {.i64=1}, 0, INT_MAX, FLAGS }, |
|
42 |
+ { "jt", "set top junk size", OFFSET(junk_top), AV_OPT_TYPE_INT, {.i64=4}, 1, INT_MAX, FLAGS }, |
|
43 |
+ { "jd", "set down junk size", OFFSET(junk_down), AV_OPT_TYPE_INT, {.i64=4}, 1, INT_MAX, FLAGS }, |
|
44 |
+ { "sb", "set strict breaks", OFFSET(strict_breaks), AV_OPT_TYPE_INT, {.i64=0},-1, 1, FLAGS }, |
|
45 |
+ { "mp", "set metric plane", OFFSET(metric_plane), AV_OPT_TYPE_INT, {.i64=0}, 0, 2, FLAGS, "mp" }, |
|
46 |
+ { "y", "luma", 0, AV_OPT_TYPE_CONST, {.i64=0}, 0, 0, FLAGS, "mp" }, |
|
47 |
+ { "u", "chroma blue", 0, AV_OPT_TYPE_CONST, {.i64=1}, 0, 0, FLAGS, "mp" }, |
|
48 |
+ { "v", "chroma red", 0, AV_OPT_TYPE_CONST, {.i64=2}, 0, 0, FLAGS, "mp" }, |
|
49 |
+ { NULL } |
|
50 |
+}; |
|
51 |
+ |
|
52 |
+AVFILTER_DEFINE_CLASS(pullup); |
|
53 |
+ |
|
54 |
+static int query_formats(AVFilterContext *ctx) |
|
55 |
+{ |
|
56 |
+ static const enum AVPixelFormat pix_fmts[] = { |
|
57 |
+ AV_PIX_FMT_YUVJ444P, AV_PIX_FMT_YUVJ440P, |
|
58 |
+ AV_PIX_FMT_YUVJ422P, AV_PIX_FMT_YUVJ420P, |
|
59 |
+ AV_PIX_FMT_YUV444P, AV_PIX_FMT_YUV440P, |
|
60 |
+ AV_PIX_FMT_YUV422P, AV_PIX_FMT_YUV420P, |
|
61 |
+ AV_PIX_FMT_YUV411P, AV_PIX_FMT_YUV410P, |
|
62 |
+ AV_PIX_FMT_YUVJ411P, AV_PIX_FMT_GRAY8, |
|
63 |
+ AV_PIX_FMT_NONE |
|
64 |
+ }; |
|
65 |
+ ff_set_common_formats(ctx, ff_make_format_list(pix_fmts)); |
|
66 |
+ return 0; |
|
67 |
+} |
|
68 |
+ |
|
69 |
+#define ABS(a) (((a) ^ ((a) >> 31)) - ((a) >> 31)) |
|
70 |
+ |
|
71 |
+static int diff_c(const uint8_t *a, const uint8_t *b, int s) |
|
72 |
+{ |
|
73 |
+ int i, j, diff = 0; |
|
74 |
+ |
|
75 |
+ for (i = 0; i < 4; i++) { |
|
76 |
+ for (j = 0; j < 8; j++) |
|
77 |
+ diff += ABS(a[j] - b[j]); |
|
78 |
+ a += s; |
|
79 |
+ b += s; |
|
80 |
+ } |
|
81 |
+ |
|
82 |
+ return diff; |
|
83 |
+} |
|
84 |
+ |
|
85 |
+static int comb_c(const uint8_t *a, const uint8_t *b, int s) |
|
86 |
+{ |
|
87 |
+ int i, j, comb = 0; |
|
88 |
+ |
|
89 |
+ for (i = 0; i < 4; i++) { |
|
90 |
+ for (j = 0; j < 8; j++) |
|
91 |
+ comb += ABS((a[j] << 1) - b[j - s] - b[j ]) + |
|
92 |
+ ABS((b[j] << 1) - a[j ] - a[j + s]); |
|
93 |
+ a += s; |
|
94 |
+ b += s; |
|
95 |
+ } |
|
96 |
+ |
|
97 |
+ return comb; |
|
98 |
+} |
|
99 |
+ |
|
100 |
+static int var_c(const uint8_t *a, const uint8_t *b, int s) |
|
101 |
+{ |
|
102 |
+ int i, j, var = 0; |
|
103 |
+ |
|
104 |
+ for (i = 0; i < 3; i++) { |
|
105 |
+ for (j = 0; j < 8; j++) |
|
106 |
+ var += ABS(a[j] - a[j + s]); |
|
107 |
+ a += s; |
|
108 |
+ } |
|
109 |
+ |
|
110 |
+ return 4 * var; /* match comb scaling */ |
|
111 |
+} |
|
112 |
+ |
|
113 |
+static int alloc_metrics(PullupContext *s, PullupField *f) |
|
114 |
+{ |
|
115 |
+ f->diffs = av_calloc(FFALIGN(s->metric_length, 16), sizeof(*f->diffs)); |
|
116 |
+ f->combs = av_calloc(FFALIGN(s->metric_length, 16), sizeof(*f->combs)); |
|
117 |
+ f->vars = av_calloc(FFALIGN(s->metric_length, 16), sizeof(*f->vars)); |
|
118 |
+ |
|
119 |
+ if (!f->diffs || !f->combs || !f->vars) { |
|
120 |
+ av_freep(&f->diffs); |
|
121 |
+ av_freep(&f->combs); |
|
122 |
+ av_freep(&f->vars); |
|
123 |
+ return AVERROR(ENOMEM); |
|
124 |
+ } |
|
125 |
+ return 0; |
|
126 |
+} |
|
127 |
+ |
|
128 |
+static PullupField *make_field_queue(PullupContext *s, int len) |
|
129 |
+{ |
|
130 |
+ PullupField *head, *f; |
|
131 |
+ |
|
132 |
+ f = head = av_mallocz(sizeof(*head)); |
|
133 |
+ if (!f) |
|
134 |
+ return NULL; |
|
135 |
+ |
|
136 |
+ if (alloc_metrics(s, f) < 0) { |
|
137 |
+ av_free(f); |
|
138 |
+ return NULL; |
|
139 |
+ } |
|
140 |
+ |
|
141 |
+ for (; len > 0; len--) { |
|
142 |
+ f->next = av_mallocz(sizeof(*f->next)); |
|
143 |
+ if (!f->next) |
|
144 |
+ return NULL; |
|
145 |
+ |
|
146 |
+ f->next->prev = f; |
|
147 |
+ f = f->next; |
|
148 |
+ if (alloc_metrics(s, f) < 0) |
|
149 |
+ return NULL; |
|
150 |
+ } |
|
151 |
+ |
|
152 |
+ f->next = head; |
|
153 |
+ head->prev = f; |
|
154 |
+ |
|
155 |
+ return head; |
|
156 |
+} |
|
157 |
+ |
|
158 |
+static int config_input(AVFilterLink *inlink) |
|
159 |
+{ |
|
160 |
+ AVFilterContext *ctx = inlink->dst; |
|
161 |
+ PullupContext *s = ctx->priv; |
|
162 |
+ const AVPixFmtDescriptor *desc = av_pix_fmt_desc_get(inlink->format); |
|
163 |
+ const int mp = s->metric_plane; |
|
164 |
+ |
|
165 |
+ s->planeheight[1] = s->planeheight[2] = FF_CEIL_RSHIFT(inlink->h, desc->log2_chroma_h); |
|
166 |
+ s->planeheight[0] = s->planeheight[3] = inlink->h; |
|
167 |
+ s->planewidth[1] = s->planewidth[2] = FF_CEIL_RSHIFT(inlink->w, desc->log2_chroma_w); |
|
168 |
+ s->planewidth[0] = s->planewidth[3] = inlink->w; |
|
169 |
+ s->nb_planes = av_pix_fmt_count_planes(inlink->format); |
|
170 |
+ |
|
171 |
+ s->metric_w = (s->planewidth[mp] - ((s->junk_left + s->junk_right) << 3)) >> 3; |
|
172 |
+ s->metric_h = (s->planeheight[mp] - ((s->junk_top + s->junk_bottom) << 1)) >> 3; |
|
173 |
+ s->metric_offset = (s->junk_left << 3) + (s->junk_top << 1) * s->planewidth[mp]; |
|
174 |
+ s->metric_length = s->metric_w * s->metric_h; |
|
175 |
+ |
|
176 |
+ av_log(ctx, AV_LOG_DEBUG, "w: %d h: %d\n", s->metric_w, s->metric_h); |
|
177 |
+ av_log(ctx, AV_LOG_DEBUG, "offset: %d length: %d\n", s->metric_offset, s->metric_length); |
|
178 |
+ |
|
179 |
+ s->head = make_field_queue(s, 8); |
|
180 |
+ if (!s->head) |
|
181 |
+ return AVERROR(ENOMEM); |
|
182 |
+ |
|
183 |
+ s->diff = diff_c; |
|
184 |
+ s->comb = comb_c; |
|
185 |
+ s->var = var_c; |
|
186 |
+ |
|
187 |
+ if (ARCH_X86) |
|
188 |
+ ff_pullup_init_x86(s); |
|
189 |
+ return 0; |
|
190 |
+} |
|
191 |
+ |
|
192 |
+static int config_output(AVFilterLink *outlink) |
|
193 |
+{ |
|
194 |
+ outlink->flags |= FF_LINK_FLAG_REQUEST_LOOP; |
|
195 |
+ return 0; |
|
196 |
+} |
|
197 |
+ |
|
198 |
+static PullupBuffer *pullup_lock_buffer(PullupBuffer *b, int parity) |
|
199 |
+{ |
|
200 |
+ if (!b) |
|
201 |
+ return NULL; |
|
202 |
+ |
|
203 |
+ if ((parity + 1) & 1) |
|
204 |
+ b->lock[0]++; |
|
205 |
+ if ((parity + 1) & 2) |
|
206 |
+ b->lock[1]++; |
|
207 |
+ |
|
208 |
+ return b; |
|
209 |
+} |
|
210 |
+ |
|
211 |
+static void pullup_release_buffer(PullupBuffer *b, int parity) |
|
212 |
+{ |
|
213 |
+ if (!b) |
|
214 |
+ return; |
|
215 |
+ |
|
216 |
+ if ((parity + 1) & 1) |
|
217 |
+ b->lock[0]--; |
|
218 |
+ if ((parity + 1) & 2) |
|
219 |
+ b->lock[1]--; |
|
220 |
+} |
|
221 |
+ |
|
222 |
+static int alloc_buffer(PullupContext *s, PullupBuffer *b) |
|
223 |
+{ |
|
224 |
+ int i; |
|
225 |
+ |
|
226 |
+ if (b->planes[0]) |
|
227 |
+ return 0; |
|
228 |
+ for (i = 0; i < s->nb_planes; i++) { |
|
229 |
+ b->planes[i] = av_malloc(s->planeheight[i] * s->planewidth[i]); |
|
230 |
+ } |
|
231 |
+ |
|
232 |
+ return 0; |
|
233 |
+} |
|
234 |
+ |
|
235 |
+static PullupBuffer *pullup_get_buffer(PullupContext *s, int parity) |
|
236 |
+{ |
|
237 |
+ int i; |
|
238 |
+ |
|
239 |
+ /* Try first to get the sister buffer for the previous field */ |
|
240 |
+ if (parity < 2 && s->last && parity != s->last->parity |
|
241 |
+ && !s->last->buffer->lock[parity]) { |
|
242 |
+ alloc_buffer(s, s->last->buffer); |
|
243 |
+ return pullup_lock_buffer(s->last->buffer, parity); |
|
244 |
+ } |
|
245 |
+ |
|
246 |
+ /* Prefer a buffer with both fields open */ |
|
247 |
+ for (i = 0; i < FF_ARRAY_ELEMS(s->buffers); i++) { |
|
248 |
+ if (s->buffers[i].lock[0]) |
|
249 |
+ continue; |
|
250 |
+ if (s->buffers[i].lock[1]) |
|
251 |
+ continue; |
|
252 |
+ alloc_buffer(s, &s->buffers[i]); |
|
253 |
+ return pullup_lock_buffer(&s->buffers[i], parity); |
|
254 |
+ } |
|
255 |
+ |
|
256 |
+ if (parity == 2) |
|
257 |
+ return 0; |
|
258 |
+ |
|
259 |
+ /* Search for any half-free buffer */ |
|
260 |
+ for (i = 0; i < FF_ARRAY_ELEMS(s->buffers); i++) { |
|
261 |
+ if (((parity + 1) & 1) && s->buffers[i].lock[0]) |
|
262 |
+ continue; |
|
263 |
+ if (((parity + 1) & 2) && s->buffers[i].lock[1]) |
|
264 |
+ continue; |
|
265 |
+ alloc_buffer(s, &s->buffers[i]); |
|
266 |
+ return pullup_lock_buffer(&s->buffers[i], parity); |
|
267 |
+ } |
|
268 |
+ |
|
269 |
+ return NULL; |
|
270 |
+} |
|
271 |
+ |
|
272 |
+static int queue_length(PullupField *begin, PullupField *end) |
|
273 |
+{ |
|
274 |
+ PullupField *f; |
|
275 |
+ int count = 1; |
|
276 |
+ |
|
277 |
+ if (!begin || !end) |
|
278 |
+ return 0; |
|
279 |
+ |
|
280 |
+ for (f = begin; f != end; f = f->next) |
|
281 |
+ count++; |
|
282 |
+ |
|
283 |
+ return count; |
|
284 |
+} |
|
285 |
+ |
|
286 |
+static int find_first_break(PullupField *f, int max) |
|
287 |
+{ |
|
288 |
+ int i; |
|
289 |
+ |
|
290 |
+ for (i = 0; i < max; i++) { |
|
291 |
+ if (f->breaks & BREAK_RIGHT || f->next->breaks & BREAK_LEFT) |
|
292 |
+ return i + 1; |
|
293 |
+ f = f->next; |
|
294 |
+ } |
|
295 |
+ |
|
296 |
+ return 0; |
|
297 |
+} |
|
298 |
+ |
|
299 |
+static void compute_breaks(PullupContext *s, PullupField *f0) |
|
300 |
+{ |
|
301 |
+ PullupField *f1 = f0->next; |
|
302 |
+ PullupField *f2 = f1->next; |
|
303 |
+ PullupField *f3 = f2->next; |
|
304 |
+ int i, l, max_l = 0, max_r = 0; |
|
305 |
+ |
|
306 |
+ if (f0->flags & F_HAVE_BREAKS) |
|
307 |
+ return; |
|
308 |
+ |
|
309 |
+ f0->flags |= F_HAVE_BREAKS; |
|
310 |
+ |
|
311 |
+ /* Special case when fields are 100% identical */ |
|
312 |
+ if (f0->buffer == f2->buffer && f1->buffer != f3->buffer) { |
|
313 |
+ f2->breaks |= BREAK_RIGHT; |
|
314 |
+ return; |
|
315 |
+ } |
|
316 |
+ |
|
317 |
+ if (f0->buffer != f2->buffer && f1->buffer == f3->buffer) { |
|
318 |
+ f1->breaks |= BREAK_LEFT; |
|
319 |
+ return; |
|
320 |
+ } |
|
321 |
+ |
|
322 |
+ for (i = 0; i < s->metric_length; i++) { |
|
323 |
+ l = f2->diffs[i] - f3->diffs[i]; |
|
324 |
+ |
|
325 |
+ if ( l > max_l) |
|
326 |
+ max_l = l; |
|
327 |
+ if (-l > max_r) |
|
328 |
+ max_r = -l; |
|
329 |
+ } |
|
330 |
+ |
|
331 |
+ /* Don't get tripped up when differences are mostly quant error */ |
|
332 |
+ if (max_l + max_r < 128) |
|
333 |
+ return; |
|
334 |
+ if (max_l > 4 * max_r) |
|
335 |
+ f1->breaks |= BREAK_LEFT; |
|
336 |
+ if (max_r > 4 * max_l) |
|
337 |
+ f2->breaks |= BREAK_RIGHT; |
|
338 |
+} |
|
339 |
+ |
|
340 |
+static void compute_affinity(PullupContext *s, PullupField *f) |
|
341 |
+{ |
|
342 |
+ int i, max_l = 0, max_r = 0, l; |
|
343 |
+ |
|
344 |
+ if (f->flags & F_HAVE_AFFINITY) |
|
345 |
+ return; |
|
346 |
+ |
|
347 |
+ f->flags |= F_HAVE_AFFINITY; |
|
348 |
+ |
|
349 |
+ if (f->buffer == f->next->next->buffer) { |
|
350 |
+ f->affinity = 1; |
|
351 |
+ f->next->affinity = 0; |
|
352 |
+ f->next->next->affinity = -1; |
|
353 |
+ f->next->flags |= F_HAVE_AFFINITY; |
|
354 |
+ f->next->next->flags |= F_HAVE_AFFINITY; |
|
355 |
+ return; |
|
356 |
+ } |
|
357 |
+ |
|
358 |
+ for (i = 0; i < s->metric_length; i++) { |
|
359 |
+ int v = f->vars[i]; |
|
360 |
+ int lv = f->prev->vars[i]; |
|
361 |
+ int rv = f->next->vars[i]; |
|
362 |
+ int lc = f->combs[i] - (v + lv) + ABS(v - lv); |
|
363 |
+ int rc = f->next->combs[i] - (v + rv) + ABS(v - rv); |
|
364 |
+ |
|
365 |
+ lc = FFMAX(lc, 0); |
|
366 |
+ rc = FFMAX(rc, 0); |
|
367 |
+ l = lc - rc; |
|
368 |
+ |
|
369 |
+ if ( l > max_l) |
|
370 |
+ max_l = l; |
|
371 |
+ if (-l > max_r) |
|
372 |
+ max_r = -l; |
|
373 |
+ } |
|
374 |
+ |
|
375 |
+ if (max_l + max_r < 64) |
|
376 |
+ return; |
|
377 |
+ |
|
378 |
+ if (max_r > 6 * max_l) |
|
379 |
+ f->affinity = -1; |
|
380 |
+ else if (max_l > 6 * max_r) |
|
381 |
+ f->affinity = 1; |
|
382 |
+} |
|
383 |
+ |
|
384 |
+static int decide_frame_length(PullupContext *s) |
|
385 |
+{ |
|
386 |
+ PullupField *f0 = s->first; |
|
387 |
+ PullupField *f1 = f0->next; |
|
388 |
+ PullupField *f2 = f1->next; |
|
389 |
+ PullupField *f; |
|
390 |
+ int i, l, n; |
|
391 |
+ |
|
392 |
+ if (queue_length(s->first, s->last) < 4) |
|
393 |
+ return 0; |
|
394 |
+ |
|
395 |
+ f = s->first; |
|
396 |
+ n = queue_length(f, s->last); |
|
397 |
+ for (i = 0; i < n - 1; i++) { |
|
398 |
+ if (i < n - 3) |
|
399 |
+ compute_breaks(s, f); |
|
400 |
+ |
|
401 |
+ compute_affinity(s, f); |
|
402 |
+ |
|
403 |
+ f = f->next; |
|
404 |
+ } |
|
405 |
+ |
|
406 |
+ if (f0->affinity == -1) |
|
407 |
+ return 1; |
|
408 |
+ |
|
409 |
+ l = find_first_break(f0, 3); |
|
410 |
+ |
|
411 |
+ if (l == 1 && s->strict_breaks < 0) |
|
412 |
+ l = 0; |
|
413 |
+ |
|
414 |
+ switch (l) { |
|
415 |
+ case 1: |
|
416 |
+ return 1 + (s->strict_breaks < 1 && f0->affinity == 1 && f1->affinity == -1); |
|
417 |
+ case 2: |
|
418 |
+ /* FIXME: strictly speaking, f0->prev is no longer valid... :) */ |
|
419 |
+ if (s->strict_pairs |
|
420 |
+ && (f0->prev->breaks & BREAK_RIGHT) && (f2->breaks & BREAK_LEFT) |
|
421 |
+ && (f0->affinity != 1 || f1->affinity != -1) ) |
|
422 |
+ return 1; |
|
423 |
+ return 1 + (f1->affinity != 1); |
|
424 |
+ case 3: |
|
425 |
+ return 2 + (f2->affinity != 1); |
|
426 |
+ default: |
|
427 |
+ /* 9 possibilities covered before switch */ |
|
428 |
+ if (f1->affinity == 1) |
|
429 |
+ return 1; /* covers 6 */ |
|
430 |
+ else if (f1->affinity == -1) |
|
431 |
+ return 2; /* covers 6 */ |
|
432 |
+ else if (f2->affinity == -1) { /* covers 2 */ |
|
433 |
+ return (f0->affinity == 1) ? 3 : 1; |
|
434 |
+ } else { |
|
435 |
+ return 2; /* the remaining 6 */ |
|
436 |
+ } |
|
437 |
+ } |
|
438 |
+} |
|
439 |
+ |
|
440 |
+static PullupFrame *pullup_get_frame(PullupContext *s) |
|
441 |
+{ |
|
442 |
+ PullupFrame *fr = &s->frame; |
|
443 |
+ int i, n = decide_frame_length(s); |
|
444 |
+ int aff = s->first->next->affinity; |
|
445 |
+ |
|
446 |
+ av_assert1(n < FF_ARRAY_ELEMS(fr->ifields)); |
|
447 |
+ if (!n || fr->lock) |
|
448 |
+ return NULL; |
|
449 |
+ |
|
450 |
+ fr->lock++; |
|
451 |
+ fr->length = n; |
|
452 |
+ fr->parity = s->first->parity; |
|
453 |
+ fr->buffer = 0; |
|
454 |
+ |
|
455 |
+ for (i = 0; i < n; i++) { |
|
456 |
+ /* We cheat and steal the buffer without release+relock */ |
|
457 |
+ fr->ifields[i] = s->first->buffer; |
|
458 |
+ s->first->buffer = 0; |
|
459 |
+ s->first = s->first->next; |
|
460 |
+ } |
|
461 |
+ |
|
462 |
+ if (n == 1) { |
|
463 |
+ fr->ofields[fr->parity ] = fr->ifields[0]; |
|
464 |
+ fr->ofields[fr->parity ^ 1] = 0; |
|
465 |
+ } else if (n == 2) { |
|
466 |
+ fr->ofields[fr->parity ] = fr->ifields[0]; |
|
467 |
+ fr->ofields[fr->parity ^ 1] = fr->ifields[1]; |
|
468 |
+ } else if (n == 3) { |
|
469 |
+ if (!aff) |
|
470 |
+ aff = (fr->ifields[0] == fr->ifields[1]) ? -1 : 1; |
|
471 |
+ fr->ofields[fr->parity ] = fr->ifields[1 + aff]; |
|
472 |
+ fr->ofields[fr->parity ^ 1] = fr->ifields[1 ]; |
|
473 |
+ } |
|
474 |
+ |
|
475 |
+ pullup_lock_buffer(fr->ofields[0], 0); |
|
476 |
+ pullup_lock_buffer(fr->ofields[1], 1); |
|
477 |
+ |
|
478 |
+ if (fr->ofields[0] == fr->ofields[1]) { |
|
479 |
+ fr->buffer = fr->ofields[0]; |
|
480 |
+ pullup_lock_buffer(fr->buffer, 2); |
|
481 |
+ return fr; |
|
482 |
+ } |
|
483 |
+ |
|
484 |
+ return fr; |
|
485 |
+} |
|
486 |
+ |
|
487 |
+static void pullup_release_frame(PullupFrame *f) |
|
488 |
+{ |
|
489 |
+ int i; |
|
490 |
+ |
|
491 |
+ for (i = 0; i < f->length; i++) |
|
492 |
+ pullup_release_buffer(f->ifields[i], f->parity ^ (i & 1)); |
|
493 |
+ |
|
494 |
+ pullup_release_buffer(f->ofields[0], 0); |
|
495 |
+ pullup_release_buffer(f->ofields[1], 1); |
|
496 |
+ |
|
497 |
+ if (f->buffer) |
|
498 |
+ pullup_release_buffer(f->buffer, 2); |
|
499 |
+ f->lock--; |
|
500 |
+} |
|
501 |
+ |
|
502 |
+static void compute_metric(PullupContext *s, int *dest, |
|
503 |
+ PullupField *fa, int pa, PullupField *fb, int pb, |
|
504 |
+ int (*func)(const uint8_t *, const uint8_t *, int)) |
|
505 |
+{ |
|
506 |
+ int mp = s->metric_plane; |
|
507 |
+ int xstep = 8; |
|
508 |
+ int ystep = s->planewidth[mp] << 3; |
|
509 |
+ int stride = s->planewidth[mp] << 1; /* field stride */ |
|
510 |
+ int w = s->metric_w * xstep; |
|
511 |
+ uint8_t *a, *b; |
|
512 |
+ int x, y; |
|
513 |
+ |
|
514 |
+ if (!fa->buffer || !fb->buffer) |
|
515 |
+ return; |
|
516 |
+ |
|
517 |
+ /* Shortcut for duplicate fields (e.g. from RFF flag) */ |
|
518 |
+ if (fa->buffer == fb->buffer && pa == pb) { |
|
519 |
+ memset(dest, 0, s->metric_length * sizeof(*dest)); |
|
520 |
+ return; |
|
521 |
+ } |
|
522 |
+ |
|
523 |
+ a = fa->buffer->planes[mp] + pa * s->planewidth[mp] + s->metric_offset; |
|
524 |
+ b = fb->buffer->planes[mp] + pb * s->planewidth[mp] + s->metric_offset; |
|
525 |
+ |
|
526 |
+ for (y = 0; y < s->metric_h; y++) { |
|
527 |
+ for (x = 0; x < w; x += xstep) |
|
528 |
+ *dest++ = func(a + x, b + x, stride); |
|
529 |
+ a += ystep; b += ystep; |
|
530 |
+ } |
|
531 |
+} |
|
532 |
+ |
|
533 |
+static int check_field_queue(PullupContext *s) |
|
534 |
+{ |
|
535 |
+ int ret; |
|
536 |
+ |
|
537 |
+ if (s->head->next == s->first) { |
|
538 |
+ PullupField *f = av_mallocz(sizeof(*f)); |
|
539 |
+ |
|
540 |
+ if (!f) |
|
541 |
+ return AVERROR(ENOMEM); |
|
542 |
+ |
|
543 |
+ if ((ret = alloc_metrics(s, f)) < 0) { |
|
544 |
+ av_free(f); |
|
545 |
+ return ret; |
|
546 |
+ } |
|
547 |
+ |
|
548 |
+ f->prev = s->head; |
|
549 |
+ f->next = s->first; |
|
550 |
+ s->head->next = f; |
|
551 |
+ s->first->prev = f; |
|
552 |
+ } |
|
553 |
+ |
|
554 |
+ return 0; |
|
555 |
+} |
|
556 |
+ |
|
557 |
+static void pullup_submit_field(PullupContext *s, PullupBuffer *b, int parity) |
|
558 |
+{ |
|
559 |
+ PullupField *f; |
|
560 |
+ |
|
561 |
+ /* Grow the circular list if needed */ |
|
562 |
+ if (check_field_queue(s) < 0) |
|
563 |
+ return; |
|
564 |
+ |
|
565 |
+ /* Cannot have two fields of same parity in a row; drop the new one */ |
|
566 |
+ if (s->last && s->last->parity == parity) |
|
567 |
+ return; |
|
568 |
+ |
|
569 |
+ f = s->head; |
|
570 |
+ f->parity = parity; |
|
571 |
+ f->buffer = pullup_lock_buffer(b, parity); |
|
572 |
+ f->flags = 0; |
|
573 |
+ f->breaks = 0; |
|
574 |
+ f->affinity = 0; |
|
575 |
+ |
|
576 |
+ compute_metric(s, f->diffs, f, parity, f->prev->prev, parity, s->diff); |
|
577 |
+ compute_metric(s, f->combs, parity ? f->prev : f, 0, parity ? f : f->prev, 1, s->comb); |
|
578 |
+ compute_metric(s, f->vars, f, parity, f, -1, s->var); |
|
579 |
+ emms_c(); |
|
580 |
+ |
|
581 |
+ /* Advance the circular list */ |
|
582 |
+ if (!s->first) |
|
583 |
+ s->first = s->head; |
|
584 |
+ |
|
585 |
+ s->last = s->head; |
|
586 |
+ s->head = s->head->next; |
|
587 |
+} |
|
588 |
+ |
|
589 |
+static void copy_field(PullupContext *s, |
|
590 |
+ PullupBuffer *dst, PullupBuffer *src, int parity) |
|
591 |
+{ |
|
592 |
+ uint8_t *dd, *ss; |
|
593 |
+ int i; |
|
594 |
+ |
|
595 |
+ for (i = 0; i < s->nb_planes; i++) { |
|
596 |
+ ss = src->planes[i] + parity * s->planewidth[i]; |
|
597 |
+ dd = dst->planes[i] + parity * s->planewidth[i]; |
|
598 |
+ |
|
599 |
+ av_image_copy_plane(dd, s->planewidth[i] << 1, |
|
600 |
+ ss, s->planewidth[i] << 1, |
|
601 |
+ s->planewidth[i], s->planeheight[i] >> 1); |
|
602 |
+ } |
|
603 |
+} |
|
604 |
+ |
|
605 |
+static void pullup_pack_frame(PullupContext *s, PullupFrame *fr) |
|
606 |
+{ |
|
607 |
+ int i; |
|
608 |
+ |
|
609 |
+ if (fr->buffer) |
|
610 |
+ return; |
|
611 |
+ |
|
612 |
+ if (fr->length < 2) |
|
613 |
+ return; /* FIXME: deal with this */ |
|
614 |
+ |
|
615 |
+ for (i = 0; i < 2; i++) { |
|
616 |
+ if (fr->ofields[i]->lock[i^1]) |
|
617 |
+ continue; |
|
618 |
+ |
|
619 |
+ fr->buffer = fr->ofields[i]; |
|
620 |
+ pullup_lock_buffer(fr->buffer, 2); |
|
621 |
+ copy_field(s, fr->buffer, fr->ofields[i^1], i^1); |
|
622 |
+ return; |
|
623 |
+ } |
|
624 |
+ |
|
625 |
+ fr->buffer = pullup_get_buffer(s, 2); |
|
626 |
+ |
|
627 |
+ copy_field(s, fr->buffer, fr->ofields[0], 0); |
|
628 |
+ copy_field(s, fr->buffer, fr->ofields[1], 1); |
|
629 |
+} |
|
630 |
+ |
|
631 |
+static int filter_frame(AVFilterLink *inlink, AVFrame *in) |
|
632 |
+{ |
|
633 |
+ AVFilterContext *ctx = inlink->dst; |
|
634 |
+ AVFilterLink *outlink = ctx->outputs[0]; |
|
635 |
+ PullupContext *s = ctx->priv; |
|
636 |
+ PullupBuffer *b; |
|
637 |
+ PullupFrame *f; |
|
638 |
+ AVFrame *out; |
|
639 |
+ int p, ret = 0; |
|
640 |
+ |
|
641 |
+ b = pullup_get_buffer(s, 2); |
|
642 |
+ if (!b) { |
|
643 |
+ av_log(ctx, AV_LOG_WARNING, "Could not get buffer!\n"); |
|
644 |
+ f = pullup_get_frame(s); |
|
645 |
+ pullup_release_frame(f); |
|
646 |
+ goto end; |
|
647 |
+ } |
|
648 |
+ |
|
649 |
+ av_image_copy(b->planes, s->planewidth, |
|
650 |
+ (const uint8_t**)in->data, in->linesize, |
|
651 |
+ inlink->format, inlink->w, inlink->h); |
|
652 |
+ |
|
653 |
+ p = !!in->interlaced_frame; |
|
654 |
+ pullup_submit_field(s, b, p ); |
|
655 |
+ pullup_submit_field(s, b, p^1); |
|
656 |
+ |
|
657 |
+ if (in->repeat_pict) |
|
658 |
+ pullup_submit_field(s, b, p); |
|
659 |
+ |
|
660 |
+ pullup_release_buffer(b, 2); |
|
661 |
+ |
|
662 |
+ f = pullup_get_frame(s); |
|
663 |
+ if (!f) |
|
664 |
+ goto end; |
|
665 |
+ |
|
666 |
+ if (f->length < 2) { |
|
667 |
+ pullup_release_frame(f); |
|
668 |
+ f = pullup_get_frame(s); |
|
669 |
+ if (!f) |
|
670 |
+ goto end; |
|
671 |
+ if (f->length < 2) { |
|
672 |
+ pullup_release_frame(f); |
|
673 |
+ if (!in->repeat_pict) |
|
674 |
+ goto end; |
|
675 |
+ f = pullup_get_frame(s); |
|
676 |
+ if (!f) |
|
677 |
+ goto end; |
|
678 |
+ if (f->length < 2) { |
|
679 |
+ pullup_release_frame(f); |
|
680 |
+ goto end; |
|
681 |
+ } |
|
682 |
+ } |
|
683 |
+ } |
|
684 |
+ |
|
685 |
+ /* If the frame isn't already exportable... */ |
|
686 |
+ if (!f->buffer) |
|
687 |
+ pullup_pack_frame(s, f); |
|
688 |
+ |
|
689 |
+ out = ff_get_video_buffer(outlink, outlink->w, outlink->h); |
|
690 |
+ if (!out) { |
|
691 |
+ ret = AVERROR(ENOMEM); |
|
692 |
+ goto end; |
|
693 |
+ } |
|
694 |
+ av_frame_copy_props(out, in); |
|
695 |
+ |
|
696 |
+ av_image_copy(out->data, out->linesize, |
|
697 |
+ (const uint8_t**)f->buffer->planes, s->planewidth, |
|
698 |
+ inlink->format, inlink->w, inlink->h); |
|
699 |
+ |
|
700 |
+ ret = ff_filter_frame(outlink, out); |
|
701 |
+ pullup_release_frame(f); |
|
702 |
+end: |
|
703 |
+ av_frame_free(&in); |
|
704 |
+ return ret; |
|
705 |
+} |
|
706 |
+ |
|
707 |
+static av_cold void uninit(AVFilterContext *ctx) |
|
708 |
+{ |
|
709 |
+ PullupContext *s = ctx->priv; |
|
710 |
+ PullupField *f; |
|
711 |
+ int i; |
|
712 |
+ |
|
713 |
+ f = s->head; |
|
714 |
+ do { |
|
715 |
+ if (!f) |
|
716 |
+ break; |
|
717 |
+ |
|
718 |
+ av_free(f->diffs); |
|
719 |
+ av_free(f->combs); |
|
720 |
+ av_free(f->vars); |
|
721 |
+ f = f->next; |
|
722 |
+ av_freep(&f->prev); |
|
723 |
+ } while (f != s->last); |
|
724 |
+ av_freep(&s->last); |
|
725 |
+ |
|
726 |
+ for (i = 0; i < FF_ARRAY_ELEMS(s->buffers); i++) { |
|
727 |
+ av_freep(&s->buffers[i].planes[0]); |
|
728 |
+ av_freep(&s->buffers[i].planes[1]); |
|
729 |
+ av_freep(&s->buffers[i].planes[2]); |
|
730 |
+ } |
|
731 |
+} |
|
732 |
+ |
|
733 |
+static const AVFilterPad pullup_inputs[] = { |
|
734 |
+ { |
|
735 |
+ .name = "default", |
|
736 |
+ .type = AVMEDIA_TYPE_VIDEO, |
|
737 |
+ .filter_frame = filter_frame, |
|
738 |
+ .config_props = config_input, |
|
739 |
+ }, |
|
740 |
+ { NULL } |
|
741 |
+}; |
|
742 |
+ |
|
743 |
+static const AVFilterPad pullup_outputs[] = { |
|
744 |
+ { |
|
745 |
+ .name = "default", |
|
746 |
+ .type = AVMEDIA_TYPE_VIDEO, |
|
747 |
+ .config_props = config_output, |
|
748 |
+ }, |
|
749 |
+ { NULL } |
|
750 |
+}; |
|
751 |
+ |
|
752 |
+AVFilter avfilter_vf_pullup = { |
|
753 |
+ .name = "pullup", |
|
754 |
+ .description = NULL_IF_CONFIG_SMALL("Pullup from field sequence to frames."), |
|
755 |
+ .priv_size = sizeof(PullupContext), |
|
756 |
+ .priv_class = &pullup_class, |
|
757 |
+ .uninit = uninit, |
|
758 |
+ .query_formats = query_formats, |
|
759 |
+ .inputs = pullup_inputs, |
|
760 |
+ .outputs = pullup_outputs, |
|
761 |
+}; |
0 | 762 |
new file mode 100644 |
... | ... |
@@ -0,0 +1,71 @@ |
0 |
+/* |
|
1 |
+ * This file is part of FFmpeg. |
|
2 |
+ * |
|
3 |
+ * FFmpeg is free software; you can redistribute it and/or |
|
4 |
+ * modify it under the terms of the GNU General Public |
|
5 |
+ * License as published by the Free Software Foundation; either |
|
6 |
+ * version 2 of the License, or (at your option) any later version. |
|
7 |
+ * |
|
8 |
+ * FFmpeg is distributed in the hope that it will be useful, |
|
9 |
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of |
|
10 |
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
|
11 |
+ * GNU General Public License for more details. |
|
12 |
+ * |
|
13 |
+ * You should have received a copy of the GNU General Public License along |
|
14 |
+ * with FFmpeg; if not, write to the Free Software |
|
15 |
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA |
|
16 |
+ */ |
|
17 |
+ |
|
18 |
+#ifndef AVFILTER_PULLUP_H |
|
19 |
+#define AVFILTER_PULLUP_H |
|
20 |
+ |
|
21 |
+#include "avfilter.h" |
|
22 |
+ |
|
23 |
+typedef struct PullupBuffer { |
|
24 |
+ int lock[2]; |
|
25 |
+ uint8_t *planes[4]; |
|
26 |
+} PullupBuffer; |
|
27 |
+ |
|
28 |
+typedef struct PullupField { |
|
29 |
+ int parity; |
|
30 |
+ PullupBuffer *buffer; |
|
31 |
+ unsigned flags; |
|
32 |
+ int breaks; |
|
33 |
+ int affinity; |
|
34 |
+ int *diffs; |
|
35 |
+ int *combs; |
|
36 |
+ int *vars; |
|
37 |
+ struct PullupField *prev, *next; |
|
38 |
+} PullupField; |
|
39 |
+ |
|
40 |
+typedef struct PullupFrame { |
|
41 |
+ int lock; |
|
42 |
+ int length; |
|
43 |
+ int parity; |
|
44 |
+ PullupBuffer *ifields[4], *ofields[2]; |
|
45 |
+ PullupBuffer *buffer; |
|
46 |
+} PullupFrame; |
|
47 |
+ |
|
48 |
+typedef struct PullupContext { |
|
49 |
+ const AVClass *class; |
|
50 |
+ int junk_left, junk_right, junk_top, junk_down, junk_bottom; |
|
51 |
+ int metric_plane; |
|
52 |
+ int strict_breaks; |
|
53 |
+ int strict_pairs; |
|
54 |
+ int metric_w, metric_h, metric_length; |
|
55 |
+ int metric_offset; |
|
56 |
+ int nb_planes; |
|
57 |
+ int planewidth[4]; |
|
58 |
+ int planeheight[4]; |
|
59 |
+ PullupField *first, *last, *head; |
|
60 |
+ PullupBuffer buffers[10]; |
|
61 |
+ PullupFrame frame; |
|
62 |
+ |
|
63 |
+ int (*diff)(const uint8_t *a, const uint8_t *b, int s); |
|
64 |
+ int (*comb)(const uint8_t *a, const uint8_t *b, int s); |
|
65 |
+ int (*var )(const uint8_t *a, const uint8_t *b, int s); |
|
66 |
+} PullupContext; |
|
67 |
+ |
|
68 |
+void ff_pullup_init_x86(PullupContext *s); |
|
69 |
+ |
|
70 |
+#endif /* AVFILTER_PULLUP_H */ |
... | ... |
@@ -1,9 +1,11 @@ |
1 | 1 |
OBJS-$(CONFIG_GRADFUN_FILTER) += x86/vf_gradfun.o |
2 | 2 |
OBJS-$(CONFIG_HQDN3D_FILTER) += x86/vf_hqdn3d_init.o |
3 |
+OBJS-$(CONFIG_PULLUP_FILTER) += x86/vf_pullup_init.o |
|
3 | 4 |
OBJS-$(CONFIG_SPP_FILTER) += x86/vf_spp.o |
4 | 5 |
OBJS-$(CONFIG_VOLUME_FILTER) += x86/af_volume_init.o |
5 | 6 |
OBJS-$(CONFIG_YADIF_FILTER) += x86/vf_yadif_init.o |
6 | 7 |
|
7 | 8 |
YASM-OBJS-$(CONFIG_HQDN3D_FILTER) += x86/vf_hqdn3d.o |
9 |
+YASM-OBJS-$(CONFIG_PULLUP_FILTER) += x86/vf_pullup.o |
|
8 | 10 |
YASM-OBJS-$(CONFIG_VOLUME_FILTER) += x86/af_volume.o |
9 | 11 |
YASM-OBJS-$(CONFIG_YADIF_FILTER) += x86/vf_yadif.o x86/yadif-16.o x86/yadif-10.o |
10 | 12 |
new file mode 100644 |
... | ... |
@@ -0,0 +1,178 @@ |
0 |
+;***************************************************************************** |
|
1 |
+;* x86-optimized functions for pullup filter |
|
2 |
+;* |
|
3 |
+;* This file is part of FFmpeg. |
|
4 |
+;* |
|
5 |
+;* FFmpeg is free software; you can redistribute it and/or modify |
|
6 |
+;* it under the terms of the GNU General Public License as published by |
|
7 |
+;* the Free Software Foundation; either version 2 of the License, or |
|
8 |
+;* (at your option) any later version. |
|
9 |
+;* |
|
10 |
+;* FFmpeg is distributed in the hope that it will be useful, |
|
11 |
+;* but WITHOUT ANY WARRANTY; without even the implied warranty of |
|
12 |
+;* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
|
13 |
+;* GNU General Public License for more details. |
|
14 |
+;* |
|
15 |
+;* You should have received a copy of the GNU General Public License along |
|
16 |
+;* with FFmpeg; if not, write to the Free Software Foundation, Inc., |
|
17 |
+;* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. |
|
18 |
+;****************************************************************************** |
|
19 |
+ |
|
20 |
+%include "libavutil/x86/x86util.asm" |
|
21 |
+ |
|
22 |
+SECTION_TEXT |
|
23 |
+ |
|
24 |
+INIT_MMX mmx |
|
25 |
+cglobal pullup_filter_diff, 3, 5, 8, first, second, size |
|
26 |
+ mov r3, 4 |
|
27 |
+ pxor m4, m4 |
|
28 |
+ pxor m7, m7 |
|
29 |
+ |
|
30 |
+.loop: |
|
31 |
+ movq m0, [firstq] |
|
32 |
+ movq m2, [firstq] |
|
33 |
+ add firstq, sizeq |
|
34 |
+ movq m1, [secondq] |
|
35 |
+ add secondq, sizeq |
|
36 |
+ psubusb m2, m1 |
|
37 |
+ psubusb m1, m0 |
|
38 |
+ movq m0, m2 |
|
39 |
+ movq m3, m1 |
|
40 |
+ punpcklbw m0, m7 |
|
41 |
+ punpcklbw m1, m7 |
|
42 |
+ punpckhbw m2, m7 |
|
43 |
+ punpckhbw m3, m7 |
|
44 |
+ paddw m4, m0 |
|
45 |
+ paddw m4, m1 |
|
46 |
+ paddw m4, m2 |
|
47 |
+ paddw m4, m3 |
|
48 |
+ |
|
49 |
+ dec r3 |
|
50 |
+ jnz .loop |
|
51 |
+ |
|
52 |
+ movq m3, m4 |
|
53 |
+ punpcklwd m4, m7 |
|
54 |
+ punpckhwd m3, m7 |
|
55 |
+ paddd m3, m4 |
|
56 |
+ movd eax, m3 |
|
57 |
+ psrlq m3, 32 |
|
58 |
+ movd r4, m3 |
|
59 |
+ add eax, r4 |
|
60 |
+ RET |
|
61 |
+ |
|
62 |
+INIT_MMX mmx |
|
63 |
+cglobal pullup_filter_comb, 3, 5, 8, first, second, size |
|
64 |
+ mov r3, 4 |
|
65 |
+ pxor m6, m6 |
|
66 |
+ pxor m7, m7 |
|
67 |
+ sub secondq, sizeq |
|
68 |
+ |
|
69 |
+.loop: |
|
70 |
+ movq m0, [secondq] |
|
71 |
+ movq m1, [secondq] |
|
72 |
+ punpcklbw m0, m7 |
|
73 |
+ movq m2, [secondq+sizeq] |
|
74 |
+ punpcklbw m1, m7 |
|
75 |
+ punpcklbw m2, m7 |
|
76 |
+ paddw m0, m0 |
|
77 |
+ paddw m1, m2 |
|
78 |
+ movq m2, m0 |
|
79 |
+ psubusw m0, m1 |
|
80 |
+ psubusw m1, m2 |
|
81 |
+ paddw m6, m0 |
|
82 |
+ paddw m6, m1 |
|
83 |
+ |
|
84 |
+ movq m0, [firstq] |
|
85 |
+ movq m1, [secondq] |
|
86 |
+ punpckhbw m0, m7 |
|
87 |
+ movq m2, [secondq+sizeq] |
|
88 |
+ punpckhbw m1, m7 |
|
89 |
+ punpckhbw m2, m7 |
|
90 |
+ paddw m0, m0 |
|
91 |
+ paddw m1, m2 |
|
92 |
+ movq m2, m0 |
|
93 |
+ psubusw m0, m1 |
|
94 |
+ psubusw m1, m2 |
|
95 |
+ paddw m6, m0 |
|
96 |
+ paddw m6, m1 |
|
97 |
+ |
|
98 |
+ movq m0, [secondq+sizeq] |
|
99 |
+ movq m1, [firstq] |
|
100 |
+ punpcklbw m0, m7 |
|
101 |
+ movq m2, [firstq+sizeq] |
|
102 |
+ punpcklbw m1, m7 |
|
103 |
+ punpcklbw m2, m7 |
|
104 |
+ paddw m0, m0 |
|
105 |
+ paddw m1, m2 |
|
106 |
+ movq m2, m0 |
|
107 |
+ psubusw m0, m1 |
|
108 |
+ psubusw m1, m2 |
|
109 |
+ paddw m6, m0 |
|
110 |
+ paddw m6, m1 |
|
111 |
+ |
|
112 |
+ movq m0, [secondq+sizeq] |
|
113 |
+ movq m1, [firstq] |
|
114 |
+ punpckhbw m0, m7 |
|
115 |
+ movq m2, [firstq+sizeq] |
|
116 |
+ punpckhbw m1, m7 |
|
117 |
+ punpckhbw m2, m7 |
|
118 |
+ paddw m0, m0 |
|
119 |
+ paddw m1, m2 |
|
120 |
+ movq m2, m0 |
|
121 |
+ psubusw m0, m1 |
|
122 |
+ psubusw m1, m2 |
|
123 |
+ paddw m6, m0 |
|
124 |
+ paddw m6, m1 |
|
125 |
+ |
|
126 |
+ add firstq, sizeq |
|
127 |
+ add secondq, sizeq |
|
128 |
+ dec r3 |
|
129 |
+ jnz .loop |
|
130 |
+ |
|
131 |
+ movq m5, m6 |
|
132 |
+ punpcklwd m6, m7 |
|
133 |
+ punpckhwd m5, m7 |
|
134 |
+ paddd m5, m6 |
|
135 |
+ movd eax, m5 |
|
136 |
+ psrlq m5, 32 |
|
137 |
+ movd r4, m5 |
|
138 |
+ add eax, r4 |
|
139 |
+ RET |
|
140 |
+ |
|
141 |
+INIT_MMX mmx |
|
142 |
+cglobal pullup_filter_var, 3, 5, 8, first, second, size |
|
143 |
+ mov r3, 3 |
|
144 |
+ pxor m4, m4 |
|
145 |
+ pxor m7, m7 |
|
146 |
+ |
|
147 |
+.loop: |
|
148 |
+ movq m0, [firstq] |
|
149 |
+ movq m2, [firstq] |
|
150 |
+ movq m1, [firstq+sizeq] |
|
151 |
+ add firstq, sizeq |
|
152 |
+ psubusb m2, m1 |
|
153 |
+ psubusb m1, m0 |
|
154 |
+ movq m0, m2 |
|
155 |
+ movq m3, m1 |
|
156 |
+ punpcklbw m0, m7 |
|
157 |
+ punpcklbw m1, m7 |
|
158 |
+ punpckhbw m2, m7 |
|
159 |
+ punpckhbw m3, m7 |
|
160 |
+ paddw m4, m0 |
|
161 |
+ paddw m4, m1 |
|
162 |
+ paddw m4, m2 |
|
163 |
+ paddw m4, m3 |
|
164 |
+ |
|
165 |
+ dec r3 |
|
166 |
+ jnz .loop |
|
167 |
+ |
|
168 |
+ movq m3, m4 |
|
169 |
+ punpcklwd m4, m7 |
|
170 |
+ punpckhwd m3, m7 |
|
171 |
+ paddd m3, m4 |
|
172 |
+ movd eax, m3 |
|
173 |
+ psrlq m3, 32 |
|
174 |
+ movd r4, m3 |
|
175 |
+ add eax, r4 |
|
176 |
+ shl eax, 2 |
|
177 |
+ RET |
0 | 178 |
new file mode 100644 |
... | ... |
@@ -0,0 +1,41 @@ |
0 |
+/* |
|
1 |
+ * This file is part of FFmpeg. |
|
2 |
+ * |
|
3 |
+ * FFmpeg is free software; you can redistribute it and/or |
|
4 |
+ * modify it under the terms of the GNU General Public |
|
5 |
+ * License as published by the Free Software Foundation; either |
|
6 |
+ * version 2 of the License, or (at your option) any later version. |
|
7 |
+ * |
|
8 |
+ * FFmpeg is distributed in the hope that it will be useful, |
|
9 |
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of |
|
10 |
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
|
11 |
+ * GNU General Public License for more details. |
|
12 |
+ * |
|
13 |
+ * You should have received a copy of the GNU General Public License along |
|
14 |
+ * with FFmpeg; if not, write to the Free Software |
|
15 |
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA |
|
16 |
+*/ |
|
17 |
+ |
|
18 |
+#include "libavutil/attributes.h" |
|
19 |
+#include "libavutil/cpu.h" |
|
20 |
+#include "libavutil/mem.h" |
|
21 |
+#include "libavutil/x86/asm.h" |
|
22 |
+#include "libavutil/x86/cpu.h" |
|
23 |
+#include "libavfilter/vf_pullup.h" |
|
24 |
+ |
|
25 |
+int ff_pullup_filter_diff_mmx(const uint8_t *a, const uint8_t *b, int s); |
|
26 |
+int ff_pullup_filter_comb_mmx(const uint8_t *a, const uint8_t *b, int s); |
|
27 |
+int ff_pullup_filter_var_mmx (const uint8_t *a, const uint8_t *b, int s); |
|
28 |
+ |
|
29 |
+av_cold void ff_pullup_init_x86(PullupContext *s) |
|
30 |
+{ |
|
31 |
+#if HAVE_YASM |
|
32 |
+ int cpu_flags = av_get_cpu_flags(); |
|
33 |
+ |
|
34 |
+ if (EXTERNAL_MMX(cpu_flags)) { |
|
35 |
+ s->diff = ff_pullup_filter_diff_mmx; |
|
36 |
+ s->comb = ff_pullup_filter_comb_mmx; |
|
37 |
+ s->var = ff_pullup_filter_var_mmx; |
|
38 |
+ } |
|
39 |
+#endif |
|
40 |
+} |