diff options
Diffstat (limited to 'libavformat/format.c')
-rw-r--r-- | libavformat/format.c | 204 |
1 files changed, 117 insertions, 87 deletions
diff --git a/libavformat/format.c b/libavformat/format.c index 24b7205d44..7df06b70fc 100644 --- a/libavformat/format.c +++ b/libavformat/format.c @@ -2,24 +2,26 @@ * Format register and lookup * Copyright (c) 2000, 2001, 2002 Fabrice Bellard * - * This file is part of Libav. + * This file is part of FFmpeg. * - * Libav is free software; you can redistribute it and/or + * FFmpeg is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * - * Libav is distributed in the hope that it will be useful, + * FFmpeg is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public - * License along with Libav; if not, write to the Free Software + * License along with FFmpeg; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ +#include "libavutil/atomic.h" #include "libavutil/avstring.h" +#include "libavutil/bprint.h" #include "libavutil/opt.h" #include "avio_internal.h" @@ -27,6 +29,7 @@ #include "id3v2.h" #include "internal.h" + /** * @file * Format register and lookup @@ -36,6 +39,9 @@ static AVInputFormat *first_iformat = NULL; /** head of registered output format linked list */ static AVOutputFormat *first_oformat = NULL; +static AVInputFormat **last_iformat = &first_iformat; +static AVOutputFormat **last_oformat = &first_oformat; + AVInputFormat *av_iformat_next(const AVInputFormat *f) { if (f) @@ -54,50 +60,34 @@ AVOutputFormat *av_oformat_next(const AVOutputFormat *f) void av_register_input_format(AVInputFormat *format) { - AVInputFormat **p = &first_iformat; - - while (*p) - p = &(*p)->next; + AVInputFormat **p = last_iformat; - *p = format; format->next = NULL; + while(*p || avpriv_atomic_ptr_cas((void * volatile *)p, NULL, format)) + p = &(*p)->next; + last_iformat = &format->next; } void av_register_output_format(AVOutputFormat *format) { - AVOutputFormat **p = &first_oformat; - - while (*p) - p = &(*p)->next; + AVOutputFormat **p = last_oformat; - *p = format; format->next = NULL; + while(*p || avpriv_atomic_ptr_cas((void * volatile *)p, NULL, format)) + p = &(*p)->next; + last_oformat = &format->next; } int av_match_ext(const char *filename, const char *extensions) { - const char *ext, *p; - char ext1[32], *q; + const char *ext; if (!filename) return 0; ext = strrchr(filename, '.'); - if (ext) { - ext++; - p = extensions; - for (;;) { - q = ext1; - while (*p != '\0' && *p != ',' && q - ext1 < sizeof(ext1) - 1) - *q++ = *p++; - *q = '\0'; - if (!av_strcasecmp(ext1, ext)) - return 1; - if (*p == '\0') - break; - p++; - } - } + if (ext) + return av_match_name(ext + 1, extensions); return 0; } @@ -120,7 +110,7 @@ AVOutputFormat *av_guess_format(const char *short_name, const char *filename, score_max = 0; while ((fmt = av_oformat_next(fmt))) { score = 0; - if (fmt->name && short_name && !av_strcasecmp(fmt->name, short_name)) + if (fmt->name && short_name && av_match_name(short_name, fmt->name)) score += 100; if (fmt->mime_type && mime_type && !strcmp(fmt->mime_type, mime_type)) score += 10; @@ -140,6 +130,12 @@ enum AVCodecID av_guess_codec(AVOutputFormat *fmt, const char *short_name, const char *filename, const char *mime_type, enum AVMediaType type) { + if (av_match_name("segment", fmt->name) || av_match_name("ssegment", fmt->name)) { + AVOutputFormat *fmt2 = av_guess_format(NULL, filename, NULL); + if (fmt2) + fmt = fmt2; + } + if (type == AVMEDIA_TYPE_VIDEO) { enum AVCodecID codec_id = AV_CODEC_ID_NONE; @@ -155,6 +151,8 @@ enum AVCodecID av_guess_codec(AVOutputFormat *fmt, const char *short_name, return fmt->audio_codec; else if (type == AVMEDIA_TYPE_SUBTITLE) return fmt->subtitle_codec; + else if (type == AVMEDIA_TYPE_DATA) + return fmt->data_codec; else return AV_CODEC_ID_NONE; } @@ -168,108 +166,123 @@ AVInputFormat *av_find_input_format(const char *short_name) return NULL; } -AVInputFormat *av_probe_input_format2(AVProbeData *pd, int is_opened, - int *score_max) +AVInputFormat *av_probe_input_format3(AVProbeData *pd, int is_opened, + int *score_ret) { AVProbeData lpd = *pd; AVInputFormat *fmt1 = NULL, *fmt; - int score, id3 = 0; + int score, nodat = 0, score_max = 0; + const static uint8_t zerobuffer[AVPROBE_PADDING_SIZE]; + + if (!lpd.buf) + lpd.buf = zerobuffer; if (lpd.buf_size > 10 && ff_id3v2_match(lpd.buf, ID3v2_DEFAULT_MAGIC)) { int id3len = ff_id3v2_tag_len(lpd.buf); if (lpd.buf_size > id3len + 16) { lpd.buf += id3len; lpd.buf_size -= id3len; - } - id3 = 1; + } else if (id3len >= PROBE_BUF_MAX) { + nodat = 2; + } else + nodat = 1; } fmt = NULL; while ((fmt1 = av_iformat_next(fmt1))) { - if (!is_opened == !(fmt1->flags & AVFMT_NOFILE)) + if (!is_opened == !(fmt1->flags & AVFMT_NOFILE) && strcmp(fmt1->name, "image2")) continue; score = 0; if (fmt1->read_probe) { score = fmt1->read_probe(&lpd); + if (score) + av_log(NULL, AV_LOG_TRACE, "Probing %s score:%d size:%d\n", fmt1->name, score, lpd.buf_size); + if (fmt1->extensions && av_match_ext(lpd.filename, fmt1->extensions)) { + if (nodat == 0) score = FFMAX(score, 1); + else if (nodat == 1) score = FFMAX(score, AVPROBE_SCORE_EXTENSION / 2 - 1); + else score = FFMAX(score, AVPROBE_SCORE_EXTENSION); + } } else if (fmt1->extensions) { if (av_match_ext(lpd.filename, fmt1->extensions)) score = AVPROBE_SCORE_EXTENSION; } if (av_match_name(lpd.mime_type, fmt1->mime_type)) score = FFMAX(score, AVPROBE_SCORE_MIME); - if (score > *score_max) { - *score_max = score; - fmt = fmt1; - } else if (score == *score_max) + if (score > score_max) { + score_max = score; + fmt = fmt1; + } else if (score == score_max) fmt = NULL; } - - // A hack for files with huge id3v2 tags -- try to guess by file extension. - if (!fmt && is_opened && *score_max < AVPROBE_SCORE_EXTENSION / 2) { - while ((fmt = av_iformat_next(fmt))) - if (fmt->extensions && - av_match_ext(lpd.filename, fmt->extensions)) { - *score_max = AVPROBE_SCORE_EXTENSION / 2; - break; - } - } - - if (!fmt && id3 && *score_max < AVPROBE_SCORE_EXTENSION / 2 - 1) { - while ((fmt = av_iformat_next(fmt))) - if (fmt->extensions && av_match_ext("mp3", fmt->extensions)) { - *score_max = AVPROBE_SCORE_EXTENSION / 2 - 1; - break; - } - } + if (nodat == 1) + score_max = FFMIN(AVPROBE_SCORE_EXTENSION / 2 - 1, score_max); + *score_ret = score_max; return fmt; } +AVInputFormat *av_probe_input_format2(AVProbeData *pd, int is_opened, int *score_max) +{ + int score_ret; + AVInputFormat *fmt = av_probe_input_format3(pd, is_opened, &score_ret); + if (score_ret > *score_max) { + *score_max = score_ret; + return fmt; + } else + return NULL; +} + AVInputFormat *av_probe_input_format(AVProbeData *pd, int is_opened) { int score = 0; return av_probe_input_format2(pd, is_opened, &score); } -/* size of probe buffer, for guessing file type from file contents */ -#define PROBE_BUF_MIN 2048 -#define PROBE_BUF_MAX (1 << 20) - -int av_probe_input_buffer(AVIOContext *pb, AVInputFormat **fmt, +int av_probe_input_buffer2(AVIOContext *pb, AVInputFormat **fmt, const char *filename, void *logctx, unsigned int offset, unsigned int max_probe_size) { AVProbeData pd = { filename ? filename : "" }; uint8_t *buf = NULL; - int ret = 0, probe_size; - uint8_t *mime_type_opt = NULL; + int ret = 0, probe_size, buf_offset = 0; + int score = 0; + int ret2; if (!max_probe_size) max_probe_size = PROBE_BUF_MAX; - else if (max_probe_size > PROBE_BUF_MAX) - max_probe_size = PROBE_BUF_MAX; - else if (max_probe_size < PROBE_BUF_MIN) + else if (max_probe_size < PROBE_BUF_MIN) { + av_log(logctx, AV_LOG_ERROR, + "Specified probe size value %u cannot be < %u\n", max_probe_size, PROBE_BUF_MIN); return AVERROR(EINVAL); + } if (offset >= max_probe_size) return AVERROR(EINVAL); - avio_skip(pb, offset); - max_probe_size -= offset; + if (pb->av_class) { + uint8_t *mime_type_opt = NULL; av_opt_get(pb, "mime_type", AV_OPT_SEARCH_CHILDREN, &mime_type_opt); pd.mime_type = (const char *)mime_type_opt; - mime_type_opt = NULL; } +#if 0 + if (!*fmt && pb->av_class && av_opt_get(pb, "mime_type", AV_OPT_SEARCH_CHILDREN, &mime_type) >= 0 && mime_type) { + if (!av_strcasecmp(mime_type, "audio/aacp")) { + *fmt = av_find_input_format("aac"); + } + av_freep(&mime_type); + } +#endif + for (probe_size = PROBE_BUF_MIN; probe_size <= max_probe_size && !*fmt; probe_size = FFMIN(probe_size << 1, FFMAX(max_probe_size, probe_size + 1))) { - int score = probe_size < max_probe_size ? AVPROBE_SCORE_MAX / 4 : 0; + score = probe_size < max_probe_size ? AVPROBE_SCORE_RETRY : 0; /* Read probe data. */ if ((ret = av_reallocp(&buf, probe_size + AVPROBE_PADDING_SIZE)) < 0) goto fail; - if ((ret = avio_read(pb, buf + pd.buf_size, - probe_size - pd.buf_size)) < 0) { + if ((ret = avio_read(pb, buf + buf_offset, + probe_size - buf_offset)) < 0) { /* Fail if error was not end of file, otherwise, lower score. */ if (ret != AVERROR_EOF) goto fail; @@ -277,8 +290,11 @@ int av_probe_input_buffer(AVIOContext *pb, AVInputFormat **fmt, score = 0; ret = 0; /* error was end of file, nothing read */ } - pd.buf_size += ret; - pd.buf = buf; + buf_offset += ret; + if (buf_offset < offset) + continue; + pd.buf_size = buf_offset - offset; + pd.buf = &buf[offset]; memset(pd.buf + pd.buf_size, 0, AVPROBE_PADDING_SIZE); @@ -286,13 +302,19 @@ int av_probe_input_buffer(AVIOContext *pb, AVInputFormat **fmt, *fmt = av_probe_input_format2(&pd, 1, &score); if (*fmt) { /* This can only be true in the last iteration. */ - if (score <= AVPROBE_SCORE_MAX / 4) { + if (score <= AVPROBE_SCORE_RETRY) { av_log(logctx, AV_LOG_WARNING, - "Format detected only with low score of %d, " - "misdetection possible!\n", score); + "Format %s detected only with low score of %d, " + "misdetection possible!\n", (*fmt)->name, score); } else av_log(logctx, AV_LOG_DEBUG, - "Probed with size=%d and score=%d\n", probe_size, score); + "Format %s probed with size=%d and score=%d\n", + (*fmt)->name, probe_size, score); +#if 0 + FILE *f = fopen("probestat.tmp", "ab"); + fprintf(f, "probe_size:%d format:%s score:%d filename:%s\n", probe_size, (*fmt)->name, score, filename); + fclose(f); +#endif } } @@ -301,10 +323,18 @@ int av_probe_input_buffer(AVIOContext *pb, AVInputFormat **fmt, fail: /* Rewind. Reuse probe buffer to avoid seeking. */ - if (ret < 0 || - (ret = ffio_rewind_with_probe_data(pb, buf, pd.buf_size)) < 0) { - av_free(buf); - } + ret2 = ffio_rewind_with_probe_data(pb, &buf, buf_offset); + if (ret >= 0) + ret = ret2; + av_freep(&pd.mime_type); - return ret; + return ret < 0 ? ret : score; +} + +int av_probe_input_buffer(AVIOContext *pb, AVInputFormat **fmt, + const char *filename, void *logctx, + unsigned int offset, unsigned int max_probe_size) +{ + int ret = av_probe_input_buffer2(pb, fmt, filename, logctx, offset, max_probe_size); + return ret < 0 ? ret : 0; } |