Coverage Report

Created: 2026-01-25 07:18

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/ffmpeg/libavformat/format.c
Line
Count
Source
1
/*
2
 * Format register and lookup
3
 * Copyright (c) 2000, 2001, 2002 Fabrice Bellard
4
 *
5
 * This file is part of FFmpeg.
6
 *
7
 * FFmpeg is free software; you can redistribute it and/or
8
 * modify it under the terms of the GNU Lesser General Public
9
 * License as published by the Free Software Foundation; either
10
 * version 2.1 of the License, or (at your option) any later version.
11
 *
12
 * FFmpeg is distributed in the hope that it will be useful,
13
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
15
 * Lesser General Public License for more details.
16
 *
17
 * You should have received a copy of the GNU Lesser General Public
18
 * License along with FFmpeg; if not, write to the Free Software
19
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
20
 */
21
22
#include "config_components.h"
23
24
#include "libavutil/avstring.h"
25
#include "libavutil/mem.h"
26
#include "libavutil/opt.h"
27
28
#include "avio_internal.h"
29
#include "avformat.h"
30
#include "demux.h"
31
#include "id3v2.h"
32
#include "internal.h"
33
#include "url.h"
34
35
36
/**
37
 * @file
38
 * Format register and lookup
39
 */
40
41
int av_match_ext(const char *filename, const char *extensions)
42
0
{
43
0
    const char *ext;
44
45
0
    if (!filename)
46
0
        return 0;
47
48
0
    ext = strrchr(filename, '.');
49
0
    if (ext)
50
0
        return av_match_name(ext + 1, extensions);
51
0
    return 0;
52
0
}
53
54
int ff_match_url_ext(const char *url, const char *extensions)
55
0
{
56
0
    const char *ext;
57
0
    URLComponents uc;
58
0
    int ret;
59
0
    char scratchpad[128];
60
61
0
    if (!url)
62
0
        return 0;
63
64
0
    ret = ff_url_decompose(&uc, url, NULL);
65
0
    if (ret < 0 || !URL_COMPONENT_HAVE(uc, scheme))
66
0
        return ret;
67
0
    for (ext = uc.query; *ext != '.' && ext > uc.path; ext--)
68
0
        ;
69
70
0
    if (*ext != '.')
71
0
        return 0;
72
0
    if (uc.query - ext > sizeof(scratchpad))
73
0
        return AVERROR(ENOMEM); //not enough memory in our scratchpad
74
0
    av_strlcpy(scratchpad, ext + 1, uc.query - ext);
75
76
0
    return av_match_name(scratchpad, extensions);
77
0
}
78
79
const AVOutputFormat *av_guess_format(const char *short_name, const char *filename,
80
                                      const char *mime_type)
81
0
{
82
0
    const AVOutputFormat *fmt = NULL;
83
0
    const AVOutputFormat *fmt_found = NULL;
84
0
    void *i = 0;
85
0
    int score_max, score;
86
87
    /* specific test for image sequences */
88
#if CONFIG_IMAGE2_MUXER
89
    if (!short_name && filename &&
90
        av_filename_number_test(filename) &&
91
        ff_guess_image2_codec(filename) != AV_CODEC_ID_NONE) {
92
        return av_guess_format("image2", NULL, NULL);
93
    }
94
#endif
95
    /* Find the proper file type. */
96
0
    score_max = 0;
97
0
    while ((fmt = av_muxer_iterate(&i))) {
98
0
        if (fmt->flags & AVFMT_EXPERIMENTAL && !short_name)
99
0
            continue;
100
0
        score = 0;
101
0
        if (fmt->name && short_name && av_match_name(short_name, fmt->name))
102
0
            score += 100;
103
0
        if (fmt->mime_type && mime_type && !strcmp(fmt->mime_type, mime_type))
104
0
            score += 10;
105
0
        if (filename && fmt->extensions &&
106
0
            av_match_ext(filename, fmt->extensions)) {
107
0
            score += 5;
108
0
        }
109
0
        if (score > score_max) {
110
0
            score_max = score;
111
0
            fmt_found = fmt;
112
0
        }
113
0
    }
114
0
    return fmt_found;
115
0
}
116
117
enum AVCodecID av_guess_codec(const AVOutputFormat *fmt, const char *short_name,
118
                              const char *filename, const char *mime_type,
119
                              enum AVMediaType type)
