]> git.sesse.net Git - ffmpeg/blob - libavfilter/vf_elbg.c
avformat: don't crash API users when demuxing mp4
[ffmpeg] / libavfilter / vf_elbg.c
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
36 typedef 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
53 static 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
63 AVFILTER_DEFINE_CLASS(elbg);
64
65 static 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
76 static int query_formats(AVFilterContext *ctx)
77 {
78     static const enum AVPixelFormat 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     AVFilterFormats *fmts_list = ff_make_format_list(pix_fmts);
84     if (!fmts_list)
85         return AVERROR(ENOMEM);
86     return ff_set_common_formats(ctx, fmts_list);
87 }
88
89 #define NB_COMPONENTS 3
90
91 static 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
123 static 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
174 static 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
183 static 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
194 static const AVFilterPad elbg_outputs[] = {
195     {
196         .name = "default",
197         .type = AVMEDIA_TYPE_VIDEO,
198     },
199     { NULL }
200 };
201
202 AVFilter 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 };