Imported Debian version 2.4.3~trusty1
[deb_ffmpeg.git] / ffmpeg / libavfilter / vf_elbg.c
CommitLineData
2ba45a60
DM
1/*
2 * Copyright (c) 2013 Stefano Sabatini
3 *
4 * This file is part of FFmpeg.
5 *
6 * FFmpeg is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License as published by the Free Software Foundation; either
9 * version 2.1 of the License, or (at your option) any later version.
10 *
11 * FFmpeg is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Lesser General Public License for more details.
15 *
16 * You should have received a copy of the GNU Lesser General Public
17 * License along with FFmpeg; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
19 */
20
21/**
22 * @file
23 * video quantizer filter based on ELBG
24 */
25
26#include "libavcodec/elbg.h"
27#include "libavutil/opt.h"
28#include "libavutil/pixdesc.h"
29#include "libavutil/random_seed.h"
30
31#include "avfilter.h"
32#include "drawutils.h"
33#include "internal.h"
34#include "video.h"
35
36typedef struct ColorContext {
37 const AVClass *class;
38 AVLFG lfg;
39 unsigned int lfg_seed;
40 int max_steps_nb;
41 int *codeword;
42 int codeword_length;
43 int *codeword_closest_codebook_idxs;
44 int *codebook;
45 int codebook_length;
46 const AVPixFmtDescriptor *pix_desc;
47 uint8_t rgba_map[4];
48} ELBGContext;
49
50#define OFFSET(x) offsetof(ELBGContext, x)
51#define FLAGS AV_OPT_FLAG_VIDEO_PARAM|AV_OPT_FLAG_FILTERING_PARAM
52
53static const AVOption elbg_options[] = {
54 { "codebook_length", "set codebook length", OFFSET(codebook_length), AV_OPT_TYPE_INT, { .i64 = 256 }, 1, INT_MAX, FLAGS },
55 { "l", "set codebook length", OFFSET(codebook_length), AV_OPT_TYPE_INT, { .i64 = 256 }, 1, INT_MAX, FLAGS },
56 { "nb_steps", "set max number of steps used to compute the mapping", OFFSET(max_steps_nb), AV_OPT_TYPE_INT, { .i64 = 1 }, 1, INT_MAX, FLAGS },
57 { "n", "set max number of steps used to compute the mapping", OFFSET(max_steps_nb), AV_OPT_TYPE_INT, { .i64 = 1 }, 1, INT_MAX, FLAGS },
58 { "seed", "set the random seed", OFFSET(lfg_seed), AV_OPT_TYPE_INT, {.i64 = -1}, -1, UINT32_MAX, FLAGS },
59 { "s", "set the random seed", OFFSET(lfg_seed), AV_OPT_TYPE_INT, { .i64 = -1 }, -1, UINT32_MAX, FLAGS },
60 { NULL }
61};
62
63AVFILTER_DEFINE_CLASS(elbg);
64
65static av_cold int init(AVFilterContext *ctx)
66{
67 ELBGContext *elbg = ctx->priv;
68
69 if (elbg->lfg_seed == -1)
70 elbg->lfg_seed = av_get_random_seed();
71
72 av_lfg_init(&elbg->lfg, elbg->lfg_seed);
73 return 0;
74}
75
76static int query_formats(AVFilterContext *ctx)
77{
78 static const enum PixelFormat pix_fmts[] = {
79 AV_PIX_FMT_ARGB, AV_PIX_FMT_RGBA, AV_PIX_FMT_ABGR, AV_PIX_FMT_BGRA,
80 AV_PIX_FMT_RGB24, AV_PIX_FMT_BGR24,
81 AV_PIX_FMT_NONE
82 };
83
84 ff_set_common_formats(ctx, ff_make_format_list(pix_fmts));
85
86 return 0;
87}
88
89#define NB_COMPONENTS 3
90
91static int config_input(AVFilterLink *inlink)
92{
93 AVFilterContext *ctx = inlink->dst;
94 ELBGContext *elbg = ctx->priv;
95
96 elbg->pix_desc = av_pix_fmt_desc_get(inlink->format);
97 elbg->codeword_length = inlink->w * inlink->h;
98 elbg->codeword = av_realloc_f(elbg->codeword, elbg->codeword_length,
99 NB_COMPONENTS * sizeof(*elbg->codeword));
100 if (!elbg->codeword)
101 return AVERROR(ENOMEM);
102
103 elbg->codeword_closest_codebook_idxs =
104 av_realloc_f(elbg->codeword_closest_codebook_idxs, elbg->codeword_length,
105 sizeof(*elbg->codeword_closest_codebook_idxs));
106 if (!elbg->codeword_closest_codebook_idxs)
107 return AVERROR(ENOMEM);
108
109 elbg->codebook = av_realloc_f(elbg->codebook, elbg->codebook_length,
110 NB_COMPONENTS * sizeof(*elbg->codebook));
111 if (!elbg->codebook)
112 return AVERROR(ENOMEM);
113
114 ff_fill_rgba_map(elbg->rgba_map, inlink->format);
115
116 return 0;
117}
118
119#define R 0
120#define G 1
121#define B 2
122
123static int filter_frame(AVFilterLink *inlink, AVFrame *frame)
124{
125 ELBGContext *elbg = inlink->dst->priv;
126 int i, j, k;
127 uint8_t *p, *p0;
128
129 const uint8_t r_idx = elbg->rgba_map[R];
130 const uint8_t g_idx = elbg->rgba_map[G];
131 const uint8_t b_idx = elbg->rgba_map[B];
132
133 /* build the codeword */
134 p0 = frame->data[0];
135 k = 0;
136 for (i = 0; i < inlink->h; i++) {
137 p = p0;
138 for (j = 0; j < inlink->w; j++) {
139 elbg->codeword[k++] = p[r_idx];
140 elbg->codeword[k++] = p[g_idx];
141 elbg->codeword[k++] = p[b_idx];
142 p += elbg->pix_desc->nb_components;
143 }
144 p0 += frame->linesize[0];
145 }
146
147 /* compute the codebook */
148 avpriv_init_elbg(elbg->codeword, NB_COMPONENTS, elbg->codeword_length,
149 elbg->codebook, elbg->codebook_length, elbg->max_steps_nb,
150 elbg->codeword_closest_codebook_idxs, &elbg->lfg);
151 avpriv_do_elbg(elbg->codeword, NB_COMPONENTS, elbg->codeword_length,
152 elbg->codebook, elbg->codebook_length, elbg->max_steps_nb,
153 elbg->codeword_closest_codebook_idxs, &elbg->lfg);
154
155 /* fill the output with the codebook values */
156 p0 = frame->data[0];
157
158 k = 0;
159 for (i = 0; i < inlink->h; i++) {
160 p = p0;
161 for (j = 0; j < inlink->w; j++) {
162 int cb_idx = NB_COMPONENTS * elbg->codeword_closest_codebook_idxs[k++];
163 p[r_idx] = elbg->codebook[cb_idx];
164 p[g_idx] = elbg->codebook[cb_idx+1];
165 p[b_idx] = elbg->codebook[cb_idx+2];
166 p += elbg->pix_desc->nb_components;
167 }
168 p0 += frame->linesize[0];
169 }
170
171 return ff_filter_frame(inlink->dst->outputs[0], frame);
172}
173
174static av_cold void uninit(AVFilterContext *ctx)
175{
176 ELBGContext *elbg = ctx->priv;
177
178 av_freep(&elbg->codebook);
179 av_freep(&elbg->codeword);
180 av_freep(&elbg->codeword_closest_codebook_idxs);
181}
182
183static const AVFilterPad elbg_inputs[] = {
184 {
185 .name = "default",
186 .type = AVMEDIA_TYPE_VIDEO,
187 .config_props = config_input,
188 .filter_frame = filter_frame,
189 .needs_writable = 1,
190 },
191 { NULL }
192};
193
194static const AVFilterPad elbg_outputs[] = {
195 {
196 .name = "default",
197 .type = AVMEDIA_TYPE_VIDEO,
198 },
199 { NULL }
200};
201
202AVFilter ff_vf_elbg = {
203 .name = "elbg",
204 .description = NULL_IF_CONFIG_SMALL("Apply posterize effect, using the ELBG algorithm."),
205 .priv_size = sizeof(ELBGContext),
206 .priv_class = &elbg_class,
207 .query_formats = query_formats,
208 .init = init,
209 .uninit = uninit,
210 .inputs = elbg_inputs,
211 .outputs = elbg_outputs,
212};