120
0
{
121
0
    if (av_match_name("segment", fmt->name) || av_match_name("ssegment", fmt->name)) {
122
0
        const AVOutputFormat *fmt2 = av_guess_format(NULL, filename, NULL);
123
0
        if (fmt2)
124
0
            fmt = fmt2;
125
0
    }
126
127
0
    if (type == AVMEDIA_TYPE_VIDEO) {
128
0
        enum AVCodecID codec_id = AV_CODEC_ID_NONE;
129
130
#if CONFIG_IMAGE2_MUXER || CONFIG_IMAGE2PIPE_MUXER
131
        if (!strcmp(fmt->name, "image2") || !strcmp(fmt->name, "image2pipe")) {
132
            codec_id = ff_guess_image2_codec(filename);
133
        }
134
#endif
135
0
        if (codec_id == AV_CODEC_ID_NONE)
136
0
            codec_id = fmt->video_codec;
137
0
        return codec_id;
138
0
    } else if (type == AVMEDIA_TYPE_AUDIO)
139
0
        return fmt->audio_codec;
140
0
    else if (type == AVMEDIA_TYPE_SUBTITLE)
141
0
        return fmt->subtitle_codec;
142
0
    else
143
0
        return AV_CODEC_ID_NONE;
144
0
}
145
146
const AVInputFormat *av_find_input_format(const char *short_name)
147
0
{
148
0
    const AVInputFormat *fmt = NULL;
149
0
    void *i = 0;
150
0
    while ((fmt = av_demuxer_iterate(&i)))
151
0
        if (av_match_name(short_name, fmt->name))
152
0
            return fmt;
153
0
    return NULL;
154
0
}
155
156
const AVInputFormat *av_probe_input_format3(const AVProbeData *pd,
157
                                            int is_opened, int *score_ret)
