Browse code

lavfi: add bbox filter

Also add bbox.h and bbox.c files, based on the remove-logo filter by
Robert Edele. These files are useful for sharing code with the pending
removelogo port.

Stefano Sabatini authored on 2012/03/11 11:05:42
Showing 8 changed files
... ...
@@ -14,6 +14,7 @@ version next:
14 14
 - blackdetect filter
15 15
 - libutvideo encoder wrapper (--enable-libutvideo)
16 16
 - swapuv filter
17
+- bbox filter
17 18
 
18 19
 
19 20
 version 0.10:
... ...
@@ -761,6 +761,16 @@ video, use the command:
761 761
 ass=sub.ass
762 762
 @end example
763 763
 
764
+@section bbox
765
+
766
+Compute the bounding box for the non-black pixels in the input frame
767
+luminance plane.
768
+
769
+This filter computes the bounding box containing all the pixels with a
770
+luminance value greater than the minimum allowed value.
771
+The parameters describing the bounding box are printed on the filter
772
+log.
773
+
764 774
 @section blackdetect
765 775
 
766 776
 Detect video intervals that are (almost) completely black. Can be
... ...
@@ -48,6 +48,7 @@ OBJS-$(CONFIG_ABUFFERSINK_FILTER)            += sink_buffer.o
48 48
 OBJS-$(CONFIG_ANULLSINK_FILTER)              += asink_anullsink.o
49 49
 
50 50
 OBJS-$(CONFIG_ASS_FILTER)                    += vf_ass.o
51
+OBJS-$(CONFIG_BBOX_FILTER)                   += bbox.o vf_bbox.o
51 52
 OBJS-$(CONFIG_BLACKDETECT_FILTER)            += vf_blackdetect.o
52 53
 OBJS-$(CONFIG_BLACKFRAME_FILTER)             += vf_blackframe.o
53 54
 OBJS-$(CONFIG_BOXBLUR_FILTER)                += vf_boxblur.o
... ...
@@ -56,6 +56,7 @@ void avfilter_register_all(void)
56 56
     REGISTER_FILTER (ANULLSINK,   anullsink,   asink);
57 57
 
58 58
     REGISTER_FILTER (ASS,         ass,  vf);
59
+    REGISTER_FILTER (BBOX,        bbox,        vf);
59 60
     REGISTER_FILTER (BLACKDETECT, blackdetect, vf);
60 61
     REGISTER_FILTER (BLACKFRAME,  blackframe,  vf);
61 62
     REGISTER_FILTER (BOXBLUR,     boxblur,     vf);
62 63
new file mode 100644
... ...
@@ -0,0 +1,75 @@
0
+/*
1
+ * Copyright (c) 2005 Robert Edele <yartrebo@earthlink.net>
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 Lesser General Public
7
+ * License as published by the Free Software Foundation; either
8
+ * version 2.1 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 GNU
13
+ * Lesser General Public License for more details.
14
+ *
15
+ * You should have received a copy of the GNU Lesser General Public
16
+ * License along 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 "bbox.h"
21
+
22
+int ff_calculate_bounding_box(FFBoundingBox *bbox,
23
+                              const uint8_t *data, int linesize, int w, int h,
24
+                              int min_val)
25
+{
26
+    int x, y;
27
+    int start_x;
28
+    int start_y;
29
+    int end_x = w - 1;
30
+    int end_y = h - 1;
31
+    const uint8_t *line;
32
+
33
+    /* left bound */
34
+    for (start_x = 0; start_x < w; start_x++)
35
+        for (y = 0; y < h; y++)
36
+            if ((data[y * linesize + start_x] > min_val))
37
+                goto outl;
38
+outl:
39
+    if (start_x == w) /* no points found */
40
+        return 0;
41
+
42
+    /* right bound */
43
+    for (end_x = w - 1; end_x >= start_x; end_x--)
44
+        for (y = 0; y < h; y++)
45
+            if ((data[y * linesize + end_x] > min_val))
46
+                goto outr;
47
+outr:
48
+
49
+    /* top bound */
50
+    line = data;
51
+    for (start_y = 0; start_y < h; start_y++) {
52
+        for (x = 0; x < w; x++)
53
+            if (line[x] > min_val)
54
+                goto outt;
55
+        line += linesize;
56
+    }
57
+outt:
58
+
59
+    /* bottom bound */
60
+    line = data + (h-1)*linesize;
61
+    for (end_y = h - 1; end_y >= start_y; end_y--) {
62
+        for (x = 0; x < w; x++)
63
+            if (line[x] > min_val)
64
+                goto outb;
65
+        line -= linesize;
66
+    }
67
+outb:
68
+
69
+    bbox->x1 = start_x;
70
+    bbox->y1 = start_y;
71
+    bbox->x2 = end_x;
72
+    bbox->y2 = end_y;
73
+    return 1;
74
+}
0 75
new file mode 100644
... ...
@@ -0,0 +1,44 @@
0
+/*
1
+ * Copyright (c) 2005 Robert Edele <yartrebo@earthlink.net>
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 Lesser General Public
7
+ * License as published by the Free Software Foundation; either
8
+ * version 2.1 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 GNU
13
+ * Lesser General Public License for more details.
14
+ *
15
+ * You should have received a copy of the GNU Lesser General Public
16
+ * License along 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
+#ifndef AVFILTER_BBOX_H
21
+#define AVFILTER_BBOX_H
22
+
23
+#include <stdint.h>
24
+
25
+typedef struct {
26
+    int x1, x2, y1, y2;
27
+} FFBoundingBox;
28
+
29
+/**
30
+ * Calculate the smallest rectangle that will encompass the
31
+ * region with values > min_val.
32
+ *
33
+ * @param bbox bounding box structure which is updated with the found values.
34
+ *             If no pixels could be found with value > min_val, the
35
+ *             structure is not modified.
36
+ * @return 1 in case at least one pixel with value > min_val was found,
37
+ *         0 otherwise
38
+ */
39
+int ff_calculate_bounding_box(FFBoundingBox *bbox,
40
+                              const uint8_t *data, int linesize,
41
+                              int w, int h, int min_val);
42
+
43
+#endif /* AVFILTER_BBOX_H */
... ...
@@ -29,8 +29,8 @@
29 29
 #include "libavutil/avutil.h"
