FFmpeg coverage


Directory: ../../../ffmpeg/
File: src/libavcodec/bsf/sink.c
Date: 2026-07-21 08:37:06
Exec Total Coverage
Lines: 4 58 6.9%
Functions: 1 7 14.3%
Branches: 0 30 0.0%

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 static int return_or_keep_packet(BufferSinkContext *buf, AVPacket *out, AVPacket *in, int flags)
40 {
41 if ((flags & AV_BSF_SINK_FLAG_PEEK)) {
42 buf->peeked_pkt = in;
43 return av_packet_ref(out, in);
44 } else {
45 buf->peeked_pkt = NULL;
46 av_packet_move_ref(out, in);
47 av_packet_free(&in);
48 return 0;
49 }
50 }
51
52 int attribute_align_arg av_bsf_sink_get_packet(AVBitStreamFilterContext *ctx, AVPacket *pkt, int flags)
53 {
54 BufferSinkContext *buf = ctx->priv_data;
55 AVBitStreamFilterLink *inlink = ctx->inputs[0];
56 BitStreamFilterLinkInternal *li = ff_link_internal(inlink);
57 int status, ret;
58 AVPacket *cur_pkt;
59 int64_t pts;
60 int buffersrc_empty = 0;
61
62 if (buf->peeked_pkt)
63 return return_or_keep_packet(buf, pkt, buf->peeked_pkt, flags);
64
65 while (1) {
66 ret = ff_bsf_inlink_consume_packet(inlink, &cur_pkt);
67 if (ret < 0) {
68 return ret;
69 } else if (ret) {
70 return return_or_keep_packet(buf, pkt, cur_pkt, flags);
71 } else if (ff_bsf_inlink_acknowledge_status(inlink, &status, &pts)) {
72 return status;
73 } else if ((flags & AV_BSF_SINK_FLAG_NO_REQUEST)) {
74 return AVERROR(EAGAIN);
75 } else if (li->packet_wanted_out) {
76 ret = ff_bsf_graph_run_once(ctx->graph);
77 if (ret == FFERROR_SOURCE_EMPTY) {
78 buffersrc_empty = 1;
79 } else if (ret == AVERROR(EAGAIN)) {
80 if (buffersrc_empty)
81 return ret;
82 ff_bsf_inlink_request_packet(inlink);
83 } else if (ret < 0) {
84 return ret;
85 }
86 } else {
87 ff_bsf_inlink_request_packet(inlink);
88 }
89 }
90 }
91
92 static int init(AVBitStreamFilterContext *ctx)
93 {
94 BufferSinkContext *s = ctx->priv_data;
95
96 s->warning_limit = 100;
97
98 return 0;
99 }
100
101 3 static void uninit(AVBitStreamFilterContext *ctx)
102 {
103 3 BufferSinkContext *buf = ctx->priv_data;
104
105 3 av_packet_free(&buf->peeked_pkt);
106 3 }
107
108 static int activate(AVBitStreamFilterContext *ctx)
109 {
110 BufferSinkContext *buf = ctx->priv_data;
111 BitStreamFilterLinkInternal * const li = ff_link_internal(ctx->inputs[0]);
112
113 if (buf->warning_limit &&
114 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 return 0;
124 }
125
126 AVRational av_bsf_sink_get_time_base(const AVBitStreamFilterContext *ctx)
127 {
128 av_assert0(ff_bsf(ctx->filter)->activate == activate);
129 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