158
1.36k
{
159
1.36k
    AVProbeData lpd = *pd;
160
1.36k
    const AVInputFormat *fmt1 = NULL;
161
1.36k
    const AVInputFormat *fmt = NULL;
162
1.36k
    int score, score_max = 0;
163
1.36k
    void *i = 0;
164
1.36k
    const static uint8_t zerobuffer[AVPROBE_PADDING_SIZE];
165
1.36k
    enum nodat {
166
1.36k
        NO_ID3,
167
1.36k
        ID3_ALMOST_GREATER_PROBE,
168
1.36k
        ID3_GREATER_PROBE,
169
1.36k
        ID3_GREATER_MAX_PROBE,
170
1.36k
    } nodat = NO_ID3;
171
172
1.36k
    if (!lpd.buf)
173
1.36k
        lpd.buf = (unsigned char *) zerobuffer;
174
175
1.36k
    while (lpd.buf_size > 10 && ff_id3v2_match(lpd.buf, ID3v2_DEFAULT_MAGIC)) {
176
0
        int id3len = ff_id3v2_tag_len(lpd.buf);
177
0
        if (lpd.buf_size > id3len + 16) {
178
0
            if (lpd.buf_size < 2LL*id3len + 16)
179
0
                nodat = ID3_ALMOST_GREATER_PROBE;
180
0
            lpd.buf      += id3len;
181
0
            lpd.buf_size -= id3len;
182
0
        } else if (id3len >= PROBE_BUF_MAX) {
183
0
            nodat = ID3_GREATER_MAX_PROBE;
184
0
            break;
185
0
        } else {
186
0
            nodat = ID3_GREATER_PROBE;
187
0
            break;
188
0
        }
189
0
    }
190
191
1.36k
    while ((fmt1 = av_demuxer_iterate(&i))) {
192
0
        if (fmt1->flags & AVFMT_EXPERIMENTAL)
193
0
            continue;
194
0
        if (!is_opened == !(fmt1->flags & AVFMT_NOFILE) && strcmp(fmt1->name, "image2"))
195
0
            continue;
196
0
        score = 0;
197
0
        if (ffifmt(fmt1)->read_probe) {
198
0
            score = ffifmt(fmt1)->read_probe(&lpd);
199
0
            if (score)
200
0
                av_log(NULL, AV_LOG_TRACE, "Probing %s score:%d size:%d\n", fmt1->name, score, lpd.buf_size);
201
0
            if (fmt1->extensions && av_match_ext(lpd.filename, fmt1->extensions)) {
202
0
                switch (nodat) {
203
0
                case NO_ID3:
204
0
                    score = FFMAX(score, 1);
205
0
                    break;
206
0
                case ID3_GREATER_PROBE:
207
0
                case ID3_ALMOST_GREATER_PROBE:
208
0
                    score = FFMAX(score, AVPROBE_SCORE_EXTENSION / 2 - 1);
209
0
                    break;
210
0
                case ID3_GREATER_MAX_PROBE:
211
0
                    score = FFMAX(score, AVPROBE_SCORE_EXTENSION);
212
0
                    break;
213
0
                }
214
0
            }
215
0
        } else if (fmt1->extensions) {
216
0
            if (av_match_ext(lpd.filename, fmt1->extensions))
217
0
                score = AVPROBE_SCORE_EXTENSION;
218
0
        }
219
0
        if (av_match_name(lpd.mime_type, fmt1->mime_type)) {
220
0
            int old_score = score;
221
0
            score += AVPROBE_SCORE_MIME_BONUS;
222
0
            if (score > AVPROBE_SCORE_MAX) score = AVPROBE_SCORE_MAX;
223
0
            av_log(NULL, AV_LOG_DEBUG, "Probing %s score:%d increased to %d due to MIME type\n", fmt1->name, old_score, score);
224
0
        }
225
0
        if (score > score_max) {
226
0
            score_max = score;
227
0
            fmt       = fmt1;
228
0
        } else if (score == score_max)
229
0
            fmt = NULL;
230
0
    }
231
1.36k
    if (nodat == ID3_GREATER_PROBE)
232
0
        score_max = FFMIN(AVPROBE_SCORE_EXTENSION / 2 - 1, score_max);
233
1.36k
    *score_ret = score_max;
234
235
1.36k
    return fmt;
236
1.36k
}
237
238
const AVInputFormat *av_probe_input_format2(const AVProbeData *pd,
239
                                            int is_opened, int *score_max)
240
1.36k
{
241
1.36k
    int score_ret;
242
1.36k
    const AVInputFormat *fmt = av_probe_input_format3(pd, is_opened, &score_ret);
243
1.36k
    if (score_ret > *score_max) {
244
0
        *score_max = score_ret;
245
0
        return fmt;
246
0
    } else
247
1.36k
        return NULL;
248
1.36k
}
249
250
const AVInputFormat *av_probe_input_format(const AVProbeData *pd, int is_opened)
251
0
{
252
0
    int score = 0;
253
0
    return av_probe_input_format2(pd, is_opened, &score);
254
0
}
255
256
int av_probe_input_buffer2(AVIOContext *pb, const AVInputFormat **fmt,
257
                           const char *filename, void *logctx,
258
                           unsigned int offset, unsigned int max_probe_size)
