Statistics
| Branch: | Revision:

ffmpeg / libavfilter / vf_fieldorder.c @ master

History | View | Annotate | Download (8.6 KB)

1
/*
2
 * Copyright (c) 2011 Mark Himsley
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 Lesser General Public
8
 * License as published by the Free Software Foundation; either
9
 * version 2.1 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 GNU
14
 * Lesser General Public License for more details.
15
 *
16
 * You should have received a copy of the GNU Lesser General Public
17
 * License along 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
/**
22
 * @file
23
 * video field order filter, heavily influenced by vf_pad.c
24
 */
25

    
26
/* #define DEBUG */
27

    
28
#include "libavutil/imgutils.h"
29
#include "libavutil/pixdesc.h"
30
#include "avfilter.h"
31

    
32
typedef struct
33
{
34
    unsigned int dst_tff;      ///< output bff/tff
35
    int          line_size[4]; ///< bytes of pixel data per line for each plane
36
} FieldOrderContext;
37

    
38
static av_cold int init(AVFilterContext *ctx, const char *args, void *opaque)
39
{
40
    FieldOrderContext *fieldorder = ctx->priv;
41

    
42
    const char *tff = "tff";
43
    const char *bff = "bff";
44

    
45
    if (!args) {
46
        fieldorder->dst_tff = 1;
47
    } else if (sscanf(args, "%u", &fieldorder->dst_tff) == 1) {
48
        fieldorder->dst_tff = !!fieldorder->dst_tff;
49
    } else if (!strcmp(tff, args)) {
50
        fieldorder->dst_tff = 1;
51
    } else if (!strcmp(bff, args)) {
52
        fieldorder->dst_tff = 0;
53
    } else {
54
        av_log(ctx, AV_LOG_ERROR, "Invalid argument '%s'.\n", args);
55
        return AVERROR(EINVAL);
56
    }
57

    
58
    av_log(ctx, AV_LOG_INFO, "output field order: %s\n",
59
            fieldorder->dst_tff ? tff : bff);
60

    
61
    return 0;
62
}
63

    
64
static int query_formats(AVFilterContext *ctx)
65
{
66
    AVFilterFormats  *formats;
67
    enum PixelFormat pix_fmt;
68
    int              ret;
69

    
70
    /** accept any input pixel format that is not hardware accelerated, not
71
     *  a bitstream format, and does not have vertically sub-sampled chroma */
72
    if (ctx->inputs[0]) {
73
        formats = NULL;
74
        for (pix_fmt = 0; pix_fmt < PIX_FMT_NB; pix_fmt++)
75
            if (!(  av_pix_fmt_descriptors[pix_fmt].flags & PIX_FMT_HWACCEL
76
                 || av_pix_fmt_descriptors[pix_fmt].flags & PIX_FMT_BITSTREAM)
77
                && av_pix_fmt_descriptors[pix_fmt].nb_components
78
                && !av_pix_fmt_descriptors[pix_fmt].log2_chroma_h
79
                && (ret = avfilter_add_format(&formats, pix_fmt)) < 0) {
80
                avfilter_formats_unref(&formats);
81
                return ret;
82
            }
83
        avfilter_formats_ref(formats, &ctx->inputs[0]->out_formats);
84
        avfilter_formats_ref(formats, &ctx->outputs[0]->in_formats);
85
    }
86

    
87
    return 0;
88
}
89

    
90
static int config_input(AVFilterLink *inlink)
91
{
92
    AVFilterContext   *ctx        = inlink->dst;
93
    FieldOrderContext *fieldorder = ctx->priv;
94
    int               plane;
95

    
96
    /** full an array with the number of bytes that the video
97
     *  data occupies per line for each plane of the input video */
98
    for (plane = 0; plane < 4; plane++) {
99
        fieldorder->line_size[plane] = av_image_get_linesize(
100
                inlink->format,
101
                inlink->w,
102
                plane);
103
    }
104

    
105
    return 0;
106
}
107

    
108
static AVFilterBufferRef *get_video_buffer(AVFilterLink *inlink, int perms, int w, int h)
109
{
110
    AVFilterContext   *ctx        = inlink->dst;
111
    AVFilterLink      *outlink    = ctx->outputs[0];
112

    
113
    return avfilter_get_video_buffer(outlink, perms, w, h);
114
}
115

    
116
static void start_frame(AVFilterLink *inlink, AVFilterBufferRef *inpicref)
117
{
118
    AVFilterContext   *ctx        = inlink->dst;
119
    AVFilterLink      *outlink    = ctx->outputs[0];
120

    
121
    AVFilterBufferRef *outpicref;
122

    
123
    outpicref = avfilter_ref_buffer(inpicref, ~0);
124
    outlink->out_buf = outpicref;
125

    
126
    avfilter_start_frame(outlink, outpicref);
127
}
128

    
129
static void draw_slice(AVFilterLink *inlink, int y, int h, int slice_dir)
130
{
131
    AVFilterContext   *ctx        = inlink->dst;
132
    FieldOrderContext *fieldorder = ctx->priv;
133
    AVFilterLink      *outlink    = ctx->outputs[0];
134

    
135
    AVFilterBufferRef *inpicref   = inlink->cur_buf;
136

    
137
    /** can only currently do slices if this filter is doing nothing
138
     *  because this filter is moving picture content, the output
139
     *  slice will contain different video lines than the input slice
140
     *  and that complexity will be added later */
141
    if (  !inpicref->video->interlaced
142
        || inpicref->video->top_field_first == fieldorder->dst_tff) {
143
        avfilter_draw_slice(outlink, y, h, slice_dir);
144
    }
145
}
146

    
147
static void end_frame(AVFilterLink *inlink)
148
{
149
    AVFilterContext   *ctx        = inlink->dst;
150
    FieldOrderContext *fieldorder = ctx->priv;
151
    AVFilterLink      *outlink    = ctx->outputs[0];
152

    
153
    AVFilterBufferRef *inpicref   = inlink->cur_buf;
154
    AVFilterBufferRef *outpicref  = outlink->out_buf;
155

    
156
    int               h, w, plane, line_step, line_size, line;
157
    uint8_t           *cpy_src, *cpy_dst;
158

    
159
    if (    inpicref->video->interlaced
160
         && inpicref->video->top_field_first != fieldorder->dst_tff) {
161
        av_dlog(ctx,
162
                "picture will move %s one line\n",
163
                fieldorder->dst_tff ? "up" : "down");
164
        h = inpicref->video->h;
165
        w = inpicref->video->w;
166
        for (plane = 0; plane < 4 && inpicref->data[plane]; plane++) {
167
            line_step = inpicref->linesize[plane];
168
            line_size = fieldorder->line_size[plane];
169
            cpy_src = inpicref->data[plane];
170
            cpy_dst = outpicref->data[plane];
171
            if (fieldorder->dst_tff) {
172
                /** Move every line up one line, working from
173
                 *  the top to the bottom of the frame.
174
                 *  The original top line is lost.
175
                 *  The new last line is created as a copy of the
176
                 *  penultimate line from that field. */
177
                for (line = 0; line < h; line++) {
178
                    if (1 + line < outpicref->video->h) {
179
                        memcpy(cpy_dst, cpy_src + line_step, line_size);
180
                    } else {
181
                        memcpy(cpy_dst, cpy_src - line_step - line_step, line_size);
182
                    }
183
                    cpy_src += line_step;
184
                    cpy_dst += line_step;
185
                }
186
            } else {
187
                /** Move every line down one line, working from
188
                 *  the bottom to the top of the frame.
189
                 *  The original bottom line is lost.
190
                 *  The new first line is created as a copy of the
191
                 *  second line from that field. */
192
                cpy_src += (h - 1) * line_step;
193
                cpy_dst += (h - 1) * line_step;
194
                for (line = h - 1; line >= 0 ; line--) {
195
                    if (line > 0) {
196
                        memcpy(cpy_dst, cpy_src - line_step, line_size);
197
                    } else {
198
                        memcpy(cpy_dst, cpy_src + line_step + line_step, line_size);
199
                    }
200
                    cpy_src -= line_step;
201
                    cpy_dst -= line_step;
202
                }
203
            }
204
        }
205
        outpicref->video->top_field_first = fieldorder->dst_tff;
206
        avfilter_draw_slice(outlink, 0, h, 1);
207
    } else {
208
        av_dlog(ctx,
209
                "not interlaced or field order already correct\n");
210
    }
211

    
212
    avfilter_end_frame(outlink);
213
    avfilter_unref_buffer(inpicref);
214
}
215

    
216
AVFilter avfilter_vf_fieldorder = {
217
    .name          = "fieldorder",
218
    .description   = NULL_IF_CONFIG_SMALL("Set the field order."),
219
    .init          = init,
220
    .priv_size     = sizeof(FieldOrderContext),
221
    .query_formats = query_formats,
222
    .inputs        = (AVFilterPad[]) {{ .name             = "default",
223
                                        .type             = AVMEDIA_TYPE_VIDEO,
224
                                        .config_props     = config_input,
225
                                        .start_frame      = start_frame,
226
                                        .get_video_buffer = get_video_buffer,
227
                                        .draw_slice       = draw_slice,
228
                                        .end_frame        = end_frame,
229
                                        .min_perms        = AV_PERM_READ,
230
                                        .rej_perms        = AV_PERM_REUSE2|AV_PERM_PRESERVE,},
231
                                      { .name = NULL}},
232
    .outputs       = (AVFilterPad[]) {{ .name             = "default",
233
                                        .type             = AVMEDIA_TYPE_VIDEO, },
234
                                      { .name = NULL}},
235
};