Coverage Report

Created: 2026-07-30 07:17

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/ffmpeg/libavcodec/bsf/sink.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 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
0
{
41
0
    if ((flags & AV_BSF_SINK_FLAG_PEEK)) {
42
0
        buf->peeked_pkt = in;
43
0
        return av_packet_ref(out, in);
44
0
    } else {
45
0
        buf->peeked_pkt = NULL;
46
0
        av_packet_move_ref(out, in);
47
0
        av_packet_free(&in);
48
0
        return 0;
49
0
    }
50
0
}
51
52
int attribute_align_arg av_bsf_sink_get_packet(AVBitStreamFilterContext *ctx, AVPacket *pkt, int flags)
53
0
{
54
0
    BufferSinkContext *buf = ctx->priv_data;
55
0
    AVBitStreamFilterLink *inlink = ctx->inputs[0];
56
0
    BitStreamFilterLinkInternal *li = ff_link_internal(inlink);
57
0
    int status, ret;
58
0
    AVPacket *cur_pkt;
59
0
    int64_t pts;
60
0
    int buffersrc_empty = 0;
61
62
0
    if (buf->peeked_pkt)
63
0
        return return_or_keep_packet(buf, pkt, buf->peeked_pkt, flags);
64
65
0
    while (1) {
66
0
        ret = ff_bsf_inlink_consume_packet(inlink, &cur_pkt);
67
0
        if (ret < 0) {
68
0
            return ret;
69
0
        } else if (ret) {
70
0
            return return_or_keep_packet(buf, pkt, cur_pkt, flags);
71
0
        } else if (ff_bsf_inlink_acknowledge_status(inlink, &status, &pts)) {
72
0
            return status;
73
0
        } else if ((flags & AV_BSF_SINK_FLAG_NO_REQUEST)) {
74
0
            return AVERROR(EAGAIN);
75
0
        } else if (li->packet_wanted_out) {
76
0
            ret = ff_bsf_graph_run_once(ctx->graph);
77
0
            if (ret == FFERROR_SOURCE_EMPTY) {
78
0
                buffersrc_empty = 1;
79
0
            } else if (ret == AVERROR(EAGAIN)) {
80
0
                if (buffersrc_empty)
81
0
                    return ret;
82
0
                ff_bsf_inlink_request_packet(inlink);
83
0
            } else if (ret < 0) {
84
0
                return ret;
85
0
            }
86
0
        } else {
87
0
            ff_bsf_inlink_request_packet(inlink);
88
0
        }
89
0
    }
90
0
}
91
92
static int init(AVBitStreamFilterContext *ctx)
93
0
{
94
0
    BufferSinkContext *s = ctx->priv_data;
95
96
0
    s->warning_limit = 100;
97
98
0
    return 0;
99
0
}
100
101
static void uninit(AVBitStreamFilterContext *ctx)
102
0
{
103
0
    BufferSinkContext *buf = ctx->priv_data;
104
105
0
    av_packet_free(&buf->peeked_pkt);
106
0
}
107
108
static int activate(AVBitStreamFilterContext *ctx)
109
0
{
110
0
    BufferSinkContext *buf = ctx->priv_data;
111
0
    BitStreamFilterLinkInternal * const li = ff_link_internal(ctx->inputs[0]);
112
113
0
    if (buf->warning_limit &&
114
0
        av_container_fifo_can_read(li->fifo) >= buf->warning_limit) {
115
0
        av_log(ctx, AV_LOG_WARNING,
116
0
               "%d buffers queued in %s, something may be wrong.\n",
117
0
               buf->warning_limit,
118
0
               (char *)av_x_if_null(ctx->name, ctx->filter->name));
119
0
        buf->warning_limit *= 10;
120
0
    }
121
122
    /* The packet is queued, the rest is up to av_bsf_sink_get_packet */
123
0
    return 0;
124
0
}
125
126
AVRational av_bsf_sink_get_time_base(const AVBitStreamFilterContext *ctx)
127
0
{
128
0
    av_assert0(ff_bsf(ctx->filter)->activate == activate);
129
0
    return ctx->inputs[0]->time_base;
130
0
}
131
132
const AVCodecParameters *av_bsf_sink_get_parameters(const AVBitStreamFilterContext *ctx)
133
0
{
134
0
    av_assert0(ff_bsf(ctx->filter)->activate == activate);
135
0
    return ctx->inputs[0]->par;
136
0
}
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
};