vf_hflip.c 5.76 KB
Newer Older
Stefano Sabatini's avatar
Stefano Sabatini committed
1 2 3 4
/*
 * Copyright (c) 2007 Benoit Fouet
 * Copyright (c) 2010 Stefano Sabatini
 *
5
 * This file is part of Libav.
Stefano Sabatini's avatar
Stefano Sabatini committed
6
 *
7
 * Libav is free software; you can redistribute it and/or
Stefano Sabatini's avatar
Stefano Sabatini committed
8 9 10 11
 * 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.
 *
12
 * Libav is distributed in the hope that it will be useful,
Stefano Sabatini's avatar
Stefano Sabatini committed
13 14 15 16 17
 * 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
18
 * License along with Libav; if not, write to the Free Software
Stefano Sabatini's avatar
Stefano Sabatini committed
19 20 21 22
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
 */

/**
23
 * @file
Stefano Sabatini's avatar
Stefano Sabatini committed
24 25 26
 * horizontal flip filter
 */

27 28
#include <string.h>

Stefano Sabatini's avatar
Stefano Sabatini committed
29
#include "avfilter.h"
30
#include "formats.h"
31
#include "internal.h"
32
#include "video.h"
Stefano Sabatini's avatar
Stefano Sabatini committed
33
#include "libavutil/pixdesc.h"
34
#include "libavutil/internal.h"
Stefano Sabatini's avatar
Stefano Sabatini committed
35
#include "libavutil/intreadwrite.h"
36
#include "libavutil/imgutils.h"
Stefano Sabatini's avatar
Stefano Sabatini committed
37

38
typedef struct FlipContext {
Stefano Sabatini's avatar
Stefano Sabatini committed
39 40 41 42 43 44
    int max_step[4];    ///< max pixel step for each plane, expressed as a number of bytes
    int hsub, vsub;     ///< chroma subsampling
} FlipContext;

static int query_formats(AVFilterContext *ctx)
{
45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68
    static const enum AVPixelFormat pix_fmts[] = {
        AV_PIX_FMT_RGB48BE,      AV_PIX_FMT_RGB48LE,
        AV_PIX_FMT_BGR48BE,      AV_PIX_FMT_BGR48LE,
        AV_PIX_FMT_ARGB,         AV_PIX_FMT_RGBA,
        AV_PIX_FMT_ABGR,         AV_PIX_FMT_BGRA,
        AV_PIX_FMT_RGB24,        AV_PIX_FMT_BGR24,
        AV_PIX_FMT_RGB565BE,     AV_PIX_FMT_RGB565LE,
        AV_PIX_FMT_RGB555BE,     AV_PIX_FMT_RGB555LE,
        AV_PIX_FMT_BGR565BE,     AV_PIX_FMT_BGR565LE,
        AV_PIX_FMT_BGR555BE,     AV_PIX_FMT_BGR555LE,
        AV_PIX_FMT_GRAY16BE,     AV_PIX_FMT_GRAY16LE,
        AV_PIX_FMT_YUV420P16LE,  AV_PIX_FMT_YUV420P16BE,
        AV_PIX_FMT_YUV422P16LE,  AV_PIX_FMT_YUV422P16BE,
        AV_PIX_FMT_YUV444P16LE,  AV_PIX_FMT_YUV444P16BE,
        AV_PIX_FMT_YUV444P,      AV_PIX_FMT_YUV422P,
        AV_PIX_FMT_YUV420P,      AV_PIX_FMT_YUV411P,
        AV_PIX_FMT_YUV410P,      AV_PIX_FMT_YUV440P,
        AV_PIX_FMT_YUVJ444P,     AV_PIX_FMT_YUVJ422P,
        AV_PIX_FMT_YUVJ420P,     AV_PIX_FMT_YUVJ440P,
        AV_PIX_FMT_YUVA420P,
        AV_PIX_FMT_RGB8,         AV_PIX_FMT_BGR8,
        AV_PIX_FMT_RGB4_BYTE,    AV_PIX_FMT_BGR4_BYTE,
        AV_PIX_FMT_PAL8,         AV_PIX_FMT_GRAY8,
        AV_PIX_FMT_NONE
Stefano Sabatini's avatar
Stefano Sabatini committed
69 70
    };

71
    ff_set_common_formats(ctx, ff_make_format_list(pix_fmts));
Stefano Sabatini's avatar
Stefano Sabatini committed
72 73 74 75 76
    return 0;
}

