2 * Original copyright (c) 2002 Remi Guyomarch <rguyom@pobox.com>
3 * Port copyright (c) 2010 Daniel G. Taylor <dan@programmer-art.org>
4 * Relicensed to the LGPL with permission from Remi Guyomarch.
6 * This file is part of Libav.
8 * Libav is free software; you can redistribute it and/or
9 * modify it under the terms of the GNU Lesser General Public
10 * License as published by the Free Software Foundation; either
11 * version 2.1 of the License, or (at your option) any later version.
13 * Libav is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 * Lesser General Public License for more details.
18 * You should have received a copy of the GNU Lesser General Public
19 * License along with Libav; if not, write to the Free Software
20 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
25 * blur / sharpen filter, ported to Libav from MPlayer
26 * libmpcodecs/unsharp.c.
28 * This code is based on:
30 * An Efficient algorithm for Gaussian blur using finite-state machines
31 * Frederick M. Waltz and John W. V. Miller
33 * SPIE Conf. on Machine Vision Systems for Inspection and Metrology VII
34 * Originally published Boston, Nov 98
36 * http://www.engin.umd.umich.edu/~jwvm/ece581/21_GBlur.pdf
43 #include "libavutil/common.h"
44 #include "libavutil/mem.h"
45 #include "libavutil/pixdesc.h"
50 /* right-shift and round-up */
51 #define SHIFTUP(x,shift) (-((-(x))>>(shift)))
53 typedef struct FilterParam
{
54 int msize_x
; ///< matrix width
55 int msize_y
; ///< matrix height
56 int amount
; ///< effect amount
57 int steps_x
; ///< horizontal step count
58 int steps_y
; ///< vertical step count
59 int scalebits
; ///< bits to shift pixel
60 int32_t halfscale
; ///< amount to add to pixel
61 uint32_t *sc
[(MAX_SIZE
* MAX_SIZE
) - 1]; ///< finite state machine storage
65 FilterParam luma
; ///< luma parameters (width, height, amount)
66 FilterParam chroma
; ///< chroma parameters (width, height, amount)
70 static void apply_unsharp( uint8_t *dst
, int dst_stride
,
71 const uint8_t *src
, int src_stride
,
72 int width
, int height
, FilterParam
*fp
)
74 uint32_t **sc
= fp
->sc
;
75 uint32_t sr
[(MAX_SIZE
* MAX_SIZE
) - 1], tmp1
, tmp2
;
82 if (dst_stride
== src_stride
)
83 memcpy(dst
, src
, src_stride
* height
);
85 for (y
= 0; y
< height
; y
++, dst
+= dst_stride
, src
+= src_stride
)
86 memcpy(dst
, src
, width
);
90 for (y
= 0; y
< 2 * fp
->steps_y
; y
++)
91 memset(sc
[y
], 0, sizeof(sc
[y
][0]) * (width
+ 2 * fp
->steps_x
));
93 for (y
= -fp
->steps_y
; y
< height
+ fp
->steps_y
; y
++) {
97 memset(sr
, 0, sizeof(sr
[0]) * (2 * fp
->steps_x
- 1));
98 for (x
= -fp
->steps_x
; x
< width
+ fp
->steps_x
; x
++) {
99 tmp1
= x
<= 0 ? src2
[0] : x
>= width
? src2
[width
-1] : src2
[x
];
100 for (z
= 0; z
< fp
->steps_x
* 2; z
+= 2) {
101 tmp2
= sr
[z
+ 0] + tmp1
; sr
[z
+ 0] = tmp1
;
102 tmp1
= sr
[z
+ 1] + tmp2
; sr
[z
+ 1] = tmp2
;
104 for (z
= 0; z
< fp
->steps_y
* 2; z
+= 2) {
105 tmp2
= sc
[z
+ 0][x
+ fp
->steps_x
] + tmp1
; sc
[z
+ 0][x
+ fp
->steps_x
] = tmp1
;
106 tmp1
= sc
[z
+ 1][x
+ fp
->steps_x
] + tmp2
; sc
[z
+ 1][x
+ fp
->steps_x
] = tmp2
;
108 if (x
>= fp
->steps_x
&& y
>= fp
->steps_y
) {
109 const uint8_t *srx
= src
- fp
->steps_y
* src_stride
+ x
- fp
->steps_x
;
110 uint8_t *dsx
= dst
- fp
->steps_y
* dst_stride
+ x
- fp
->steps_x
;
112 res
= (int32_t)*srx
+ ((((int32_t) * srx
- (int32_t)((tmp1
+ fp
->halfscale
) >> fp
->scalebits
)) * fp
->amount
) >> 16);
113 *dsx
= av_clip_uint8(res
);
123 static void set_filter_param(FilterParam
*fp
, int msize_x
, int msize_y
, double amount
)
125 fp
->msize_x
= msize_x
;
126 fp
->msize_y
= msize_y
;
127 fp
->amount
= amount
* 65536.0;
129 fp
->steps_x
= msize_x
/ 2;
130 fp
->steps_y
= msize_y
/ 2;
131 fp
->scalebits
= (fp
->steps_x
+ fp
->steps_y
) * 2;
132 fp
->halfscale
= 1 << (fp
->scalebits
- 1);
135 static av_cold
int init(AVFilterContext
*ctx
, const char *args
)
137 UnsharpContext
*unsharp
= ctx
->priv
;
138 int lmsize_x
= 5, cmsize_x
= 5;
139 int lmsize_y
= 5, cmsize_y
= 5;
140 double lamount
= 1.0f
, camount
= 0.0f
;
143 sscanf(args
, "%d:%d:%lf:%d:%d:%lf", &lmsize_x
, &lmsize_y
, &lamount
,
144 &cmsize_x
, &cmsize_y
, &camount
);
146 if ((lamount
&& (lmsize_x
< 2 || lmsize_y
< 2)) ||
147 (camount
&& (cmsize_x
< 2 || cmsize_y
< 2))) {
148 av_log(ctx
, AV_LOG_ERROR
,
149 "Invalid value <2 for lmsize_x:%d or lmsize_y:%d or cmsize_x:%d or cmsize_y:%d\n",
150 lmsize_x
, lmsize_y
, cmsize_x
, cmsize_y
);
151 return AVERROR(EINVAL
);
154 set_filter_param(&unsharp
->luma
, lmsize_x
, lmsize_y
, lamount
);
155 set_filter_param(&unsharp
->chroma
, cmsize_x
, cmsize_y
, camount
);
160 static int query_formats(AVFilterContext
*ctx
)
162 enum AVPixelFormat pix_fmts
[] = {
163 AV_PIX_FMT_YUV420P
, AV_PIX_FMT_YUV422P
, AV_PIX_FMT_YUV444P
, AV_PIX_FMT_YUV410P
,
164 AV_PIX_FMT_YUV411P
, AV_PIX_FMT_YUV440P
, AV_PIX_FMT_YUVJ420P
, AV_PIX_FMT_YUVJ422P
,
165 AV_PIX_FMT_YUVJ444P
, AV_PIX_FMT_YUVJ440P
, AV_PIX_FMT_NONE
168 ff_set_common_formats(ctx
, ff_make_format_list(pix_fmts
));
173 static void init_filter_param(AVFilterContext
*ctx
, FilterParam
*fp
, const char *effect_type
, int width
)
178 effect
= fp
->amount
== 0 ? "none" : fp
->amount
< 0 ? "blur" : "sharpen";
180 av_log(ctx
, AV_LOG_VERBOSE
, "effect:%s type:%s msize_x:%d msize_y:%d amount:%0.2f\n",
181 effect
, effect_type
, fp
->msize_x
, fp
->msize_y
, fp
->amount
/ 65535.0);
183 for (z
= 0; z
< 2 * fp
->steps_y
; z
++)
184 fp
->sc
[z
] = av_malloc(sizeof(*(fp
->sc
[z
])) * (width
+ 2 * fp
->steps_x
));
187 static int config_props(AVFilterLink
*link
)
189 UnsharpContext
*unsharp
= link
->dst
->priv
;
190 const AVPixFmtDescriptor
*desc
= av_pix_fmt_desc_get(link
->format
);
192 unsharp
->hsub
= desc
->log2_chroma_w
;
193 unsharp
->vsub
= desc
->log2_chroma_h
;
195 init_filter_param(link
->dst
, &unsharp
->luma
, "luma", link
->w
);
196 init_filter_param(link
->dst
, &unsharp
->chroma
, "chroma", SHIFTUP(link
->w
, unsharp
->hsub
));
201 static void free_filter_param(FilterParam
*fp
)
205 for (z
= 0; z
< 2 * fp
->steps_y
; z
++)
209 static av_cold
void uninit(AVFilterContext
*ctx
)
211 UnsharpContext
*unsharp
= ctx
->priv
;
213 free_filter_param(&unsharp
->luma
);
214 free_filter_param(&unsharp
->chroma
);
217 static int filter_frame(AVFilterLink
*link
, AVFilterBufferRef
*in
)
219 UnsharpContext
*unsharp
= link
->dst
->priv
;
220 AVFilterLink
*outlink
= link
->dst
->outputs
[0];
221 AVFilterBufferRef
*out
;
222 int cw
= SHIFTUP(link
->w
, unsharp
->hsub
);
223 int ch
= SHIFTUP(link
->h
, unsharp
->vsub
);
225 out
= ff_get_video_buffer(outlink
, AV_PERM_WRITE
, outlink
->w
, outlink
->h
);
227 avfilter_unref_bufferp(&in
);
228 return AVERROR(ENOMEM
);
230 avfilter_copy_buffer_ref_props(out
, in
);
232 apply_unsharp(out
->data
[0], out
->linesize
[0], in
->data
[0], in
->linesize
[0], link
->w
, link
->h
, &unsharp
->luma
);
233 apply_unsharp(out
->data
[1], out
->linesize
[1], in
->data
[1], in
->linesize
[1], cw
, ch
, &unsharp
->chroma
);
234 apply_unsharp(out
->data
[2], out
->linesize
[2], in
->data
[2], in
->linesize
[2], cw
, ch
, &unsharp
->chroma
);
236 avfilter_unref_bufferp(&in
);
237 return ff_filter_frame(outlink
, out
);
240 static const AVFilterPad avfilter_vf_unsharp_inputs
[] = {
243 .type
= AVMEDIA_TYPE_VIDEO
,
244 .filter_frame
= filter_frame
,
245 .config_props
= config_props
,
246 .min_perms
= AV_PERM_READ
,
251 static const AVFilterPad avfilter_vf_unsharp_outputs
[] = {
254 .type
= AVMEDIA_TYPE_VIDEO
,
259 AVFilter avfilter_vf_unsharp
= {
261 .description
= NULL_IF_CONFIG_SMALL("Sharpen or blur the input video."),
263 .priv_size
= sizeof(UnsharpContext
),
267 .query_formats
= query_formats
,
269 .inputs
= avfilter_vf_unsharp_inputs
,
271 .outputs
= avfilter_vf_unsharp_outputs
,