X-Git-Url: https://git.sesse.net/?a=blobdiff_plain;f=libavformat%2Futils.c;h=425b4b3e688ba386545976ab8b5a0a866982837e;hb=847aaec682f2bbfaac55ee623364dd4527e0f341;hp=d12bbc26c686fd221f2d05a8a1b95e193cad29f3;hpb=f124b087eea442b65d809582527dfb5092a3463c;p=ffmpeg diff --git a/libavformat/utils.c b/libavformat/utils.c index d12bbc26c68..425b4b3e688 100644 --- a/libavformat/utils.c +++ b/libavformat/utils.c @@ -1,24 +1,28 @@ /* - * various utility functions for use within FFmpeg + * various utility functions for use within Libav * Copyright (c) 2000, 2001, 2002 Fabrice Bellard * - * This file is part of FFmpeg. + * This file is part of Libav. * - * FFmpeg is free software; you can redistribute it and/or + * Libav 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. * - * FFmpeg is distributed in the hope that it will be useful, + * Libav 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 FFmpeg; if not, write to the Free Software + * License along with Libav; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ + +/* #define DEBUG */ + #include "avformat.h" +#include "avio_internal.h" #include "internal.h" #include "libavcodec/internal.h" #include "libavutil/opt.h" @@ -27,6 +31,7 @@ #include "libavutil/avstring.h" #include "riff.h" #include "audiointerleave.h" +#include "url.h" #include #include #include @@ -40,7 +45,7 @@ /** * @file - * various utility functions for use within FFmpeg + * various utility functions for use within Libav */ unsigned avformat_version(void) @@ -50,13 +55,13 @@ unsigned avformat_version(void) const char *avformat_configuration(void) { - return FFMPEG_CONFIGURATION; + return LIBAV_CONFIGURATION; } const char *avformat_license(void) { #define LICENSE_PREFIX "libavformat license: " - return LICENSE_PREFIX FFMPEG_LICENSE + sizeof(LICENSE_PREFIX) - 1; + return LICENSE_PREFIX LIBAV_LICENSE + sizeof(LICENSE_PREFIX) - 1; } /* fraction handling */ @@ -110,15 +115,9 @@ static void av_frac_add(AVFrac *f, int64_t incr) } /** head of registered input format linked list */ -#if !FF_API_FIRST_FORMAT -static -#endif -AVInputFormat *first_iformat = NULL; +static AVInputFormat *first_iformat = NULL; /** head of registered output format linked list */ -#if !FF_API_FIRST_FORMAT -static -#endif -AVOutputFormat *first_oformat = NULL; +static AVOutputFormat *first_oformat = NULL; AVInputFormat *av_iformat_next(AVInputFormat *f) { @@ -195,14 +194,6 @@ static int match_format(const char *name, const char *names) return !strcasecmp(name, names); } -#if FF_API_GUESS_FORMAT -AVOutputFormat *guess_format(const char *short_name, const char *filename, - const char *mime_type) -{ - return av_guess_format(short_name, filename, mime_type); -} -#endif - AVOutputFormat *av_guess_format(const char *short_name, const char *filename, const char *mime_type) { @@ -213,7 +204,7 @@ AVOutputFormat *av_guess_format(const char *short_name, const char *filename, #if CONFIG_IMAGE2_MUXER if (!short_name && filename && av_filename_number_test(filename) && - av_guess_image2_codec(filename) != CODEC_ID_NONE) { + ff_guess_image2_codec(filename) != CODEC_ID_NONE) { return av_guess_format("image2", NULL, NULL); } #endif @@ -238,27 +229,6 @@ AVOutputFormat *av_guess_format(const char *short_name, const char *filename, return fmt_found; } -#if FF_API_GUESS_FORMAT -AVOutputFormat *guess_stream_format(const char *short_name, const char *filename, - const char *mime_type) -{ - AVOutputFormat *fmt = av_guess_format(short_name, filename, mime_type); - - if (fmt) { - AVOutputFormat *stream_fmt; - char stream_format_name[64]; - - snprintf(stream_format_name, sizeof(stream_format_name), "%s_stream", fmt->name); - stream_fmt = av_guess_format(stream_format_name, NULL, NULL); - - if (stream_fmt) - fmt = stream_fmt; - } - - return fmt; -} -#endif - enum CodecID av_guess_codec(AVOutputFormat *fmt, const char *short_name, const char *filename, const char *mime_type, enum AVMediaType type){ if(type == AVMEDIA_TYPE_VIDEO){ @@ -266,7 +236,7 @@ enum CodecID av_guess_codec(AVOutputFormat *fmt, const char *short_name, #if CONFIG_IMAGE2_MUXER if(!strcmp(fmt->name, "image2") || !strcmp(fmt->name, "image2pipe")){ - codec_id= av_guess_image2_codec(filename); + codec_id= ff_guess_image2_codec(filename); } #endif if(codec_id == CODEC_ID_NONE) @@ -290,49 +260,17 @@ AVInputFormat *av_find_input_format(const char *short_name) return NULL; } -#if FF_API_SYMVER && CONFIG_SHARED && HAVE_SYMVER -FF_SYMVER(void, av_destruct_packet_nofree, (AVPacket *pkt), "LIBAVFORMAT_52") -{ - av_destruct_packet_nofree(pkt); -} -FF_SYMVER(void, av_destruct_packet, (AVPacket *pkt), "LIBAVFORMAT_52") -{ - av_destruct_packet(pkt); -} - -FF_SYMVER(int, av_new_packet, (AVPacket *pkt, int size), "LIBAVFORMAT_52") -{ - return av_new_packet(pkt, size); -} - -FF_SYMVER(int, av_dup_packet, (AVPacket *pkt), "LIBAVFORMAT_52") -{ - return av_dup_packet(pkt); -} - -FF_SYMVER(void, av_free_packet, (AVPacket *pkt), "LIBAVFORMAT_52") -{ - av_free_packet(pkt); -} - -FF_SYMVER(void, av_init_packet, (AVPacket *pkt), "LIBAVFORMAT_52") -{ - av_log(NULL, AV_LOG_WARNING, "Diverting av_*_packet function calls to libavcodec. Recompile to improve performance\n"); - av_init_packet(pkt); -} -#endif - -int av_get_packet(ByteIOContext *s, AVPacket *pkt, int size) +int av_get_packet(AVIOContext *s, AVPacket *pkt, int size) { int ret= av_new_packet(pkt, size); if(ret<0) return ret; - pkt->pos= url_ftell(s); + pkt->pos= avio_tell(s); - ret= get_buffer(s, pkt->data, size); + ret= avio_read(s, pkt->data, size); if(ret<=0) av_free_packet(pkt); else @@ -341,7 +279,7 @@ int av_get_packet(ByteIOContext *s, AVPacket *pkt, int size) return ret; } -int av_append_packet(ByteIOContext *s, AVPacket *pkt, int size) +int av_append_packet(AVIOContext *s, AVPacket *pkt, int size) { int ret; int old_size; @@ -351,7 +289,7 @@ int av_append_packet(ByteIOContext *s, AVPacket *pkt, int size) ret = av_grow_packet(pkt, size); if (ret < 0) return ret; - ret = get_buffer(s, pkt->data + old_size, size); + ret = avio_read(s, pkt->data + old_size, size); av_shrink_packet(pkt, old_size + FFMAX(ret, 0)); return ret; } @@ -367,7 +305,7 @@ AVInputFormat *av_probe_input_format2(AVProbeData *pd, int is_opened, int *score { AVProbeData lpd = *pd; AVInputFormat *fmt1 = NULL, *fmt; - int score; + int score, id3 = 0; if (lpd.buf_size > 10 && ff_id3v2_match(lpd.buf, ID3v2_DEFAULT_MAGIC)) { int id3len = ff_id3v2_tag_len(lpd.buf); @@ -375,6 +313,7 @@ AVInputFormat *av_probe_input_format2(AVProbeData *pd, int is_opened, int *score lpd.buf += id3len; lpd.buf_size -= id3len; } + id3 = 1; } fmt = NULL; @@ -395,6 +334,16 @@ AVInputFormat *av_probe_input_format2(AVProbeData *pd, int is_opened, int *score }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; + } + } + return fmt; } @@ -442,7 +391,7 @@ static int set_codec_from_probe_data(AVFormatContext *s, AVStream *st, AVProbeDa * Open a media file from an IO stream. 'fmt' must be specified. */ int av_open_input_stream(AVFormatContext **ic_ptr, - ByteIOContext *pb, const char *filename, + AVIOContext *pb, const char *filename, AVInputFormat *fmt, AVFormatParameters *ap) { int err; @@ -479,7 +428,7 @@ int av_open_input_stream(AVFormatContext **ic_ptr, ic->priv_data = NULL; } - // e.g. AVFMT_NOFILE formats will not have a ByteIOContext + // e.g. AVFMT_NOFILE formats will not have a AVIOContext if (ic->pb) ff_id3v2_read(ic, ID3v2_DEFAULT_MAGIC); @@ -490,11 +439,7 @@ int av_open_input_stream(AVFormatContext **ic_ptr, } if (pb && !ic->data_offset) - ic->data_offset = url_ftell(ic->pb); - -#if FF_API_OLD_METADATA - ff_metadata_demux_compat(ic); -#endif + ic->data_offset = avio_tell(ic->pb); ic->raw_packet_buffer_remaining_size = RAW_PACKET_BUFFER_SIZE; @@ -524,7 +469,7 @@ int av_open_input_stream(AVFormatContext **ic_ptr, #define PROBE_BUF_MIN 2048 #define PROBE_BUF_MAX (1<<20) -int ff_probe_input_buffer(ByteIOContext **pb, AVInputFormat **fmt, +int av_probe_input_buffer(AVIOContext *pb, AVInputFormat **fmt, const char *filename, void *logctx, unsigned int offset, unsigned int max_probe_size) { @@ -555,7 +500,7 @@ int ff_probe_input_buffer(ByteIOContext **pb, AVInputFormat **fmt, /* read probe data */ buf = av_realloc(buf, probe_size + AVPROBE_PADDING_SIZE); - if ((ret = get_buffer(*pb, buf + buf_offset, probe_size - buf_offset)) < 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) { av_free(buf); @@ -585,7 +530,7 @@ int ff_probe_input_buffer(ByteIOContext **pb, AVInputFormat **fmt, } /* rewind. reuse probe buffer to avoid seeking */ - if ((ret = ff_rewind_with_probe_data(*pb, buf, pd.buf_size)) < 0) + if ((ret = ffio_rewind_with_probe_data(pb, buf, pd.buf_size)) < 0) av_free(buf); return ret; @@ -598,7 +543,7 @@ int av_open_input_file(AVFormatContext **ic_ptr, const char *filename, { int err; AVProbeData probe_data, *pd = &probe_data; - ByteIOContext *pb = NULL; + AVIOContext *pb = NULL; void *logctx= ap && ap->prealloced_context ? *ic_ptr : NULL; pd->filename = ""; @@ -616,13 +561,13 @@ int av_open_input_file(AVFormatContext **ic_ptr, const char *filename, hack needed to handle RTSP/TCP */ if (!fmt || !(fmt->flags & AVFMT_NOFILE)) { /* if no file needed do not try to open one */ - if ((err=url_fopen(&pb, filename, URL_RDONLY)) < 0) { + if ((err=avio_open(&pb, filename, AVIO_FLAG_READ)) < 0) { goto fail; } if (buf_size > 0) { - url_setbufsize(pb, buf_size); + ffio_set_buf_size(pb, buf_size); } - if (!fmt && (err = ff_probe_input_buffer(&pb, &fmt, filename, logctx, 0, logctx ? (*ic_ptr)->probesize : 0)) < 0) { + if (!fmt && (err = av_probe_input_buffer(pb, &fmt, filename, logctx, 0, logctx ? (*ic_ptr)->probesize : 0)) < 0) { goto fail; } } @@ -636,7 +581,7 @@ int av_open_input_file(AVFormatContext **ic_ptr, const char *filename, /* check filename in case an image number is expected */ if (fmt->flags & AVFMT_NEEDNUMBER) { if (!av_filename_number_test(filename)) { - err = AVERROR_NUMEXPECTED; + err = AVERROR(EINVAL); goto fail; } } @@ -647,7 +592,7 @@ int av_open_input_file(AVFormatContext **ic_ptr, const char *filename, fail: av_freep(&pd->buf); if (pb) - url_fclose(pb); + avio_close(pb); if (ap && ap->prealloced_context) av_free(*ic_ptr); *ic_ptr = NULL; @@ -923,17 +868,23 @@ static void compute_pkt_fields(AVFormatContext *s, AVStream *st, if((s->flags & AVFMT_FLAG_IGNDTS) && pkt->pts != AV_NOPTS_VALUE) pkt->dts= AV_NOPTS_VALUE; - if (st->codec->codec_id != CODEC_ID_H264 && pc && pc->pict_type == FF_B_TYPE) + if (st->codec->codec_id != CODEC_ID_H264 && pc && pc->pict_type == AV_PICTURE_TYPE_B) //FIXME Set low_delay = 0 when has_b_frames = 1 st->codec->has_b_frames = 1; /* do we have a video B-frame ? */ delay= st->codec->has_b_frames; presentation_delayed = 0; + + // ignore delay caused by frame threading so that the mpeg2-without-dts + // warning will not trigger + if (delay && st->codec->active_thread_type&FF_THREAD_FRAME) + delay -= st->codec->thread_count-1; + /* XXX: need has_b_frame, but cannot get it if the codec is not initialized */ if (delay && - pc && pc->pict_type != FF_B_TYPE) + pc && pc->pict_type != AV_PICTURE_TYPE_B) presentation_delayed = 1; if(pkt->pts != AV_NOPTS_VALUE && pkt->dts != AV_NOPTS_VALUE && pkt->dts > pkt->pts && st->pts_wrap_bits<63 @@ -1061,7 +1012,7 @@ static void compute_pkt_fields(AVFormatContext *s, AVStream *st, /* keyframe computation */ if (pc->key_frame == 1) pkt->flags |= AV_PKT_FLAG_KEY; - else if (pc->key_frame == -1 && pc->pict_type == FF_I_TYPE) + else if (pc->key_frame == -1 && pc->pict_type == AV_PICTURE_TYPE_I) pkt->flags |= AV_PKT_FLAG_KEY; } if (pc) @@ -1525,7 +1476,7 @@ int av_seek_frame_binary(AVFormatContext *s, int stream_index, int64_t target_ts return -1; /* do the seek */ - if ((ret = url_fseek(s->pb, pos, SEEK_SET)) < 0) + if ((ret = avio_seek(s->pb, pos, SEEK_SET)) < 0) return ret; av_update_cur_dts(s, st, ts); @@ -1551,7 +1502,7 @@ int64_t av_gen_search(AVFormatContext *s, int stream_index, int64_t target_ts, i if(ts_max == AV_NOPTS_VALUE){ int step= 1024; - filesize = url_fsize(s->pb); + filesize = avio_size(s->pb); pos_max = filesize - 1; do{ pos_max -= step; @@ -1660,12 +1611,12 @@ static int av_seek_frame_byte(AVFormatContext *s, int stream_index, int64_t pos, #endif pos_min = s->data_offset; - pos_max = url_fsize(s->pb) - 1; + pos_max = avio_size(s->pb) - 1; if (pos < pos_min) pos= pos_min; else if(pos > pos_max) pos= pos_max; - url_fseek(s->pb, pos, SEEK_SET); + avio_seek(s->pb, pos, SEEK_SET); #if 0 av_update_cur_dts(s, st, ts); @@ -1695,11 +1646,11 @@ static int av_seek_frame_generic(AVFormatContext *s, if(st->nb_index_entries){ assert(st->index_entries); ie= &st->index_entries[st->nb_index_entries-1]; - if ((ret = url_fseek(s->pb, ie->pos, SEEK_SET)) < 0) + if ((ret = avio_seek(s->pb, ie->pos, SEEK_SET)) < 0) return ret; av_update_cur_dts(s, st, ie->timestamp); }else{ - if ((ret = url_fseek(s->pb, s->data_offset, SEEK_SET)) < 0) + if ((ret = avio_seek(s->pb, s->data_offset, SEEK_SET)) < 0) return ret; } for(i=0;; i++) { @@ -1726,7 +1677,7 @@ static int av_seek_frame_generic(AVFormatContext *s, return 0; } ie = &st->index_entries[index]; - if ((ret = url_fseek(s->pb, ie->pos, SEEK_SET)) < 0) + if ((ret = avio_seek(s->pb, ie->pos, SEEK_SET)) < 0) return ret; av_update_cur_dts(s, st, ie->timestamp); @@ -1950,7 +1901,7 @@ static void av_estimate_timings_from_pts(AVFormatContext *ic, int64_t old_offset if (offset < 0) offset = 0; - url_fseek(ic->pb, offset, SEEK_SET); + avio_seek(ic->pb, offset, SEEK_SET); read_size = 0; for(;;) { if (read_size >= DURATION_MAX_READ_SIZE<<(FFMAX(retry-1,0))) @@ -1985,7 +1936,7 @@ static void av_estimate_timings_from_pts(AVFormatContext *ic, int64_t old_offset fill_all_stream_timings(ic); - url_fseek(ic->pb, old_offset, SEEK_SET); + avio_seek(ic->pb, old_offset, SEEK_SET); for (i=0; inb_streams; i++) { st= ic->streams[i]; st->cur_dts= st->first_dts; @@ -2001,7 +1952,7 @@ static void av_estimate_timings(AVFormatContext *ic, int64_t old_offset) if (ic->iformat->flags & AVFMT_NOFILE) { file_size = 0; } else { - file_size = url_fsize(ic->pb); + file_size = avio_size(ic->pb); if (file_size < 0) file_size = 0; } @@ -2009,7 +1960,7 @@ static void av_estimate_timings(AVFormatContext *ic, int64_t old_offset) if ((!strcmp(ic->iformat->name, "mpeg") || !strcmp(ic->iformat->name, "mpegts")) && - file_size && !url_is_streamed(ic->pb)) { + file_size && ic->pb->seekable) { /* get accurate estimate from the PTSes */ av_estimate_timings_from_pts(ic, old_offset); } else if (av_has_duration(ic)) { @@ -2023,22 +1974,20 @@ static void av_estimate_timings(AVFormatContext *ic, int64_t old_offset) } av_update_stream_timings(ic); -#if 0 { int i; AVStream *st; for(i = 0;i < ic->nb_streams; i++) { st = ic->streams[i]; - 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, "%d: start_time: %0.3f duration: %0.3f\n", i, + (double) st->start_time / AV_TIME_BASE, + (double) st->duration / AV_TIME_BASE); } - 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); + 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); } -#endif } static int has_codec_parameters(AVCodecContext *enc) @@ -2158,22 +2107,23 @@ enum CodecID av_codec_get_id(const AVCodecTag * const *tags, unsigned int tag) static void compute_chapters_end(AVFormatContext *s) { - unsigned int i; + unsigned int i, j; + int64_t max_time = s->duration + (s->start_time == AV_NOPTS_VALUE) ? 0 : s->start_time; - for (i=0; i+1nb_chapters; i++) + for (i = 0; i < s->nb_chapters; i++) if (s->chapters[i]->end == AV_NOPTS_VALUE) { - assert(s->chapters[i]->start <= s->chapters[i+1]->start); - assert(!av_cmp_q(s->chapters[i]->time_base, s->chapters[i+1]->time_base)); - s->chapters[i]->end = s->chapters[i+1]->start; + AVChapter *ch = s->chapters[i]; + int64_t end = max_time ? av_rescale_q(max_time, AV_TIME_BASE_Q, ch->time_base) + : INT64_MAX; + + for (j = 0; j < s->nb_chapters; j++) { + AVChapter *ch1 = s->chapters[j]; + int64_t next_start = av_rescale_q(ch1->start, ch1->time_base, ch->time_base); + if (j != i && next_start > ch->start && next_start < end) + end = next_start; + } + ch->end = (end == INT64_MAX) ? ch->start : end; } - - if (s->nb_chapters && s->chapters[i]->end == AV_NOPTS_VALUE) { - assert(s->start_time != AV_NOPTS_VALUE); - assert(s->duration > 0); - s->chapters[i]->end = av_rescale_q(s->start_time + s->duration, - AV_TIME_BASE_Q, - s->chapters[i]->time_base); - } } static int get_std_framerate(int i){ @@ -2206,7 +2156,7 @@ int av_find_stream_info(AVFormatContext *ic) int i, count, ret, read_size, j; AVStream *st; AVPacket pkt1, *pkt; - int64_t old_offset = url_ftell(ic->pb); + int64_t old_offset = avio_tell(ic->pb); for(i=0;inb_streams;i++) { AVCodec *codec; @@ -2260,19 +2210,27 @@ int av_find_stream_info(AVFormatContext *ic) read_size = 0; for(;;) { if(url_interrupt_cb()){ - ret= AVERROR(EINTR); + ret= AVERROR_EXIT; av_log(ic, AV_LOG_DEBUG, "interrupted\n"); break; } /* check if one codec still needs to be handled */ for(i=0;inb_streams;i++) { + int fps_analyze_framecount = 20; + st = ic->streams[i]; if (!has_codec_parameters(st->codec)) break; + /* if the timebase is coarse (like the usual millisecond precision + of mkv), we need to analyze more frames to reliably arrive at + the correct fps */ + if (av_q2d(st->time_base) > 0.0005) + fps_analyze_framecount *= 2; /* variable fps and no guess at the real fps */ if( tb_unreliable(st->codec) && !(st->r_frame_rate.num && st->avg_frame_rate.num) - && st->info->duration_count<20 && st->codec->codec_type == AVMEDIA_TYPE_VIDEO) + && st->info->duration_count < fps_analyze_framecount + && st->codec->codec_type == AVMEDIA_TYPE_VIDEO) break; if(st->parser && st->parser->parser->split && !st->codec->extradata) break; @@ -2435,6 +2393,19 @@ int av_find_stream_info(AVFormatContext *ic) }else if(st->codec->codec_type == AVMEDIA_TYPE_AUDIO) { if(!st->codec->bits_per_coded_sample) st->codec->bits_per_coded_sample= av_get_bits_per_sample(st->codec->codec_id); + // set stream disposition based on audio service type + switch (st->codec->audio_service_type) { + case AV_AUDIO_SERVICE_TYPE_EFFECTS: + st->disposition = AV_DISPOSITION_CLEAN_EFFECTS; break; + case AV_AUDIO_SERVICE_TYPE_VISUALLY_IMPAIRED: + st->disposition = AV_DISPOSITION_VISUAL_IMPAIRED; break; + case AV_AUDIO_SERVICE_TYPE_HEARING_IMPAIRED: + st->disposition = AV_DISPOSITION_HEARING_IMPAIRED; break; + case AV_AUDIO_SERVICE_TYPE_COMMENTARY: + st->disposition = AV_DISPOSITION_COMMENT; break; + case AV_AUDIO_SERVICE_TYPE_KARAOKE: + st->disposition = AV_DISPOSITION_KARAOKE; break; + } } } @@ -2510,6 +2481,8 @@ int av_find_best_stream(AVFormatContext *ic, continue; if (wanted_stream_nb >= 0 && stream_number++ != wanted_stream_nb) continue; + if (st->disposition & (AV_DISPOSITION_HEARING_IMPAIRED|AV_DISPOSITION_VISUAL_IMPAIRED)) + continue; if (decoder_ret) { decoder = avcodec_find_decoder(ic->streams[i]->codec->codec_id); if (!decoder) { @@ -2521,7 +2494,7 @@ int av_find_best_stream(AVFormatContext *ic, if (best_count >= st->codec_info_nb_frames) continue; best_count = st->codec_info_nb_frames; - ret = i; + ret = program ? program[i] : i; best_decoder = decoder; if (program && i == nb_streams - 1 && ret < 0) { program = NULL; @@ -2541,7 +2514,7 @@ int av_read_play(AVFormatContext *s) if (s->iformat->read_play) return s->iformat->read_play(s); if (s->pb) - return av_url_read_fpause(s->pb, 0); + return avio_pause(s->pb, 0); return AVERROR(ENOSYS); } @@ -2550,7 +2523,7 @@ int av_read_pause(AVFormatContext *s) if (s->iformat->read_pause) return s->iformat->read_pause(s); if (s->pb) - return av_url_read_fpause(s->pb, 1); + return avio_pause(s->pb, 1); return AVERROR(ENOSYS); } @@ -2579,18 +2552,11 @@ void avformat_free_context(AVFormatContext *s) av_free(st->codec->extradata); av_free(st->codec->subtitle_header); av_free(st->codec); -#if FF_API_OLD_METADATA - av_free(st->filename); -#endif av_free(st->priv_data); av_free(st->info); av_free(st); } for(i=s->nb_programs-1; i>=0; i--) { -#if FF_API_OLD_METADATA - av_freep(&s->programs[i]->provider_name); - av_freep(&s->programs[i]->name); -#endif av_metadata_free(&s->programs[i]->metadata); av_freep(&s->programs[i]->stream_index); av_freep(&s->programs[i]); @@ -2598,37 +2564,28 @@ void avformat_free_context(AVFormatContext *s) av_freep(&s->programs); av_freep(&s->priv_data); while(s->nb_chapters--) { -#if FF_API_OLD_METADATA - av_free(s->chapters[s->nb_chapters]->title); -#endif av_metadata_free(&s->chapters[s->nb_chapters]->metadata); av_free(s->chapters[s->nb_chapters]); } av_freep(&s->chapters); av_metadata_free(&s->metadata); av_freep(&s->key); + av_freep(&s->streams); av_free(s); } void av_close_input_file(AVFormatContext *s) { - ByteIOContext *pb = s->iformat->flags & AVFMT_NOFILE ? NULL : s->pb; + AVIOContext *pb = s->iformat->flags & AVFMT_NOFILE ? NULL : s->pb; av_close_input_stream(s); if (pb) - url_fclose(pb); + avio_close(pb); } AVStream *av_new_stream(AVFormatContext *s, int id) { AVStream *st; int i; - -#if FF_API_MAX_STREAMS - if (s->nb_streams >= MAX_STREAMS){ - av_log(s, AV_LOG_ERROR, "Too many streams\n"); - return NULL; - } -#else AVStream **streams; if (s->nb_streams >= INT_MAX/sizeof(*streams)) @@ -2637,7 +2594,6 @@ AVStream *av_new_stream(AVFormatContext *s, int id) if (!streams) return NULL; s->streams = streams; -#endif st = av_mallocz(sizeof(AVStream)); if (!st) @@ -2717,9 +2673,6 @@ AVChapter *ff_new_chapter(AVFormatContext *s, int id, AVRational time_base, int6 return NULL; dynarray_add(&s->chapters, &s->nb_chapters, chapter); } -#if FF_API_OLD_METADATA - av_free(chapter->title); -#endif av_metadata_set2(&chapter->metadata, "title", title, 0); chapter->id = id; chapter->time_base= time_base; @@ -2857,10 +2810,6 @@ int av_write_header(AVFormatContext *s) return AVERROR(ENOMEM); } -#if FF_API_OLD_METADATA - ff_metadata_mux_compat(s); -#endif - /* set muxer identification string */ if (s->nb_streams && !(s->streams[0]->codec->flags & CODEC_FLAG_BITEXACT)) { av_metadata_set2(&s->metadata, "encoder", LIBAVFORMAT_IDENT, 0); @@ -2901,7 +2850,8 @@ static int compute_pkt_fields2(AVFormatContext *s, AVStream *st, AVPacket *pkt){ int delay = FFMAX(st->codec->has_b_frames, !!st->codec->max_b_frames); int num, den, frame_size, i; -// av_log(s, AV_LOG_DEBUG, "av_write_frame: pts:%"PRId64" dts:%"PRId64" cur_dts:%"PRId64" b:%d size:%d st:%d\n", pkt->pts, pkt->dts, st->cur_dts, delay, pkt->size, pkt->stream_index); + av_dlog(s, "av_write_frame: pts:%"PRId64" dts:%"PRId64" cur_dts:%"PRId64" b:%d size:%d st:%d\n", + pkt->pts, pkt->dts, st->cur_dts, delay, pkt->size, pkt->stream_index); /* if(pkt->pts == AV_NOPTS_VALUE && pkt->dts == AV_NOPTS_VALUE) return -1;*/ @@ -2979,8 +2929,6 @@ int av_write_frame(AVFormatContext *s, AVPacket *pkt) return ret; ret= s->oformat->write_packet(s, pkt); - if(!ret) - ret= url_ferror(s->pb); return ret; } @@ -3026,7 +2974,10 @@ static int ff_interleave_compare_dts(AVFormatContext *s, AVPacket *next, AVPacke AVStream *st2= s->streams[ next->stream_index]; int64_t a= st2->time_base.num * (int64_t)st ->time_base.den; int64_t b= st ->time_base.num * (int64_t)st2->time_base.den; - return av_rescale_rnd(pkt->dts, b, a, AV_ROUND_DOWN) < next->dts; + int64_t dts1 = av_rescale_rnd(pkt->dts, b, a, AV_ROUND_DOWN); + if (dts1 == next->dts) + return pkt->stream_index < next->stream_index; + return dts1 < next->dts; } int av_interleave_packet_per_dts(AVFormatContext *s, AVPacket *out, AVPacket *pkt, int flush){ @@ -3077,17 +3028,19 @@ static int av_interleave_packet(AVFormatContext *s, AVPacket *out, AVPacket *in, int av_interleaved_write_frame(AVFormatContext *s, AVPacket *pkt){ AVStream *st= s->streams[ pkt->stream_index]; + int ret; //FIXME/XXX/HACK drop zero sized packets if(st->codec->codec_type == AVMEDIA_TYPE_AUDIO && pkt->size==0) return 0; -//av_log(NULL, AV_LOG_DEBUG, "av_interleaved_write_frame %d %"PRId64" %"PRId64"\n", pkt->size, pkt->dts, pkt->pts); - if(compute_pkt_fields2(s, st, pkt) < 0 && !(s->oformat->flags & AVFMT_NOTIMESTAMPS)) - return -1; + av_dlog(s, "av_interleaved_write_frame size:%d dts:%"PRId64" pts:%"PRId64"\n", + pkt->size, pkt->dts, pkt->pts); + if((ret = compute_pkt_fields2(s, st, pkt)) < 0 && !(s->oformat->flags & AVFMT_NOTIMESTAMPS)) + return ret; if(pkt->dts == AV_NOPTS_VALUE && !(s->oformat->flags & AVFMT_NOTIMESTAMPS)) - return -1; + return AVERROR(EINVAL); for(;;){ AVPacket opkt; @@ -3102,8 +3055,6 @@ int av_interleaved_write_frame(AVFormatContext *s, AVPacket *pkt){ if(ret<0) return ret; - if(url_ferror(s->pb)) - return url_ferror(s->pb); } } @@ -3125,15 +3076,11 @@ 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;inb_streams;i++) { av_freep(&s->streams[i]->priv_data); av_freep(&s->streams[i]->index_entries); @@ -3229,14 +3176,44 @@ static void dump_stream_format(AVFormatContext *ic, int i, int index, int is_out if(st->codec->time_base.den && st->codec->time_base.num) print_fps(1/av_q2d(st->codec->time_base), "tbc"); } + if (st->disposition & AV_DISPOSITION_DEFAULT) + av_log(NULL, AV_LOG_INFO, " (default)"); + if (st->disposition & AV_DISPOSITION_DUB) + av_log(NULL, AV_LOG_INFO, " (dub)"); + if (st->disposition & AV_DISPOSITION_ORIGINAL) + av_log(NULL, AV_LOG_INFO, " (original)"); + if (st->disposition & AV_DISPOSITION_COMMENT) + av_log(NULL, AV_LOG_INFO, " (comment)"); + if (st->disposition & AV_DISPOSITION_LYRICS) + av_log(NULL, AV_LOG_INFO, " (lyrics)"); + if (st->disposition & AV_DISPOSITION_KARAOKE) + av_log(NULL, AV_LOG_INFO, " (karaoke)"); + if (st->disposition & AV_DISPOSITION_FORCED) + av_log(NULL, AV_LOG_INFO, " (forced)"); + if (st->disposition & AV_DISPOSITION_HEARING_IMPAIRED) + av_log(NULL, AV_LOG_INFO, " (hearing impaired)"); + if (st->disposition & AV_DISPOSITION_VISUAL_IMPAIRED) + av_log(NULL, AV_LOG_INFO, " (visual impaired)"); + if (st->disposition & AV_DISPOSITION_CLEAN_EFFECTS) + av_log(NULL, AV_LOG_INFO, " (clean effects)"); av_log(NULL, AV_LOG_INFO, "\n"); dump_metadata(NULL, st->metadata, " "); } +#if FF_API_DUMP_FORMAT void dump_format(AVFormatContext *ic, int index, const char *url, int is_output) +{ + av_dump_format(ic, index, url, is_output); +} +#endif + +void av_dump_format(AVFormatContext *ic, + int index, + const char *url, + int is_output) { int i; uint8_t *printed = av_mallocz(ic->nb_streams); @@ -3312,24 +3289,6 @@ void dump_format(AVFormatContext *ic, av_free(printed); } -#if FF_API_PARSE_FRAME_PARAM -#include "libavcore/parseutils.h" - -int parse_image_size(int *width_ptr, int *height_ptr, const char *str) -{ - return av_parse_video_size(width_ptr, height_ptr, str); -} - -int parse_frame_rate(int *frame_rate_num, int *frame_rate_den, const char *arg) -{ - AVRational frame_rate; - int ret = av_parse_video_rate(&frame_rate, arg); - *frame_rate_num= frame_rate.num; - *frame_rate_den= frame_rate.den; - return ret; -} -#endif - int64_t av_gettime(void) { struct timeval tv; @@ -3342,163 +3301,25 @@ uint64_t ff_ntp_time(void) return (av_gettime() / 1000) * 1000 + NTP_OFFSET_US; } -int64_t parse_date(const char *datestr, int duration) -{ - const char *p; - int64_t t; - struct tm dt; - int i; - static const char * const date_fmt[] = { - "%Y-%m-%d", - "%Y%m%d", - }; - static const char * const time_fmt[] = { - "%H:%M:%S", - "%H%M%S", - }; - const char *q; - int is_utc, len; - char lastch; - int negative = 0; - -#undef time - time_t now = time(0); - - len = strlen(datestr); - if (len > 0) - lastch = datestr[len - 1]; - else - lastch = '\0'; - is_utc = (lastch == 'z' || lastch == 'Z'); - - memset(&dt, 0, sizeof(dt)); - - p = datestr; - q = NULL; - if (!duration) { - if (!strncasecmp(datestr, "now", len)) - return (int64_t) now * 1000000; - - /* parse the year-month-day part */ - for (i = 0; i < FF_ARRAY_ELEMS(date_fmt); i++) { - q = small_strptime(p, date_fmt[i], &dt); - if (q) { - break; - } - } - - /* if the year-month-day part is missing, then take the - * current year-month-day time */ - if (!q) { - if (is_utc) { - dt = *gmtime(&now); - } else { - dt = *localtime(&now); - } - dt.tm_hour = dt.tm_min = dt.tm_sec = 0; - } else { - p = q; - } - - if (*p == 'T' || *p == 't' || *p == ' ') - p++; +#if FF_API_PARSE_DATE +#include "libavutil/parseutils.h" - /* parse the hour-minute-second part */ - for (i = 0; i < FF_ARRAY_ELEMS(time_fmt); i++) { - q = small_strptime(p, time_fmt[i], &dt); - if (q) { - break; - } - } - } else { - /* parse datestr as a duration */ - if (p[0] == '-') { - negative = 1; - ++p; - } - /* parse datestr as HH:MM:SS */ - q = small_strptime(p, time_fmt[0], &dt); - if (!q) { - /* parse datestr as S+ */ - dt.tm_sec = strtol(p, (char **)&q, 10); - if (q == p) - /* the parsing didn't succeed */ - return INT64_MIN; - dt.tm_min = 0; - dt.tm_hour = 0; - } - } - - /* Now we have all the fields that we can get */ - if (!q) { - return INT64_MIN; - } - - if (duration) { - t = dt.tm_hour * 3600 + dt.tm_min * 60 + dt.tm_sec; - } else { - dt.tm_isdst = -1; /* unknown */ - if (is_utc) { - t = mktimegm(&dt); - } else { - t = mktime(&dt); - } - } - - t *= 1000000; - - /* parse the .m... part */ - if (*q == '.') { - int val, n; - q++; - for (val = 0, n = 100000; n >= 1; n /= 10, q++) { - if (!isdigit(*q)) - break; - val += n * (*q - '0'); - } - t += val; - } - return negative ? -t : t; +int64_t parse_date(const char *timestr, int duration) +{ + int64_t timeval; + av_parse_time(&timeval, timestr, duration); + return timeval; } +#endif + +#if FF_API_FIND_INFO_TAG +#include "libavutil/parseutils.h" int find_info_tag(char *arg, int arg_size, const char *tag1, const char *info) { - const char *p; - char tag[128], *q; - - p = info; - if (*p == '?') - p++; - for(;;) { - q = tag; - while (*p != '\0' && *p != '=' && *p != '&') { - if ((q - tag) < sizeof(tag) - 1) - *q++ = *p; - p++; - } - *q = '\0'; - q = arg; - if (*p == '=') { - p++; - while (*p != '&' && *p != '\0') { - if ((q - arg) < arg_size - 1) { - if (*p == '+') - *q++ = ' '; - else - *q++ = *p; - } - p++; - } - } - *q = '\0'; - if (!strcmp(tag, tag1)) - return 1; - if (*p != '&') - break; - p++; - } - return 0; + return av_find_info_tag(arg, arg_size, tag1, info); } +#endif int av_get_frame_filename(char *buf, int buf_size, const char *path, int number) @@ -3594,26 +3415,25 @@ void av_hex_dump_log(void *avcl, int level, uint8_t *buf, int size) hex_dump_internal(avcl, NULL, level, buf, size); } - //FIXME needs to know the time_base -static void pkt_dump_internal(void *avcl, FILE *f, int level, AVPacket *pkt, int dump_payload) +static void pkt_dump_internal(void *avcl, FILE *f, int level, AVPacket *pkt, int dump_payload, AVRational time_base) { #undef fprintf #define PRINT(...) do { if (!f) av_log(avcl, level, __VA_ARGS__); else fprintf(f, __VA_ARGS__); } while(0) PRINT("stream #%d:\n", pkt->stream_index); PRINT(" keyframe=%d\n", ((pkt->flags & AV_PKT_FLAG_KEY) != 0)); - PRINT(" duration=%0.3f\n", (double)pkt->duration / AV_TIME_BASE); + PRINT(" duration=%0.3f\n", pkt->duration * av_q2d(time_base)); /* DTS is _always_ valid after av_read_frame() */ PRINT(" dts="); if (pkt->dts == AV_NOPTS_VALUE) PRINT("N/A"); else - PRINT("%0.3f", (double)pkt->dts / AV_TIME_BASE); + PRINT("%0.3f", pkt->dts * av_q2d(time_base)); /* PTS may not be known if B-frames are present. */ PRINT(" pts="); if (pkt->pts == AV_NOPTS_VALUE) PRINT("N/A"); else - PRINT("%0.3f", (double)pkt->pts / AV_TIME_BASE); + PRINT("%0.3f", pkt->pts * av_q2d(time_base)); PRINT("\n"); PRINT(" size=%d\n", pkt->size); #undef PRINT @@ -3621,34 +3441,33 @@ static void pkt_dump_internal(void *avcl, FILE *f, int level, AVPacket *pkt, int av_hex_dump(f, pkt->data, pkt->size); } +#if FF_API_PKT_DUMP void av_pkt_dump(FILE *f, AVPacket *pkt, int dump_payload) { - pkt_dump_internal(NULL, f, 0, pkt, dump_payload); + AVRational tb = { 1, AV_TIME_BASE }; + pkt_dump_internal(NULL, f, 0, pkt, dump_payload, tb); } +#endif -void av_pkt_dump_log(void *avcl, int level, AVPacket *pkt, int dump_payload) +void av_pkt_dump2(FILE *f, AVPacket *pkt, int dump_payload, AVStream *st) { - pkt_dump_internal(avcl, NULL, level, pkt, dump_payload); + pkt_dump_internal(NULL, f, 0, pkt, dump_payload, st->time_base); } -#if FF_API_URL_SPLIT -attribute_deprecated -void ff_url_split(char *proto, int proto_size, - char *authorization, int authorization_size, - char *hostname, int hostname_size, - int *port_ptr, - char *path, int path_size, - const char *url) +#if FF_API_PKT_DUMP +void av_pkt_dump_log(void *avcl, int level, AVPacket *pkt, int dump_payload) { - av_url_split(proto, proto_size, - authorization, authorization_size, - hostname, hostname_size, - port_ptr, - path, path_size, - url); + AVRational tb = { 1, AV_TIME_BASE }; + pkt_dump_internal(avcl, NULL, level, pkt, dump_payload, tb); } #endif +void av_pkt_dump_log2(void *avcl, int level, AVPacket *pkt, int dump_payload, + AVStream *st) +{ + pkt_dump_internal(avcl, NULL, level, pkt, dump_payload, st->time_base); +} + void av_url_split(char *proto, int proto_size, char *authorization, int authorization_size, char *hostname, int hostname_size, @@ -3762,16 +3581,19 @@ int ff_hex_to_data(uint8_t *data, const char *p) void av_set_pts_info(AVStream *s, int pts_wrap_bits, unsigned int pts_num, unsigned int pts_den) { - s->pts_wrap_bits = pts_wrap_bits; - - if(av_reduce(&s->time_base.num, &s->time_base.den, pts_num, pts_den, INT_MAX)){ - if(s->time_base.num != pts_num) - av_log(NULL, AV_LOG_DEBUG, "st:%d removing common factor %d from timebase\n", s->index, pts_num/s->time_base.num); + AVRational new_tb; + if(av_reduce(&new_tb.num, &new_tb.den, pts_num, pts_den, INT_MAX)){ + if(new_tb.num != pts_num) + av_log(NULL, AV_LOG_DEBUG, "st:%d removing common factor %d from timebase\n", s->index, pts_num/new_tb.num); }else av_log(NULL, AV_LOG_WARNING, "st:%d has too large timebase, reducing\n", s->index); - if(!s->time_base.num || !s->time_base.den) - s->time_base.num= s->time_base.den= 0; + if(new_tb.num <= 0 || new_tb.den <= 0) { + av_log(NULL, AV_LOG_ERROR, "Ignoring attempt to set invalid timebase for st:%d\n", s->index); + return; + } + s->time_base = new_tb; + s->pts_wrap_bits = pts_wrap_bits; } int ff_url_join(char *str, int size, const char *proto, @@ -3900,3 +3722,54 @@ int ff_find_stream_index(AVFormatContext *s, int id) } return -1; } + +void ff_make_absolute_url(char *buf, int size, const char *base, + const char *rel) +{ + char *sep; + /* Absolute path, relative to the current server */ + if (base && strstr(base, "://") && rel[0] == '/') { + if (base != buf) + av_strlcpy(buf, base, size); + sep = strstr(buf, "://"); + if (sep) { + sep += 3; + sep = strchr(sep, '/'); + if (sep) + *sep = '\0'; + } + av_strlcat(buf, rel, size); + return; + } + /* If rel actually is an absolute url, just copy it */ + if (!base || strstr(rel, "://") || rel[0] == '/') { + av_strlcpy(buf, rel, size); + return; + } + if (base != buf) + av_strlcpy(buf, base, size); + /* Remove the file name from the base url */ + sep = strrchr(buf, '/'); + if (sep) + sep[1] = '\0'; + else + buf[0] = '\0'; + while (av_strstart(rel, "../", NULL) && sep) { + /* Remove the path delimiter at the end */ + sep[0] = '\0'; + sep = strrchr(buf, '/'); + /* If the next directory name to pop off is "..", break here */ + if (!strcmp(sep ? &sep[1] : buf, "..")) { + /* Readd the slash we just removed */ + av_strlcat(buf, "/", size); + break; + } + /* Cut off the directory name */ + if (sep) + sep[1] = '\0'; + else + buf[0] = '\0'; + rel += 3; + } + av_strlcat(buf, rel, size); +}