summaryrefslogtreecommitdiffstats
path: root/libavfilter
diff options
context:
space:
mode:
authorClément Bœsch <u@pkh.me>2014-05-03 17:41:32 +0200
committerClément Bœsch <u@pkh.me>2014-05-03 19:07:14 +0200
commitb17e98ded0e2489427009acc7f8a8fffaa1ff075 (patch)
tree96b62b5bf177ad2ef5c599a5af813d89cee08e92 /libavfilter
parent3f3c3318be419bbc5b3b5fbf1bbcb8664f83f212 (diff)
downloadffmpeg-streaming-b17e98ded0e2489427009acc7f8a8fffaa1ff075.zip
ffmpeg-streaming-b17e98ded0e2489427009acc7f8a8fffaa1ff075.tar.gz
avfilter/edgedetect: add a colormix mode.
Diffstat (limited to 'libavfilter')
-rw-r--r--libavfilter/vf_edgedetect.c96
1 files changed, 79 insertions, 17 deletions
diff --git a/libavfilter/vf_edgedetect.c b/libavfilter/vf_edgedetect.c
index b312334..0e87f92 100644
--- a/libavfilter/vf_edgedetect.c
+++ b/libavfilter/vf_edgedetect.c
@@ -25,19 +25,32 @@
* @see https://en.wikipedia.org/wiki/Canny_edge_detector
*/
+#include "libavutil/avassert.h"
#include "libavutil/opt.h"
#include "avfilter.h"
#include "formats.h"
#include "internal.h"
#include "video.h"
-typedef struct {
- const AVClass *class;
+enum FilterMode {
+ MODE_WIRES,
+ MODE_COLORMIX,
+ NB_MODE
+};
+
+struct plane_info {
uint8_t *tmpbuf;
uint16_t *gradients;
char *directions;
+};
+
+typedef struct {
+ const AVClass *class;
+ struct plane_info planes[3];
+ int nb_planes;
double low, high;
uint8_t low_u8, high_u8;
+ enum FilterMode mode;
} EdgeDetectContext;
#define OFFSET(x) offsetof(EdgeDetectContext, x)
@@ -45,6 +58,9 @@ typedef struct {
static const AVOption edgedetect_options[] = {
{ "high", "set high threshold", OFFSET(high), AV_OPT_TYPE_DOUBLE, {.dbl=50/255.}, 0, 1, FLAGS },
{ "low", "set low threshold", OFFSET(low), AV_OPT_TYPE_DOUBLE, {.dbl=20/255.}, 0, 1, FLAGS },
+ { "mode", "set mode", OFFSET(mode), AV_OPT_TYPE_INT, {.i64=MODE_WIRES}, 0, NB_MODE-1, FLAGS, "mode" },
+ { "wires", "white/gray wires on black", 0, AV_OPT_TYPE_CONST, {.i64=MODE_WIRES}, INT_MIN, INT_MAX, FLAGS, "mode" },
+ { "colormix", "mix colors", 0, AV_OPT_TYPE_CONST, {.i64=MODE_COLORMIX}, INT_MIN, INT_MAX, FLAGS, "mode" },
{ NULL }
};
@@ -61,21 +77,37 @@ static av_cold int init(AVFilterContext *ctx)
static int query_formats(AVFilterContext *ctx)
{
+ const EdgeDetectContext *edgedetect = ctx->priv;
+
+ if (edgedetect->mode == MODE_WIRES) {
+ /* TODO: reindent */
static const enum AVPixelFormat pix_fmts[] = {AV_PIX_FMT_GRAY8, AV_PIX_FMT_NONE};
ff_set_common_formats(ctx, ff_make_format_list(pix_fmts));
+ } else if (edgedetect->mode == MODE_COLORMIX) {
+ static const enum AVPixelFormat pix_fmts[] = {AV_PIX_FMT_GBRP, AV_PIX_FMT_GRAY8, AV_PIX_FMT_NONE};
+ ff_set_common_formats(ctx, ff_make_format_list(pix_fmts));
+ } else {
+ av_assert0(0);
+ }
return 0;
}
static int config_props(AVFilterLink *inlink)
{
+ int p;
AVFilterContext *ctx = inlink->dst;
EdgeDetectContext *edgedetect = ctx->priv;
- edgedetect->tmpbuf = av_malloc(inlink->w * inlink->h);
- edgedetect->gradients = av_calloc(inlink->w * inlink->h, sizeof(*edgedetect->gradients));
- edgedetect->directions = av_malloc(inlink->w * inlink->h);
- if (!edgedetect->tmpbuf || !edgedetect->gradients || !edgedetect->directions)
- return AVERROR(ENOMEM);
+ edgedetect->nb_planes = inlink->format == AV_PIX_FMT_GRAY8 ? 1 : 3;
+ for (p = 0; p < edgedetect->nb_planes; p++) {
+ struct plane_info *plane = &edgedetect->planes[p];
+
+ plane->tmpbuf = av_malloc(inlink->w * inlink->h);
+ plane->gradients = av_calloc(inlink->w * inlink->h, sizeof(*plane->gradients));
+ plane->directions = av_malloc(inlink->w * inlink->h);
+ if (!plane->tmpbuf || !plane->gradients || !plane->directions)
+ return AVERROR(ENOMEM);
+ }
return 0;
}
@@ -241,18 +273,29 @@ static void double_threshold(int low, int high, int w, int h,
}
}
+static void color_mix(int w, int h,
+ uint8_t *dst, int dst_linesize,
+ const uint8_t *src, int src_linesize)
+{
+ int i, j;
+
+ for (j = 0; j < h; j++) {
+ for (i = 0; i < w; i++)
+ dst[i] = (dst[i] + src[i]) >> 1;
+ dst += dst_linesize;
+ src += src_linesize;
+ }
+}
+
static int filter_frame(AVFilterLink *inlink, AVFrame *in)
{
AVFilterContext *ctx = inlink->dst;
EdgeDetectContext *edgedetect = ctx->priv;
AVFilterLink *outlink = inlink->dst->outputs[0];
- uint8_t *tmpbuf = edgedetect->tmpbuf;
- uint16_t *gradients = edgedetect->gradients;
- int8_t *directions= edgedetect->directions;
- int direct = 0;
+ int p, direct = 0;
AVFrame *out;
- if (av_frame_is_writable(in)) {
+ if (edgedetect->mode != MODE_COLORMIX && av_frame_is_writable(in)) {
direct = 1;
out = in;
} else {
@@ -264,10 +307,17 @@ static int filter_frame(AVFilterLink *inlink, AVFrame *in)
av_frame_copy_props(out, in);
}
+ for (p = 0; p < edgedetect->nb_planes; p++) {
+ struct plane_info *plane = &edgedetect->planes[p];
+ uint8_t *tmpbuf = plane->tmpbuf;
+ uint16_t *gradients = plane->gradients;
+ int8_t *directions = plane->directions;
+
+ /* TODO: reindent */
/* gaussian filter to reduce noise */
gaussian_blur(ctx, inlink->w, inlink->h,
tmpbuf, inlink->w,
- in->data[0], in->linesize[0]);
+ in->data[p], in->linesize[p]);
/* compute the 16-bits gradients and directions for the next step */
sobel(inlink->w, inlink->h,
@@ -286,9 +336,16 @@ static int filter_frame(AVFilterLink *inlink, AVFrame *in)
/* keep high values, or low values surrounded by high values */
double_threshold(edgedetect->low_u8, edgedetect->high_u8,
inlink->w, inlink->h,
- out->data[0], out->linesize[0],
+ out->data[p], out->linesize[p],
tmpbuf, inlink->w);
+ if (edgedetect->mode == MODE_COLORMIX) {
+ color_mix(inlink->w, inlink->h,
+ out->data[p], out->linesize[p],
+ in->data[p], in->linesize[p]);
+ }
+ }
+
if (!direct)
av_frame_free(&in);
return ff_filter_frame(outlink, out);
@@ -296,10 +353,15 @@ static int filter_frame(AVFilterLink *inlink, AVFrame *in)
static av_cold void uninit(AVFilterContext *ctx)
{
+ int p;
EdgeDetectContext *edgedetect = ctx->priv;
- av_freep(&edgedetect->tmpbuf);
- av_freep(&edgedetect->gradients);
- av_freep(&edgedetect->directions);
+
+ for (p = 0; p < edgedetect->nb_planes; p++) {
+ struct plane_info *plane = &edgedetect->planes[p];
+ av_freep(&plane->tmpbuf);
+ av_freep(&plane->gradients);
+ av_freep(&plane->directions);
+ }
}
static const AVFilterPad edgedetect_inputs[] = {
OpenPOWER on IntegriCloud