]> git.sesse.net Git - ffmpeg/blob - libavfilter/f_reverse.c
Merge commit 'f00f6d538dcbaa122eb5e2784f41f4a299296b7b'
[ffmpeg] / libavfilter / f_reverse.c
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 "libavutil/opt.h"
22 #include "avfilter.h"
23 #include "formats.h"
24 #include "internal.h"
25 #include "video.h"
26
27 #define DEFAULT_LENGTH 300
28
29 typedef struct ReverseContext {
30     int nb_frames;
31     AVFrame **frames;
32     unsigned int frames_size;
33     unsigned int pts_size;
34     int64_t *pts;
35     int flush_idx;
36 } ReverseContext;
37
38 static av_cold int init(AVFilterContext *ctx)
39 {
40     ReverseContext *s = ctx->priv;
41
42     s->pts = av_fast_realloc(NULL, &s->pts_size,
43                              DEFAULT_LENGTH * sizeof(*(s->pts)));
44     if (!s->pts)
45         return AVERROR(ENOMEM);
46
47     s->frames = av_fast_realloc(NULL, &s->frames_size,
48                                 DEFAULT_LENGTH * sizeof(*(s->frames)));
49     if (!s->frames) {
50         av_freep(&s->pts);
51         return AVERROR(ENOMEM);
52     }
53
54     return 0;
55 }
56
57 static av_cold void uninit(AVFilterContext *ctx)
58 {
59     ReverseContext *s = ctx->priv;
60
61     av_freep(&s->pts);
62     av_freep(&s->frames);
63 }
64
65 static int config_output(AVFilterLink *outlink)
66 {
67     outlink->flags |= FF_LINK_FLAG_REQUEST_LOOP;
68     return 0;
69 }
70
71 static int filter_frame(AVFilterLink *inlink, AVFrame *in)
72 {
73     AVFilterContext *ctx = inlink->dst;
74     ReverseContext *s    = ctx->priv;
75     void *ptr;
76
77     if (s->nb_frames + 1 > s->pts_size / sizeof(*(s->pts))) {
78         ptr = av_fast_realloc(s->pts, &s->pts_size, s->pts_size * 2);
79         if (!ptr)
80             return AVERROR(ENOMEM);
81         s->pts = ptr;
82     }
83
84     if (s->nb_frames + 1 > s->frames_size / sizeof(*(s->frames))) {
85         ptr = av_fast_realloc(s->frames, &s->frames_size, s->frames_size * 2);
86         if (!ptr)
87             return AVERROR(ENOMEM);
88         s->frames = ptr;
89     }
90
91     s->frames[s->nb_frames] = in;
92     s->pts[s->nb_frames]    = in->pts;
93     s->nb_frames++;
94
95     return 0;
96 }
97
98 #if CONFIG_REVERSE_FILTER
99
100 static int request_frame(AVFilterLink *outlink)
101 {
102     AVFilterContext *ctx = outlink->src;
103     ReverseContext *s = ctx->priv;
104     int ret;
105
106     ret = ff_request_frame(ctx->inputs[0]);
107
108     if (ret == AVERROR_EOF && s->nb_frames > 0) {
109         AVFrame *out = s->frames[s->nb_frames - 1];
110         out->pts     = s->pts[s->flush_idx++];
111         ret          = ff_filter_frame(outlink, out);
112         s->nb_frames--;
113     }
114
115     return ret;
116 }
117
118 static const AVFilterPad reverse_inputs[] = {
119     {
120         .name         = "default",
121         .type         = AVMEDIA_TYPE_VIDEO,
122         .filter_frame = filter_frame,
123     },
124     { NULL }
125 };
126
127 static const AVFilterPad reverse_outputs[] = {
128     {
129         .name          = "default",
130         .type          = AVMEDIA_TYPE_VIDEO,
131         .request_frame = request_frame,
132         .config_props  = config_output,
133     },
134     { NULL }
135 };
136
137 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     .inputs      = reverse_inputs,
144     .outputs     = reverse_outputs,
145 };
146
147 #endif /* CONFIG_REVERSE_FILTER */
148
149 #if CONFIG_AREVERSE_FILTER
150
151 static int query_formats(AVFilterContext *ctx)
152 {
153     AVFilterFormats *formats;
154     AVFilterChannelLayouts *layouts;
155     int ret;
156
157     layouts = ff_all_channel_layouts();
158     if (!layouts)
159         return AVERROR(ENOMEM);
160     ret = ff_set_common_channel_layouts(ctx, layouts);
161     if (ret < 0)
162         return ret;
163
164     ret = ff_set_common_formats(ctx, ff_planar_sample_fmts());
165     if (ret < 0)
166         return ret;
167
168     formats = ff_all_samplerates();
169     if (!formats)
170         return AVERROR(ENOMEM);
171     return ff_set_common_samplerates(ctx, formats);
172 }
173
174 static int areverse_request_frame(AVFilterLink *outlink)
175 {
176     AVFilterContext *ctx = outlink->src;
177     ReverseContext *s = ctx->priv;
178     int ret, p, i, j;
179
180     ret = ff_request_frame(ctx->inputs[0]);
181
182     if (ret == AVERROR_EOF && s->nb_frames > 0) {
183         AVFrame *out = s->frames[s->nb_frames - 1];
184         out->pts     = s->pts[s->flush_idx++];
185
186         for (p = 0; p < outlink->channels; p++) {
187             switch (outlink->format) {
188             case AV_SAMPLE_FMT_U8P: {
189                 uint8_t *dst = (uint8_t *)out->extended_data[p];
190                 for (i = 0, j = out->nb_samples - 1; i < j; i++, j--)
191                     FFSWAP(uint8_t, dst[i], dst[j]);
192             }
193                 break;
194             case AV_SAMPLE_FMT_S16P: {
195                 int16_t *dst = (int16_t *)out->extended_data[p];
196                 for (i = 0, j = out->nb_samples - 1; i < j; i++, j--)
197                     FFSWAP(int16_t, dst[i], dst[j]);
198             }
199                 break;
200             case AV_SAMPLE_FMT_S32P: {
201                 int32_t *dst = (int32_t *)out->extended_data[p];
202                 for (i = 0, j = out->nb_samples - 1; i < j; i++, j--)
203                     FFSWAP(int32_t, dst[i], dst[j]);
204             }
205                 break;
206             case AV_SAMPLE_FMT_FLTP: {
207                 float *dst = (float *)out->extended_data[p];
208                 for (i = 0, j = out->nb_samples - 1; i < j; i++, j--)
209                     FFSWAP(float, dst[i], dst[j]);
210             }
211                 break;
212             case AV_SAMPLE_FMT_DBLP: {
213                 double *dst = (double *)out->extended_data[p];
214                 for (i = 0, j = out->nb_samples - 1; i < j; i++, j--)
215                     FFSWAP(double, dst[i], dst[j]);
216             }
217                 break;
218             }
219         }
220
221         ret = ff_filter_frame(outlink, out);
222         s->nb_frames--;
223     }
224
225     return ret;
226 }
227
228 static const AVFilterPad areverse_inputs[] = {
229     {
230         .name           = "default",
231         .type           = AVMEDIA_TYPE_AUDIO,
232         .filter_frame   = filter_frame,
233         .needs_writable = 1,
234     },
235     { NULL }
236 };
237
238 static const AVFilterPad areverse_outputs[] = {
239     {
240         .name          = "default",
241         .type          = AVMEDIA_TYPE_AUDIO,
242         .request_frame = areverse_request_frame,
243         .config_props  = config_output,
244     },
245     { NULL }
246 };
247
248 AVFilter ff_af_areverse = {
249     .name          = "areverse",
250     .description   = NULL_IF_CONFIG_SMALL("Reverse an audio clip."),
251     .query_formats = query_formats,
252     .priv_size     = sizeof(ReverseContext),
253     .init          = init,
254     .uninit        = uninit,
255     .inputs        = areverse_inputs,
256     .outputs       = areverse_outputs,
257 };
258
259 #endif /* CONFIG_AREVERSE_FILTER */