FFmpeg coverage


Directory: ../../../ffmpeg/
File: src/libavfilter/split.c
Date: 2024-04-25 15:36:26
Exec Total Coverage
Lines: 39 49 79.6%
Functions: 2 2 100.0%
Branches: 27 36 75.0%

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 "internal.h"
37 #include "video.h"
38
39 typedef struct SplitContext {
40 const AVClass *class;
41 int nb_outputs;
42 } SplitContext;
43
44 34 static av_cold int split_init(AVFilterContext *ctx)
45 {
46 34 SplitContext *s = ctx->priv;
47 int i, ret;
48
49
2/2
✓ Branch 0 taken 68 times.
✓ Branch 1 taken 34 times.
102 for (i = 0; i < s->nb_outputs; i++) {
50 68 AVFilterPad pad = { 0 };
51
52 68 pad.type = ctx->filter->inputs[0].type;
53 68 pad.name = av_asprintf("output%d", i);
54
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 68 times.
68 if (!pad.name)
55 return AVERROR(ENOMEM);
56
57
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 68 times.
68 if ((ret = ff_append_outpad_free_name(ctx, &pad)) < 0)
58 return ret;
59 }
60
61 34 return 0;
62 }
63
64 1649 static int activate(AVFilterContext *ctx)
65 {
66 1649 AVFilterLink *inlink = ctx->inputs[0];
67 AVFrame *in;
68 1649 int status, ret, nb_eofs = 0;
69 int64_t pts;
70
71
2/2
✓ Branch 0 taken 3298 times.
✓ Branch 1 taken 1649 times.
4947 for (int i = 0; i < ctx->nb_outputs; i++)
72 3298 nb_eofs += ff_outlink_get_status(ctx->outputs[i]) == AVERROR_EOF;
73
74
2/2
✓ Branch 0 taken 20 times.
✓ Branch 1 taken 1629 times.
1649 if (nb_eofs == ctx->nb_outputs) {
75 20 ff_inlink_set_status(inlink, AVERROR_EOF);
76 20 return 0;
77 }
78
79 1629 ret = ff_inlink_consume_frame(inlink, &in);
80
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1629 times.
1629 if (ret < 0)
81 return ret;
82
2/2
✓ Branch 0 taken 529 times.
✓ Branch 1 taken 1100 times.
1629 if (ret > 0) {
83
2/2
✓ Branch 0 taken 1058 times.
✓ Branch 1 taken 529 times.
1587 for (int i = 0; i < ctx->nb_outputs; i++) {
84 AVFrame *buf_out;
85
86
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 1058 times.
1058 if (ff_outlink_get_status(ctx->outputs[i]))
87 continue;
88 1058 buf_out = av_frame_clone(in);
89
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1058 times.
1058 if (!buf_out) {
90 ret = AVERROR(ENOMEM);
91 break;
92 }
93
94 1058 ret = ff_filter_frame(ctx->outputs[i], buf_out);
95
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1058 times.
1058 if (ret < 0)
96 break;
97 }
98
99 529 av_frame_free(&in);
100
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 529 times.
529 if (ret < 0)
101 return ret;
102 }
103
104
2/2
✓ Branch 1 taken 14 times.
✓ Branch 2 taken 1615 times.
1629 if (ff_inlink_acknowledge_status(inlink, &status, &pts)) {
105
2/2
✓ Branch 0 taken 28 times.
✓ Branch 1 taken 14 times.
42 for (int i = 0; i < ctx->nb_outputs; i++) {
106
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 28 times.
28 if (ff_outlink_get_status(ctx->outputs[i]))
107 continue;
108 28 ff_outlink_set_status(ctx->outputs[i], status, pts);
109 }
110 14 return 0;
111 }
112
113
2/2
✓ Branch 0 taken 2406 times.
✓ Branch 1 taken 529 times.
2935 for (int i = 0; i < ctx->nb_outputs; i++) {
114
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 2406 times.
2406 if (ff_outlink_get_status(ctx->outputs[i]))
115 continue;
116
117
2/2
✓ Branch 1 taken 1086 times.
✓ Branch 2 taken 1320 times.
2406 if (ff_outlink_frame_wanted(ctx->outputs[i])) {
118 1086 ff_inlink_request_frame(inlink);
119 1086 return 0;
120 }
121 }
122
123 529 return FFERROR_NOT_READY;
124 }
125
126 #define OFFSET(x) offsetof(SplitContext, x)
127 #define FLAGS (AV_OPT_FLAG_AUDIO_PARAM | AV_OPT_FLAG_VIDEO_PARAM | AV_OPT_FLAG_FILTERING_PARAM)
128 static const AVOption options[] = {
129 { "outputs", "set number of outputs", OFFSET(nb_outputs), AV_OPT_TYPE_INT, { .i64 = 2 }, 1, INT_MAX, FLAGS },
130 { NULL }
131 };
132
133 AVFILTER_DEFINE_CLASS_EXT(split, "(a)split", options);
134
135 const AVFilter ff_vf_split = {
136 .name = "split",
137 .description = NULL_IF_CONFIG_SMALL("Pass on the input to N video outputs."),
138 .priv_size = sizeof(SplitContext),
139 .priv_class = &split_class,
140 .init = split_init,
141 .activate = activate,
142 FILTER_INPUTS(ff_video_default_filterpad),
143 .outputs = NULL,
144 .flags = AVFILTER_FLAG_DYNAMIC_OUTPUTS | AVFILTER_FLAG_METADATA_ONLY,
145 };
146
147 const AVFilter ff_af_asplit = {
148 .name = "asplit",
149 .description = NULL_IF_CONFIG_SMALL("Pass on the audio input to N audio outputs."),
150 .priv_class = &split_class,
151 .priv_size = sizeof(SplitContext),
152 .init = split_init,
153 .activate = activate,
154 FILTER_INPUTS(ff_audio_default_filterpad),
155 .outputs = NULL,
156 .flags = AVFILTER_FLAG_DYNAMIC_OUTPUTS | AVFILTER_FLAG_METADATA_ONLY,
157 };
158