vf_hflip.c 5.75 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
 */

/**
Stefano Sabatini's avatar
Stefano Sabatini committed
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 39 40 41 42 43 44

typedef struct {
    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;
}

Anton Khirnov's avatar
Anton Khirnov committed
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];
Anton Khirnov's avatar
Anton Khirnov committed
92
    AVFrame *out;
Stefano Sabatini's avatar
Stefano Sabatini committed
93 94 95
    uint8_t *inrow, *outrow;
    int i, j, plane, step, hsub, vsub;

Anton Khirnov's avatar
Anton Khirnov committed
96
    out = ff_get_video_buffer(outlink, outlink->w, outlink->h);
97
    if (!out) {
Anton Khirnov's avatar
Anton Khirnov committed
98
        av_frame_free(&in);
99 100
        return AVERROR(ENOMEM);
    }
Anton Khirnov's avatar
Anton Khirnov committed
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;
Anton Khirnov's avatar
Anton Khirnov committed
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
        }
    }

Anton Khirnov's avatar
Anton Khirnov committed
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 }
};

Stefano Sabatini's avatar
Stefano Sabatini committed
178 179 180 181 182 183
AVFilter avfilter_vf_hflip = {
    .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
};