static int config_props(AVFilterLink *inlink)
{
77
    FlipContext *s = inlink->dst->priv;
78
    const AVPixFmtDescriptor *pix_desc = av_pix_fmt_desc_get(inlink->format);
Stefano Sabatini's avatar
Stefano Sabatini committed
79

80 81 82
    av_image_fill_max_pixsteps(s->max_step, NULL, pix_desc);
    s->hsub = pix_desc->log2_chroma_w;
    s->vsub = pix_desc->log2_chroma_h;
Stefano Sabatini's avatar
Stefano Sabatini committed
83 84 85 86

    return 0;
}

87
static int filter_frame(AVFilterLink *inlink, AVFrame *in)
Stefano Sabatini's avatar
Stefano Sabatini committed
88
{
89
    AVFilterContext *ctx  = inlink->dst;
90
    FlipContext *s     = ctx->priv;
91
    AVFilterLink *outlink = ctx->outputs[0];
92
    AVFrame *out;
Stefano Sabatini's avatar
Stefano Sabatini committed
93 94 95
    uint8_t *inrow, *outrow;
    int i, j, plane, step, hsub, vsub;

96
    out = ff_get_video_buffer(outlink, outlink->w, outlink->h);
97
    if (!out) {
98
        av_frame_free(&in);
99 100
        return AVERROR(ENOMEM);
    }
101
    av_frame_copy_props(out, in);
102 103

    for (plane = 0; plane < 4 && in->data[plane]; plane++) {
104 105 106
        step = s->max_step[plane];
        hsub = (plane == 1 || plane == 2) ? s->hsub : 0;
        vsub = (plane == 1 || plane == 2) ? s->vsub : 0;
Stefano Sabatini's avatar
Stefano Sabatini committed
107

108 109
        outrow = out->data[plane];
        inrow  = in ->data[plane] + ((inlink->w >> hsub) - 1) * step;
110
        for (i = 0; i < in->height >> vsub; i++) {
Stefano Sabatini's avatar
Stefano Sabatini committed
111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150
            switch (step) {
            case 1:
                for (j = 0; j < (inlink->w >> hsub); j++)
                    outrow[j] = inrow[-j];
            break;

            case 2:
            {
                uint16_t *outrow16 = (uint16_t *)outrow;
                uint16_t * inrow16 = (uint16_t *) inrow;
                for (j = 0; j < (inlink->w >> hsub); j++)
                    outrow16[j] = inrow16[-j];
            }
            break;

            case 3:
            {
                uint8_t *in  =  inrow;
                uint8_t *out = outrow;
                for (j = 0; j < (inlink->w >> hsub); j++, out += 3, in -= 3) {
                    int32_t v = AV_RB24(in);
                    AV_WB24(out, v);
                }
            }
            break;

            case 4:
            {
                uint32_t *outrow32 = (uint32_t *)outrow;
                uint32_t * inrow32 = (uint32_t *) inrow;
                for (j = 0; j < (inlink->w >> hsub); j++)
                    outrow32[j] = inrow32[-j];
            }
            break;

            default:
                for (j = 0; j < (inlink->w >> hsub); j++)
                    memcpy(outrow + j*step, inrow - j*step, step);
            }

151 152
            inrow  += in ->linesize[plane];
            outrow += out->linesize[plane];
Stefano Sabatini's avatar
Stefano Sabatini committed
153 154 155
        }
    }

156
    av_frame_free(&in);
157
    return ff_filter_frame(outlink, out);
Stefano Sabatini's avatar
Stefano Sabatini committed
158 159
}

160 161 162 163
static const AVFilterPad avfilter_vf_hflip_inputs[] = {
    {
        .name         = "default",
        .type         = AVMEDIA_TYPE_VIDEO,
164
        .filter_frame = filter_frame,
165 166 167 168 169 170 171 172 173 174 175 176 177
        .config_props = config_props,
    },
    { NULL }
};

static const AVFilterPad avfilter_vf_hflip_outputs[] = {
    {
        .name = "default",
        .type = AVMEDIA_TYPE_VIDEO,
    },
    { NULL }
};

178
AVFilter ff_vf_hflip = {
Stefano Sabatini's avatar
Stefano Sabatini committed
179 180 181 182 183
    .name      = "hflip",
    .description = NULL_IF_CONFIG_SMALL("Horizontally flip the input video."),
    .priv_size = sizeof(FlipContext),
    .query_formats = query_formats,

184 185
    .inputs    = avfilter_vf_hflip_inputs,
    .outputs   = avfilter_vf_hflip_outputs,
Stefano Sabatini's avatar
Stefano Sabatini committed
186
};