FFmpeg
Loading...
Searching...
No Matches
vf_tiltandshift.c
Go to the documentation of this file.
1/*
2 * Copyright (c) 2014 Vittorio Giovara
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 vf_tiltandshift.c
23 * Simple time and space inverter.
24 */
25
26#include <string.h>
27
28#include "libavutil/avassert.h"
29#include "libavutil/fifo.h"
30#include "libavutil/imgutils.h"
31#include "libavutil/mem.h"
32#include "libavutil/opt.h"
33#include "libavutil/pixdesc.h"
34
35#include "avfilter.h"
36#include "filters.h"
37#include "video.h"
38
45
46typedef struct TiltandshiftContext {
47 const AVClass *class;
48
49 /* set when all input frames have been processed and we have to
50 * empty buffers, pad and then return */
52
53 /* live or static sliding */
54 int tilt;
55
56 /* initial or final actions to perform (pad/hold a frame/black/nothing) */
57 int start;
58 int end;
59
60 /* columns to hold or pad at the beginning or at the end (respectively) */
61 int hold;
62 int pad;
63
64 /* buffers for black columns */
65 uint8_t *black_buffers[4];
67
68 /* FIFO containing all input frames */
71
74
82
84{
85 TiltandshiftContext *s = ctx->priv;
86
87 s->input = av_fifo_alloc2(32, sizeof(AVFrame*), AV_FIFO_FLAG_AUTO_GROW);
88 if (!s->input)
89 return AVERROR(ENOMEM);
90
91 return 0;
92}
93
95{
96 TiltandshiftContext *s = ctx->priv;
97
98 if (s->input) {
100
101 while (av_fifo_read(s->input, &frame, 1) >= 0)
103
104 av_fifo_freep2(&s->input);
105 }
106
107 av_freep(&s->black_buffers);
108}
109
110static int config_props(AVFilterLink *outlink)
111{
112 AVFilterContext *ctx = outlink->src;
113 TiltandshiftContext *s = ctx->priv;
114
115 outlink->w = ctx->inputs[0]->w;
116 outlink->h = ctx->inputs[0]->h;
117 outlink->format = ctx->inputs[0]->format;
118
119 // when we have to pad black or a frame at the start, skip navigating
120 // the list and use either the frame or black for the requested value
121 if (s->start != TILT_NONE && !s->hold)
122 s->hold = outlink->w;
123
124 // Init black buffers if we pad with black at the start or at the end.
125 // For the end, we always have to init on NONE and BLACK because we never
126 // know if there are going to be enough input frames to fill an output one.
127 if (s->start == TILT_BLACK || s->end != TILT_FRAME) {
128 int i, j, ret;
129 uint8_t black_data[] = { 0x10, 0x80, 0x80, 0x10 };
131 if (!desc)
132 return AVERROR_BUG;
133
134 if (outlink->format == AV_PIX_FMT_YUVJ420P ||
135 outlink->format == AV_PIX_FMT_YUVJ422P ||
136 outlink->format == AV_PIX_FMT_YUVJ444P ||
137 outlink->format == AV_PIX_FMT_YUVJ440P ||
138 outlink->color_range == AVCOL_RANGE_JPEG)
139 black_data[0] = black_data[3] = 0;
140
141 ret = av_image_alloc(s->black_buffers, s->black_linesizes, 1,
142 outlink->h, outlink->format, 1);
143 if (ret < 0)
144 return ret;
145
146 for (i = 0; i < FFMIN(desc->nb_components, 4); i++)
147 for (j = 0; j < (!i ? outlink->h
148 : -((-outlink->h) >> desc->log2_chroma_h)); j++)
149 memset(s->black_buffers[i] + j * s->black_linesizes[i],
150 black_data[i], 1);
151
152 av_log(ctx, AV_LOG_VERBOSE, "Padding buffers initialized.\n");
153 }
154
155 s->desc = av_pix_fmt_desc_get(outlink->format);
156 if (!s->desc)
157 return AVERROR_BUG;
158
159 return 0;
160}
161
162
163static void copy_column(AVFilterLink *outlink,
164 uint8_t *dst_data[4], int dst_linesizes[4],
165 const uint8_t *src_data[4], const int src_linesizes[4],
166 int ncol, int tilt)
167{
168 AVFilterContext *ctx = outlink->src;
169 TiltandshiftContext *s = ctx->priv;
170 uint8_t *dst[4];
171 const uint8_t *src[4];
172
173 dst[0] = dst_data[0] + ncol;
174 dst[1] = dst_data[1] + (ncol >> s->desc->log2_chroma_w);
175 dst[2] = dst_data[2] + (ncol >> s->desc->log2_chroma_w);
176
177 if (!tilt)
178 ncol = 0;
179 src[0] = src_data[0] + ncol;
180 src[1] = src_data[1] + (ncol >> s->desc->log2_chroma_w);
181 src[2] = src_data[2] + (ncol >> s->desc->log2_chroma_w);
182
183 av_image_copy(dst, dst_linesizes, src, src_linesizes, outlink->format, 1, outlink->h);
184}
185
186static int output_frame(AVFilterLink *outlink)
187{
188 TiltandshiftContext *s = outlink->src->priv;
189 AVFrame *head;
190 int ret;
191 int nb_buffered;
192
193 int ncol = 0;
194 AVFrame *dst = ff_get_video_buffer(outlink, outlink->w, outlink->h);
195 if (!dst)
196 return AVERROR(ENOMEM);
197
198 // in case we have to do any initial black padding
199 if (s->start == TILT_BLACK) {
200 for ( ; ncol < s->hold; ncol++)
201 copy_column(outlink, dst->data, dst->linesize,
202 (const uint8_t **)s->black_buffers, s->black_linesizes,
203 ncol, 0);
204 }
205
206 nb_buffered = av_fifo_can_read(s->input);
207 av_assert0(nb_buffered);
208 // copy a column from each input frame
209 for (int in_idx = 0; ncol < nb_buffered; ncol++) {
210 AVFrame *src;
211
212 av_fifo_peek(s->input, &src, 1, in_idx);
213
214 copy_column(outlink, dst->data, dst->linesize,
215 (const uint8_t **)src->data, src->linesize,
216 ncol, s->tilt);
217
218 // keep track of the last known frame in case we need it below
219 s->prev = src;
220 // advance to the next frame unless we have to hold it
221 if (s->hold <= ncol)
222 in_idx++;
223 }
224
225 // pad any remaining space with black or last frame
226 if (s->end == TILT_FRAME) {
227 for ( ; ncol < outlink->w; ncol++)
228 copy_column(outlink, dst->data, dst->linesize,
229 (const uint8_t **)s->prev->data,
230 s->prev->linesize, ncol, 1);
231 } else { // TILT_BLACK and TILT_NONE
232 for ( ; ncol < outlink->w; ncol++)
233 copy_column(outlink, dst->data, dst->linesize,
234 (const uint8_t **)s->black_buffers, s->black_linesizes,
235 ncol, 0);
236 }
237
238 // set correct timestamps and props as long as there is proper input
239 av_fifo_read(s->input, &head, 1);
240 ret = av_frame_copy_props(dst, head);
241 av_frame_free(&head);
242 if (ret < 0) {
244 return ret;
245 }
246
247 // and it is safe to reduce the hold value (even if unused)
248 s->hold--;
249
250 // output
251 return ff_filter_frame(outlink, dst);
252}
253
254// This function just polls for new frames and queues them on a list
256{
257 AVFilterLink *outlink = inlink->dst->outputs[0];
258 AVFilterContext *ctx = outlink->src;
259 TiltandshiftContext *s = inlink->dst->priv;
260 int ret;
261
262 ret = av_fifo_write(s->input, &frame, 1);
263 if (ret < 0) {
265 return ret;
266 }
267
268 // load up enough frames to fill a frame and keep the queue filled on subsequent
269 // calls, until we receive EOF, and then we either pad or end
270 if (!s->eof_recv &&
271 av_fifo_can_read(s->input) < outlink->w - s->pad) {
273 "Not enough frames in the list (%zu/%d), waiting for more.\n",
274 av_fifo_can_read(s->input), outlink->w - s->pad);
275 return 0;
276 }
277
278 return output_frame(outlink);
279}
280
281static int request_frame(AVFilterLink *outlink)
282{
283 AVFilterContext *ctx = outlink->src;
284 TiltandshiftContext *s = ctx->priv;
285 size_t nb_buffered = av_fifo_can_read(s->input);
286 int ret;
287
288 // signal job finished when list is empty or when padding is either
289 // limited or disabled and eof was received
290 if ((nb_buffered <= 0 || nb_buffered == outlink->w - s->pad ||
291 s->end == TILT_NONE) && s->eof_recv) {
292 return AVERROR_EOF;
293 }
294
295 ret = ff_request_frame(ctx->inputs[0]);
296 if (ret == AVERROR_EOF) {
297 s->eof_recv = 1;
298 } else if (ret < 0) {
299 return ret;
300 }
301
302 if (s->eof_recv) {
303 while (av_fifo_can_read(s->input)) {
304 av_log(ctx, AV_LOG_DEBUG, "Emptying buffers (%zu/%d).\n",
305 av_fifo_can_read(s->input), outlink->w - s->pad);
306 ret = output_frame(outlink);
307 if (ret < 0) {
308 return ret;
309 }
310 }
311 }
312
313 return 0;
314}
315
316#define OFFSET(x) offsetof(TiltandshiftContext, x)
317#define V AV_OPT_FLAG_VIDEO_PARAM
319 { "tilt", "Tilt the video horizontally while shifting", OFFSET(tilt), AV_OPT_TYPE_INT,
320 { .i64 = 1 }, 0, 1, .flags = V, .unit = "tilt" },
321
322 { "start", "Action at the start of input", OFFSET(start), AV_OPT_TYPE_INT,
323 { .i64 = TILT_NONE }, 0, TILT_OPT_MAX, .flags = V, .unit = "start" },
324 { "none", "Start immediately (default)", 0, AV_OPT_TYPE_CONST,
325 { .i64 = TILT_NONE }, INT_MIN, INT_MAX, .flags = V, .unit = "start" },
326 { "frame", "Use the first frames", 0, AV_OPT_TYPE_CONST,
327 { .i64 = TILT_FRAME }, INT_MIN, INT_MAX, .flags = V, .unit = "start" },
328 { "black", "Fill with black", 0, AV_OPT_TYPE_CONST,
329 { .i64 = TILT_BLACK }, INT_MIN, INT_MAX, .flags = V, .unit = "start" },
330
331 { "end", "Action at the end of input", OFFSET(end), AV_OPT_TYPE_INT,
332 { .i64 = TILT_NONE }, 0, TILT_OPT_MAX, .flags = V, .unit = "end" },
333 { "none", "Do not pad at the end (default)", 0, AV_OPT_TYPE_CONST,
334 { .i64 = TILT_NONE }, INT_MIN, INT_MAX, .flags = V, .unit = "end" },
335 { "frame", "Use the last frame", 0, AV_OPT_TYPE_CONST,
336 { .i64 = TILT_FRAME }, INT_MIN, INT_MAX, .flags = V, .unit = "end" },
337 { "black", "Fill with black", 0, AV_OPT_TYPE_CONST,
338 { .i64 = TILT_BLACK }, INT_MIN, INT_MAX, .flags = V, .unit = "end" },
339
340 { "hold", "Number of columns to hold at the start of the video", OFFSET(hold), AV_OPT_TYPE_INT,
341 { .i64 = 0 }, 0, INT_MAX, .flags = V, .unit = "hold" },
342 { "pad", "Number of columns to pad at the end of the video", OFFSET(pad), AV_OPT_TYPE_INT,
343 { .i64 = 0 }, 0, INT_MAX, .flags = V, .unit = "pad" },
344
345 { NULL },
346};
347
349
351 {
352 .name = "in",
353 .type = AVMEDIA_TYPE_VIDEO,
354 .filter_frame = filter_frame,
355 },
356};
357
359 {
360 .name = "out",
361 .type = AVMEDIA_TYPE_VIDEO,
362 .config_props = config_props,
363 .request_frame = request_frame,
364 },
365};
366
368 .p.name = "tiltandshift",
369 .p.description = NULL_IF_CONFIG_SMALL("Generate a tilt-and-shift'd video."),
370 .p.priv_class = &tiltandshift_class,
371 .priv_size = sizeof(TiltandshiftContext),
372 .init = init,
373 .uninit = uninit,
377};
uint8_t ptrdiff_t const uint8_t ptrdiff_t int intptr_t intptr_t int int16_t * dst
Definition dsp.h:87
static int request_frame(AVFilterLink *outlink)
Definition af_aecho.c:272
const FFFilter ff_vf_tiltandshift
static AVFormatContext * ctx
simple assert() macros that are a bit more flexible than ISO C assert().
#define av_assert0(cond)
assert() equivalent, that is always enabled.
Definition avassert.h:42
#define V
Definition avdct.c:32
int ff_filter_frame(AVFilterLink *link, AVFrame *frame)
Send a frame of data to the next filter.
Definition avfilter.c:1068
int ff_request_frame(AVFilterLink *link)
Request an input frame from the filter at the other end of the link.
Definition avfilter.c:483
Main libavfilter public API header.
#define i(width, name, range_min, range_max)
Definition cbs_h264.c:63
#define s(width, name)
Definition cbs_vp9.c:198
#define NULL
Definition coverity.c:32
static AVFrame * frame
static int filter_frame(DBEDecodeContext *s, AVFrame *frame)
Definition dolby_e.c:1067
int(* init)(AVBSFContext *ctx)
Definition dts2pts.c:608
A generic FIFO API.
@ AV_OPT_TYPE_CONST
Special option type for declaring named constants.
Definition opt.h:298
@ AV_OPT_TYPE_INT
Underlying C type is int.
Definition opt.h:258
#define AVERROR_BUG
Internal bug, also see AVERROR_BUG2.
Definition error.h:52
#define AVERROR_EOF
End of file.
Definition error.h:57
#define AVERROR(e)
Definition error.h:45
AVFifo * av_fifo_alloc2(size_t nb_elems, size_t elem_size, unsigned int flags)
Allocate and initialize an AVFifo with a given element size.
Definition fifo.c:47
void av_fifo_freep2(AVFifo **f)
Free an AVFifo and reset pointer to NULL.
Definition fifo.c:286
#define AV_FIFO_FLAG_AUTO_GROW
Automatically resize the FIFO on writes, so that the data fits.
Definition fifo.h:63
size_t av_fifo_can_read(const AVFifo *f)
Definition fifo.c:87
int av_fifo_peek(const AVFifo *f, void *buf, size_t nb_elems, size_t offset)
Read data from a FIFO without modifying FIFO state.
Definition fifo.c:255
int av_fifo_write(AVFifo *f, const void *buf, size_t nb_elems)
Write data into a FIFO.
Definition fifo.c:188
int av_fifo_read(AVFifo *f, void *buf, size_t nb_elems)
Read data from a FIFO.
Definition fifo.c:240
void av_frame_free(AVFrame **frame)
Free the frame and any dynamically allocated objects in it, e.g.
Definition frame.c:64
int av_frame_copy_props(AVFrame *dst, const AVFrame *src)
Copy only "metadata" fields from src to dst.
Definition frame.c:599
#define AV_LOG_DEBUG
Stuff which is only useful for libav* developers.
Definition log.h:231
#define AV_LOG_VERBOSE
Detailed information.
Definition log.h:226
@ AVMEDIA_TYPE_VIDEO
Definition avutil.h:200
void av_image_copy(uint8_t *const dst_data[4], const int dst_linesizes[4], const uint8_t *const src_data[4], const int src_linesizes[4], enum AVPixelFormat pix_fmt, int width, int height)
Copy image in src_data to dst_data.
Definition imgutils.c:422
int av_image_alloc(uint8_t *pointers[4], int linesizes[4], int w, int h, enum AVPixelFormat pix_fmt, int align)
Allocate an image with size w and h and pixel format pix_fmt, and fill pointers and linesizes accordi...
Definition imgutils.c:218
misc image utilities
static av_cold void uninit(AVBitStreamFilterContext *ctx)
#define FILTER_INPUTS(array)
Definition filters.h:264
#define FILTER_OUTPUTS(array)
Definition filters.h:265
#define FILTER_PIXFMTS_ARRAY(array)
Definition filters.h:244
#define AVFILTER_DEFINE_CLASS(fname)
Definition filters.h:478
#define av_cold
Definition attributes.h:117
#define NULL_IF_CONFIG_SMALL(x)
Return NULL if CONFIG_SMALL is true, otherwise the argument without modification.
Definition internal.h:88
static enum AVPixelFormat pix_fmts[]
Definition libkvazaar.c:296
const char * desc
Definition libsvtav1.c:83
uint8_t w
Definition llvidencdsp.c:39
#define FFMIN(a, b)
Definition macros.h:49
Memory handling functions.
AVOptions.
const AVPixFmtDescriptor * av_pix_fmt_desc_get(enum AVPixelFormat pix_fmt)
Definition pixdesc.c:3460
@ AVCOL_RANGE_JPEG
Full range content.
Definition pixfmt.h:783
AVPixelFormat
Pixel format.
Definition pixfmt.h:71
@ AV_PIX_FMT_NONE
Definition pixfmt.h:72
@ AV_PIX_FMT_YUV420P
planar YUV 4:2:0, 12bpp, (1 Cr & Cb sample per 2x2 Y samples)
Definition pixfmt.h:73
@ AV_PIX_FMT_YUV422P
planar YUV 4:2:2, 16bpp, (1 Cr & Cb sample per 2x1 Y samples)
Definition pixfmt.h:77
@ AV_PIX_FMT_YUVJ440P
planar YUV 4:4:0 full scale (JPEG), deprecated in favor of AV_PIX_FMT_YUV440P and setting color_range
Definition pixfmt.h:107
@ AV_PIX_FMT_YUV410P
planar YUV 4:1:0, 9bpp, (1 Cr & Cb sample per 4x4 Y samples)
Definition pixfmt.h:79
@ AV_PIX_FMT_YUV444P
planar YUV 4:4:4, 24bpp, (1 Cr & Cb sample per 1x1 Y samples)
Definition pixfmt.h:78
@ AV_PIX_FMT_YUVJ422P
planar YUV 4:2:2, 16bpp, full scale (JPEG), deprecated in favor of AV_PIX_FMT_YUV422P and setting col...
Definition pixfmt.h:86
@ AV_PIX_FMT_YUVJ444P
planar YUV 4:4:4, 24bpp, full scale (JPEG), deprecated in favor of AV_PIX_FMT_YUV444P and setting col...
Definition pixfmt.h:87
@ AV_PIX_FMT_YUVJ420P
planar YUV 4:2:0, 12bpp, full scale (JPEG), deprecated in favor of AV_PIX_FMT_YUV420P and setting col...
Definition pixfmt.h:85
static int config_props(AVBitStreamFilterLink *link)
Definition source.c:181
Describe the class of an AVClass context structure.
Definition log.h:76
Definition fifo.c:35
An instance of a filter.
Definition avfilter.h:273
void * priv
private data for use by the filter
Definition avfilter.h:288
AVFilterLink ** outputs
array of pointers to output links
Definition avfilter.h:285
A filter pad used for either input or output.
Definition filters.h:40
This structure describes decoded (raw) audio or video data.
Definition frame.h:472
AVOption.
Definition opt.h:428
Descriptor that unambiguously describes how the bits of a pixel are stored in the up to 4 data planes...
Definition pixdesc.h:69
const AVPixFmtDescriptor * desc
uint8_t * black_buffers[4]
#define av_freep(p)
#define av_log(a,...)
#define src
Definition vp8dsp.c:248
static const AVFilterPad tiltandshift_outputs[]
static int config_props(AVFilterLink *outlink)
static int output_frame(AVFilterLink *outlink)
static const AVOption tiltandshift_options[]
static int filter_frame(AVFilterLink *inlink, AVFrame *frame)
static int request_frame(AVFilterLink *outlink)
PaddingOption
@ TILT_FRAME
@ TILT_BLACK
@ TILT_OPT_MAX
@ TILT_NONE
static const AVFilterPad tiltandshift_inputs[]
static av_cold void uninit(AVFilterContext *ctx)
#define OFFSET(x)
static void copy_column(AVFilterLink *outlink, uint8_t *dst_data[4], int dst_linesizes[4], const uint8_t *src_data[4], const int src_linesizes[4], int ncol, int tilt)
AVFrame * ff_get_video_buffer(AVFilterLink *link, int w, int h)
Request a picture buffer with a specific set of permissions.
Definition video.c:89