FFmpeg coverage


Directory: ../../../ffmpeg/
File: src/libavcodec/bsf/sink.c
Date: 2026-10-30 17:37:53
Exec Total Coverage
Lines: 45 58 77.6%
Functions: 6 7 85.7%
Branches: 19 30 63.3%

Line Branch Exec 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 sink. Heavily based on libavfilter/buffersink.c
22 */
23
24 #include "libavutil/avassert.h"
25 #include "libavutil/opt.h"
26
27 #include "libavcodec/bsf.h"
28 #include "libavcodec/bsf_internal.h"
29 #include "libavcodec/packet.h"
30 #include "libavcodec/packet_internal.h"
31
32 typedef struct BufferSinkContext {
33 const AVClass *class;
34 unsigned warning_limit;
35
36 AVPacket *peeked_pkt;
37 } BufferSinkContext;
38
39 60 static int return_or_keep_packet(BufferSinkContext *buf, AVPacket *out, AVPacket *in, int flags)
40 {
41
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 60 times.
60 if ((flags & AV_BSF_SINK_FLAG_PEEK)) {
42 ✗ buf->peeked_pkt = in;
43 ✗ return av_packet_ref(out, in);
44 } else {
45 60 buf->peeked_pkt = NULL;
46 60 av_packet_move_ref(out, in);
47 60 av_packet_free(&in);
48 60 return 0;
49 }
50 }
51
52 124 int attribute_align_arg av_bsf_sink_get_packet(AVBitStreamFilterContext *ctx, AVPacket *pkt, int flags)
53 {
54 124 BufferSinkContext *buf = ctx->priv_data;
55 124 AVBitStreamFilterLink *inlink = ctx->inputs[0];
56 124 BitStreamFilterLinkInternal *li = ff_link_internal(inlink);
57 int status, ret;
58 AVPacket *cur_pkt;
59 int64_t pts;
60 124 int buffersrc_empty = 0;
61
62
1/2
✓ Branch 0 taken 124 times.
✗ Branch 1 not taken.
124 if (buf->peeked_pkt)
63 ✗ return return_or_keep_packet(buf, pkt, buf->peeked_pkt, flags);
64
65 while (1) {
66 308 ret = ff_bsf_inlink_consume_packet(inlink, &cur_pkt);
67
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 308 times.
308 if (ret < 0) {
68 ✗ return ret;
69
2/2
✓ Branch 0 taken 60 times.
✓ Branch 1 taken 248 times.
308 } else if (ret) {
70 60 return return_or_keep_packet(buf, pkt, cur_pkt, flags);
71
2/2
✓ Branch 1 taken 4 times.
✓ Branch 2 taken 244 times.
248 } else if (ff_bsf_inlink_acknowledge_status(inlink, &status, &pts)) {
72 4 return status;
73
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 244 times.
244 } else if ((flags & AV_BSF_SINK_FLAG_NO_REQUEST)) {
74 ✗ return AVERROR(EAGAIN);
75
2/2
✓ Branch 0 taken 182 times.
✓ Branch 1 taken 62 times.
244 } else if (li->packet_wanted_out) {
76 182 ret = ff_bsf_graph_run_once(ctx->graph);
77
2/2
✓ Branch 0 taken 60 times.
✓ Branch 1 taken 122 times.
182 if (ret == FFERROR_SOURCE_EMPTY) {
78 60 buffersrc_empty = 1;
79
2/2
✓ Branch 0 taken 60 times.
✓ Branch 1 taken 62 times.
122 } else if (ret == AVERROR(EAGAIN)) {
80
1/2
✓ Branch 0 taken 60 times.
✗ Branch 1 not taken.
60 if (buffersrc_empty)
81 60 return ret;
82 ✗ ff_bsf_inlink_request_packet(inlink);
83
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 62 times.
62 } else if (ret < 0) {
84 ✗ return ret;
85 }
86 } else {
87 62 ff_bsf_inlink_request_packet(inlink);
88 }
89 }
90 }
91
92 2 static int init(AVBitStreamFilterContext *ctx)
93 {
94 2 BufferSinkContext *s = ctx->priv_data;
95
96 2 s->warning_limit = 100;
97
98 2 return 0;
99 }
100
101 7 static void uninit(AVBitStreamFilterContext *ctx)
102 {
103 7 BufferSinkContext *buf = ctx->priv_data;
104
105 7 av_packet_free(&buf->peeked_pkt);
106 7 }
107
108 60 static int activate(AVBitStreamFilterContext *ctx)
109 {
110 60 BufferSinkContext *buf = ctx->priv_data;
111 60 BitStreamFilterLinkInternal * const li = ff_link_internal(ctx->inputs[0]);
112
113
1/2
✓ Branch 0 taken 60 times.
✗ Branch 1 not taken.
60 if (buf->warning_limit &&
114
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 60 times.
60 av_container_fifo_can_read(li->fifo) >= buf->warning_limit) {
115 ✗ av_log(ctx, AV_LOG_WARNING,
116 "%d buffers queued in %s, something may be wrong.\n",
117 buf->warning_limit,
118 ✗ (char *)av_x_if_null(ctx->name, ctx->filter->name));
119 ✗ buf->warning_limit *= 10;
120 }
121
122 /* The packet is queued, the rest is up to av_bsf_sink_get_packet */
123 60 return 0;
124 }
125
126 60 AVRational av_bsf_sink_get_time_base(const AVBitStreamFilterContext *ctx)
127 {
128
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 60 times.
60 av_assert0(ff_bsf(ctx->filter)->activate == activate);
129 60 return ctx->inputs[0]->time_base;
130 }
131
132 ✗ const AVCodecParameters *av_bsf_sink_get_parameters(const AVBitStreamFilterContext *ctx)
133 {
134 ✗ av_assert0(ff_bsf(ctx->filter)->activate == activate);
135 ✗ return ctx->inputs[0]->par;
136 }
137
138 BSF_DEFINE_CLASS_EXT(sink, "sink", NULL);
139
140 const FFBitStreamFilter ff_sink_bsf = {
141 .p.name = "sink",
142 .p.priv_class = &sink_class,
143 .priv_data_size = sizeof(BufferSinkContext),
144 .init2 = init,
145 .uninit = uninit,
146 .activate = activate,
147 BSFILTER_INPUTS(ff_default_bsf_pad),
148 };
149