30 30
 
31 31
 #define LIBAVFILTER_VERSION_MAJOR  2
32
-#define LIBAVFILTER_VERSION_MINOR 64
33
-#define LIBAVFILTER_VERSION_MICRO 101
32
+#define LIBAVFILTER_VERSION_MINOR 65
33
+#define LIBAVFILTER_VERSION_MICRO 100
34 34
 
35 35
 #define LIBAVFILTER_VERSION_INT AV_VERSION_INT(LIBAVFILTER_VERSION_MAJOR, \
36 36
                                                LIBAVFILTER_VERSION_MINOR, \
37 37
new file mode 100644
... ...
@@ -0,0 +1,113 @@
0
+/*
1
+ * Copyright (c) 2012 Stefano Sabatini
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 Lesser General Public
7
+ * License as published by the Free Software Foundation; either
8
+ * version 2.1 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 GNU
13
+ * Lesser General Public License for more details.
14
+ *
15
+ * You should have received a copy of the GNU Lesser General Public
16
+ * License along 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
+/**
21
+ * @file
22
+ * bounding box detection filter
23
+ */
24
+
25
+#include "libavutil/pixdesc.h"
26
+#include "libavutil/timestamp.h"
27
+#include "avfilter.h"
28
+#include "bbox.h"
29
+
30
+typedef struct {
31
+    unsigned int frame;
32
+    int vsub, hsub;
33
+} BBoxContext;
34
+
35
+static av_cold int init(AVFilterContext *ctx, const char *args, void *opaque)
36
+{
37
+    BBoxContext *bbox = ctx->priv;
38
+    bbox->frame = 0;
39
+    return 0;
40
+}
41
+
42
+static int query_formats(AVFilterContext *ctx)
43
+{
44
+    static const enum PixelFormat pix_fmts[] = {
45
+        PIX_FMT_YUV420P,
46
+        PIX_FMT_YUV444P,
47
+        PIX_FMT_YUV440P,
48
+        PIX_FMT_YUV422P,
49
+        PIX_FMT_YUV411P,
50
+        PIX_FMT_NONE,
51
+    };
52
+
53
+    avfilter_set_common_pixel_formats(ctx, avfilter_make_format_list(pix_fmts));
54
+    return 0;
55
+}
56
+
57
+static void end_frame(AVFilterLink *inlink)
58
+{
59
+    AVFilterContext *ctx = inlink->dst;
60
+    BBoxContext *bbox = ctx->priv;
61
+    AVFilterBufferRef *picref = inlink->cur_buf;
62
+    FFBoundingBox box;
63
+    int has_bbox, w, h;
64
+
65
+    has_bbox =
66
+        ff_calculate_bounding_box(&box,
67
+                                  picref->data[0], picref->linesize[0],
68
+                                  inlink->w, inlink->h, 16);
69
+    w = box.x2 - box.x1 + 1;
70
+    h = box.y2 - box.y1 + 1;
71
+
72
+    av_log(ctx, AV_LOG_INFO,
73
+           "n:%d pts:%s pts_time:%s", bbox->frame,
74
+           av_ts2str(picref->pts), av_ts2timestr(picref->pts, &inlink->time_base));
75
+
76
+    if (has_bbox) {
77
+        av_log(ctx, AV_LOG_INFO,
78
+               "x1:%d x2:%d y1:%d y2:%d w:%d h:%d"
79
+               " crop=%d:%d:%d:%d drawbox=%d:%d:%d:%d",
80
+               box.x1, box.x2, box.y1, box.y2, w, h,
81
+               w, h, box.x1, box.y1,    /* crop params */
82
+               box.x1, box.y1, w, h);   /* drawbox params */
83
+    }
84
+    av_log(ctx, AV_LOG_INFO, "\n");
85
+
86
+    bbox->frame++;
87
+    avfilter_end_frame(inlink->dst->outputs[0]);
88
+}
89
+
90
+AVFilter avfilter_vf_bbox = {
91
+    .name          = "bbox",
92
+    .description   = NULL_IF_CONFIG_SMALL("Compute bounding box for each frame."),
93
+    .priv_size     = sizeof(BBoxContext),
94
+    .query_formats = query_formats,
95
+    .init          = init,
96
+
97
+    .inputs = (const AVFilterPad[]) {
98
+        { .name             = "default",
99
+          .type             = AVMEDIA_TYPE_VIDEO,
100
+          .get_video_buffer = avfilter_null_get_video_buffer,
101
+          .start_frame      = avfilter_null_start_frame,
102
+          .end_frame        = end_frame,
103
+          .min_perms        = AV_PERM_READ, },
104
+        { .name = NULL }
105
+    },
106
+
107
+    .outputs = (const AVFilterPad[]) {
108
+        { .name             = "default",
109
+          .type             = AVMEDIA_TYPE_VIDEO },
110
+        { .name = NULL }
111
+    },
112
+};