Coverage Report

Created: 2026-07-30 07:17

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/ffmpeg/libavcodec/bsf/source.c
Line
Count
Source
1
/*
2
 * This file is part of FFmpeg.
3
 *
4
 * FFmpeg is free software; you can redistribute it and/or
5
 * modify it under the terms of the GNU Lesser General Public
6
 * License as published by the Free Software Foundation; either
7
 * version 2.1 of the License, or (at your option) any later version.
8
 *
9
 * FFmpeg is distributed in the hope that it will be useful,
10
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
12
 * Lesser General Public License for more details.
13
 *
14
 * You should have received a copy of the GNU Lesser General Public
15
 * License along with FFmpeg; if not, write to the Free Software
16
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
17
 */
18
19
/**
20
 * @file
21
 * Packet source. Heavily based on libavfilter/buffersrc.c
22
 */
23
24
#include <float.h>
25
26
#include "libavutil/container_fifo.h"
27
#include "libavutil/opt.h"
28
29
#include "libavcodec/bsf.h"
30
#include "libavcodec/bsf_internal.h"
31
#include "libavcodec/packet.h"
32
#include "libavcodec/packet_internal.h"
33
34
typedef struct SourceContext {
35
    const AVClass    *class;
36
    AVCodecParameters *par;
37
    AVRational        time_base;     ///< time_base to set in the output link
38
39
    unsigned          nb_failed_requests;
40
    unsigned          warning_limit;
41
42
    int eof;
43
    int64_t last_pts;
44
} SourceContext;
45
46
int av_bsf_source_parameters_set(AVBitStreamFilterContext *ctx, const AVCodecParameters *par)
47
0
{
48
0
    SourceContext *s = ctx->priv_data;
49
50
0
    return avcodec_parameters_copy(s->par, par);
51
0
}
52
53
static int push_packet(AVBitStreamFilterGraph *graph)
54
0
{
55
0
    int ret;
56
57
0
    while (1) {
58
0
        ret = ff_bsf_graph_run_once(graph);
59
0
        if (ret == AVERROR(EAGAIN))
60
0
            break;
61
0
        if (ret < 0 && ret != FFERROR_SOURCE_EMPTY)
62
0
            return ret;
63
0
    }
64
0
    return 0;
65
0
}
66
67
int attribute_align_arg av_bsf_source_add_packet(AVBitStreamFilterContext *ctx, AVPacket *pkt, int flags)
68
0
{
69
0
    SourceContext *s = ctx->priv_data;
70
0
    AVPacket *copy;
71
0
    int ret;
72
73
0
    s->nb_failed_requests = 0;
74
75
0
    if (!pkt || AVPACKET_IS_EMPTY(pkt))
76
0
        return av_bsf_source_close(ctx, s->last_pts, flags);
77
0
    if (s->eof)
78
0
        return AVERROR_EOF;
79
80
0
    s->last_pts = pkt->pts + pkt->duration;
81
82
0
    copy = av_packet_alloc();
83
0
    if (!copy)
84
0
        return AVERROR(ENOMEM);
85
86
0
    if ((flags & AV_BSF_SOURCE_FLAG_KEEP_REF)) {
87
0
        ret = av_packet_ref(copy, pkt);
88
0
        if (ret < 0) {
89
0
            av_packet_free(&copy);
90
0
            return ret;
91
0
        }
92
0
    } else
93
0
        av_packet_move_ref(copy, pkt);
94
95
0
    ret = ff_bsf_filter_packet(ctx->outputs[0], copy);
96
0
    if (ret < 0)
97
0
        return ret;
98
99
0
    if ((flags & AV_BSF_SOURCE_FLAG_PUSH)) {
100
0
        ret = push_packet(ctx->graph);
101
0
        if (ret < 0)
102
0
            return ret;
103
0
    }
104
105
0
    BitStreamFilterLinkInternal *const li = ff_link_internal(ctx->outputs[0]);
106
0
    if (s->warning_limit &&
107
0
        av_container_fifo_can_read(li->fifo) >= s->warning_limit) {
108
0
        av_log(s, AV_LOG_WARNING,
109
0
               "%d buffers queued in %s, something may be wrong.\n",
110
0
               s->warning_limit,
111
0
               (char *)av_x_if_null(ctx->name, ctx->filter->name));
112
0
        s->warning_limit *= 10;
113
0
    }
114
115
0
    return 0;
116
0
}
117
118
int av_bsf_source_close(AVBitStreamFilterContext *ctx, int64_t pts, unsigned flags)
119
0
{
120
0
    SourceContext *s = ctx->priv_data;
121
122
0
    s->eof = 1;
123
0
    ff_bsf_link_set_in_status(ctx->outputs[0], AVERROR_EOF, pts);
124
0
    return 0;
125
0
}
126
127
int av_bsf_source_get_status(AVBitStreamFilterContext *ctx)
128
0
{
129
0
    SourceContext *s = ctx->priv_data;
130
131
0
    if (!s->eof && ff_bsf_outlink_get_status(ctx->outputs[0]))
132
0
        s->eof = 1;
133
134
0
    return s->eof ? AVERROR(EOF) : 0;
135
0
}
136
137
static av_cold int preinit(AVBitStreamFilterContext *ctx)
138
0
{
139
0
    SourceContext *c = ctx->priv_data;
140
141
0
    c->par = avcodec_parameters_alloc();
142
0
    if (!c->par)
143
0
        return AVERROR(ENOMEM);
144
145
0
    return 0;
146
0
}
147
148
static av_cold int init(AVBitStreamFilterContext *ctx)
149
0
{
150
0
    SourceContext *c = ctx->priv_data;
151
152
0
    if (av_q2d(c->time_base) <= 0) {
153
0
        av_log(ctx, AV_LOG_ERROR, "Invalid time base %d/%d\n", c->time_base.num, c->time_base.den);
154
0
        return AVERROR(EINVAL);
155
0
    }
156
157
0
    c->warning_limit = 100;
158
0
    return 0;
159
0
}
160
161
unsigned ff_bsf_source_get_nb_failed_requests(const AVBitStreamFilterContext *buffer_src)
162
0
{
163
0
    return ((SourceContext *)buffer_src->priv_data)->nb_failed_requests;
164
0
}
165
166
#define OFFSET(x) offsetof(SourceContext, x)
167
#define FLAGS (AV_OPT_FLAG_BSF_PARAM|AV_OPT_FLAG_AUDIO_PARAM|AV_OPT_FLAG_VIDEO_PARAM)
168
static const AVOption buffer_options[] = {
169
    { "time_base", NULL, OFFSET(time_base), AV_OPT_TYPE_RATIONAL, { .dbl = 0 }, 0, DBL_MAX, FLAGS },
170
    { NULL },
171
};
172
173
BSF_DEFINE_CLASS(buffer);
174
175
static av_cold void uninit(AVBitStreamFilterContext *ctx)
176
0
{
177
0
    SourceContext *s = ctx->priv_data;
178
0
    avcodec_parameters_free(&s->par);
179
0
}
180
181
static int config_props(AVBitStreamFilterLink *link)
182
0
{
183
0
    SourceContext *c = link->src->priv_data;
184
185
0
    link->time_base = c->time_base;
186
0
    return avcodec_parameters_copy(link->par, c->par);
187
0
}
188
189
static int activate(AVBitStreamFilterContext *ctx)
190
0
{
191
0
    AVBitStreamFilterLink *outlink = ctx->outputs[0];
192
0
    SourceContext *c = ctx->priv_data;
193
194
0
    if (!c->eof && ff_bsf_outlink_get_status(outlink)) {
195
0
        c->eof = 1;
196
0
        return 0;
197
0
    }
198
199
0
    if (c->eof) {
200
0
        ff_bsf_link_set_in_status(outlink, AVERROR_EOF, c->last_pts);
201
0
        return 0;
202
0
    }
203
0
    c->nb_failed_requests++;
204
0
    return FFERROR_SOURCE_EMPTY;
205
0
}
206
207
static const AVBitStreamFilterPad source_outputs[] = {
208
    {
209
        .name          = "default",
210
        .config_props  = config_props,
211
    },
212
};
213
214
const FFBitStreamFilter ff_source_bsf = {
215
    .p.name        = "source",
216
    .p.priv_class  = &buffer_class,
217
    .priv_data_size = sizeof(SourceContext),
218
    .activate  = activate,
219
    .preinit   = preinit,
220
    .init2     = init,
221
    .uninit    = uninit,
222
223
    BSFILTER_OUTPUTS(source_outputs),
224
};