2 * Copyright (c) 2002 Michael Niedermayer <michaelni@gmx.at>
3 * Copyright (c) 2013 Paul B Mahol
5 * This file is part of FFmpeg.
7 * FFmpeg is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU Lesser General Public
9 * License as published by the Free Software Foundation; either
10 * version 2.1 of the License, or (at your option) any later version.
12 * FFmpeg is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 * Lesser General Public License for more details.
17 * You should have received a copy of the GNU Lesser General Public
18 * License along with FFmpeg; if not, write to the Free Software
19 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
24 * (de)interleave fields filter
27 #include "libavutil/opt.h"
28 #include "libavutil/imgutils.h"
29 #include "libavutil/pixdesc.h"
41 enum FilterMode luma_mode
, chroma_mode
, alpha_mode
;
42 int luma_swap
, chroma_swap
, alpha_swap
;
44 int linesize
[4], chroma_height
;
48 #define OFFSET(x) offsetof(IlContext, x)
49 #define FLAGS AV_OPT_FLAG_FILTERING_PARAM|AV_OPT_FLAG_VIDEO_PARAM
51 static const AVOption il_options
[] = {
52 {"luma_mode", "select luma mode", OFFSET(luma_mode
), AV_OPT_TYPE_INT
, {.i64
=MODE_NONE
}, MODE_NONE
, MODE_DEINTERLEAVE
, FLAGS
, "luma_mode"},
53 {"l", "select luma mode", OFFSET(luma_mode
), AV_OPT_TYPE_INT
, {.i64
=MODE_NONE
}, MODE_NONE
, MODE_DEINTERLEAVE
, FLAGS
, "luma_mode"},
54 {"none", NULL
, 0, AV_OPT_TYPE_CONST
, {.i64
=MODE_NONE
}, 0, 0, FLAGS
, "luma_mode"},
55 {"interleave", NULL
, 0, AV_OPT_TYPE_CONST
, {.i64
=MODE_INTERLEAVE
}, 0, 0, FLAGS
, "luma_mode"},
56 {"i", NULL
, 0, AV_OPT_TYPE_CONST
, {.i64
=MODE_INTERLEAVE
}, 0, 0, FLAGS
, "luma_mode"},
57 {"deinterleave", NULL
, 0, AV_OPT_TYPE_CONST
, {.i64
=MODE_DEINTERLEAVE
}, 0, 0, FLAGS
, "luma_mode"},
58 {"d", NULL
, 0, AV_OPT_TYPE_CONST
, {.i64
=MODE_DEINTERLEAVE
}, 0, 0, FLAGS
, "luma_mode"},
59 {"chroma_mode", "select chroma mode", OFFSET(chroma_mode
), AV_OPT_TYPE_INT
, {.i64
=MODE_NONE
}, MODE_NONE
, MODE_DEINTERLEAVE
, FLAGS
, "chroma_mode"},
60 {"c", "select chroma mode", OFFSET(chroma_mode
), AV_OPT_TYPE_INT
, {.i64
=MODE_NONE
}, MODE_NONE
, MODE_DEINTERLEAVE
, FLAGS
, "chroma_mode"},
61 {"none", NULL
, 0, AV_OPT_TYPE_CONST
, {.i64
=MODE_NONE
}, 0, 0, FLAGS
, "chroma_mode"},
62 {"interleave", NULL
, 0, AV_OPT_TYPE_CONST
, {.i64
=MODE_INTERLEAVE
}, 0, 0, FLAGS
, "chroma_mode"},
63 {"i", NULL
, 0, AV_OPT_TYPE_CONST
, {.i64
=MODE_INTERLEAVE
}, 0, 0, FLAGS
, "chroma_mode"},
64 {"deinterleave", NULL
, 0, AV_OPT_TYPE_CONST
, {.i64
=MODE_DEINTERLEAVE
}, 0, 0, FLAGS
, "chroma_mode"},
65 {"d", NULL
, 0, AV_OPT_TYPE_CONST
, {.i64
=MODE_DEINTERLEAVE
}, 0, 0, FLAGS
, "chroma_mode"},
66 {"alpha_mode", "select alpha mode", OFFSET(alpha_mode
), AV_OPT_TYPE_INT
, {.i64
=MODE_NONE
}, MODE_NONE
, MODE_DEINTERLEAVE
, FLAGS
, "alpha_mode"},
67 {"a", "select alpha mode", OFFSET(alpha_mode
), AV_OPT_TYPE_INT
, {.i64
=MODE_NONE
}, MODE_NONE
, MODE_DEINTERLEAVE
, FLAGS
, "alpha_mode"},
68 {"none", NULL
, 0, AV_OPT_TYPE_CONST
, {.i64
=MODE_NONE
}, 0, 0, FLAGS
, "alpha_mode"},
69 {"interleave", NULL
, 0, AV_OPT_TYPE_CONST
, {.i64
=MODE_INTERLEAVE
}, 0, 0, FLAGS
, "alpha_mode"},
70 {"i", NULL
, 0, AV_OPT_TYPE_CONST
, {.i64
=MODE_INTERLEAVE
}, 0, 0, FLAGS
, "alpha_mode"},
71 {"deinterleave", NULL
, 0, AV_OPT_TYPE_CONST
, {.i64
=MODE_DEINTERLEAVE
}, 0, 0, FLAGS
, "alpha_mode"},
72 {"d", NULL
, 0, AV_OPT_TYPE_CONST
, {.i64
=MODE_DEINTERLEAVE
}, 0, 0, FLAGS
, "alpha_mode"},
73 {"luma_swap", "swap luma fields", OFFSET(luma_swap
), AV_OPT_TYPE_INT
, {.i64
=0}, 0, 1, FLAGS
},
74 {"ls", "swap luma fields", OFFSET(luma_swap
), AV_OPT_TYPE_INT
, {.i64
=0}, 0, 1, FLAGS
},
75 {"chroma_swap", "swap chroma fields", OFFSET(chroma_swap
), AV_OPT_TYPE_INT
, {.i64
=0}, 0, 1, FLAGS
},
76 {"cs", "swap chroma fields", OFFSET(chroma_swap
), AV_OPT_TYPE_INT
, {.i64
=0}, 0, 1, FLAGS
},
77 {"alpha_swap", "swap alpha fields", OFFSET(alpha_swap
), AV_OPT_TYPE_INT
, {.i64
=0}, 0, 1, FLAGS
},
78 {"as", "swap alpha fields", OFFSET(alpha_swap
), AV_OPT_TYPE_INT
, {.i64
=0}, 0, 1, FLAGS
},
82 AVFILTER_DEFINE_CLASS(il
);
84 static int query_formats(AVFilterContext
*ctx
)
86 AVFilterFormats
*formats
= NULL
;
89 for (fmt
= 0; av_pix_fmt_desc_get(fmt
); fmt
++) {
90 const AVPixFmtDescriptor
*desc
= av_pix_fmt_desc_get(fmt
);
91 if (!(desc
->flags
& AV_PIX_FMT_FLAG_PAL
) && !(desc
->flags
& AV_PIX_FMT_FLAG_HWACCEL
))
92 ff_add_format(&formats
, fmt
);
95 ff_set_common_formats(ctx
, formats
);
99 static int config_input(AVFilterLink
*inlink
)
101 IlContext
*il
= inlink
->dst
->priv
;
102 const AVPixFmtDescriptor
*desc
= av_pix_fmt_desc_get(inlink
->format
);
105 il
->nb_planes
= av_pix_fmt_count_planes(inlink
->format
);
107 il
->has_alpha
= !!(desc
->flags
& AV_PIX_FMT_FLAG_ALPHA
);
108 if ((ret
= av_image_fill_linesizes(il
->linesize
, inlink
->format
, inlink
->w
)) < 0)
111 il
->chroma_height
= FF_CEIL_RSHIFT(inlink
->h
, desc
->log2_chroma_h
);
116 static void interleave(uint8_t *dst
, uint8_t *src
, int w
, int h
,
117 int dst_linesize
, int src_linesize
,
118 enum FilterMode mode
, int swap
)
122 const int m
= h
>> 1;
126 case MODE_DEINTERLEAVE
:
127 for (y
= 0; y
< m
; y
++) {
128 memcpy(dst
+ dst_linesize
* y
, src
+ src_linesize
* (y
* 2 + a
), w
);
129 memcpy(dst
+ dst_linesize
* (y
+ m
), src
+ src_linesize
* (y
* 2 + b
), w
);
133 for (y
= 0; y
< m
; y
++) {
134 memcpy(dst
+ dst_linesize
* y
* 2 , src
+ src_linesize
* (y
* 2 + a
), w
);
135 memcpy(dst
+ dst_linesize
* (y
* 2 + 1), src
+ src_linesize
* (y
* 2 + b
), w
);
138 case MODE_INTERLEAVE
:
139 for (y
= 0; y
< m
; y
++) {
140 memcpy(dst
+ dst_linesize
* (y
* 2 + a
), src
+ src_linesize
* y
, w
);
141 memcpy(dst
+ dst_linesize
* (y
* 2 + b
), src
+ src_linesize
* (y
+ m
), w
);
147 static int filter_frame(AVFilterLink
*inlink
, AVFrame
*inpicref
)
149 IlContext
*il
= inlink
->dst
->priv
;
150 AVFilterLink
*outlink
= inlink
->dst
->outputs
[0];
154 out
= ff_get_video_buffer(outlink
, outlink
->w
, outlink
->h
);
156 av_frame_free(&inpicref
);
157 return AVERROR(ENOMEM
);
159 av_frame_copy_props(out
, inpicref
);
161 interleave(out
->data
[0], inpicref
->data
[0],
162 il
->linesize
[0], inlink
->h
,
163 out
->linesize
[0], inpicref
->linesize
[0],
164 il
->luma_mode
, il
->luma_swap
);
166 for (comp
= 1; comp
< (il
->nb_planes
- il
->has_alpha
); comp
++) {
167 interleave(out
->data
[comp
], inpicref
->data
[comp
],
168 il
->linesize
[comp
], il
->chroma_height
,
169 out
->linesize
[comp
], inpicref
->linesize
[comp
],
170 il
->chroma_mode
, il
->chroma_swap
);
174 comp
= il
->nb_planes
- 1;
175 interleave(out
->data
[comp
], inpicref
->data
[comp
],
176 il
->linesize
[comp
], inlink
->h
,
177 out
->linesize
[comp
], inpicref
->linesize
[comp
],
178 il
->alpha_mode
, il
->alpha_swap
);
181 av_frame_free(&inpicref
);
182 return ff_filter_frame(outlink
, out
);
185 static const AVFilterPad inputs
[] = {
188 .type
= AVMEDIA_TYPE_VIDEO
,
189 .filter_frame
= filter_frame
,
190 .config_props
= config_input
,
195 static const AVFilterPad outputs
[] = {
198 .type
= AVMEDIA_TYPE_VIDEO
,
203 AVFilter ff_vf_il
= {
205 .description
= NULL_IF_CONFIG_SMALL("Deinterleave or interleave fields."),
206 .priv_size
= sizeof(IlContext
),
207 .query_formats
= query_formats
,
210 .priv_class
= &il_class
,
211 .flags
= AVFILTER_FLAG_SUPPORT_TIMELINE_GENERIC
,