Signed-off-by: Paul B Mahol <onemda@gmail.com>
Paul B Mahol authored on 2017/06/19 19:54:29... | ... |
@@ -12118,6 +12118,23 @@ trim=end=5,reverse |
12118 | 12118 |
@end example |
12119 | 12119 |
@end itemize |
12120 | 12120 |
|
12121 |
+@section roberts |
|
12122 |
+Apply roberts cross operator to input video stream. |
|
12123 |
+ |
|
12124 |
+The filter accepts the following option: |
|
12125 |
+ |
|
12126 |
+@table @option |
|
12127 |
+@item planes |
|
12128 |
+Set which planes will be processed, unprocessed planes will be copied. |
|
12129 |
+By default value 0xf, all planes will be processed. |
|
12130 |
+ |
|
12131 |
+@item scale |
|
12132 |
+Set value which will be multiplied with filtered result. |
|
12133 |
+ |
|
12134 |
+@item delta |
|
12135 |
+Set value which will be added to filtered result. |
|
12136 |
+@end table |
|
12137 |
+ |
|
12121 | 12138 |
@section rotate |
12122 | 12139 |
|
12123 | 12140 |
Rotate video by an arbitrary angle expressed in radians. |
... | ... |
@@ -268,6 +268,7 @@ OBJS-$(CONFIG_REMOVEGRAIN_FILTER) += vf_removegrain.o |
268 | 268 |
OBJS-$(CONFIG_REMOVELOGO_FILTER) += bbox.o lswsutils.o lavfutils.o vf_removelogo.o |
269 | 269 |
OBJS-$(CONFIG_REPEATFIELDS_FILTER) += vf_repeatfields.o |
270 | 270 |
OBJS-$(CONFIG_REVERSE_FILTER) += f_reverse.o |
271 |
+OBJS-$(CONFIG_ROBERTS_FILTER) += vf_convolution.o |
|
271 | 272 |
OBJS-$(CONFIG_ROTATE_FILTER) += vf_rotate.o |
272 | 273 |
OBJS-$(CONFIG_SAB_FILTER) += vf_sab.o |
273 | 274 |
OBJS-$(CONFIG_SCALE_FILTER) += vf_scale.o scale.o |
... | ... |
@@ -279,6 +279,7 @@ static void register_all(void) |
279 | 279 |
REGISTER_FILTER(REMOVELOGO, removelogo, vf); |
280 | 280 |
REGISTER_FILTER(REPEATFIELDS, repeatfields, vf); |
281 | 281 |
REGISTER_FILTER(REVERSE, reverse, vf); |
282 |
+ REGISTER_FILTER(ROBERTS, roberts, vf); |
|
282 | 283 |
REGISTER_FILTER(ROTATE, rotate, vf); |
283 | 284 |
REGISTER_FILTER(SAB, sab, vf); |
284 | 285 |
REGISTER_FILTER(SCALE, scale, vf); |
... | ... |
@@ -30,7 +30,7 @@ |
30 | 30 |
#include "libavutil/version.h" |
31 | 31 |
|
32 | 32 |
#define LIBAVFILTER_VERSION_MAJOR 6 |
33 |
-#define LIBAVFILTER_VERSION_MINOR 93 |
|
33 |
+#define LIBAVFILTER_VERSION_MINOR 94 |
|
34 | 34 |
#define LIBAVFILTER_VERSION_MICRO 100 |
35 | 35 |
|
36 | 36 |
#define LIBAVFILTER_VERSION_INT AV_VERSION_INT(LIBAVFILTER_VERSION_MAJOR, \ |
... | ... |
@@ -198,6 +198,55 @@ static int filter16_prewitt(AVFilterContext *ctx, void *arg, int jobnr, int nb_j |
198 | 198 |
return 0; |
199 | 199 |
} |
200 | 200 |
|
201 |
+static int filter16_roberts(AVFilterContext *ctx, void *arg, int jobnr, int nb_jobs) |
|
202 |
+{ |
|
203 |
+ ConvolutionContext *s = ctx->priv; |
|
204 |
+ ThreadData *td = arg; |
|
205 |
+ AVFrame *in = td->in; |
|
206 |
+ AVFrame *out = td->out; |
|
207 |
+ const int plane = td->plane; |
|
208 |
+ const int peak = (1 << s->depth) - 1; |
|
209 |
+ const int stride = in->linesize[plane] / 2; |
|
210 |
+ const int bstride = s->bstride; |
|
211 |
+ const int height = s->planeheight[plane]; |
|
212 |
+ const int width = s->planewidth[plane]; |
|
213 |
+ const int slice_start = (height * jobnr) / nb_jobs; |
|
214 |
+ const int slice_end = (height * (jobnr+1)) / nb_jobs; |
|
215 |
+ const uint16_t *src = (const uint16_t *)in->data[plane] + slice_start * stride; |
|
216 |
+ uint16_t *dst = (uint16_t *)out->data[plane] + slice_start * (out->linesize[plane] / 2); |
|
217 |
+ const float scale = s->scale; |
|
218 |
+ const float delta = s->delta; |
|
219 |
+ uint16_t *p0 = (uint16_t *)s->bptrs[jobnr] + 16; |
|
220 |
+ uint16_t *p1 = p0 + bstride; |
|
221 |
+ uint16_t *p2 = p1 + bstride; |
|
222 |
+ uint16_t *orig = p0, *end = p2; |
|
223 |
+ int y, x; |
|
224 |
+ |
|
225 |
+ line_copy16(p0, src + stride * (slice_start == 0 ? 1 : -1), width, 1); |
|
226 |
+ line_copy16(p1, src, width, 1); |
|
227 |
+ |
|
228 |
+ for (y = slice_start; y < slice_end; y++) { |
|
229 |
+ src += stride * (y < height - 1 ? 1 : -1); |
|
230 |
+ line_copy16(p2, src, width, 1); |
|
231 |
+ |
|
232 |
+ for (x = 0; x < width; x++) { |
|
233 |
+ int suma = p0[x - 1] * 1 + |
|
234 |
+ p1[x ] * -1; |
|
235 |
+ int sumb = p0[x ] * 1 + |
|
236 |
+ p1[x - 1] * -1; |
|
237 |
+ |
|
238 |
+ dst[x] = av_clip(sqrt(suma*suma + sumb*sumb) * scale + delta, 0, peak); |
|
239 |
+ } |
|
240 |
+ |
|
241 |
+ p0 = p1; |
|
242 |
+ p1 = p2; |
|
243 |
+ p2 = (p2 == end) ? orig: p2 + bstride; |
|
244 |
+ dst += out->linesize[plane] / 2; |
|
245 |
+ } |
|
246 |
+ |
|
247 |
+ return 0; |
|
248 |
+} |
|
249 |
+ |
|
201 | 250 |
static int filter16_sobel(AVFilterContext *ctx, void *arg, int jobnr, int nb_jobs) |
202 | 251 |
{ |
203 | 252 |
ConvolutionContext *s = ctx->priv; |
... | ... |
@@ -311,6 +360,54 @@ static int filter_prewitt(AVFilterContext *ctx, void *arg, int jobnr, int nb_job |
311 | 311 |
return 0; |
312 | 312 |
} |
313 | 313 |
|
314 |
+static int filter_roberts(AVFilterContext *ctx, void *arg, int jobnr, int nb_jobs) |
|
315 |
+{ |
|
316 |
+ ConvolutionContext *s = ctx->priv; |
|
317 |
+ ThreadData *td = arg; |
|
318 |
+ AVFrame *in = td->in; |
|
319 |
+ AVFrame *out = td->out; |
|
320 |
+ const int plane = td->plane; |
|
321 |
+ const int stride = in->linesize[plane]; |
|
322 |
+ const int bstride = s->bstride; |
|
323 |
+ const int height = s->planeheight[plane]; |
|
324 |
+ const int width = s->planewidth[plane]; |
|
325 |
+ const int slice_start = (height * jobnr) / nb_jobs; |
|
326 |
+ const int slice_end = (height * (jobnr+1)) / nb_jobs; |
|
327 |
+ const uint8_t *src = in->data[plane] + slice_start * stride; |
|
328 |
+ uint8_t *dst = out->data[plane] + slice_start * out->linesize[plane]; |
|
329 |
+ const float scale = s->scale; |
|
330 |
+ const float delta = s->delta; |
|
331 |
+ uint8_t *p0 = s->bptrs[jobnr] + 16; |
|
332 |
+ uint8_t *p1 = p0 + bstride; |
|
333 |
+ uint8_t *p2 = p1 + bstride; |
|
334 |
+ uint8_t *orig = p0, *end = p2; |
|
335 |
+ int y, x; |
|
336 |
+ |
|
337 |
+ line_copy8(p0, src + stride * (slice_start == 0 ? 1 : -1), width, 1); |
|
338 |
+ line_copy8(p1, src, width, 1); |
|
339 |
+ |
|
340 |
+ for (y = slice_start; y < slice_end; y++) { |
|
341 |
+ src += stride * (y < height - 1 ? 1 : -1); |
|
342 |
+ line_copy8(p2, src, width, 1); |
|
343 |
+ |
|
344 |
+ for (x = 0; x < width; x++) { |
|
345 |
+ int suma = p0[x - 1] * 1 + |
|
346 |
+ p1[x ] * -1; |
|
347 |
+ int sumb = p0[x ] * 1 + |
|
348 |
+ p1[x - 1] * -1; |
|
349 |
+ |
|
350 |
+ dst[x] = av_clip_uint8(sqrt(suma*suma + sumb*sumb) * scale + delta); |
|
351 |
+ } |
|
352 |
+ |
|
353 |
+ p0 = p1; |
|
354 |
+ p1 = p2; |
|
355 |
+ p2 = (p2 == end) ? orig: p2 + bstride; |
|
356 |
+ dst += out->linesize[plane]; |
|
357 |
+ } |
|
358 |
+ |
|
359 |
+ return 0; |
|
360 |
+} |
|
361 |
+ |
|
314 | 362 |
static int filter_sobel(AVFilterContext *ctx, void *arg, int jobnr, int nb_jobs) |
315 | 363 |
{ |
316 | 364 |
ConvolutionContext *s = ctx->priv; |
... | ... |
@@ -651,6 +748,10 @@ static int config_input(AVFilterLink *inlink) |
651 | 651 |
if (s->depth > 8) |
652 | 652 |
for (p = 0; p < s->nb_planes; p++) |
653 | 653 |
s->filter[p] = filter16_prewitt; |
654 |
+ } else if (!strcmp(ctx->filter->name, "roberts")) { |
|
655 |
+ if (s->depth > 8) |
|
656 |
+ for (p = 0; p < s->nb_planes; p++) |
|
657 |
+ s->filter[p] = filter16_roberts; |
|
654 | 658 |
} else if (!strcmp(ctx->filter->name, "sobel")) { |
655 | 659 |
if (s->depth > 8) |
656 | 660 |
for (p = 0; p < s->nb_planes; p++) |
... | ... |
@@ -739,6 +840,13 @@ static av_cold int init(AVFilterContext *ctx) |
739 | 739 |
else |
740 | 740 |
s->copy[i] = 1; |
741 | 741 |
} |
742 |
+ } else if (!strcmp(ctx->filter->name, "roberts")) { |
|
743 |
+ for (i = 0; i < 4; i++) { |
|
744 |
+ if ((1 << i) & s->planes) |
|
745 |
+ s->filter[i] = filter_roberts; |
|
746 |
+ else |
|
747 |
+ s->copy[i] = 1; |
|
748 |
+ } |
|
742 | 749 |
} else if (!strcmp(ctx->filter->name, "sobel")) { |
743 | 750 |
for (i = 0; i < 4; i++) { |
744 | 751 |
if ((1 << i) & s->planes) |
... | ... |
@@ -845,3 +953,29 @@ AVFilter ff_vf_sobel = { |
845 | 845 |
}; |
846 | 846 |
|
847 | 847 |
#endif /* CONFIG_SOBEL_FILTER */ |
848 |
+ |
|
849 |
+#if CONFIG_ROBERTS_FILTER |
|
850 |
+ |
|
851 |
+static const AVOption roberts_options[] = { |
|
852 |
+ { "planes", "set planes to filter", OFFSET(planes), AV_OPT_TYPE_INT, {.i64=15}, 0, 15, FLAGS}, |
|
853 |
+ { "scale", "set scale", OFFSET(scale), AV_OPT_TYPE_FLOAT, {.dbl=1.0}, 0.0, 65535, FLAGS}, |
|
854 |
+ { "delta", "set delta", OFFSET(delta), AV_OPT_TYPE_FLOAT, {.dbl=0}, -65535, 65535, FLAGS}, |
|
855 |
+ { NULL } |
|
856 |
+}; |
|
857 |
+ |
|
858 |
+AVFILTER_DEFINE_CLASS(roberts); |
|
859 |
+ |
|
860 |
+AVFilter ff_vf_roberts = { |
|
861 |
+ .name = "roberts", |
|
862 |
+ .description = NULL_IF_CONFIG_SMALL("Apply roberts cross operator."), |
|
863 |
+ .priv_size = sizeof(ConvolutionContext), |
|
864 |
+ .priv_class = &roberts_class, |
|
865 |
+ .init = init, |
|
866 |
+ .uninit = uninit, |
|
867 |
+ .query_formats = query_formats, |
|
868 |
+ .inputs = convolution_inputs, |
|
869 |
+ .outputs = convolution_outputs, |
|
870 |
+ .flags = AVFILTER_FLAG_SUPPORT_TIMELINE_GENERIC | AVFILTER_FLAG_SLICE_THREADS, |
|
871 |
+}; |
|
872 |
+ |
|
873 |
+#endif /* CONFIG_ROBERTS_FILTER */ |