1 /*
2 * Copyright (c) 2015 Derek Buitenhuis
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 #include "config_components.h"
22
23 #include "libavutil/opt.h"
24 #include "avfilter.h"
25 #include "formats.h"
26 #include "internal.h"
27 #include "video.h"
28
29 #define DEFAULT_LENGTH 300
30
31 typedef struct ReverseContext {
32 int nb_frames;
33 AVFrame **frames;
34 unsigned int frames_size;
35 unsigned int pts_size;
36 int64_t *pts;
37 int flush_idx;
38 int64_t nb_samples;
39 } ReverseContext;
40
init(AVFilterContext *ctx)41 static av_cold int init(AVFilterContext *ctx)
42 {
43 ReverseContext *s = ctx->priv;
44
45 s->pts = av_fast_realloc(NULL, &s->pts_size,
46 DEFAULT_LENGTH * sizeof(*(s->pts)));
47 if (!s->pts)
48 return AVERROR(ENOMEM);
49
50 s->frames = av_fast_realloc(NULL, &s->frames_size,
51 DEFAULT_LENGTH * sizeof(*(s->frames)));
52 if (!s->frames) {
53 av_freep(&s->pts);
54 return AVERROR(ENOMEM);
55 }
56
57 return 0;
58 }
59
uninit(AVFilterContext *ctx)60 static av_cold void uninit(AVFilterContext *ctx)
61 {
62 ReverseContext *s = ctx->priv;
63
64 while (s->nb_frames > 0) {
65 av_frame_free(&s->frames[s->nb_frames - 1]);
66 s->nb_frames--;
67 }
68
69 av_freep(&s->pts);
70 av_freep(&s->frames);
71 }
72
filter_frame(AVFilterLink *inlink, AVFrame *in)73 static int filter_frame(AVFilterLink *inlink, AVFrame *in)
74 {
75 AVFilterContext *ctx = inlink->dst;
76 ReverseContext *s = ctx->priv;
77 void *ptr;
78
79 if (s->nb_frames + 1 > s->pts_size / sizeof(*(s->pts))) {
80 ptr = av_fast_realloc(s->pts, &s->pts_size, s->pts_size * 2);
81 if (!ptr)
82 return AVERROR(ENOMEM);
83 s->pts = ptr;
84 }
85
86 if (s->nb_frames + 1 > s->frames_size / sizeof(*(s->frames))) {
87 ptr = av_fast_realloc(s->frames, &s->frames_size, s->frames_size * 2);
88 if (!ptr)
89 return AVERROR(ENOMEM);
90 s->frames = ptr;
91 }
92
93 s->frames[s->nb_frames] = in;
94 s->pts[s->nb_frames] = in->pts;
95 s->nb_frames++;
96
97 return 0;
98 }
99
100 #if CONFIG_REVERSE_FILTER
101
request_frame(AVFilterLink *outlink)102 static int request_frame(AVFilterLink *outlink)
103 {
104 AVFilterContext *ctx = outlink->src;
105 ReverseContext *s = ctx->priv;
106 int ret;
107
108 ret = ff_request_frame(ctx->inputs[0]);
109
110 if (ret == AVERROR_EOF && s->nb_frames > 0) {
111 AVFrame *out = s->frames[s->nb_frames - 1];
112 out->pts = s->pts[s->flush_idx++];
113 ret = ff_filter_frame(outlink, out);
114 s->frames[s->nb_frames - 1] = NULL;
115 s->nb_frames--;
116 }
117
118 return ret;
119 }
120
121 static const AVFilterPad reverse_inputs[] = {
122 {
123 .name = "default",
124 .type = AVMEDIA_TYPE_VIDEO,
125 .filter_frame = filter_frame,
126 },
127 };
128
129 static const AVFilterPad reverse_outputs[] = {
130 {
131 .name = "default",
132 .type = AVMEDIA_TYPE_VIDEO,
133 .request_frame = request_frame,
134 },
135 };
136
137 const AVFilter ff_vf_reverse = {
138 .name = "reverse",
139 .description = NULL_IF_CONFIG_SMALL("Reverse a clip."),
140 .priv_size = sizeof(ReverseContext),
141 .init = init,
142 .uninit = uninit,
143 FILTER_INPUTS(reverse_inputs),
144 FILTER_OUTPUTS(reverse_outputs),
145 };
146
147 #endif /* CONFIG_REVERSE_FILTER */
148
149 #if CONFIG_AREVERSE_FILTER
150
reverse_samples_planar(AVFrame *out)151 static void reverse_samples_planar(AVFrame *out)
152 {
153 for (int p = 0; p < out->ch_layout.nb_channels; p++) {
154 switch (out->format) {
155 case AV_SAMPLE_FMT_U8P: {
156 uint8_t *dst = (uint8_t *)out->extended_data[p];
157 for (int i = 0, j = out->nb_samples - 1; i < j; i++, j--)
158 FFSWAP(uint8_t, dst[i], dst[j]);
159 }
160 break;
161 case AV_SAMPLE_FMT_S16P: {
162 int16_t *dst = (int16_t *)out->extended_data[p];
163 for (int i = 0, j = out->nb_samples - 1; i < j; i++, j--)
164 FFSWAP(int16_t, dst[i], dst[j]);
165 }
166 break;
167 case AV_SAMPLE_FMT_S32P: {
168 int32_t *dst = (int32_t *)out->extended_data[p];
169 for (int i = 0, j = out->nb_samples - 1; i < j; i++, j--)
170 FFSWAP(int32_t, dst[i], dst[j]);
171 }
172 break;
173 case AV_SAMPLE_FMT_S64P: {
174 int64_t *dst = (int64_t *)out->extended_data[p];
175 for (int i = 0, j = out->nb_samples - 1; i < j; i++, j--)
176 FFSWAP(int64_t, dst[i], dst[j]);
177 }
178 break;
179 case AV_SAMPLE_FMT_FLTP: {
180 float *dst = (float *)out->extended_data[p];
181 for (int i = 0, j = out->nb_samples - 1; i < j; i++, j--)
182 FFSWAP(float, dst[i], dst[j]);
183 }
184 break;
185 case AV_SAMPLE_FMT_DBLP: {
186 double *dst = (double *)out->extended_data[p];
187 for (int i = 0, j = out->nb_samples - 1; i < j; i++, j--)
188 FFSWAP(double, dst[i], dst[j]);
189 }
190 break;
191 }
192 }
193 }
194
reverse_samples_packed(AVFrame *out)195 static void reverse_samples_packed(AVFrame *out)
196 {
197 const int channels = out->ch_layout.nb_channels;
198
199 switch (out->format) {
200 case AV_SAMPLE_FMT_U8: {
201 uint8_t *dst = (uint8_t *)out->extended_data[0];
202 for (int i = 0, j = out->nb_samples - 1; i < j; i++, j--)
203 for (int p = 0; p < channels; p++)
204 FFSWAP(uint8_t, dst[i * channels + p], dst[j * channels + p]);
205 }
206 break;
207 case AV_SAMPLE_FMT_S16: {
208 int16_t *dst = (int16_t *)out->extended_data[0];
209 for (int i = 0, j = out->nb_samples - 1; i < j; i++, j--)
210 for (int p = 0; p < channels; p++)
211 FFSWAP(int16_t, dst[i * channels + p], dst[j * channels + p]);
212 }
213 break;
214 case AV_SAMPLE_FMT_S32: {
215 int32_t *dst = (int32_t *)out->extended_data[0];
216 for (int i = 0, j = out->nb_samples - 1; i < j; i++, j--)
217 for (int p = 0; p < channels; p++)
218 FFSWAP(int32_t, dst[i * channels + p], dst[j * channels + p]);
219 }
220 break;
221 case AV_SAMPLE_FMT_S64: {
222 int64_t *dst = (int64_t *)out->extended_data[0];
223 for (int i = 0, j = out->nb_samples - 1; i < j; i++, j--)
224 for (int p = 0; p < channels; p++)
225 FFSWAP(int64_t, dst[i * channels + p], dst[j * channels + p]);
226 }
227 break;
228 case AV_SAMPLE_FMT_FLT: {
229 float *dst = (float *)out->extended_data[0];
230 for (int i = 0, j = out->nb_samples - 1; i < j; i++, j--)
231 for (int p = 0; p < channels; p++)
232 FFSWAP(float, dst[i * channels + p], dst[j * channels + p]);
233 }
234 break;
235 case AV_SAMPLE_FMT_DBL: {
236 double *dst = (double *)out->extended_data[0];
237 for (int i = 0, j = out->nb_samples - 1; i < j; i++, j--)
238 for (int p = 0; p < channels; p++)
239 FFSWAP(double, dst[i * channels + p], dst[j * channels + p]);
240 }
241 break;
242 }
243 }
244
areverse_request_frame(AVFilterLink *outlink)245 static int areverse_request_frame(AVFilterLink *outlink)
246 {
247 AVFilterContext *ctx = outlink->src;
248 ReverseContext *s = ctx->priv;
249 int ret;
250
251 ret = ff_request_frame(ctx->inputs[0]);
252
253 if (ret == AVERROR_EOF && s->nb_frames > 0) {
254 AVFrame *out = s->frames[s->nb_frames - 1];
255 out->pts = s->pts[s->flush_idx++] - s->nb_samples;
256 if (s->nb_frames > 1)
257 s->nb_samples += s->pts[s->flush_idx] - s->pts[s->flush_idx - 1] - out->nb_samples;
258
259 if (av_sample_fmt_is_planar(out->format))
260 reverse_samples_planar(out);
261 else
262 reverse_samples_packed(out);
263 ret = ff_filter_frame(outlink, out);
264 s->frames[s->nb_frames - 1] = NULL;
265 s->nb_frames--;
266 }
267
268 return ret;
269 }
270
271 static const AVFilterPad areverse_inputs[] = {
272 {
273 .name = "default",
274 .type = AVMEDIA_TYPE_AUDIO,
275 .flags = AVFILTERPAD_FLAG_NEEDS_WRITABLE,
276 .filter_frame = filter_frame,
277 },
278 };
279
280 static const AVFilterPad areverse_outputs[] = {
281 {
282 .name = "default",
283 .type = AVMEDIA_TYPE_AUDIO,
284 .request_frame = areverse_request_frame,
285 },
286 };
287
288 const AVFilter ff_af_areverse = {
289 .name = "areverse",
290 .description = NULL_IF_CONFIG_SMALL("Reverse an audio clip."),
291 .priv_size = sizeof(ReverseContext),
292 .init = init,
293 .uninit = uninit,
294 FILTER_INPUTS(areverse_inputs),
295 FILTER_OUTPUTS(areverse_outputs),
296 };
297
298 #endif /* CONFIG_AREVERSE_FILTER */
299