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
32
36
42 };
43
46
47 /* set when all input frames have been processed and we have to
48 * empty buffers, pad and then return */
50
51 /* live or static sliding */
53
54 /* initial or final actions to perform (pad/hold a frame/black/nothing) */
57
58 /* columns to hold or pad at the beginning or at the end (respectively) */
61
62 /* buffers for black columns */
65
66 /* list containing all input frames */
70
73
75 {
76 if (
s->input ==
NULL) {
78 } else {
83 }
85 return 0;
86 }
87
89 {
91 if (head) {
94 }
96 }
97
104 };
105
107 {
112 }
113
115 {
118
119 outlink->
w =
ctx->inputs[0]->w;
120 outlink->
h =
ctx->inputs[0]->h;
121 outlink->
format =
ctx->inputs[0]->format;
122
123 // when we have to pad black or a frame at the start, skip navigating
124 // the list and use either the frame or black for the requested value
126 s->hold = outlink->
w;
127
128 // Init black buffers if we pad with black at the start or at the end.
129 // For the end, we always have to init on NONE and BLACK because we never
130 // know if there are going to be enough input frames to fill an output one.
133 uint8_t black_data[] = { 0x10, 0x80, 0x80, 0x10 };
137
143 black_data[0] = black_data[3] = 0;
144
146 outlink->
h, outlink->
format, 1);
149
151 for (j = 0; j < (!
i ? outlink->
h
152 : -((-outlink->
h) >>
desc->log2_chroma_h)); j++)
153 memset(
s->black_buffers[
i] + j *
s->black_linesizes[
i],
155
157 }
158
162
163 return 0;
164 }
165
166
168 uint8_t *dst_data[4], int dst_linesizes[4],
169 const uint8_t *src_data[4], const int src_linesizes[4],
170 int ncol, int tilt)
171 {
175 const uint8_t *
src[4];
176
177 dst[0] = dst_data[0] + ncol;
178 dst[1] = dst_data[1] + (ncol >>
s->desc->log2_chroma_w);
179 dst[2] = dst_data[2] + (ncol >>
s->desc->log2_chroma_w);
180
181 if (!tilt)
182 ncol = 0;
183 src[0] = src_data[0] + ncol;
184 src[1] = src_data[1] + (ncol >>
s->desc->log2_chroma_w);
185 src[2] = src_data[2] + (ncol >>
s->desc->log2_chroma_w);
186
188 }
189
191 {
195
196 int ncol = 0;
200
201 // in case we have to do any initial black padding
203 for ( ; ncol <
s->hold; ncol++)
205 (
const uint8_t **)
s->black_buffers,
s->black_linesizes,
206 ncol, 0);
207 }
208
210 // copy a column from each input frame
211 for ( ; ncol <
s->input_size; ncol++) {
213
215 (
const uint8_t **)
src->data,
src->linesize,
217
218 // keep track of the last known frame in case we need it below
220 // advance to the next frame unless we have to hold it
223 }
224
225 // pad any remaining space with black or last frame
227 for ( ; ncol < outlink->
w; ncol++)
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++)
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
243 }
244
245 // discard frame at the top of the list since it has been fully processed
247 // and it is safe to reduce the hold value (even if unused)
249
250 // output
252 }
253
254 // This function just polls for new frames and queues them on a list
256 {
260
264 }
265
266 // load up enough frames to fill a frame and keep the queue filled on subsequent
267 // calls, until we receive EOF, and then we either pad or end
268 if (!
s->eof_recv &&
s->input_size < outlink->
w -
s->pad) {
269 av_log(
ctx,
AV_LOG_DEBUG,
"Not enough frames in the list (%zu/%d), waiting for more.\n",
s->input_size, outlink->
w -
s->pad);
270 return 0;
271 }
272
274 }
275
277 {
281
282 // signal job finished when list is empty or when padding is either
283 // limited or disabled and eof was received
284 if ((
s->input_size <= 0 ||
s->input_size == outlink->
w -
s->pad ||
s->end ==
TILT_NONE) &&
s->eof_recv) {
286 }
287
291 }
else if (
ret < 0) {
293 }
294
296 while (
s->input_size) {
301 }
302 }
303 }
304
305 return 0;
306 }
307
308 #define OFFSET(x) offsetof(TiltandshiftContext, x)
309 #define V AV_OPT_FLAG_VIDEO_PARAM
312 { .i64 = 1 }, 0, 1, .flags =
V, .unit =
"tilt" },
313
317 { .i64 =
TILT_NONE }, INT_MIN, INT_MAX, .flags =
V, .unit =
"start" },
319 { .i64 =
TILT_FRAME }, INT_MIN, INT_MAX, .flags =
V, .unit =
"start" },
321 { .i64 =
TILT_BLACK }, INT_MIN, INT_MAX, .flags =
V, .unit =
"start" },
322
326 { .i64 =
TILT_NONE }, INT_MIN, INT_MAX, .flags =
V, .unit =
"end" },
328 { .i64 =
TILT_FRAME }, INT_MIN, INT_MAX, .flags =
V, .unit =
"end" },
330 { .i64 =
TILT_BLACK }, INT_MIN, INT_MAX, .flags =
V, .unit =
"end" },
331
333 { .i64 = 0 }, 0, INT_MAX, .flags =
V, .unit =
"hold" },
335 { .i64 = 0 }, 0, INT_MAX, .flags =
V, .unit =
"pad" },
336
338 };
339
341
343 {
347 },
348 };
349
351 {
356 },
357 };
358
360 .
p.
name =
"tiltandshift",
362 .p.priv_class = &tiltandshift_class,
368 };