FFmpeg coverage


Directory: ../../../ffmpeg/
File: src/libavfilter/f_reverse.c
Date: 2024-02-29 09:57:37
Exec Total Coverage
Lines: 0 147 0.0%
Functions: 0 7 0.0%
Branches: 0 84 0.0%

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