FFmpeg coverage


Directory: ../../../ffmpeg/
File: src/libavfilter/split.c
Date: 2025-07-28 20:30:09
Exec Total Coverage
Lines: 37 45 82.2%
Functions: 2 2 100.0%
Branches: 27 34 79.4%

Line Branch Exec Source
1 /*
2 * Copyright (c) 2007 Bobby Bingham
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
23 * audio and video splitter
24 */
25
26 #include <stdio.h>
27
28 #include "libavutil/attributes.h"
29 #include "libavutil/avstring.h"
30 #include "libavutil/internal.h"
31 #include "libavutil/opt.h"
32
33 #include "avfilter.h"
34 #include "audio.h"
35 #include "filters.h"
36 #include "video.h"
37
38 typedef struct SplitContext {
39 const AVClass *class;
40 int nb_outputs;
41 } SplitContext;
42
43 40 static av_cold int split_init(AVFilterContext *ctx)
44 {
45 40 SplitContext *s = ctx->priv;
46 int i, ret;
47
48
2/2
✓ Branch 0 taken 80 times.
✓ Branch 1 taken 40 times.
120 for (i = 0; i < s->nb_outputs; i++) {
49 80 AVFilterPad pad = { 0 };
50
51 80 pad.type = ctx->filter->inputs[0].type;
52 80 pad.name = av_asprintf("output%d", i);
53
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 80 times.
80 if (!pad.name)
54 return AVERROR(ENOMEM);
55
56
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 80 times.
80 if ((ret = ff_append_outpad_free_name(ctx, &pad)) < 0)
57 return ret;
58 }
59
60 40 return 0;
61 }
62
63 1749 static int activate(AVFilterContext *ctx)
64 {
65 1749 AVFilterLink *inlink = ctx->inputs[0];
66 AVFrame *in;
67 1749 int status, ret, nb_eofs = 0;
68 int64_t pts;
69
70
2/2
✓ Branch 0 taken 3498 times.
✓ Branch 1 taken 1749 times.
5247 for (int i = 0; i < ctx->nb_outputs; i++)
71 3498 nb_eofs += ff_outlink_get_status(ctx->outputs[i]) == AVERROR_EOF;
72
73
2/2
✓ Branch 0 taken 3 times.
✓ Branch 1 taken 1746 times.
1749 if (nb_eofs == ctx->nb_outputs) {
74 3 ff_inlink_set_status(inlink, AVERROR_EOF);
75 3 return 0;
76 }
77
78 1746 ret = ff_inlink_consume_frame(inlink, &in);
79
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1746 times.
1746 if (ret < 0)
80 return ret;
81
2/2
✓ Branch 0 taken 570 times.
✓ Branch 1 taken 1176 times.
1746 if (ret > 0) {
82
2/2
✓ Branch 0 taken 1140 times.
✓ Branch 1 taken 570 times.
1710 for (int i = 0; i < ctx->nb_outputs; i++) {
83 AVFrame *buf_out;
84
85
2/2
✓ Branch 1 taken 26 times.
✓ Branch 2 taken 1114 times.
1140 if (ff_outlink_get_status(ctx->outputs[i]))
86 26 continue;
87 1114 buf_out = av_frame_clone(in);
88
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1114 times.
1114 if (!buf_out) {
89 ret = AVERROR(ENOMEM);
90 break;
91 }
92
93 1114 ret = ff_filter_frame(ctx->outputs[i], buf_out);
94
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1114 times.
1114 if (ret < 0)
95 break;
96 }
97
98 570 av_frame_free(&in);
99
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 570 times.
570 if (ret < 0)
100 return ret;
101 570 return 0;
102 }
103
104
2/2
✓ Branch 1 taken 17 times.
✓ Branch 2 taken 1159 times.
1176 if (ff_inlink_acknowledge_status(inlink, &status, &pts)) {
105
2/2
✓ Branch 0 taken 34 times.
✓ Branch 1 taken 17 times.
51 for (int i = 0; i < ctx->nb_outputs; i++) {
106
2/2
✓ Branch 1 taken 1 times.
✓ Branch 2 taken 33 times.
34 if (ff_outlink_get_status(ctx->outputs[i]))
107 1 continue;
108 33 ff_outlink_set_status(ctx->outputs[i], status, pts);
109 }
110 17 return 0;
111 }
112
113
3/4
✓ Branch 1 taken 1159 times.
✓ Branch 2 taken 268 times.
✓ Branch 4 taken 1427 times.
✗ Branch 5 not taken.
1427 FF_FILTER_FORWARD_WANTED_ANY(ctx, inlink);
114
115 return FFERROR_NOT_READY;
116 }
117
118 #define OFFSET(x) offsetof(SplitContext, x)
119 #define FLAGS (AV_OPT_FLAG_AUDIO_PARAM | AV_OPT_FLAG_VIDEO_PARAM | AV_OPT_FLAG_FILTERING_PARAM)
120 static const AVOption options[] = {
121 { "outputs", "set number of outputs", OFFSET(nb_outputs), AV_OPT_TYPE_INT, { .i64 = 2 }, 1, INT_MAX, FLAGS },
122 { NULL }
123 };
124
125 AVFILTER_DEFINE_CLASS_EXT(split, "(a)split", options);
126
127 const FFFilter ff_vf_split = {
128 .p.name = "split",
129 .p.description = NULL_IF_CONFIG_SMALL("Pass on the input to N video outputs."),
130 .p.priv_class = &split_class,
131 .p.flags = AVFILTER_FLAG_DYNAMIC_OUTPUTS | AVFILTER_FLAG_METADATA_ONLY,
132 .priv_size = sizeof(SplitContext),
133 .init = split_init,
134 .activate = activate,
135 FILTER_INPUTS(ff_video_default_filterpad),
136 };
137
138 const FFFilter ff_af_asplit = {
139 .p.name = "asplit",
140 .p.description = NULL_IF_CONFIG_SMALL("Pass on the audio input to N audio outputs."),
141 .p.priv_class = &split_class,
142 .p.flags = AVFILTER_FLAG_DYNAMIC_OUTPUTS | AVFILTER_FLAG_METADATA_ONLY,
143 .priv_size = sizeof(SplitContext),
144 .init = split_init,
145 .activate = activate,
146 FILTER_INPUTS(ff_audio_default_filterpad),
147 };
148