Subversion Repositories Kolibri OS

Rev

Go to most recent revision | Details | Last modification | View Log | RSS feed

Rev Author Line No. Line
4349 Serge 1
/*
2
 * Copyright (c) 2004 Ville Saari
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 General Public
8
 * License as published by the Free Software Foundation; either
9
 * version 2 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
14
 * GNU General Public License for more details.
15
 *
16
 * You should have received a copy of the GNU General Public License along
17
 * 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/avassert.h"
22
#include "libavutil/imgutils.h"
23
#include "libavutil/pixdesc.h"
24
#include "libavutil/opt.h"
25
#include "avfilter.h"
26
#include "formats.h"
27
#include "internal.h"
28
#include "video.h"
29
 
30
enum PhaseMode {
31
    PROGRESSIVE,
32
    TOP_FIRST,
33
    BOTTOM_FIRST,
34
    TOP_FIRST_ANALYZE,
35
    BOTTOM_FIRST_ANALYZE,
36
    ANALYZE,
37
    FULL_ANALYZE,
38
    AUTO,
39
    AUTO_ANALYZE
40
};
41
 
42
typedef struct PhaseContext {
43
    const AVClass *class;
44
    enum PhaseMode mode;
45
    AVFrame *frame;
46
    int nb_planes;
47
    int planeheight[4];
48
    int linesize[4];
49
} PhaseContext;
50
 
51
#define OFFSET(x) offsetof(PhaseContext, x)
52
#define FLAGS AV_OPT_FLAG_FILTERING_PARAM|AV_OPT_FLAG_VIDEO_PARAM
53
#define CONST(name, help, val, unit) { name, help, 0, AV_OPT_TYPE_CONST, {.i64=val}, 0, 0, FLAGS, unit }
54
 
55
static const AVOption phase_options[] = {
56
    { "mode", "set phase mode", OFFSET(mode), AV_OPT_TYPE_INT, {.i64=AUTO_ANALYZE}, PROGRESSIVE, AUTO_ANALYZE, FLAGS, "mode" },
57
    CONST("p", "progressive",          PROGRESSIVE,          "mode"),
58
    CONST("t", "top first",            TOP_FIRST,            "mode"),
59
    CONST("b", "bottom first",         BOTTOM_FIRST,         "mode"),
60
    CONST("T", "top first analyze",    TOP_FIRST_ANALYZE,    "mode"),
61
    CONST("B", "bottom first analyze", BOTTOM_FIRST_ANALYZE, "mode"),
62
    CONST("u", "analyze",              ANALYZE,              "mode"),
63
    CONST("U", "full analyze",         FULL_ANALYZE,         "mode"),
64
    CONST("a", "auto",                 AUTO,                 "mode"),
65
    CONST("A", "auto analyze",         AUTO_ANALYZE,         "mode"),
66
    { NULL }
67
};
68
 
69
AVFILTER_DEFINE_CLASS(phase);
70
 
71
static int query_formats(AVFilterContext *ctx)
72
{
73
    static const enum AVPixelFormat pix_fmts[] = {
74
        AV_PIX_FMT_YUVA444P, AV_PIX_FMT_YUVA422P, AV_PIX_FMT_YUVA420P,
75
        AV_PIX_FMT_YUVJ444P, AV_PIX_FMT_YUVJ440P, AV_PIX_FMT_YUVJ422P,AV_PIX_FMT_YUVJ420P, AV_PIX_FMT_YUVJ411P,
76
        AV_PIX_FMT_YUV444P, AV_PIX_FMT_YUV440P, AV_PIX_FMT_YUV422P, AV_PIX_FMT_YUV420P, AV_PIX_FMT_YUV411P, AV_PIX_FMT_YUV410P,
77
        AV_PIX_FMT_GBRP, AV_PIX_FMT_GBRAP, AV_PIX_FMT_GRAY8, AV_PIX_FMT_NONE
78
    };
79
 
80
    ff_set_common_formats(ctx, ff_make_format_list(pix_fmts));
81
    return 0;
82
}
83
 
84
static int config_input(AVFilterLink *inlink)
85
{
86
    PhaseContext *s = inlink->dst->priv;
87
    const AVPixFmtDescriptor *desc = av_pix_fmt_desc_get(inlink->format);
88
    int ret;
89
 
90
    if ((ret = av_image_fill_linesizes(s->linesize, inlink->format, inlink->w)) < 0)
91
        return ret;
92
 
93
    s->planeheight[1] = s->planeheight[2] = FF_CEIL_RSHIFT(inlink->h, desc->log2_chroma_h);
94
    s->planeheight[0] = s->planeheight[3] = inlink->h;
95
 
96
    s->nb_planes = av_pix_fmt_count_planes(inlink->format);
97
 
98
    return 0;
99
}
100
 
101
/*
102
 * This macro interpolates the value of both fields at a point halfway
103
 * between lines and takes the squared difference. In field resolution
104
 * the point is a quarter pixel below a line in one field and a quarter
105
 * pixel above a line in other.
106
 *
107
 * (The result is actually multiplied by 25)
108
 */
