Coverage Report

Created: 2026-09-14 08:00

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/ffmpeg/libavcodec/bsf/remove_extradata.c
Line
Count
Source
1
/*
2
 * copyright (c) 2006 Michael Niedermayer <michaelni@gmx.at>
3
 *
4
 * This file is part of FFmpeg.
5
 *
6
 * FFmpeg is free software; you can redistribute it and/or
7
 * modify it under the terms of the GNU Lesser General Public
8
 * License as published by the Free Software Foundation; either
9
 * version 2.1 of the License, or (at your option) any later version.
10
 *
11
 * FFmpeg is distributed in the hope that it will be useful,
12
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14
 * Lesser General Public License for more details.
15
 *
16
 * You should have received a copy of the GNU Lesser General Public
17
 * License along with FFmpeg; if not, write to the Free Software
18
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
19
 */
20
21
#include "libavutil/log.h"
22
#include "libavutil/opt.h"
23
24
#include "libavcodec/av1_parse.h"
25
#include "libavcodec/bsf.h"
26
#include "libavcodec/bsf_internal.h"
27
#include "libavcodec/h264.h"
28
#include "libavcodec/startcode.h"
29
#include "libavcodec/vc1_common.h"
30
31
#include "libavcodec/hevc/hevc.h"
32
33
enum RemoveFreq {
34
    REMOVE_FREQ_KEYFRAME,
35
    REMOVE_FREQ_ALL,
36
    REMOVE_FREQ_NONKEYFRAME,
37
};
38
39
0
#define START_CODE 0x000001
40
41
typedef struct RemoveExtradataContext {
42
    const AVClass *class;
43
    int freq;
44
} RemoveExtradataContext;
45
46
static int av1_split(const uint8_t *buf, int buf_size, void *logctx)
47
0
{
48
0
    AV1OBU obu;
49
0
    const uint8_t *ptr = buf, *end = buf + buf_size;
50
51
0
    while (ptr < end) {
52
0
        int len = ff_av1_extract_obu(&obu, ptr, buf_size, logctx);
53
0
        if (len < 0)
54
0
            break;
55
56
0
        if (obu.type == AV1_OBU_FRAME_HEADER ||
57
0
            obu.type == AV1_OBU_FRAME) {
58
0
            return ptr - buf;
59
0
        }
60
0
        ptr      += len;
61
0
        buf_size -= len;
62
0
    }
63
64
0
    return 0;
65
0
}
66
67
static int h264_split(const uint8_t *buf, int buf_size)
68
0
{
69
0
    const uint8_t *ptr = buf, *end = buf + buf_size;
70
0
    uint32_t state = -1;
71
0
    int has_sps    = 0;
72
0
    int has_pps    = 0;
73
0
    int nalu_type;
74
75
0
    while (ptr < end) {
76
0
        ptr = avpriv_find_start_code(ptr, end, &state);
77
0
        if ((state & 0xFFFFFF00) != 0x100)
78
0
            break;
79
0
        nalu_type = state & 0x1F;
80
0
        if (nalu_type == H264_NAL_SPS) {
81
0
            has_sps = 1;
82
0
        } else if (nalu_type == H264_NAL_PPS)
83
0
            has_pps = 1;
84
        /* else if (nalu_type == 0x01 ||
85
         *     nalu_type == 0x02 ||
86
         *     nalu_type == 0x05) {
87
         *  }
88
         */
89
0
        else if ((nalu_type != H264_NAL_SEI || has_pps) &&
90
0
                  nalu_type != H264_NAL_AUD && nalu_type != H264_NAL_SPS_EXT &&
91
0
                  nalu_type != 0x0f) {
92
0
            if (has_sps) {
93
0
                while (ptr - 4 > buf && ptr[-5] == 0)
94
0
                    ptr--;
95
0
                return ptr - 4 - buf;
96
0
            }
97
0
        }
98
0
    }
99
100
0
    return 0;
101
0
}
102
103
// Split after the parameter sets at the beginning of the stream if they exist.
104
static int hevc_split(const uint8_t *buf, int buf_size)
105
0
{
106
0
    const uint8_t *ptr = buf, *end = buf + buf_size;
107
0
    uint32_t state = -1;
108
0
    int has_vps = 0;
109
0
    int has_sps = 0;
110
0
    int has_pps = 0;
111
0
    int nut;
112
113
0
    while (ptr < end) {
114
0
        ptr = avpriv_find_start_code(ptr, end, &state);
115
0
        if ((state >> 8) != START_CODE)
116
0
            break;
117
0
        nut = (state >> 1) & 0x3F;
118
0
        if (nut == HEVC_NAL_VPS)
119
0
            has_vps = 1;
120
0
        else if (nut == HEVC_NAL_SPS)
121
0
            has_sps = 1;
122
0
        else if (nut == HEVC_NAL_PPS)
123
0
            has_pps = 1;
124
0
        else if ((nut != HEVC_NAL_SEI_PREFIX || has_pps) &&
125
0
                  nut != HEVC_NAL_AUD) {
126
0
            if (has_vps && has_sps) {
127
0
                while (ptr - 4 > buf && ptr[-5] == 0)
128
0
                    ptr--;
129
0
                return ptr - 4 - buf;
130
0
            }
131
0
        }
132
0
    }
133
0
    return 0;
134
0
}
135
136
static int mpegvideo_split(const uint8_t *buf, int buf_size)
137
0
{
138
0
    uint32_t state = -1;
139
0
    int found = 0;
140
141
0
    for (int i = 0; i < buf_size; i++) {
142
0
        state = (state << 8) | buf[i];
143
0
        if (state == 0x1B3) {
144
0
            found = 1;
145
0
        } else if (found && state != 0x1B5 && state < 0x200 && state >= 0x100)
146
0
            return i - 3;
147
0
    }
148
0
    return 0;
149
0
}
150
151
static int mpeg4video_split(const uint8_t *buf, int buf_size)
152
0
{
153
0
    const uint8_t *ptr = buf, *end = buf + buf_size;
154
0
    uint32_t state = -1;
155
156
0
    while (ptr < end) {
157
0
        ptr = avpriv_find_start_code(ptr, end, &state);
158
0
        if (state == 0x1B3 || state == 0x1B6)
159
0
            return ptr - 4 - buf;
160
0
    }
161
162
0
    return 0;
163
0
}
164
165
static int vc1_split(const uint8_t *buf, int buf_size)
166
0
{
167
0
    const uint8_t *ptr = buf, *end = buf + buf_size;
168
0
    uint32_t state = -1;
169
0
    int charged = 0;
170
171
0
    while (ptr < end) {
172
0
        ptr = avpriv_find_start_code(ptr, end, &state);
173
0
        if (state == VC1_CODE_SEQHDR || state == VC1_CODE_ENTRYPOINT) {
174
0
            charged = 1;
175
0
        } else if (charged && IS_MARKER(state))
176
0
            return ptr - 4 - buf;
177
0
    }
178
179
0
    return 0;
180
0
}
181
182
static int remove_extradata(AVBSFContext *ctx, AVPacket *pkt)
183
17.1k
{
184
17.1k
    RemoveExtradataContext *s = ctx->priv_data;
185
186
17.1k
    int ret;
187
188
17.1k
    ret = ff_bsf_get_packet_ref(ctx, pkt);
189
17.1k
    if (ret < 0)
190
8.75k
        return ret;
191
192
8.36k
    if (s->freq == REMOVE_FREQ_ALL ||
193
8.36k
        (s->freq == REMOVE_FREQ_NONKEYFRAME && !(pkt->flags & AV_PKT_FLAG_KEY)) ||
194
8.36k
        (s->freq == REMOVE_FREQ_KEYFRAME && pkt->flags & AV_PKT_FLAG_KEY)) {
195
2.49k
        int i;
196
197
2.49k
        switch (ctx->par_in->codec_id) {
198
0
        case AV_CODEC_ID_AV1:
199
0
            i = av1_split(pkt->data, pkt->size, ctx);
200
0
            break;
201
0
        case AV_CODEC_ID_AVS2:
202
0
        case AV_CODEC_ID_AVS3:
203
0
        case AV_CODEC_ID_CAVS:
204
0
        case AV_CODEC_ID_MPEG4:
205
0
            i = mpeg4video_split(pkt->data, pkt->size);
206
0
            break;
207
0
        case AV_CODEC_ID_H264:
208
0
            i = h264_split(pkt->data, pkt->size);
209
0
            break;
210
0
        case AV_CODEC_ID_HEVC:
211
0
            i = hevc_split(pkt->data, pkt->size);
212
0
            break;
213
0
        case AV_CODEC_ID_MPEG1VIDEO:
214
0
        case AV_CODEC_ID_MPEG2VIDEO:
215
0
            i = mpegvideo_split(pkt->data, pkt->size);
216
0
            break;
217
0
        case AV_CODEC_ID_VC1:
218
0
            i = vc1_split(pkt->data, pkt->size);
219
0
            break;
220
2.49k
        default:
221
2.49k
            i = 0;
222
2.49k
        }
223
224
2.49k
        pkt->data += i;
225
2.49k
        pkt->size -= i;
226
2.49k
    }
227
228
8.36k
    return 0;
229
8.36k
}
230
231
#define OFFSET(x) offsetof(RemoveExtradataContext, x)
232
#define FLAGS (AV_OPT_FLAG_VIDEO_PARAM|AV_OPT_FLAG_BSF_PARAM)
233
static const AVOption options[] = {
234
    { "freq", NULL, OFFSET(freq), AV_OPT_TYPE_INT, { .i64 = REMOVE_FREQ_KEYFRAME }, REMOVE_FREQ_KEYFRAME, REMOVE_FREQ_NONKEYFRAME, FLAGS, .unit = "freq" },
235
        { "k",        NULL, 0, AV_OPT_TYPE_CONST, { .i64 = REMOVE_FREQ_NONKEYFRAME }, .flags = FLAGS, .unit = "freq" },
236
        { "keyframe", NULL, 0, AV_OPT_TYPE_CONST, { .i64 = REMOVE_FREQ_KEYFRAME }, .flags = FLAGS, .unit = "freq" },
237
        { "e",        NULL, 0, AV_OPT_TYPE_CONST, { .i64 = REMOVE_FREQ_ALL      }, .flags = FLAGS, .unit = "freq" },
238
        { "all",      NULL, 0, AV_OPT_TYPE_CONST, { .i64 = REMOVE_FREQ_ALL      }, .flags = FLAGS, .unit = "freq" },
239
    { NULL },
240
};
241
242
static const AVClass remove_extradata_class = {
243
    .class_name = "remove_extradata",
244
    .item_name  = av_default_item_name,
245
    .option     = options,
246
    .version    = LIBAVUTIL_VERSION_INT,
247
};
248
249
const FFBitStreamFilter ff_remove_extradata_bsf = {
250
    .p.name         = "remove_extra",
251
    .p.priv_class   = &remove_extradata_class,
252
    .priv_data_size = sizeof(RemoveExtradataContext),
253
    .filter         = remove_extradata,
254
};