diff options
Diffstat (limited to 'libavformat/utils.c')
-rw-r--r-- | libavformat/utils.c | 263 |
1 files changed, 191 insertions, 72 deletions
diff --git a/libavformat/utils.c b/libavformat/utils.c index bbd1b2d..654bc8a 100644 --- a/libavformat/utils.c +++ b/libavformat/utils.c @@ -1,21 +1,21 @@ /* - * various utility functions for use within Libav + * various utility functions for use within FFmpeg * 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 */ @@ -25,6 +25,7 @@ #include "avio_internal.h" #include "internal.h" #include "libavcodec/internal.h" +#include "libavcodec/raw.h" #include "libavutil/opt.h" #include "libavutil/dict.h" #include "libavutil/pixdesc.h" @@ -48,7 +49,7 @@ /** * @file - * various utility functions for use within Libav + * various utility functions for use within FFmpeg */ unsigned avformat_version(void) @@ -58,13 +59,13 @@ unsigned avformat_version(void) const char *avformat_configuration(void) { - return LIBAV_CONFIGURATION; + return FFMPEG_CONFIGURATION; } const char *avformat_license(void) { #define LICENSE_PREFIX "libavformat license: " - return LICENSE_PREFIX LIBAV_LICENSE + sizeof(LICENSE_PREFIX) - 1; + return LICENSE_PREFIX FFMPEG_LICENSE + sizeof(LICENSE_PREFIX) - 1; } /* fraction handling */ @@ -304,11 +305,11 @@ int av_filename_number_test(const char *filename) return filename && (av_get_frame_filename(buf, sizeof(buf), filename, 1)>=0); } -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, score_max=0; if (lpd.buf_size > 10 && ff_id3v2_match(lpd.buf, ID3v2_DEFAULT_MAGIC)) { int id3len = ff_id3v2_tag_len(lpd.buf); @@ -316,7 +317,6 @@ AVInputFormat *av_probe_input_format2(AVProbeData *pd, int is_opened, int *score lpd.buf += id3len; lpd.buf_size -= id3len; } - id3 = 1; } fmt = NULL; @@ -326,36 +326,40 @@ AVInputFormat *av_probe_input_format2(AVProbeData *pd, int is_opened, int *score score = 0; if (fmt1->read_probe) { score = fmt1->read_probe(&lpd); + if(!score && fmt1->extensions && av_match_ext(lpd.filename, fmt1->extensions)) + score = 1; } else if (fmt1->extensions) { if (av_match_ext(lpd.filename, fmt1->extensions)) { score = 50; } } - if (score > *score_max) { - *score_max = score; + if (score > score_max) { + score_max = score; fmt = fmt1; - }else if (score == *score_max) + }else if (score == score_max) fmt = NULL; } - - /* a hack for files with huge id3v2 tags -- try to guess by file extension. */ - if (!fmt && id3 && *score_max < AVPROBE_SCORE_MAX/4) { - while ((fmt = av_iformat_next(fmt))) - if (fmt->extensions && av_match_ext(lpd.filename, fmt->extensions)) { - *score_max = AVPROBE_SCORE_MAX/4; - break; - } - } - + *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); } -static int set_codec_from_probe_data(AVFormatContext *s, AVStream *st, AVProbeData *pd, int score) +static int set_codec_from_probe_data(AVFormatContext *s, AVStream *st, AVProbeData *pd) { static const struct { const char *name; enum CodecID id; enum AVMediaType type; @@ -370,7 +374,8 @@ static int set_codec_from_probe_data(AVFormatContext *s, AVStream *st, AVProbeDa { "mpegvideo", CODEC_ID_MPEG2VIDEO, AVMEDIA_TYPE_VIDEO }, { 0 } }; - AVInputFormat *fmt = av_probe_input_format2(pd, 1, &score); + int score; + AVInputFormat *fmt = av_probe_input_format3(pd, 1, &score); if (fmt) { int i; @@ -384,7 +389,7 @@ static int set_codec_from_probe_data(AVFormatContext *s, AVStream *st, AVProbeDa } } } - return !!fmt; + return score; } /************************************************************/ @@ -453,7 +458,7 @@ int av_open_input_stream(AVFormatContext **ic_ptr, opts = convert_format_parameters(ap); if(!ap->prealloced_context) - ic = avformat_alloc_context(); + *ic_ptr = ic = avformat_alloc_context(); else ic = *ic_ptr; if (!ic) { @@ -476,6 +481,22 @@ fail: } #endif +int av_demuxer_open(AVFormatContext *ic, AVFormatParameters *ap){ + int err; + + if (ic->iformat->read_header) { + err = ic->iformat->read_header(ic, ap); + if (err < 0) + return err; + } + + if (ic->pb && !ic->data_offset) + ic->data_offset = avio_tell(ic->pb); + + return 0; +} + + /** size of probe buffer, for guessing file type from file contents */ #define PROBE_BUF_MIN 2048 #define PROBE_BUF_MAX (1<<20) @@ -529,9 +550,9 @@ int av_probe_input_buffer(AVIOContext *pb, AVInputFormat **fmt, *fmt = av_probe_input_format2(&pd, 1, &score); if(*fmt){ if(score <= AVPROBE_SCORE_MAX/4){ //this can only be true in the last iteration - av_log(logctx, AV_LOG_WARNING, "Format detected only with low score of %d, misdetection possible!\n", score); + av_log(logctx, AV_LOG_WARNING, "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); + av_log(logctx, AV_LOG_DEBUG, "Format %s probed with size=%d and score=%d\n", (*fmt)->name, probe_size, score); } } @@ -577,7 +598,8 @@ static int init_input(AVFormatContext *s, const char *filename) if (!s->iformat) return av_probe_input_buffer(s->pb, &s->iformat, filename, s, 0, 0); else if (s->iformat->flags & AVFMT_NOFILE) - return AVERROR(EINVAL); + av_log(s, AV_LOG_WARNING, "Custom AVIOContext makes no sense and " + "will be ignored with AVFMT_NOFILE format.\n"); return 0; } @@ -642,11 +664,11 @@ int avformat_open_input(AVFormatContext **ps, const char *filename, AVInputForma if (s->pb) ff_id3v2_read(s, ID3v2_DEFAULT_MAGIC); - if (s->iformat->read_header) + if (!(s->flags&AVFMT_FLAG_PRIV_OPT) && s->iformat->read_header) if ((ret = s->iformat->read_header(s, &ap)) < 0) goto fail; - if (s->pb && !s->data_offset) + if (!(s->flags&AVFMT_FLAG_PRIV_OPT) && s->pb && !s->data_offset) s->data_offset = avio_tell(s->pb); s->raw_packet_buffer_remaining_size = RAW_PACKET_BUFFER_SIZE; @@ -696,12 +718,7 @@ int av_read_packet(AVFormatContext *s, AVPacket *pkt) if (pktl) { *pkt = pktl->pkt; - if(s->streams[pkt->stream_index]->codec->codec_id != CODEC_ID_PROBE || - !s->streams[pkt->stream_index]->probe_packets || - s->raw_packet_buffer_remaining_size < pkt->size){ - AVProbeData *pd = &s->streams[pkt->stream_index]->probe_data; - av_freep(&pd->buf); - pd->buf_size = 0; + if(s->streams[pkt->stream_index]->request_probe <= 0){ s->raw_packet_buffer = pktl->next; s->raw_packet_buffer_remaining_size += pkt->size; av_free(pktl); @@ -715,9 +732,13 @@ int av_read_packet(AVFormatContext *s, AVPacket *pkt) if (!pktl || ret == AVERROR(EAGAIN)) return ret; for (i = 0; i < s->nb_streams; i++) - s->streams[i]->probe_packets = 0; + if(s->streams[i]->request_probe > 0) + s->streams[i]->request_probe = -1; continue; } + + if(!(s->flags & AVFMT_FLAG_KEEP_SIDE_DATA)) + av_packet_merge_side_data(pkt); st= s->streams[pkt->stream_index]; switch(st->codec->codec_type){ @@ -732,16 +753,16 @@ int av_read_packet(AVFormatContext *s, AVPacket *pkt) break; } - if(!pktl && (st->codec->codec_id != CODEC_ID_PROBE || - !st->probe_packets)) + if(!pktl && st->request_probe <= 0) return ret; add_to_pktbuf(&s->raw_packet_buffer, pkt, &s->raw_packet_buffer_end); s->raw_packet_buffer_remaining_size -= pkt->size; - if(st->codec->codec_id == CODEC_ID_PROBE){ + if(st->request_probe>0){ AVProbeData *pd = &st->probe_data; - av_log(s, AV_LOG_DEBUG, "probing stream %d\n", st->index); + int end; + av_log(s, AV_LOG_DEBUG, "probing stream %d pp:%d\n", st->index, st->probe_packets); --st->probe_packets; pd->buf = av_realloc(pd->buf, pd->buf_size+pkt->size+AVPROBE_PADDING_SIZE); @@ -749,13 +770,20 @@ int av_read_packet(AVFormatContext *s, AVPacket *pkt) pd->buf_size += pkt->size; memset(pd->buf+pd->buf_size, 0, AVPROBE_PADDING_SIZE); - if(av_log2(pd->buf_size) != av_log2(pd->buf_size - pkt->size)){ - //FIXME we dont reduce score to 0 for the case of running out of buffer space in bytes - set_codec_from_probe_data(s, st, pd, st->probe_packets > 0 ? AVPROBE_SCORE_MAX/4 : 0); - if(st->codec->codec_id != CODEC_ID_PROBE){ + end= s->raw_packet_buffer_remaining_size <= 0 + || st->probe_packets<=0; + + if(end || av_log2(pd->buf_size) != av_log2(pd->buf_size - pkt->size)){ + int score= set_codec_from_probe_data(s, st, pd); + if( (st->codec->codec_id != CODEC_ID_NONE && score > AVPROBE_SCORE_MAX/4) + || end){ pd->buf_size=0; av_freep(&pd->buf); + st->request_probe= -1; + if(st->codec->codec_id != CODEC_ID_NONE){ av_log(s, AV_LOG_DEBUG, "probed stream %d\n", st->index); + }else + av_log(s, AV_LOG_WARNING, "probed stream %d failed\n", st->index); } } } @@ -1141,8 +1169,9 @@ static int av_read_frame_internal(AVFormatContext *s, AVPacket *pkt) compute_pkt_fields(s, st, st->parser, pkt); if((s->iformat->flags & AVFMT_GENERIC_INDEX) && pkt->flags & AV_PKT_FLAG_KEY){ + int64_t pos= (st->parser->flags & PARSER_FLAG_COMPLETE_FRAMES) ? pkt->pos : st->parser->frame_offset; ff_reduce_index(s, st->index); - av_add_index_entry(st, st->parser->frame_offset, pkt->dts, + av_add_index_entry(st, pos, pkt->dts, 0, 0, AVINDEX_KEYFRAME); } @@ -1820,18 +1849,23 @@ static int av_has_duration(AVFormatContext *ic) */ static void av_update_stream_timings(AVFormatContext *ic) { - int64_t start_time, start_time1, end_time, end_time1; + int64_t start_time, start_time1, start_time_text, end_time, end_time1; int64_t duration, duration1; int i; AVStream *st; start_time = INT64_MAX; + start_time_text = INT64_MAX; end_time = INT64_MIN; duration = INT64_MIN; for(i = 0;i < ic->nb_streams; i++) { st = ic->streams[i]; if (st->start_time != AV_NOPTS_VALUE && st->time_base.den) { start_time1= av_rescale_q(st->start_time, st->time_base, AV_TIME_BASE_Q); + if (st->codec->codec_id == CODEC_ID_DVB_TELETEXT) { + if (start_time1 < start_time_text) + start_time_text = start_time1; + } else if (start_time1 < start_time) start_time = start_time1; if (st->duration != AV_NOPTS_VALUE) { @@ -1847,6 +1881,8 @@ static void av_update_stream_timings(AVFormatContext *ic) duration = duration1; } } + if (start_time == INT64_MAX || (start_time > start_time_text && start_time - start_time_text < AV_TIME_BASE)) + start_time = start_time_text; if (start_time != INT64_MAX) { ic->start_time = start_time; if (end_time != INT64_MIN) { @@ -2027,20 +2063,22 @@ static void av_estimate_timings(AVFormatContext *ic, int64_t old_offset) } av_update_stream_timings(ic); +#if 0 { int i; AVStream av_unused *st; for(i = 0;i < ic->nb_streams; i++) { st = ic->streams[i]; - av_dlog(ic, "%d: start_time: %0.3f duration: %0.3f\n", i, - (double) st->start_time / AV_TIME_BASE, - (double) st->duration / AV_TIME_BASE); + printf("%d: start_time: %0.3f duration: %0.3f\n", + i, (double)st->start_time / AV_TIME_BASE, + (double)st->duration / AV_TIME_BASE); } - av_dlog(ic, "stream: start_time: %0.3f duration: %0.3f bitrate=%d kb/s\n", - (double) ic->start_time / AV_TIME_BASE, - (double) ic->duration / AV_TIME_BASE, - ic->bit_rate / 1000); + printf("stream: start_time: %0.3f duration: %0.3f bitrate=%d kb/s\n", + (double)ic->start_time / AV_TIME_BASE, + (double)ic->duration / AV_TIME_BASE, + ic->bit_rate / 1000); } +#endif } static int has_codec_parameters(AVCodecContext *enc) @@ -2055,7 +2093,8 @@ static int has_codec_parameters(AVCodecContext *enc) enc->codec_id == CODEC_ID_MP1 || enc->codec_id == CODEC_ID_MP2 || enc->codec_id == CODEC_ID_MP3 || - enc->codec_id == CODEC_ID_SPEEX)) + enc->codec_id == CODEC_ID_SPEEX || + enc->codec_id == CODEC_ID_CELT)) return 0; break; case AVMEDIA_TYPE_VIDEO: @@ -2337,8 +2376,9 @@ int avformat_find_stream_info(AVFormatContext *ic, AVDictionary **options) st = ic->streams[pkt->stream_index]; if (st->codec_info_nb_frames>1) { - if (st->time_base.den > 0 && av_rescale_q(st->info->codec_info_duration, st->time_base, AV_TIME_BASE_Q) >= ic->max_analyze_duration) { - av_log(ic, AV_LOG_WARNING, "max_analyze_duration reached\n"); + int64_t t; + if (st->time_base.den > 0 && (t=av_rescale_q(st->info->codec_info_duration, st->time_base, AV_TIME_BASE_Q)) >= ic->max_analyze_duration) { + av_log(ic, AV_LOG_WARNING, "max_analyze_duration %d reached at %"PRId64"\n", ic->max_analyze_duration, t); break; } st->info->codec_info_duration += pkt->duration; @@ -2410,13 +2450,16 @@ int avformat_find_stream_info(AVFormatContext *ic, AVDictionary **options) (st->codec_info_nb_frames-2)*(int64_t)st->time_base.den, st->info->codec_info_duration*(int64_t)st->time_base.num, 60000); if (st->codec->codec_type == AVMEDIA_TYPE_VIDEO) { - if(st->codec->codec_id == CODEC_ID_RAWVIDEO && !st->codec->codec_tag && !st->codec->bits_per_coded_sample) - st->codec->codec_tag= avcodec_pix_fmt_to_codec_tag(st->codec->pix_fmt); + if(st->codec->codec_id == CODEC_ID_RAWVIDEO && !st->codec->codec_tag && !st->codec->bits_per_coded_sample){ + uint32_t tag= avcodec_pix_fmt_to_codec_tag(st->codec->pix_fmt); + if(ff_find_pix_fmt(ff_raw_pix_fmt_tags, tag) == st->codec->pix_fmt) + st->codec->codec_tag= tag; + } // the check for tb_unreliable() is not completely correct, since this is not about handling // a unreliable/inexact time base, but a time base that is finer than necessary, as e.g. // ipmovie.c produces. - if (tb_unreliable(st->codec) && st->info->duration_count > 15 && st->info->duration_gcd > 1 && !st->r_frame_rate.num) + if (tb_unreliable(st->codec) && st->info->duration_count > 15 && st->info->duration_gcd > FFMAX(1, st->time_base.den/(500LL*st->time_base.num)) && !st->r_frame_rate.num) av_reduce(&st->r_frame_rate.num, &st->r_frame_rate.den, st->time_base.den, st->time_base.num * st->info->duration_gcd, INT_MAX); if (st->info->duration_count && !st->r_frame_rate.num && tb_unreliable(st->codec) /*&& @@ -2751,8 +2794,6 @@ AVChapter *ff_new_chapter(AVFormatContext *s, int id, AVRational time_base, int6 #if FF_API_FORMAT_PARAMETERS int av_set_parameters(AVFormatContext *s, AVFormatParameters *ap) { - int ret; - if (s->oformat->priv_data_size > 0) { s->priv_data = av_mallocz(s->oformat->priv_data_size); if (!s->priv_data) @@ -2764,12 +2805,70 @@ int av_set_parameters(AVFormatContext *s, AVFormatParameters *ap) } else s->priv_data = NULL; - if (s->oformat->set_parameters) { - ret = s->oformat->set_parameters(s, ap); - if (ret < 0) - return ret; + return 0; +} +#endif + +int avformat_alloc_output_context2(AVFormatContext **avctx, AVOutputFormat *oformat, + const char *format, const char *filename) +{ + AVFormatContext *s = avformat_alloc_context(); + int ret = 0; + + *avctx = NULL; + if (!s) + goto nomem; + + if (!oformat) { + if (format) { + oformat = av_guess_format(format, NULL, NULL); + if (!oformat) { + av_log(s, AV_LOG_ERROR, "Requested output format '%s' is not a suitable output format\n", format); + ret = AVERROR(EINVAL); + goto error; + } + } else { + oformat = av_guess_format(NULL, filename, NULL); + if (!oformat) { + ret = AVERROR(EINVAL); + av_log(s, AV_LOG_ERROR, "Unable to find a suitable output format for '%s'\n", + filename); + goto error; + } + } } + + s->oformat = oformat; + if (s->oformat->priv_data_size > 0) { + s->priv_data = av_mallocz(s->oformat->priv_data_size); + if (!s->priv_data) + goto nomem; + if (s->oformat->priv_class) { + *(const AVClass**)s->priv_data= s->oformat->priv_class; + av_opt_set_defaults(s->priv_data); + } + } else + s->priv_data = NULL; + + if (filename) + av_strlcpy(s->filename, filename, sizeof(s->filename)); + *avctx = s; return 0; +nomem: + av_log(s, AV_LOG_ERROR, "Out of memory\n"); + ret = AVERROR(ENOMEM); +error: + avformat_free_context(s); + return ret; +} + +#if FF_API_ALLOC_OUTPUT_CONTEXT +AVFormatContext *avformat_alloc_output_context(const char *format, + AVOutputFormat *oformat, const char *filename) +{ + AVFormatContext *avctx; + int ret = avformat_alloc_output_context2(&avctx, oformat, format, filename); + return ret < 0 ? NULL : avctx; } #endif @@ -2987,7 +3086,7 @@ static int compute_pkt_fields2(AVFormatContext *s, AVStream *st, AVPacket *pkt){ pkt->dts= st->pts_buffer[0]; } - if(st->cur_dts && st->cur_dts != AV_NOPTS_VALUE && st->cur_dts >= pkt->dts){ + if(st->cur_dts && st->cur_dts != AV_NOPTS_VALUE && ((!(s->oformat->flags & AVFMT_TS_NONSTRICT) && st->cur_dts >= pkt->dts) || st->cur_dts > pkt->dts)){ av_log(s, AV_LOG_ERROR, "Application provided invalid, non monotonically increasing dts to muxer in stream %d: %"PRId64" >= %"PRId64"\n", st->index, st->cur_dts, pkt->dts); @@ -3162,6 +3261,8 @@ int av_interleaved_write_frame(AVFormatContext *s, AVPacket *pkt){ if(ret<0) return ret; + if(url_ferror(s->pb)) + return url_ferror(s->pb); } } @@ -3185,11 +3286,15 @@ int av_write_trailer(AVFormatContext *s) if(ret<0) goto fail; + if(url_ferror(s->pb)) + goto fail; } if(s->oformat->write_trailer) ret = s->oformat->write_trailer(s); fail: + if(ret == 0) + ret=url_ferror(s->pb); for(i=0;i<s->nb_streams;i++) { av_freep(&s->streams[i]->priv_data); av_freep(&s->streams[i]->index_entries); @@ -3200,6 +3305,15 @@ fail: return ret; } +int av_get_output_timestamp(struct AVFormatContext *s, int stream, + int64_t *dts, int64_t *wall) +{ + if (!s->oformat || !s->oformat->get_output_timestamp) + return AVERROR(ENOSYS); + s->oformat->get_output_timestamp(s, stream, dts, wall); + return 0; +} + void ff_program_add_stream_index(AVFormatContext *ac, int progid, unsigned int idx) { int i, j; @@ -3242,8 +3356,13 @@ static void dump_metadata(void *ctx, AVDictionary *m, const char *indent) av_log(ctx, AV_LOG_INFO, "%sMetadata:\n", indent); while((tag=av_dict_get(m, "", tag, AV_DICT_IGNORE_SUFFIX))) { - if(strcmp("language", tag->key)) - av_log(ctx, AV_LOG_INFO, "%s %-16s: %s\n", indent, tag->key, tag->value); + if(strcmp("language", tag->key)){ + char tmp[256]; + int i; + av_strlcpy(tmp, tag->value, sizeof(tmp)); + for(i=0; i<strlen(tmp); i++) if(tmp[i]==0xd) tmp[i]=' '; + av_log(ctx, AV_LOG_INFO, "%s %-16s: %s\n", indent, tag->key, tmp); + } } } } |