FFmpeg coverage


Directory: ../../../ffmpeg/
File: src/libavcodec/bsf/lcevc_merge.c
Date: 2026-07-21 08:37:06
Exec Total Coverage
Lines: 5 70 7.1%
Functions: 2 9 22.2%
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 #include "libavutil/opt.h"
20
21 #include "libavcodec/bsf.h"
22 #include "libavcodec/bsf_internal.h"
23 #include "libavcodec/bsf/packetsync.h"
24 #include "libavcodec/bytestream.h"
25 #include "libavcodec/h2645_parse.h"
26 #include "libavcodec/packet.h"
27 #include "libavcodec/packet_internal.h"
28
29 typedef struct LCEVCMergeContext {
30 AVClass *class;
31 FFPacketSync ps;
32 int nal_length_size;
33 } LCEVCMergeContext;
34
35 static AVPacket *lcevc_merge_packets(AVBitStreamFilterContext *ctx,
36 AVPacket *base_pkt, const AVPacket *lcevc_pkt)
37 {
38 LCEVCMergeContext *lcevc = ctx->priv_data;
39
40 if (lcevc->nal_length_size && lcevc_pkt->size > lcevc->nal_length_size) {
41 GetByteContext bc;
42 size_t size = 0;
43
44 bytestream2_init(&bc, lcevc_pkt->data, lcevc_pkt->size);
45 do {
46 int i = 0;
47 int nal_size = get_nalsize(lcevc->nal_length_size,
48 bc.buffer, bytestream2_get_bytes_left(&bc), &i, ctx);
49 if (nal_size < 0)
50 return base_pkt;
51 if (nal_size > INT_MAX - 4)
52 return base_pkt;
53 size += nal_size + 4;
54 nal_size += i;
55 if (nal_size > bytestream2_get_bytes_left(&bc))
56 return base_pkt;
57 bytestream2_skip(&bc, nal_size);
58 } while (bytestream2_get_bytes_left(&bc) > 0);
59
60 uint8_t *buf = av_packet_new_side_data(base_pkt, AV_PKT_DATA_LCEVC, size);
61 if (!buf)
62 return base_pkt;
63
64 PutByteContext pc;
65 bytestream2_init_writer(&pc, buf, size);
66 bytestream2_init(&bc, lcevc_pkt->data, lcevc_pkt->size);
67 do {
68 int i = 0;
69 int nal_size = get_nalsize(lcevc->nal_length_size,
70 bc.buffer, bytestream2_get_bytes_left(&bc), &i, ctx);
71 bytestream2_skipu(&bc, i);
72 bytestream2_put_be32u(&pc, 1); // start code
73 bytestream2_put_bufferu(&pc, bc.buffer, nal_size);
74 bytestream2_skipu(&bc, nal_size);
75 } while (bytestream2_get_bytes_left(&bc) > 0);
76 } else {
77 uint8_t *buf = av_packet_new_side_data(base_pkt, AV_PKT_DATA_LCEVC, lcevc_pkt->size);
78 if (buf)
79 memcpy(buf, lcevc_pkt->data, lcevc_pkt->size);
80 }
81
82 return base_pkt;
83 }
84
85 static int lcevc_merge(FFPacketSync *fs)
86 {
87 AVBitStreamFilterContext *ctx = fs->parent;
88 AVPacket *base, *enhancement, *out = NULL;
89 int ret;
90
91 ret = ff_packetsync_dualinput_get(fs, &base, &enhancement);
92 if (ret < 0)
93 return ret;
94 if (!enhancement)
95 return ff_bsf_filter_packet(ctx->outputs[0], base);
96 out = lcevc_merge_packets(ctx, base, enhancement);
97 return ff_bsf_filter_packet(ctx->outputs[0], out);
98 }
99
100 static av_cold int config_enhancement(AVBitStreamFilterLink *inlink)
101 {
102 AVBitStreamFilterContext *ctx = inlink->dst;
103 LCEVCMergeContext *lcevc = ctx->priv_data;
104
105 if (inlink->par->extradata_size > 4 && inlink->par->extradata[0])
106 lcevc->nal_length_size = (inlink->par->extradata[4] >> 6) + 1;
107
108 return 0;
109 }
110
111 static int config_output(AVBitStreamFilterLink *outlink)
112 {
113 AVBitStreamFilterContext *ctx = outlink->src;
114 LCEVCMergeContext *lcevc = ctx->priv_data;
115 int ret;
116
117 ret = ff_packetsync_init_dualinput(&lcevc->ps, ctx);
118 if (ret < 0)
119 return ret;
120
121 ret = ff_packetsync_configure(&lcevc->ps);
122 outlink->time_base = lcevc->ps.time_base;
123
124 return ret;
125 }
126
127 static av_cold int init(AVBitStreamFilterContext *ctx)
128 {
129 LCEVCMergeContext *lcevc = ctx->priv_data;
130
131 lcevc->ps.on_event = lcevc_merge;
132 return 0;
133 }
134
135 3 static av_cold void uninit(AVBitStreamFilterContext *ctx)
136 {
137 3 LCEVCMergeContext *lcevc = ctx->priv_data;
138
139 3 ff_packetsync_uninit(&lcevc->ps);
140 3 }
141
142
0/2
✗ Branch 0 not taken.
✗ Branch 1 not taken.
6 PACKETSYNC_DEFINE_CLASS_EXT(lcevc_merge, LCEVCMergeContext, ps, NULL);
143
144 static int activate(AVBitStreamFilterContext *ctx)
145 {
146 LCEVCMergeContext *lcevc = ctx->priv_data;
147 return ff_packetsync_activate(&lcevc->ps);
148 }
149
150 static const enum AVCodecID enhancement_codec_ids[] = {
151 AV_CODEC_ID_LCEVC, AV_CODEC_ID_NONE,
152 };
153
154 static const AVBitStreamFilterPad lcevc_merge_inputs[] = {
155 {
156 .name = "base",
157 },
158 {
159 .name = "enhancement",
160 .codec_ids = enhancement_codec_ids,
161 .config_props = config_enhancement,
162 },
163 };
164
165 static const AVBitStreamFilterPad lcevc_merge_outputs[] = {
166 {
167 .name = "default",
168 .config_props = config_output,
169 },
170 };
171
172 const FFBitStreamFilter ff_lcevc_merge_bsf = {
173 .p.name = "lcevc_merge",
174 .p.priv_class = &lcevc_merge_class,
175 .priv_data_size = sizeof(LCEVCMergeContext),
176 .preinit = lcevc_merge_packetsync_preinit,
177 .init2 = init,
178 .uninit = uninit,
179 .activate = activate,
180 BSFILTER_INPUTS(lcevc_merge_inputs),
181 BSFILTER_OUTPUTS(lcevc_merge_outputs),
182 };
183