259
0
{
260
0
    AVProbeData pd = { filename ? filename : "" };
261
0
    uint8_t *buf = NULL;
262
0
    int ret = 0, probe_size, buf_offset = 0;
263
0
    int score = 0;
264
0
    int ret2;
265
0
    int eof = 0;
266
267
0
    if (!max_probe_size)
268
0
        max_probe_size = PROBE_BUF_MAX;
269
0
    else if (max_probe_size < PROBE_BUF_MIN) {
270
0
        av_log(logctx, AV_LOG_ERROR,
271
0
               "Specified probe size value %u cannot be < %u\n", max_probe_size, PROBE_BUF_MIN);
272
0
        return AVERROR(EINVAL);
273
0
    }
274
275
0
    if (offset >= max_probe_size)
276
0
        return AVERROR(EINVAL);
277
278
0
    if (pb->av_class) {
279
0
        uint8_t *mime_type_opt = NULL;
280
0
        char *semi;
281
0
        av_opt_get(pb, "mime_type", AV_OPT_SEARCH_CHILDREN, &mime_type_opt);
282
0
        pd.mime_type = (const char *)mime_type_opt;
283
0
        semi = pd.mime_type ? strchr(pd.mime_type, ';') : NULL;
284
0
        if (semi) {
285
0
            *semi = '\0';
286
0
        }
287
0
    }
288
289
0
    for (probe_size = PROBE_BUF_MIN; probe_size <= max_probe_size && !*fmt && !eof;
290
0
         probe_size = FFMIN(probe_size << 1,
291
0
                            FFMAX(max_probe_size, probe_size + 1))) {
292
0
        score = probe_size < max_probe_size ? AVPROBE_SCORE_RETRY : 0;
293
294
        /* Read probe data. */
295
0
        if ((ret = av_reallocp(&buf, probe_size + AVPROBE_PADDING_SIZE)) < 0)
296
0
            goto fail;
297
0
        if ((ret = avio_read(pb, buf + buf_offset,
298
0
                             probe_size - buf_offset)) < 0) {
299
            /* Fail if error was not end of file, otherwise, lower score. */
300
0
            if (ret != AVERROR_EOF)
301
0
                goto fail;
302
303
0
            score = 0;
304
0
            ret   = 0;          /* error was end of file, nothing read */
305
0
            eof   = 1;
306
0
        }
307
0
        buf_offset += ret;
308
0
        if (buf_offset < offset)
309
0
            continue;
310
0
        pd.buf_size = buf_offset - offset;
311
0
        pd.buf = &buf[offset];
312
313
0
        memset(pd.buf + pd.buf_size, 0, AVPROBE_PADDING_SIZE);
314
315
        /* Guess file format. */
316
0
        *fmt = av_probe_input_format2(&pd, 1, &score);
317
0
        if (*fmt) {
318
            /* This can only be true in the last iteration. */
319
0
            if (score <= AVPROBE_SCORE_RETRY) {
320
0
                av_log(logctx, AV_LOG_WARNING,
321
0
                       "Format %s detected only with low score of %d, "
322
0
                       "misdetection possible!\n", (*fmt)->name, score);
323
0
            } else
324
0
                av_log(logctx, AV_LOG_DEBUG,
325
0
                       "Format %s probed with size=%d and score=%d\n",
326
0
                       (*fmt)->name, probe_size, score);
327
#if 0
328
            FILE *f = fopen("probestat.tmp", "ab");
329
            fprintf(f, "probe_size:%d format:%s score:%d filename:%s\n", probe_size, (*fmt)->name, score, filename);
330
            fclose(f);
331
#endif
332
0
        }
333
0
    }
334
335
0
    if (!*fmt)
336
0
        ret = AVERROR_INVALIDDATA;
337
338
0
fail:
339
    /* Rewind. Reuse probe buffer to avoid seeking. */
340
0
    ret2 = ffio_rewind_with_probe_data(pb, &buf, buf_offset);
341
0
    if (ret >= 0)
342
0
        ret = ret2;
343
344
0
    av_freep(&pd.mime_type);
345
0
    return ret < 0 ? ret : score;
346
0
}
347
348
int av_probe_input_buffer(AVIOContext *pb, const AVInputFormat **fmt,
349
                          const char *filename, void *logctx,
350
                          unsigned int offset, unsigned int max_probe_size)
351
0
{
352
0
    int ret = av_probe_input_buffer2(pb, fmt, filename, logctx, offset, max_probe_size);
353
0
    return ret < 0 ? ret : 0;
354
0
}