109
#define DIFF(a, as, b, bs) (t = ((*a - b[bs]) << 2) + a[as << 1] - b[-bs], t * t)
110
 
111
/*
112
 * Find which field combination has the smallest average squared difference
113
 * between the fields.
114
 */
115
static enum PhaseMode analyze_plane(AVFilterContext *ctx, PhaseContext *s,
116
                                    AVFrame *old, AVFrame *new)
117
{
118
    double bdiff, tdiff, pdiff, scale;
119
    const int ns = new->linesize[0];
120
    const int os = old->linesize[0];
121
    uint8_t *nptr = new->data[0];
122
    uint8_t *optr = old->data[0];
123
    const int h = new->height;
124
    const int w = new->width;
125
    int bdif, tdif, pdif;
126
    enum PhaseMode mode = s->mode;
127
    uint8_t *end, *rend;
128
    int top, t;
129
 
130
    if (mode == AUTO) {
131
        mode = new->interlaced_frame ? new->top_field_first ?
132
               TOP_FIRST : BOTTOM_FIRST : PROGRESSIVE;
133
    } else if (mode == AUTO_ANALYZE) {
134
        mode = new->interlaced_frame ? new->top_field_first ?
135
               TOP_FIRST_ANALYZE : BOTTOM_FIRST_ANALYZE : FULL_ANALYZE;
136
    }
137
 
138
    if (mode <= BOTTOM_FIRST) {
139
        bdiff = pdiff = tdiff = 65536.0;
140
    } else {
141
        bdiff = pdiff = tdiff = 0.0;
142
 
143
        for (end = nptr + (h - 2) * ns, nptr += ns, optr += os, top = 0;
144
             nptr < end; nptr += ns - w, optr += os - w, top ^= 1) {
145
            pdif = tdif = bdif = 0;
146
 
147
            switch (mode) {
148
            case TOP_FIRST_ANALYZE:
149
                if (top) {
150
                    for (rend = nptr + w; nptr < rend; nptr++, optr++) {
151
                        pdif += DIFF(nptr, ns, nptr, ns);
152
                        tdif += DIFF(nptr, ns, optr, os);
153
                    }
154
                } else {
155
                    for (rend = nptr + w; nptr < rend; nptr++, optr++) {
156
                        pdif += DIFF(nptr, ns, nptr, ns);
157
                        tdif += DIFF(optr, os, nptr, ns);
158
                    }
159
                }
160
                break;
161
            case BOTTOM_FIRST_ANALYZE:
162
                if (top) {
163
                    for (rend = nptr + w; nptr < rend; nptr++, optr++) {
164
                        pdif += DIFF(nptr, ns, nptr, ns);
165
                        bdif += DIFF(optr, os, nptr, ns);
166
                    }
167
                } else {
168
                    for (rend = nptr + w; nptr < rend; nptr++, optr++) {
169
                        pdif += DIFF(nptr, ns, nptr, ns);
170
                        bdif += DIFF(nptr, ns, optr, os);
171
                    }
172
                }
173
                break;
174
            case ANALYZE:
175
                if (top) {
176
                    for (rend = nptr + w; nptr < rend; nptr++, optr++) {
177
                        tdif += DIFF(nptr, ns, optr, os);
178
                        bdif += DIFF(optr, os, nptr, ns);
179
                    }
180
                } else {
181
                    for (rend = nptr + w; nptr < rend; nptr++, optr++) {
182
                        bdif += DIFF(nptr, ns, optr, os);
183
                        tdif += DIFF(optr, os, nptr, ns);
184
                    }
185
                }
186
                break;
187
            case FULL_ANALYZE:
188
                if (top) {
189
                    for (rend = nptr + w; nptr < rend; nptr++, optr++) {
190
                        pdif += DIFF(nptr, ns, nptr, ns);
191
                        tdif += DIFF(nptr, ns, optr, os);
192
                        bdif += DIFF(optr, os, nptr, ns);
193
                    }
194
                } else {
195
                    for (rend = nptr + w; nptr < rend; nptr++, optr++) {
196
                        pdif += DIFF(nptr, ns, nptr, ns);
197
                        bdif += DIFF(nptr, ns, optr, os);
198
                        tdif += DIFF(optr, os, nptr, ns);
199
                    }
200
                }
201
                break;
202
            default:
203
                av_assert0(0);
204
            }
205
 
206
            pdiff += (double)pdif;
207
            tdiff += (double)tdif;
208
            bdiff += (double)bdif;
209
        }
210
 
211
        scale = 1.0 / (w * (h - 3)) / 25.0;
212
        pdiff *= scale;
213
        tdiff *= scale;
214
        bdiff *= scale;
215
 
216
        if (mode == TOP_FIRST_ANALYZE) {
217
            bdiff = 65536.0;
218
        } else if (mode == BOTTOM_FIRST_ANALYZE) {
219
            tdiff = 65536.0;
220
        } else if (mode == ANALYZE) {
221
            pdiff = 65536.0;
222
        }
223
 
224
        if (bdiff < pdiff && bdiff < tdiff) {
225
            mode = BOTTOM_FIRST;
226
        } else if (tdiff < pdiff && tdiff < bdiff) {
227
            mode = TOP_FIRST;
228
        } else {
229
            mode = PROGRESSIVE;
230
        }
231
    }
232
 
233
    av_log(ctx, AV_LOG_DEBUG, "mode=%c tdiff=%f bdiff=%f pdiff=%f\n",
234
           mode == BOTTOM_FIRST ? 'b' : mode == TOP_FIRST ? 't' : 'p',
235
           tdiff, bdiff, pdiff);
236
    return mode;
237
}
238
 
