Line | Branch | Exec | Source |
---|---|---|---|
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 "filters.h" | ||
27 | #include "video.h" | ||
28 | |||
29 | enum PhaseMode { | ||
30 | PROGRESSIVE, | ||
31 | TOP_FIRST, | ||
32 | BOTTOM_FIRST, | ||
33 | TOP_FIRST_ANALYZE, | ||
34 | BOTTOM_FIRST_ANALYZE, | ||
35 | ANALYZE, | ||
36 | FULL_ANALYZE, | ||
37 | AUTO, | ||
38 | AUTO_ANALYZE | ||
39 | }; | ||
40 | |||
41 | #define DEPTH 8 | ||
42 | #include "phase_template.c" | ||
43 | |||
44 | #undef DEPTH | ||
45 | #define DEPTH 9 | ||
46 | #include "phase_template.c" | ||
47 | |||
48 | #undef DEPTH | ||
49 | #define DEPTH 10 | ||
50 | #include "phase_template.c" | ||
51 | |||
52 | #undef DEPTH | ||
53 | #define DEPTH 12 | ||
54 | #include "phase_template.c" | ||
55 | |||
56 | #undef DEPTH | ||
57 | #define DEPTH 14 | ||
58 | #include "phase_template.c" | ||
59 | |||
60 | #undef DEPTH | ||
61 | #define DEPTH 16 | ||
62 | #include "phase_template.c" | ||
63 | |||
64 | typedef struct PhaseContext { | ||
65 | const AVClass *class; | ||
66 | int mode; ///<PhaseMode | ||
67 | AVFrame *frame; /* previous frame */ | ||
68 | int nb_planes; | ||
69 | int planeheight[4]; | ||
70 | int linesize[4]; | ||
71 | |||
72 | enum PhaseMode (*analyze_plane)(void *ctx, enum PhaseMode mode, AVFrame *old, AVFrame *new); | ||
73 | } PhaseContext; | ||
74 | |||
75 | #define OFFSET(x) offsetof(PhaseContext, x) | ||
76 | #define FLAGS AV_OPT_FLAG_FILTERING_PARAM|AV_OPT_FLAG_VIDEO_PARAM|AV_OPT_FLAG_RUNTIME_PARAM | ||
77 | #define CONST(name, help, val, u) { name, help, 0, AV_OPT_TYPE_CONST, {.i64=val}, 0, 0, FLAGS, .unit = u } | ||
78 | |||
79 | static const AVOption phase_options[] = { | ||
80 | { "mode", "set phase mode", OFFSET(mode), AV_OPT_TYPE_INT, {.i64=AUTO_ANALYZE}, PROGRESSIVE, AUTO_ANALYZE, FLAGS, .unit = "mode" }, | ||
81 | CONST("p", "progressive", PROGRESSIVE, "mode"), | ||
82 | CONST("t", "top first", TOP_FIRST, "mode"), | ||
83 | CONST("b", "bottom first", BOTTOM_FIRST, "mode"), | ||
84 | CONST("T", "top first analyze", TOP_FIRST_ANALYZE, "mode"), | ||
85 | CONST("B", "bottom first analyze", BOTTOM_FIRST_ANALYZE, "mode"), | ||
86 | CONST("u", "analyze", ANALYZE, "mode"), | ||
87 | CONST("U", "full analyze", FULL_ANALYZE, "mode"), | ||
88 | CONST("a", "auto", AUTO, "mode"), | ||
89 | CONST("A", "auto analyze", AUTO_ANALYZE, "mode"), | ||
90 | { NULL } | ||
91 | }; | ||
92 | |||
93 | AVFILTER_DEFINE_CLASS(phase); | ||
94 | |||
95 | static const enum AVPixelFormat pix_fmts[] = { | ||
96 | AV_PIX_FMT_GRAY8, | ||
97 | AV_PIX_FMT_GRAY9, | ||
98 | AV_PIX_FMT_GRAY10, | ||
99 | AV_PIX_FMT_GRAY12, | ||
100 | AV_PIX_FMT_GRAY14, | ||
101 | AV_PIX_FMT_GRAY16, | ||
102 | AV_PIX_FMT_YUV410P, AV_PIX_FMT_YUV411P, | ||
103 | AV_PIX_FMT_YUV420P, AV_PIX_FMT_YUV422P, | ||
104 | AV_PIX_FMT_YUV440P, AV_PIX_FMT_YUV444P, | ||
105 | AV_PIX_FMT_YUVJ420P, AV_PIX_FMT_YUVJ422P, | ||
106 | AV_PIX_FMT_YUVJ440P, AV_PIX_FMT_YUVJ444P, | ||
107 | AV_PIX_FMT_YUVJ411P, | ||
108 | AV_PIX_FMT_YUV420P9, AV_PIX_FMT_YUV422P9, AV_PIX_FMT_YUV444P9, | ||
109 | AV_PIX_FMT_YUV420P10, AV_PIX_FMT_YUV422P10, AV_PIX_FMT_YUV444P10, | ||
110 | AV_PIX_FMT_YUV440P10, | ||
111 | AV_PIX_FMT_YUV444P12, AV_PIX_FMT_YUV422P12, AV_PIX_FMT_YUV420P12, | ||
112 | AV_PIX_FMT_YUV440P12, | ||
113 | AV_PIX_FMT_YUV444P14, AV_PIX_FMT_YUV422P14, AV_PIX_FMT_YUV420P14, | ||
114 | AV_PIX_FMT_YUV420P16, AV_PIX_FMT_YUV422P16, AV_PIX_FMT_YUV444P16, | ||
115 | AV_PIX_FMT_GBRP, AV_PIX_FMT_GBRP9, AV_PIX_FMT_GBRP10, | ||
116 | AV_PIX_FMT_GBRP12, AV_PIX_FMT_GBRP14, AV_PIX_FMT_GBRP16, | ||
117 | AV_PIX_FMT_YUVA420P, AV_PIX_FMT_YUVA422P, AV_PIX_FMT_YUVA444P, | ||
118 | AV_PIX_FMT_YUVA444P9, AV_PIX_FMT_YUVA444P10, AV_PIX_FMT_YUVA444P12, AV_PIX_FMT_YUVA444P16, | ||
119 | AV_PIX_FMT_YUVA422P9, AV_PIX_FMT_YUVA422P10, AV_PIX_FMT_YUVA422P12, AV_PIX_FMT_YUVA422P16, | ||
120 | AV_PIX_FMT_YUVA420P9, AV_PIX_FMT_YUVA420P10, AV_PIX_FMT_YUVA420P16, | ||
121 | AV_PIX_FMT_GBRAP, AV_PIX_FMT_GBRAP10, AV_PIX_FMT_GBRAP12, AV_PIX_FMT_GBRAP16, | ||
122 | AV_PIX_FMT_NONE | ||
123 | }; | ||
124 | |||
125 | 1 | static int config_input(AVFilterLink *inlink) | |
126 | { | ||
127 | 1 | PhaseContext *s = inlink->dst->priv; | |
128 | 1 | const AVPixFmtDescriptor *desc = av_pix_fmt_desc_get(inlink->format); | |
129 | int ret; | ||
130 | |||
131 |
1/7✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
✗ Branch 6 not taken.
|
1 | switch (desc->comp[0].depth) { |
132 | 1 | case 8: s->analyze_plane = analyze_plane_8; break; | |
133 | ✗ | case 9: s->analyze_plane = analyze_plane_9; break; | |
134 | ✗ | case 10: s->analyze_plane = analyze_plane_10; break; | |
135 | ✗ | case 12: s->analyze_plane = analyze_plane_12; break; | |
136 | ✗ | case 14: s->analyze_plane = analyze_plane_14; break; | |
137 | ✗ | case 16: s->analyze_plane = analyze_plane_16; break; | |
138 | ✗ | default: av_assert0(0); | |
139 | }; | ||
140 | |||
141 |
1/2✗ Branch 1 not taken.
✓ Branch 2 taken 1 times.
|
1 | if ((ret = av_image_fill_linesizes(s->linesize, inlink->format, inlink->w)) < 0) |
142 | ✗ | return ret; | |
143 | |||
144 | 1 | s->planeheight[1] = s->planeheight[2] = AV_CEIL_RSHIFT(inlink->h, desc->log2_chroma_h); | |
145 | 1 | s->planeheight[0] = s->planeheight[3] = inlink->h; | |
146 | |||
147 | 1 | s->nb_planes = av_pix_fmt_count_planes(inlink->format); | |
148 | |||
149 | 1 | return 0; | |
150 | } | ||
151 | |||
152 | 50 | static int filter_frame(AVFilterLink *inlink, AVFrame *in) | |
153 | { | ||
154 | 50 | AVFilterContext *ctx = inlink->dst; | |
155 | 50 | AVFilterLink *outlink = ctx->outputs[0]; | |
156 | 50 | PhaseContext *s = ctx->priv; | |
157 | enum PhaseMode mode; | ||
158 | int plane, top, y; | ||
159 | AVFrame *out; | ||
160 | |||
161 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 50 times.
|
50 | if (ctx->is_disabled) { |
162 | ✗ | av_frame_free(&s->frame); | |
163 | /* we keep a reference to the previous frame so the filter can start | ||
164 | * being useful as soon as it's not disabled, avoiding the 1-frame | ||
165 | * delay. */ | ||
166 | ✗ | s->frame = av_frame_clone(in); | |
167 | ✗ | return ff_filter_frame(outlink, in); | |
168 | } | ||
169 | |||
170 | 50 | out = ff_get_video_buffer(outlink, outlink->w, outlink->h); | |
171 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 50 times.
|
50 | if (!out) { |
172 | ✗ | av_frame_free(&in); | |
173 | ✗ | return AVERROR(ENOMEM); | |
174 | } | ||
175 | 50 | av_frame_copy_props(out, in); | |
176 | |||
177 |
2/2✓ Branch 0 taken 1 times.
✓ Branch 1 taken 49 times.
|
50 | if (!s->frame) { |
178 | 1 | s->frame = in; | |
179 | 1 | mode = PROGRESSIVE; | |
180 | } else { | ||
181 | 49 | mode = s->analyze_plane(ctx, s->mode, s->frame, in); | |
182 | } | ||
183 | |||
184 |
2/2✓ Branch 0 taken 150 times.
✓ Branch 1 taken 50 times.
|
200 | for (plane = 0; plane < s->nb_planes; plane++) { |
185 | 150 | const uint8_t *buf = s->frame->data[plane]; | |
186 | 150 | const uint8_t *from = in->data[plane]; | |
187 | 150 | uint8_t *to = out->data[plane]; | |
188 | |||
189 |
2/2✓ Branch 0 taken 28800 times.
✓ Branch 1 taken 150 times.
|
28950 | for (y = 0, top = 1; y < s->planeheight[plane]; y++, top ^= 1) { |
190 |
3/4✓ Branch 0 taken 14400 times.
✓ Branch 1 taken 14400 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 28800 times.
|
28800 | memcpy(to, mode == (top ? BOTTOM_FIRST : TOP_FIRST) ? buf : from, s->linesize[plane]); |
191 | |||
192 | 28800 | buf += s->frame->linesize[plane]; | |
193 | 28800 | from += in->linesize[plane]; | |
194 | 28800 | to += out->linesize[plane]; | |
195 | } | ||
196 | } | ||
197 | |||
198 |
2/2✓ Branch 0 taken 49 times.
✓ Branch 1 taken 1 times.
|
50 | if (in != s->frame) |
199 | 49 | av_frame_free(&s->frame); | |
200 | 50 | s->frame = in; | |
201 | 50 | return ff_filter_frame(outlink, out); | |
202 | } | ||
203 | |||
204 | 2 | static av_cold void uninit(AVFilterContext *ctx) | |
205 | { | ||
206 | 2 | PhaseContext *s = ctx->priv; | |
207 | |||
208 | 2 | av_frame_free(&s->frame); | |
209 | 2 | } | |
210 | |||
211 | static const AVFilterPad phase_inputs[] = { | ||
212 | { | ||
213 | .name = "default", | ||
214 | .type = AVMEDIA_TYPE_VIDEO, | ||
215 | .filter_frame = filter_frame, | ||
216 | .config_props = config_input, | ||
217 | }, | ||
218 | }; | ||
219 | |||
220 | const AVFilter ff_vf_phase = { | ||
221 | .name = "phase", | ||
222 | .description = NULL_IF_CONFIG_SMALL("Phase shift fields."), | ||
223 | .priv_size = sizeof(PhaseContext), | ||
224 | .priv_class = &phase_class, | ||
225 | .uninit = uninit, | ||
226 | FILTER_INPUTS(phase_inputs), | ||
227 | FILTER_OUTPUTS(ff_video_default_filterpad), | ||
228 | FILTER_PIXFMTS_ARRAY(pix_fmts), | ||
229 | .flags = AVFILTER_FLAG_SUPPORT_TIMELINE_INTERNAL, | ||
230 | .process_command = ff_filter_process_command, | ||
231 | }; | ||
232 |