]> git.sesse.net Git - ffmpeg/blob - libavfilter/vf_idet.c
vf_idet: remove unused function
[ffmpeg] / libavfilter / vf_idet.c
1 /*
2  * Copyright (C) 2012 Michael Niedermayer <michaelni@gmx.at>
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 #include "libavutil/cpu.h"
22 #include "libavutil/common.h"
23 #include "libavutil/pixdesc.h"
24 #include "avfilter.h"
25
26 #undef NDEBUG
27 #include <assert.h>
28
29 typedef struct {
30     float interlace_threshold;
31     float progressive_threshold;
32
33     AVFilterBufferRef *cur;
34     AVFilterBufferRef *next;
35     AVFilterBufferRef *prev;
36     AVFilterBufferRef *out;
37     int (*filter_line)(uint8_t *prev, uint8_t *cur, uint8_t *next, int w);
38
39     const AVPixFmtDescriptor *csp;
40 } IDETContext;
41
42
43 static int filter_line_c(const uint8_t *a, const uint8_t *b, const uint8_t *c, int w)
44 {
45     int x;
46     int ret=0;
47
48     for(x=0; x<w; x++){
49         ret += FFABS((*a++ + *c++) - 2 * *b++);
50     }
51
52     return ret;
53 }
54
55 static int filter_line_c_16bit(const uint16_t *a, const uint16_t *b, const uint16_t *c, int w)
56 {
57     int x;
58     int ret=0;
59
60     for(x=0; x<w; x++){
61         ret += FFABS((*a++ + *c++) - 2 * *b++);
62     }
63
64     return ret;
65 }
66
67 static void filter(AVFilterContext *ctx)
68 {
69     IDETContext *idet = ctx->priv;
70     int y, i;
71     int64_t alpha[2]={0};
72     int64_t delta=0;
73     static int p=0, t=0, b=0, u=0;
74
75     for (i = 0; i < idet->csp->nb_components; i++) {
76         int w = idet->cur->video->w;
77         int h = idet->cur->video->h;
78         int refs = idet->cur->linesize[i];
79         int df = (idet->csp->comp[i].depth_minus1 + 8) / 8;
80
81         if (i && i<3) {
82             w >>= idet->csp->log2_chroma_w;
83             h >>= idet->csp->log2_chroma_h;
84         }
85
86         for (y = 2; y < h - 2; y++) {
87             uint8_t *prev = &idet->prev->data[i][y*refs];
88             uint8_t *cur  = &idet->cur ->data[i][y*refs];
89             uint8_t *next = &idet->next->data[i][y*refs];
90             alpha[ y   &1] += idet->filter_line(cur-refs, prev, cur+refs, w);
91             alpha[(y^1)&1] += idet->filter_line(cur-refs, next, cur+refs, w);
92             delta          += idet->filter_line(cur-refs,  cur, cur+refs, w);
93         }
94     }
95 #if HAVE_MMX
96     __asm__ volatile("emms \n\t" : : : "memory");
97 #endif
98
99     if      (alpha[0] / (float)alpha[1] > idet->interlace_threshold){
100         av_log(ctx, AV_LOG_INFO, "Interlaced, top field first\n");
101         t++;
102     }else if(alpha[1] / (float)alpha[0] > idet->interlace_threshold){
103         av_log(ctx, AV_LOG_INFO, "Interlaced, bottom field first\n");
104         b++;
105     }else if(alpha[1] / (float)delta    > idet->progressive_threshold){
106         av_log(ctx, AV_LOG_INFO, "Progressive\n");
107         p++;
108     }else{
109         av_log(ctx, AV_LOG_INFO, "Undetermined\n");
110         u++;
111     }
112 //     av_log(ctx,0, "t%d b%d p%d u%d\n", t,b,p,u);
113 }
114
115 static void start_frame(AVFilterLink *link, AVFilterBufferRef *picref)
116 {
117     AVFilterContext *ctx = link->dst;
118     IDETContext *idet = ctx->priv;
119
120     if (idet->prev)
121         avfilter_unref_buffer(idet->prev);
122     idet->prev = idet->cur;
123     idet->cur  = idet->next;
124     idet->next = picref;
125
126     if (!idet->cur)
127         return;
128
129     if (!idet->prev)
130         idet->prev = avfilter_ref_buffer(idet->cur, AV_PERM_READ);
131
132     avfilter_start_frame(ctx->outputs[0], avfilter_ref_buffer(idet->cur, AV_PERM_READ));
133 }
134
135 static void end_frame(AVFilterLink *link)
136 {
137     AVFilterContext *ctx = link->dst;
138     IDETContext *idet = ctx->priv;
139
140     if (!idet->cur)
141         return;
142
143     if (!idet->csp)
144         idet->csp = &av_pix_fmt_descriptors[link->format];
145     if (idet->csp->comp[0].depth_minus1 / 8 == 1)
146         idet->filter_line = (void*)filter_line_c_16bit;
147
148     filter(ctx);
149
150     avfilter_draw_slice(ctx->outputs[0], 0, link->h, 1);
151     avfilter_end_frame(ctx->outputs[0]);
152 }
153
154 static int request_frame(AVFilterLink *link)
155 {
156     AVFilterContext *ctx = link->src;
157     IDETContext *idet = ctx->priv;
158
159     do {
160         int ret;
161
162         if ((ret = avfilter_request_frame(link->src->inputs[0])))
163             return ret;
164     } while (!idet->cur);
165
166     return 0;
167 }
168
169 static int poll_frame(AVFilterLink *link)
170 {
171     IDETContext *idet = link->src->priv;
172     int ret, val;
173
174     val = avfilter_poll_frame(link->src->inputs[0]);
175
176     if (val >= 1 && !idet->next) { //FIXME change API to not requre this red tape
177         if ((ret = avfilter_request_frame(link->src->inputs[0])) < 0)
178             return ret;
179         val = avfilter_poll_frame(link->src->inputs[0]);
180     }
181     assert(idet->next || !val);
182
183     return val;
184 }
185
186 static av_cold void uninit(AVFilterContext *ctx)
187 {
188     IDETContext *idet = ctx->priv;
189
190     if (idet->prev) avfilter_unref_buffer(idet->prev);
191     if (idet->cur ) avfilter_unref_buffer(idet->cur );
192     if (idet->next) avfilter_unref_buffer(idet->next);
193 }
194
195 static int query_formats(AVFilterContext *ctx)
196 {
197     static const enum PixelFormat pix_fmts[] = {
198         PIX_FMT_YUV420P,
199         PIX_FMT_YUV422P,
200         PIX_FMT_YUV444P,
201         PIX_FMT_YUV410P,
202         PIX_FMT_YUV411P,
203         PIX_FMT_GRAY8,
204         PIX_FMT_YUVJ420P,
205         PIX_FMT_YUVJ422P,
206         PIX_FMT_YUVJ444P,
207         AV_NE( PIX_FMT_GRAY16BE, PIX_FMT_GRAY16LE ),
208         PIX_FMT_YUV440P,
209         PIX_FMT_YUVJ440P,
210         AV_NE( PIX_FMT_YUV420P10BE, PIX_FMT_YUV420P10LE ),
211         AV_NE( PIX_FMT_YUV422P10BE, PIX_FMT_YUV422P10LE ),
212         AV_NE( PIX_FMT_YUV444P10BE, PIX_FMT_YUV444P10LE ),
213         AV_NE( PIX_FMT_YUV420P16BE, PIX_FMT_YUV420P16LE ),
214         AV_NE( PIX_FMT_YUV422P16BE, PIX_FMT_YUV422P16LE ),
215         AV_NE( PIX_FMT_YUV444P16BE, PIX_FMT_YUV444P16LE ),
216         PIX_FMT_YUVA420P,
217         PIX_FMT_NONE
218     };
219
220     avfilter_set_common_pixel_formats(ctx, avfilter_make_format_list(pix_fmts));
221
222     return 0;
223 }
224
225 static av_cold int init(AVFilterContext *ctx, const char *args, void *opaque)
226 {
227     IDETContext *idet = ctx->priv;
228     int cpu_flags = av_get_cpu_flags();
229
230     idet->csp = NULL;
231
232     idet->interlace_threshold   = 1.01;
233     idet->progressive_threshold = 2.5;
234
235     if (args) sscanf(args, "%f:%f", &idet->interlace_threshold, &idet->progressive_threshold);
236
237     idet->filter_line = filter_line_c;
238
239     return 0;
240 }
241
242 static void null_draw_slice(AVFilterLink *link, int y, int h, int slice_dir) { }
243
244 AVFilter avfilter_vf_idet = {
245     .name          = "idet",
246     .description   = NULL_IF_CONFIG_SMALL("Interlace detect Filter."),
247
248     .priv_size     = sizeof(IDETContext),
249     .init          = init,
250     .uninit        = uninit,
251     .query_formats = query_formats,
252
253     .inputs    = (const AVFilterPad[]) {{ .name       = "default",
254                                     .type             = AVMEDIA_TYPE_VIDEO,
255                                     .start_frame      = start_frame,
256                                     .draw_slice       = null_draw_slice,
257                                     .end_frame        = end_frame,
258                                     .rej_perms        = AV_PERM_REUSE2, },
259                                   { .name = NULL}},
260
261     .outputs   = (const AVFilterPad[]) {{ .name       = "default",
262                                     .type             = AVMEDIA_TYPE_VIDEO,
263                                     .poll_frame       = poll_frame,
264                                     .request_frame    = request_frame, },
265                                   { .name = NULL}},
266 };