239
static int filter_frame(AVFilterLink *inlink, AVFrame *in)
240
{
241
    AVFilterContext *ctx = inlink->dst;
242
    AVFilterLink *outlink = ctx->outputs[0];
243
    PhaseContext *s = ctx->priv;
244
    enum PhaseMode mode;
245
    int plane, top, y;
246
    AVFrame *out;
247
 
248
    out = ff_get_video_buffer(outlink, outlink->w, outlink->h);
249
    if (!out) {
250
        av_frame_free(&in);
251
        return AVERROR(ENOMEM);
252
    }
253
    av_frame_copy_props(out, in);
254
 
255
    if (!s->frame) {
256
        mode = PROGRESSIVE;
257
        s->frame = ff_get_video_buffer(outlink, outlink->w, outlink->h);
258
        if (!s->frame) {
259
            av_frame_free(&in);
260
            av_frame_free(&out);
261
            return AVERROR(ENOMEM);
262
        }
263
    } else {
264
        mode = analyze_plane(ctx, s, s->frame, in);
265
    }
266
 
267
    for (plane = 0; plane < s->nb_planes; plane++) {
268
        uint8_t *buf = s->frame->data[plane];
269
        uint8_t *from = in->data[plane];
270
        uint8_t *to = out->data[plane];
271
 
272
        for (y = 0, top = 1; y < s->planeheight[plane]; y++, top ^= 1) {
273
            memcpy(to, mode == (top ? BOTTOM_FIRST : TOP_FIRST) ? buf : from, s->linesize[plane]);
274
            memcpy(buf, from, s->linesize[plane]);
275
 
276
            buf += s->frame->linesize[plane];
277
            from += in->linesize[plane];
278
            to += out->linesize[plane];
279
        }
280
    }
281
 
282
    av_frame_free(&in);
283
    return ff_filter_frame(outlink, out);
284
}
285
 
286
static av_cold void uninit(AVFilterContext *ctx)
287
{
288
    PhaseContext *s = ctx->priv;
289
 
290
    av_frame_free(&s->frame);
291
}
292
 
293
static const AVFilterPad phase_inputs[] = {
294
    {
295
        .name         = "default",
296
        .type         = AVMEDIA_TYPE_VIDEO,
297
        .filter_frame = filter_frame,
298
        .config_props = config_input,
299
    },
300
    { NULL }
301
};
302
 
303
static const AVFilterPad phase_outputs[] = {
304
    {
305
        .name = "default",
306
        .type = AVMEDIA_TYPE_VIDEO,
307
    },
308
    { NULL }
309
};
310
 
311
AVFilter avfilter_vf_phase = {
312
    .name          = "phase",
313
    .description   = NULL_IF_CONFIG_SMALL("Phase shift fields."),
314
    .priv_size     = sizeof(PhaseContext),
315
    .priv_class    = &phase_class,
316
    .uninit        = uninit,
317
    .query_formats = query_formats,
318
    .inputs        = phase_inputs,
319
    .outputs       = phase_outputs,
320
};