Commit 6e9abce5 authored by Paul B Mahol's avatar Paul B Mahol

lavfi: port MP il filter

Signed-off-by: 's avatarPaul B Mahol <onemda@gmail.com>
parent 796012af
......@@ -15,6 +15,7 @@ version <next>:
- improved showspectrum filter, with multichannel support and sox-like colors
- histogram filter
- tee muxer
- il filter ported from libmpcodecs
version 1.1:
......
......@@ -4648,6 +4648,43 @@ Useful for enlarging pixel art images without reducing sharpness.
@section swapuv
Swap U & V plane.
@section il
Deinterleave or interleave fields.
This filter allows to process interlaced images fields without
deinterlacing them. Deinterleaving splits the input frame into 2
fields (so called half pictures). Odd lines are moved to the top
half of the output image, even lines to the bottom half.
You can process (filter) them independently and then re-interleave them.
It accepts a list of options in the form of @var{key}=@var{value} pairs
separated by ":". A description of the accepted options follows.
@table @option
@item luma_mode, l
@item chroma_mode, s
@item alpha_mode, a
Available values for @var{luma_mode}, @var{chroma_mode} and
@var{alpha_mode} are:
@table @samp
@item none
Do nothing.
@item deinterleave, d
Deinterleave fields, placing one above the other.
@item interleave, i
Interleave fields. Reversing effect of deinterleave.
@end table
Default value is @code{none}.
@item luma_swap, ls
@item chroma_swap, cs
@item alpha_swap, as
Swap luma/chroma/alpha fields. Exchange even & odd lines. Default value is @code{0}.
@end table
@section thumbnail
Select the most representative frame in a given sequence of consecutive frames.
......
......@@ -126,6 +126,7 @@ OBJS-$(CONFIG_HISTOGRAM_FILTER) += vf_histogram.o
OBJS-$(CONFIG_HQDN3D_FILTER) += vf_hqdn3d.o
OBJS-$(CONFIG_HUE_FILTER) += vf_hue.o
OBJS-$(CONFIG_IDET_FILTER) += vf_idet.o
OBJS-$(CONFIG_IL_FILTER) += vf_il.o
OBJS-$(CONFIG_KERNDEINT_FILTER) += vf_kerndeint.o
OBJS-$(CONFIG_LUT_FILTER) += vf_lut.o
OBJS-$(CONFIG_LUTRGB_FILTER) += vf_lut.o
......
......@@ -120,6 +120,7 @@ void avfilter_register_all(void)
REGISTER_FILTER(HQDN3D, hqdn3d, vf);
REGISTER_FILTER(HUE, hue, vf);
REGISTER_FILTER(IDET, idet, vf);
REGISTER_FILTER(IL, il, vf);
REGISTER_FILTER(KERNDEINT, kerndeint, vf);
REGISTER_FILTER(LUT, lut, vf);
REGISTER_FILTER(LUTRGB, lutrgb, vf);
......
......@@ -29,7 +29,7 @@
#include "libavutil/avutil.h"
#define LIBAVFILTER_VERSION_MAJOR 3
#define LIBAVFILTER_VERSION_MINOR 36
#define LIBAVFILTER_VERSION_MINOR 37
#define LIBAVFILTER_VERSION_MICRO 100
#define LIBAVFILTER_VERSION_INT AV_VERSION_INT(LIBAVFILTER_VERSION_MAJOR, \
......
/*
* Copyright (c) 2002 Michael Niedmayer
* Copyright (c) 2013 Paul B Mahol
*
* This file is part of FFmpeg.
*
* FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
/**
* @file
* (de)interleave fields filter
*/
#include "libavutil/opt.h"
#include "libavutil/pixdesc.h"
#include "avfilter.h"
#include "internal.h"
enum FilterMode {
MODE_NONE,
MODE_INTERLEAVE,
MODE_DEINTERLEAVE
};
typedef struct {
const AVClass *class;
enum FilterMode luma_mode, chroma_mode, alpha_mode;
int luma_swap, chroma_swap, alpha_swap;
int nb_planes;
int chroma_width, chroma_height;
int width;
} IlContext;
#define OFFSET(x) offsetof(IlContext, x)
#define FLAGS AV_OPT_FLAG_FILTERING_PARAM|AV_OPT_FLAG_VIDEO_PARAM
static const AVOption il_options[] = {
{"luma_mode", "select luma mode", OFFSET(luma_mode), AV_OPT_TYPE_INT, {.i64=MODE_NONE}, MODE_NONE, MODE_DEINTERLEAVE, FLAGS, "luma_mode"},
{"l", "select luma mode", OFFSET(luma_mode), AV_OPT_TYPE_INT, {.i64=MODE_NONE}, MODE_NONE, MODE_DEINTERLEAVE, FLAGS, "luma_mode"},
{"none", NULL, 0, AV_OPT_TYPE_CONST, {.i64=MODE_NONE}, 0, 0, FLAGS, "luma_mode"},
{"interleave", NULL, 0, AV_OPT_TYPE_CONST, {.i64=MODE_INTERLEAVE}, 0, 0, FLAGS, "luma_mode"},
{"i", NULL, 0, AV_OPT_TYPE_CONST, {.i64=MODE_INTERLEAVE}, 0, 0, FLAGS, "luma_mode"},
{"deinterleave", NULL, 0, AV_OPT_TYPE_CONST, {.i64=MODE_DEINTERLEAVE}, 0, 0, FLAGS, "luma_mode"},
{"d", NULL, 0, AV_OPT_TYPE_CONST, {.i64=MODE_DEINTERLEAVE}, 0, 0, FLAGS, "luma_mode"},
{"chroma_mode", "select chroma mode", OFFSET(chroma_mode), AV_OPT_TYPE_INT, {.i64=MODE_NONE}, MODE_NONE, MODE_DEINTERLEAVE, FLAGS, "chroma_mode"},
{"c", "select chroma mode", OFFSET(chroma_mode), AV_OPT_TYPE_INT, {.i64=MODE_NONE}, MODE_NONE, MODE_DEINTERLEAVE, FLAGS, "chroma_mode"},
{"none", NULL, 0, AV_OPT_TYPE_CONST, {.i64=MODE_NONE}, 0, 0, FLAGS, "chroma_mode"},
{"interleave", NULL, 0, AV_OPT_TYPE_CONST, {.i64=MODE_INTERLEAVE}, 0, 0, FLAGS, "chroma_mode"},
{"i", NULL, 0, AV_OPT_TYPE_CONST, {.i64=MODE_INTERLEAVE}, 0, 0, FLAGS, "chroma_mode"},
{"deinterleave", NULL, 0, AV_OPT_TYPE_CONST, {.i64=MODE_DEINTERLEAVE}, 0, 0, FLAGS, "chroma_mode"},
{"d", NULL, 0, AV_OPT_TYPE_CONST, {.i64=MODE_DEINTERLEAVE}, 0, 0, FLAGS, "chroma_mode"},
{"alpha_mode", "select alpha mode", OFFSET(alpha_mode), AV_OPT_TYPE_INT, {.i64=MODE_NONE}, MODE_NONE, MODE_DEINTERLEAVE, FLAGS, "alpha_mode"},
{"a", "select alpha mode", OFFSET(alpha_mode), AV_OPT_TYPE_INT, {.i64=MODE_NONE}, MODE_NONE, MODE_DEINTERLEAVE, FLAGS, "alpha_mode"},
{"none", NULL, 0, AV_OPT_TYPE_CONST, {.i64=MODE_NONE}, 0, 0, FLAGS, "alpha_mode"},
{"interleave", NULL, 0, AV_OPT_TYPE_CONST, {.i64=MODE_INTERLEAVE}, 0, 0, FLAGS, "alpha_mode"},
{"i", NULL, 0, AV_OPT_TYPE_CONST, {.i64=MODE_INTERLEAVE}, 0, 0, FLAGS, "alpha_mode"},
{"deinterleave", NULL, 0, AV_OPT_TYPE_CONST, {.i64=MODE_DEINTERLEAVE}, 0, 0, FLAGS, "alpha_mode"},
{"d", NULL, 0, AV_OPT_TYPE_CONST, {.i64=MODE_DEINTERLEAVE}, 0, 0, FLAGS, "alpha_mode"},
{"luma_swap", "swap luma fields", OFFSET(luma_swap), AV_OPT_TYPE_INT, {.i64=0}, 0, 1, FLAGS},
{"ls", "swap luma fields", OFFSET(luma_swap), AV_OPT_TYPE_INT, {.i64=0}, 0, 1, FLAGS},
{"chroma_swap", "swap chroma fields", OFFSET(chroma_swap), AV_OPT_TYPE_INT, {.i64=0}, 0, 1, FLAGS},
{"cs", "swap chroma fields", OFFSET(chroma_swap), AV_OPT_TYPE_INT, {.i64=0}, 0, 1, FLAGS},
{"alpha_swap", "swap alpha fields", OFFSET(alpha_swap), AV_OPT_TYPE_INT, {.i64=0}, 0, 1, FLAGS},
{"as", "swap alpha fields", OFFSET(alpha_swap), AV_OPT_TYPE_INT, {.i64=0}, 0, 1, FLAGS},
{NULL}
};
AVFILTER_DEFINE_CLASS(il);
static av_cold int init(AVFilterContext *ctx, const char *args)
{
IlContext *il = ctx->priv;
int ret;
il->class = &il_class;
av_opt_set_defaults(il);
if ((ret = av_set_options_string(il, args, "=", ":")) < 0)
return ret;
return 0;
}
static int config_input(AVFilterLink *inlink)
{
IlContext *il = inlink->dst->priv;
const AVPixFmtDescriptor *desc = av_pix_fmt_desc_get(inlink->format);
int bpp = av_get_padded_bits_per_pixel(desc) >> 3;
int bytes = FFALIGN(desc->comp[0].depth_minus1 + 1, 8) / 8;
int i;
for (i = 0; i < desc->nb_components; i++)
il->nb_planes = FFMAX(il->nb_planes, desc->comp[i].plane);
il->nb_planes++;
il->chroma_height = inlink->h >> desc->log2_chroma_h;
il->chroma_width = (inlink->w >> desc->log2_chroma_w) * bytes;
il->width = inlink->w * bytes;
if (!(desc->flags & PIX_FMT_PLANAR))
il->width *= bpp;
return 0;
}
static void interleave(uint8_t *dst, uint8_t *src, int w, int h,
int dst_linesize, int src_linesize,
enum FilterMode mode, int swap)
{
const int a = swap;
const int b = 1 - a;
const int m = h >> 1;
int y;
switch (mode) {
case MODE_DEINTERLEAVE:
for (y = 0; y < m; y++) {
memcpy(dst + dst_linesize * y , src + src_linesize * (y * 2 + a), w);
memcpy(dst + dst_linesize * (y + m), src + src_linesize * (y * 2 + b), w);
}
break;
case MODE_NONE:
for (y = 0; y < m; y++) {
memcpy(dst + dst_linesize * y * 2 , src + src_linesize * (y * 2 + a), w);
memcpy(dst + dst_linesize * (y * 2 + 1), src + src_linesize * (y * 2 + b), w);
}
break;
case MODE_INTERLEAVE:
for (y = 0; y < m; y++) {
memcpy(dst + dst_linesize * (y * 2 + a), src + src_linesize * y , w);
memcpy(dst + dst_linesize * (y * 2 + b), src + src_linesize * (y + m), w);
}
break;
}
}
static int filter_frame(AVFilterLink *inlink, AVFilterBufferRef *inpicref)
{
IlContext *il = inlink->dst->priv;
AVFilterLink *outlink = inlink->dst->outputs[0];
AVFilterBufferRef *out;
int ret;
out = ff_get_video_buffer(outlink, AV_PERM_WRITE, outlink->w, outlink->h);
if (!out) {
avfilter_unref_bufferp(&inpicref);
return AVERROR(ENOMEM);
}
avfilter_copy_buffer_ref_props(out, inpicref);
interleave(out->data[0], inpicref->data[0],
il->width, inlink->h,
out->linesize[0], inpicref->linesize[0],
il->luma_mode, il->luma_swap);
if (il->nb_planes > 2) {
interleave(out->data[1], inpicref->data[1],
il->chroma_width, il->chroma_height,
out->linesize[1], inpicref->linesize[1],
il->chroma_mode, il->chroma_swap);
interleave(out->data[2], inpicref->data[2],
il->chroma_width, il->chroma_height,
out->linesize[2], inpicref->linesize[2],
il->chroma_mode, il->chroma_swap);
}
if (il->nb_planes == 2 && il->nb_planes == 4) {
int comp = il->nb_planes - 1;
interleave(out->data[comp], inpicref->data[comp],
il->width, inlink->h,
out->linesize[comp], inpicref->linesize[comp],
il->alpha_mode, il->alpha_swap);
}
ret = ff_filter_frame(outlink, out);
avfilter_unref_bufferp(&inpicref);
return ret;
}
static int query_formats(AVFilterContext *ctx)
{
AVFilterFormats *formats = NULL;
int fmt;
for (fmt = 0; fmt < AV_PIX_FMT_NB; fmt++) {
const AVPixFmtDescriptor *desc = av_pix_fmt_desc_get(fmt);
if (!(desc->flags & PIX_FMT_PAL ||
fmt == AV_PIX_FMT_NV21 ||
fmt == AV_PIX_FMT_NV12))
ff_add_format(&formats, fmt);
}
ff_set_common_formats(ctx, formats);
return 0;
}
static const AVFilterPad inputs[] = {
{
.name = "default",
.type = AVMEDIA_TYPE_VIDEO,
.get_video_buffer = ff_null_get_video_buffer,
.filter_frame = filter_frame,
.config_props = config_input,
},
{ NULL }
};
static const AVFilterPad outputs[] = {
{
.name = "default",
.type = AVMEDIA_TYPE_VIDEO,
},
{ NULL }
};
AVFilter avfilter_vf_il = {
.name = "il",
.description = NULL_IF_CONFIG_SMALL("Deinterleave or interleave fields."),
.priv_size = sizeof(IlContext),
.init = init,
.query_formats = query_formats,
.inputs = inputs,
.outputs = outputs,
.priv_class = &il_class,
};
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment