diff options
Diffstat (limited to 'demux/demux_lavf.c')
-rw-r--r-- | demux/demux_lavf.c | 350 |
1 files changed, 233 insertions, 117 deletions
diff --git a/demux/demux_lavf.c b/demux/demux_lavf.c index f4bbfc5739..75a47ed3ad 100644 --- a/demux/demux_lavf.c +++ b/demux/demux_lavf.c @@ -29,12 +29,17 @@ #include <libavformat/avformat.h> #include <libavformat/avio.h> + #include <libavutil/avutil.h> #include <libavutil/avstring.h> -#include <libavutil/mathematics.h> -#include <libavutil/replaygain.h> #include <libavutil/display.h> +#include <libavutil/dovi_meta.h> +#include <libavutil/mathematics.h> #include <libavutil/opt.h> +#include <libavutil/pixdesc.h> +#include <libavutil/replaygain.h> + +#include "audio/chmap_avchannel.h" #include "common/msg.h" #include "common/tags.h" @@ -72,47 +77,48 @@ struct demux_lavf_opts { int probescore; float analyzeduration; int buffersize; - int allow_mimetype; + bool allow_mimetype; char *format; char **avopts; - int hacks; + bool hacks; char *sub_cp; int rtsp_transport; int linearize_ts; - int propagate_opts; + bool propagate_opts; }; const struct m_sub_options demux_lavf_conf = { .opts = (const m_option_t[]) { - OPT_INTRANGE("demuxer-lavf-probesize", probesize, 0, 32, INT_MAX), - OPT_CHOICE("demuxer-lavf-probe-info", probeinfo, 0, - ({"no", 0}, {"yes", 1}, {"auto", -1}, {"nostreams", -2})), - OPT_STRING("demuxer-lavf-format", format, 0), - OPT_FLOATRANGE("demuxer-lavf-analyzeduration", analyzeduration, 0, - 0, 3600), - OPT_INTRANGE("demuxer-lavf-buffersize", buffersize, 0, 1, - 10 * 1024 * 1024, OPTDEF_INT(BIO_BUFFER_SIZE)), - OPT_FLAG("demuxer-lavf-allow-mimetype", allow_mimetype, 0), - OPT_INTRANGE("demuxer-lavf-probescore", probescore, 0, - 1, AVPROBE_SCORE_MAX), - OPT_FLAG("demuxer-lavf-hacks", hacks, 0), - OPT_KEYVALUELIST("demuxer-lavf-o", avopts, 0), - OPT_STRING("sub-codepage", sub_cp, 0), - OPT_CHOICE("rtsp-transport", rtsp_transport, 0, - ({"lavf", 0}, - {"udp", 1}, - {"tcp", 2}, - {"http", 3})), - OPT_CHOICE("demuxer-lavf-linearize-timestamps", linearize_ts, 0, - ({"no", 0}, {"auto", -1}, {"yes", 1})), - OPT_FLAG("demuxer-lavf-propagate-opts", propagate_opts, 0), + {"demuxer-lavf-probesize", OPT_INT(probesize), M_RANGE(32, INT_MAX)}, + {"demuxer-lavf-probe-info", OPT_CHOICE(probeinfo, + {"no", 0}, {"yes", 1}, {"auto", -1}, {"nostreams", -2})}, + {"demuxer-lavf-format", OPT_STRING(format)}, + {"demuxer-lavf-analyzeduration", OPT_FLOAT(analyzeduration), + M_RANGE(0, 3600)}, + {"demuxer-lavf-buffersize", OPT_INT(buffersize), + M_RANGE(1, 10 * 1024 * 1024), OPTDEF_INT(BIO_BUFFER_SIZE)}, + {"demuxer-lavf-allow-mimetype", OPT_BOOL(allow_mimetype)}, + {"demuxer-lavf-probescore", OPT_INT(probescore), + M_RANGE(1, AVPROBE_SCORE_MAX)}, + {"demuxer-lavf-hacks", OPT_BOOL(hacks)}, + {"demuxer-lavf-o", OPT_KEYVALUELIST(avopts)}, + {"sub-codepage", OPT_STRING(sub_cp)}, + {"rtsp-transport", OPT_CHOICE(rtsp_transport, + {"lavf", 0}, + {"udp", 1}, + {"tcp", 2}, + {"http", 3}, + {"udp_multicast", 4})}, + {"demuxer-lavf-linearize-timestamps", OPT_CHOICE(linearize_ts, + {"no", 0}, {"auto", -1}, {"yes", 1})}, + {"demuxer-lavf-propagate-opts", OPT_BOOL(propagate_opts)}, {0} }, .size = sizeof(struct demux_lavf_opts), .defaults = &(const struct demux_lavf_opts){ .probeinfo = -1, - .allow_mimetype = 1, - .hacks = 1, + .allow_mimetype = true, + .hacks = true, // AVPROBE_SCORE_MAX/4 + 1 is the "recommended" limit. Below that, the // user is supposed to retry with larger probe sizes until a higher // value is reached. @@ -120,7 +126,7 @@ const struct m_sub_options demux_lavf_conf = { .sub_cp = "auto", .rtsp_transport = 2, .linearize_ts = -1, - .propagate_opts = 1, + .propagate_opts = true, }, }; @@ -137,15 +143,15 @@ struct format_hack { bool use_stream_ids : 1; // has a meaningful native stream IDs (export it) bool fully_read : 1; // set demuxer.fully_read flag bool detect_charset : 1; // format is a small text file, possibly not UTF8 - bool image_format : 1; // expected to contain exactly 1 frame // Do not confuse player's position estimation (position is into external // segment, with e.g. HLS, player knows about the playlist main file only). bool clear_filepos : 1; bool linearize_audio_ts : 1;// compensate timestamp resets (audio only) - bool fix_editlists : 1; bool is_network : 1; bool no_seek : 1; bool no_pcm_seek : 1; + bool no_seek_on_no_duration : 1; + bool readall_on_no_streamseek : 1; }; #define BLACKLIST(fmt) {fmt, .ignore = true} @@ -169,11 +175,11 @@ static const struct format_hack format_hacks[] = { {"mxf", .use_stream_ids = true}, {"avi", .use_stream_ids = true}, {"asf", .use_stream_ids = true}, - {"mp4", .skipinfo = true, .fix_editlists = true, .no_pcm_seek = true, - .use_stream_ids = true}, + {"mp4", .skipinfo = true, .no_pcm_seek = true, .use_stream_ids = true}, {"matroska", .skipinfo = true, .no_pcm_seek = true, .use_stream_ids = true}, {"v4l2", .no_seek = true}, + {"rtsp", .no_seek_on_no_duration = true}, // In theory, such streams might contain timestamps, but virtually none do. {"h264", .if_flags = AVFMT_NOTIMESTAMPS }, @@ -183,6 +189,10 @@ static const struct format_hack format_hacks[] = { // reset timestamps, which causes all sorts of problems. {"ogg", .linearize_audio_ts = true, .use_stream_ids = true}, + // At some point, FFmpeg lost the ability to read gif from unseekable + // streams. + {"gif", .readall_on_no_streamseek = true}, + TEXTSUB("aqtitle"), TEXTSUB("jacosub"), TEXTSUB("microdvd"), TEXTSUB("mpl2"), TEXTSUB("mpsub"), TEXTSUB("pjs"), TEXTSUB("realtext"), TEXTSUB("sami"), TEXTSUB("srt"), TEXTSUB("stl"), TEXTSUB("subviewer"), @@ -197,8 +207,6 @@ static const struct format_hack format_hacks[] = { BLACKLIST("bin"), // Useless, does not work with custom streams. BLACKLIST("image2"), - // Image demuxers ("<name>_pipe" is detected explicitly) - {"image2pipe", .image_format = true}, {0} }; @@ -214,12 +222,18 @@ struct stream_info { double ts_offset; }; +#if LIBAVFORMAT_VERSION_INT >= AV_VERSION_INT(59, 10, 100) + #define HAVE_IO_CLOSE2 1 +#else + #define HAVE_IO_CLOSE2 0 +#endif + typedef struct lavf_priv { struct stream *stream; bool own_stream; char *filename; struct format_hack format_hack; - AVInputFormat *avif; + const AVInputFormat *avif; int avif_flags; AVFormatContext *avfc; AVIOContext *pb; @@ -229,7 +243,6 @@ typedef struct lavf_priv { double seek_delay; struct demux_lavf_opts *opts; - double mf_fps; bool pcm_seek_hack_disabled; AVStream *pcm_seek_hack; @@ -238,6 +251,8 @@ typedef struct lavf_priv { int linearize_ts; bool any_ts_fixed; + int retry_counter; + AVDictionary *av_opts; // Proxying nested streams. @@ -245,7 +260,11 @@ typedef struct lavf_priv { int num_nested; int (*default_io_open)(struct AVFormatContext *s, AVIOContext **pb, const char *url, int flags, AVDictionary **options); +#if HAVE_IO_CLOSE2 + int (*default_io_close2)(struct AVFormatContext *s, AVIOContext *pb); +#else void (*default_io_close)(struct AVFormatContext *s, AVIOContext *pb); +#endif } lavf_priv_t; static void update_read_stats(struct demuxer *demuxer) @@ -255,16 +274,10 @@ static void update_read_stats(struct demuxer *demuxer) for (int n = 0; n < priv->num_nested; n++) { struct nested_stream *nest = &priv->nested[n]; -#if !HAVE_FFMPEG_STRICT_ABI - // Note: accessing the bytes_read field is not allowed by FFmpeg's API. - // This is fully intentional - there is no other way to get this - // information (not even by custom I/O, because the connection reuse - // mechanism by the HLS demuxer would get disabled). int64_t cur = nest->id->bytes_read; int64_t new = cur - nest->last_bytes; nest->last_bytes = cur; demux_report_unbuffered_read_bytes(demuxer, new); -#endif } } @@ -433,7 +446,7 @@ static int lavf_check_file(demuxer_t *demuxer, enum demux_check check) if (!lavfdopts->allow_mimetype || !mime_type) mime_type = ""; - AVInputFormat *forced_format = NULL; + const AVInputFormat *forced_format = NULL; const char *format = lavfdopts->format; if (!format) format = s->lavf_type; @@ -451,11 +464,22 @@ static int lavf_check_file(demuxer_t *demuxer, enum demux_check check) } } + // HLS streams do not seem to be well tagged, so matching by MIME type is + // not enough - we need to strip the query string and match by their + // extensions. We also pass jpg filenames to fix issues like #13192 (jpgs + // being treated as videos due to a bogus second frame) and #13431 (jpgs + // misdetected as mpegts). We don't pass filenames otherwise to not + // misdetect files with a wrong extension, as described in 74e62ed2d1. + bstr ext = bstr_get_ext(mp_is_url(bstr0(priv->filename)) + ? bstr_split(bstr0(priv->filename), "?#", NULL) + : bstr0(priv->filename)); AVProbeData avpd = { - // Disable file-extension matching with normal checks - .filename = priv->filename, + .filename = !bstrcasecmp0(ext, "m3u8") || !bstrcasecmp0(ext, "m3u") || + !bstrcasecmp0(ext, "jpg") || !bstrcasecmp0(ext, "jpeg") || + check <= DEMUX_CHECK_REQUEST ? priv->filename : "", .buf_size = 0, .buf = av_mallocz(PROBE_BUF_SIZE + AV_INPUT_BUFFER_PADDING_SIZE), + .mime_type = lavfdopts->allow_mimetype ? mime_type : NULL, }; if (!avpd.buf) return -1; @@ -493,6 +517,10 @@ static int lavf_check_file(demuxer_t *demuxer, enum demux_check check) break; } + // AVIF always needs to find stream info + if (bstrcasecmp0(ext, "avif") == 0) + priv->format_hack.skipinfo = false; + if (score >= lavfdopts->probescore) break; @@ -518,11 +546,6 @@ static int lavf_check_file(demuxer_t *demuxer, enum demux_check check) return -1; } - if (bstr_endswith0(bstr0(priv->avif->name), "_pipe")) { - MP_VERBOSE(demuxer, "Assuming this is an image format.\n"); - priv->format_hack.image_format = true; - } - if (lavfdopts->hacks) priv->avif_flags = priv->avif->flags | priv->format_hack.if_flags; @@ -590,16 +613,25 @@ static void select_tracks(struct demuxer *demuxer, int start) static void export_replaygain(demuxer_t *demuxer, struct sh_stream *sh, AVStream *st) { - for (int i = 0; i < st->nb_side_data; i++) { +#if LIBAVFORMAT_VERSION_INT >= AV_VERSION_INT(60, 15, 100) + AVPacketSideData *side_data = st->codecpar->coded_side_data; + int nb_side_data = st->codecpar->nb_coded_side_data; +#else + AVPacketSideData *side_data = st->side_data; + int nb_side_data = st->nb_side_data; +#endif + for (int i = 0; i < nb_side_data; i++) { AVReplayGain *av_rgain; struct replaygain_data *rgain; - AVPacketSideData *src_sd = &st->side_data[i]; + AVPacketSideData *src_sd = &side_data[i]; if (src_sd->type != AV_PKT_DATA_REPLAYGAIN) continue; av_rgain = (AVReplayGain*)src_sd->data; rgain = talloc_ptrtype(demuxer, rgain); + rgain->track_gain = rgain->album_gain = 0; + rgain->track_peak = rgain->album_peak = 1; // Set values in *rgain, using track gain as a fallback for album gain // if the latter is not present. This behavior matches that in @@ -643,6 +675,33 @@ static int dict_get_decimal(AVDictionary *dict, const char *entry, int def) return def; } +static bool is_image(AVStream *st, bool attached_picture, const AVInputFormat *avif) +{ + return st->nb_frames <= 1 && ( + attached_picture || + bstr_endswith0(bstr0(avif->name), "_pipe") || + strcmp(avif->name, "alias_pix") == 0 || + strcmp(avif->name, "gif") == 0 || + strcmp(avif->name, "ico") == 0 || + strcmp(avif->name, "image2pipe") == 0 || + (st->codecpar->codec_id == AV_CODEC_ID_AV1 && st->nb_frames == 1) + ); +} + +#if LIBAVFORMAT_VERSION_INT >= AV_VERSION_INT(60, 15, 100) +static inline const uint8_t *mp_av_stream_get_side_data(const AVStream *st, + enum AVPacketSideDataType type) +{ + const AVPacketSideData *sd; + sd = av_packet_side_data_get(st->codecpar->coded_side_data, + st->codecpar->nb_coded_side_data, + type); + return sd ? sd->data : NULL; +} +#else +#define mp_av_stream_get_side_data(st, type) av_stream_get_side_data(st, type, NULL) +#endif + static void handle_new_stream(demuxer_t *demuxer, int i) { lavf_priv_t *priv = demuxer->priv; @@ -656,12 +715,25 @@ static void handle_new_stream(demuxer_t *demuxer, int i) case AVMEDIA_TYPE_AUDIO: { sh = demux_alloc_sh_stream(STREAM_AUDIO); +#if !HAVE_AV_CHANNEL_LAYOUT // probably unneeded mp_chmap_set_unknown(&sh->codec->channels, codec->channels); if (codec->channel_layout) mp_chmap_from_lavc(&sh->codec->channels, codec->channel_layout); +#else + if (!mp_chmap_from_av_layout(&sh->codec->channels, &codec->ch_layout)) { + char layout[128] = {0}; + MP_WARN(demuxer, + "Failed to convert channel layout %s to mpv one!\n", + av_channel_layout_describe(&codec->ch_layout, + layout, 128) < 0 ? + "undefined" : layout); + } +#endif + sh->codec->samplerate = codec->sample_rate; sh->codec->bitrate = codec->bit_rate; + sh->codec->format_name = talloc_strdup(sh, av_get_sample_fmt_name(codec->format)); double delay = 0; if (codec->sample_rate > 0) @@ -700,20 +772,31 @@ static void handle_new_stream(demuxer_t *demuxer, int i) sh->codec->disp_w = codec->width; sh->codec->disp_h = codec->height; + sh->codec->format_name = talloc_strdup(sh, av_get_pix_fmt_name(codec->format)); if (st->avg_frame_rate.num) sh->codec->fps = av_q2d(st->avg_frame_rate); - if (priv->format_hack.image_format) - sh->codec->fps = priv->mf_fps; + if (is_image(st, sh->attached_picture, priv->avif)) { + MP_VERBOSE(demuxer, "Assuming this is an image format.\n"); + sh->image = true; + sh->codec->fps = demuxer->opts->mf_fps; + } sh->codec->par_w = st->sample_aspect_ratio.num; sh->codec->par_h = st->sample_aspect_ratio.den; - uint8_t *sd = av_stream_get_side_data(st, AV_PKT_DATA_DISPLAYMATRIX, NULL); + const uint8_t *sd = mp_av_stream_get_side_data(st, AV_PKT_DATA_DISPLAYMATRIX); if (sd) { - double r = av_display_rotation_get((uint32_t *)sd); + double r = av_display_rotation_get((int32_t *)sd); if (!isnan(r)) sh->codec->rotate = (((int)(-r) % 360) + 360) % 360; } + if ((sd = mp_av_stream_get_side_data(st, AV_PKT_DATA_DOVI_CONF))) { + const AVDOVIDecoderConfigurationRecord *cfg = (void *) sd; + MP_VERBOSE(demuxer, "Found Dolby Vision config record: profile " + "%d level %d\n", cfg->dv_profile, cfg->dv_level); + av_format_inject_global_side_data(avfc); + } + // This also applies to vfw-muxed mkv, but we can't detect these easily. sh->codec->avi_dts = matches_avinputformat_name(priv, "avi"); @@ -796,10 +879,11 @@ static void handle_new_stream(demuxer_t *demuxer, int i) if (lang && lang->value && strcmp(lang->value, "und") != 0) sh->lang = talloc_strdup(sh, lang->value); sh->hls_bitrate = dict_get_decimal(st->metadata, "variant_bitrate", 0); - if (!sh->title && sh->hls_bitrate > 0) - sh->title = talloc_asprintf(sh, "bitrate %d", sh->hls_bitrate); + AVProgram *prog = av_find_program_from_stream(avfc, NULL, i); + if (prog) + sh->program_id = prog->id; sh->missing_timestamps = !!(priv->avif_flags & AVFMT_NOTIMESTAMPS); - mp_tags_copy_from_av_dictionary(sh->tags, st->metadata); + mp_tags_move_from_av_dictionary(sh->tags, &st->metadata); demux_add_sh_stream(demuxer, sh); // Unfortunately, there is no better way to detect PCM codecs, other @@ -837,7 +921,7 @@ static void update_metadata(demuxer_t *demuxer) { lavf_priv_t *priv = demuxer->priv; if (priv->avfc->event_flags & AVFMT_EVENT_FLAG_METADATA_UPDATED) { - mp_tags_copy_from_av_dictionary(demuxer->metadata, priv->avfc->metadata); + mp_tags_move_from_av_dictionary(demuxer->metadata, &priv->avfc->metadata); priv->avfc->event_flags = 0; demux_metadata_changed(demuxer); } @@ -892,7 +976,11 @@ static int nested_io_open(struct AVFormatContext *s, AVIOContext **pb, return r; } +#if HAVE_IO_CLOSE2 +static int nested_io_close2(struct AVFormatContext *s, AVIOContext *pb) +#else static void nested_io_close(struct AVFormatContext *s, AVIOContext *pb) +#endif { struct demuxer *demuxer = s->opaque; lavf_priv_t *priv = demuxer->priv; @@ -904,36 +992,35 @@ static void nested_io_close(struct AVFormatContext *s, AVIOContext *pb) } } - +#if HAVE_IO_CLOSE2 + return priv->default_io_close2(s, pb); +#else priv->default_io_close(s, pb); +#endif } static int demux_open_lavf(demuxer_t *demuxer, enum demux_check check) { - AVFormatContext *avfc; + AVFormatContext *avfc = NULL; AVDictionaryEntry *t = NULL; float analyze_duration = 0; lavf_priv_t *priv = talloc_zero(NULL, lavf_priv_t); + AVDictionary *dopts = NULL; + demuxer->priv = priv; priv->stream = demuxer->stream; priv->opts = mp_get_config_group(priv, demuxer->global, &demux_lavf_conf); struct demux_lavf_opts *lavfdopts = priv->opts; - int index_mode; - mp_read_option_raw(demuxer->global, "index", &m_option_type_choice, - &index_mode); - mp_read_option_raw(demuxer->global, "mf-fps", &m_option_type_double, - &priv->mf_fps); - if (lavf_check_file(demuxer, check) < 0) - return -1; + goto fail; avfc = avformat_alloc_context(); if (!avfc) - return -1; + goto fail; - if (index_mode != 1) + if (demuxer->opts->index_mode != 1) avfc->flags |= AVFMT_FLAG_IGNIDX; if (lavfdopts->probesize) { @@ -953,8 +1040,6 @@ static int demux_open_lavf(demuxer_t *demuxer, enum demux_check check) "analyzeduration to %f\n", analyze_duration); } - AVDictionary *dopts = NULL; - if ((priv->avif_flags & AVFMT_NOFILE) || priv->format_hack.no_stream) { mp_setup_av_network_options(&dopts, priv->avif->name, demuxer->global, demuxer->log); @@ -963,12 +1048,12 @@ static int demux_open_lavf(demuxer_t *demuxer, enum demux_check check) } else { void *buffer = av_malloc(lavfdopts->buffersize); if (!buffer) - return -1; + goto fail; priv->pb = avio_alloc_context(buffer, lavfdopts->buffersize, 0, demuxer, mp_read, NULL, mp_seek); if (!priv->pb) { av_free(buffer); - return -1; + goto fail; } priv->pb->read_seek = mp_read_seek; priv->pb->seekable = demuxer->seekable ? AVIO_SEEKABLE_NORMAL : 0; @@ -984,6 +1069,7 @@ static int demux_open_lavf(demuxer_t *demuxer, enum demux_check check) case 1: transport = "udp"; break; case 2: transport = "tcp"; break; case 3: transport = "http"; break; + case 4: transport = "udp_multicast"; break; } if (transport) av_dict_set(&dopts, "rtsp_transport", transport, 0); @@ -991,9 +1077,6 @@ static int demux_open_lavf(demuxer_t *demuxer, enum demux_check check) guess_and_set_vobsub_name(demuxer, &dopts); - if (priv->format_hack.fix_editlists) - av_dict_set(&dopts, "advanced_editlist", "0", 0); - avfc->interrupt_callback = (AVIOInterruptCB){ .callback = interrupt_cb, .opaque = demuxer, @@ -1002,9 +1085,14 @@ static int demux_open_lavf(demuxer_t *demuxer, enum demux_check check) avfc->opaque = demuxer; if (demuxer->access_references) { priv->default_io_open = avfc->io_open; - priv->default_io_close = avfc->io_close; avfc->io_open = nested_io_open; +#if HAVE_IO_CLOSE2 + priv->default_io_close2 = avfc->io_close2; + avfc->io_close2 = nested_io_close2; +#else + priv->default_io_close = avfc->io_close; avfc->io_close = nested_io_close; +#endif } else { avfc->io_open = block_io_open; } @@ -1012,14 +1100,27 @@ static int demux_open_lavf(demuxer_t *demuxer, enum demux_check check) mp_set_avdict(&dopts, lavfdopts->avopts); if (av_dict_copy(&priv->av_opts, dopts, 0) < 0) { - av_dict_free(&dopts); - return -1; + MP_ERR(demuxer, "av_dict_copy() failed\n"); + goto fail; + } + + if (priv->format_hack.readall_on_no_streamseek && priv->pb && + !priv->pb->seekable) + { + MP_VERBOSE(demuxer, "Non-seekable demuxer pre-read hack...\n"); + // Read incremental to avoid unnecessary large buffer sizes. + int r = 0; + for (int n = 16; n < 29; n++) { + r = stream_peek(priv->stream, 1 << n); + if (r < (1 << n)) + break; + } + MP_VERBOSE(demuxer, "...did read %d bytes.\n", r); } if (avformat_open_input(&avfc, priv->filename, priv->avif, &dopts) < 0) { MP_ERR(demuxer, "avformat_open_input() failed\n"); - av_dict_free(&dopts); - return -1; + goto fail; } mp_avdict_print_unset(demuxer->log, MSGL_V, dopts); @@ -1037,7 +1138,7 @@ static int demux_open_lavf(demuxer_t *demuxer, enum demux_check check) if (probeinfo) { if (avformat_find_stream_info(avfc, NULL) < 0) { MP_ERR(demuxer, "av_find_stream_info() failed\n"); - return -1; + goto fail; } MP_VERBOSE(demuxer, "avformat_find_stream_info() finished after %"PRId64 @@ -1049,12 +1150,12 @@ static int demux_open_lavf(demuxer_t *demuxer, enum demux_check check) t = av_dict_get(c->metadata, "title", NULL, 0); int index = demuxer_add_chapter(demuxer, t ? t->value : "", c->start * av_q2d(c->time_base), i); - mp_tags_copy_from_av_dictionary(demuxer->chapters[index].metadata, c->metadata); + mp_tags_move_from_av_dictionary(demuxer->chapters[index].metadata, &c->metadata); } add_new_streams(demuxer); - mp_tags_copy_from_av_dictionary(demuxer->metadata, avfc->metadata); + mp_tags_move_from_av_dictionary(demuxer->metadata, &avfc->metadata); demuxer->ts_resets_possible = priv->avif_flags & (AVFMT_TS_DISCONT | AVFMT_NOTIMESTAMPS); @@ -1072,25 +1173,28 @@ static int demux_open_lavf(demuxer_t *demuxer, enum demux_check check) demuxer->is_network |= priv->format_hack.is_network; demuxer->seekable &= !priv->format_hack.no_seek; - if (priv->avfc->duration > 0) { - demuxer->duration = (double)priv->avfc->duration / AV_TIME_BASE; - } else { - double total_duration = 0; - double av_duration = 0; - for (int n = 0; n < priv->avfc->nb_streams; n++) { - AVStream *st = priv->avfc->streams[n]; - if (st->duration <= 0) - continue; - double f_duration = st->duration * av_q2d(st->time_base); - total_duration = MPMAX(total_duration, f_duration); - if (st->codecpar->codec_type == AVMEDIA_TYPE_AUDIO || - st->codecpar->codec_type == AVMEDIA_TYPE_VIDEO) - av_duration = MPMAX(av_duration, f_duration); - } - double duration = av_duration > 0 ? av_duration : total_duration; - if (duration > 0) - demuxer->duration = duration; + // We initially prefer track durations over container durations because they + // have a higher degree of precision over the container duration which are + // only accurate to the 6th decimal place. This is probably a lavf bug. + double total_duration = -1; + double av_duration = -1; + for (int n = 0; n < priv->avfc->nb_streams; n++) { + AVStream *st = priv->avfc->streams[n]; + if (st->duration <= 0) + continue; + double f_duration = st->duration * av_q2d(st->time_base); + total_duration = MPMAX(total_duration, f_duration); + if (st->codecpar->codec_type == AVMEDIA_TYPE_AUDIO || + st->codecpar->codec_type == AVMEDIA_TYPE_VIDEO) + av_duration = MPMAX(av_duration, f_duration); } + double duration = av_duration > 0 ? av_duration : total_duration; + if (duration <= 0 && priv->avfc->duration > 0) + duration = (double)priv->avfc->duration / AV_TIME_BASE; + demuxer->duration = duration; + + if (demuxer->duration < 0 && priv->format_hack.no_seek_on_no_duration) + demuxer->seekable = false; // In some cases, libavformat will export bogus bullshit timestamps anyway, // such as with mjpeg. @@ -1099,7 +1203,7 @@ static int demux_open_lavf(demuxer_t *demuxer, enum demux_check check) "This format is marked by FFmpeg as having no timestamps!\n" "FFmpeg will likely make up its own broken timestamps. For\n" "video streams you can correct this with:\n" - " --no-correct-pts --fps=VALUE\n" + " --no-correct-pts --container-fps-override=VALUE\n" "with VALUE being the real framerate of the stream. You can\n" "expect seeking and buffering estimation to be generally\n" "broken as well.\n"); @@ -1114,6 +1218,13 @@ static int demux_open_lavf(demuxer_t *demuxer, enum demux_check check) } return 0; + +fail: + if (!priv->avfc) + avformat_free_context(avfc); + av_dict_free(&dopts); + + return -1; } static bool demux_lavf_read_packet(struct demuxer *demux, @@ -1126,13 +1237,17 @@ static bool demux_lavf_read_packet(struct demuxer *demux, update_read_stats(demux); if (r < 0) { av_packet_unref(pkt); - if (r == AVERROR(EAGAIN)) - return true; if (r == AVERROR_EOF) return false; MP_WARN(demux, "error reading packet: %s.\n", av_err2str(r)); - return false; + if (priv->retry_counter >= 10) { + MP_ERR(demux, "...treating it as fatal error.\n"); + return false; + } + priv->retry_counter += 1; + return true; } + priv->retry_counter = 0; add_new_streams(demux); update_metadata(demux); @@ -1161,8 +1276,6 @@ static bool demux_lavf_read_packet(struct demuxer *demux, dp->duration = pkt->duration * av_q2d(st->time_base); dp->pos = pkt->pos; dp->keyframe = pkt->flags & AV_PKT_FLAG_KEY; - if (pkt->flags & AV_PKT_FLAG_DISCARD) - MP_ERR(demux, "Edit lists are not correctly supported (FFmpeg issue).\n"); av_packet_unref(pkt); if (priv->format_hack.clear_filepos) @@ -1197,7 +1310,7 @@ static bool demux_lavf_read_packet(struct demuxer *demux, if (st->event_flags & AVSTREAM_EVENT_FLAG_METADATA_UPDATED) { st->event_flags = 0; struct mp_tags *tags = talloc_zero(NULL, struct mp_tags); - mp_tags_copy_from_av_dictionary(tags, st->metadata); + mp_tags_move_from_av_dictionary(tags, &st->metadata); double pts = MP_PTS_OR_DEF(dp->pts, dp->dts); demux_stream_tags_changed(demux, stream, tags, pts); } @@ -1251,10 +1364,11 @@ static void demux_seek_lavf(demuxer_t *demuxer, double seek_pts, int flags) if (priv->pcm_seek_hack && !priv->pcm_seek_hack_packet_size) { // This might for example be the initial seek. Fuck it up like the // bullshit it is. - AVPacket pkt = {0}; - if (av_read_frame(priv->avfc, &pkt) >= 0) - priv->pcm_seek_hack_packet_size = pkt.size; - av_packet_unref(&pkt); + AVPacket *pkt = av_packet_alloc(); + MP_HANDLE_OOM(pkt); + if (av_read_frame(priv->avfc, pkt) >= 0) + priv->pcm_seek_hack_packet_size = pkt->size; + av_packet_free(&pkt); add_new_streams(demuxer); } if (priv->pcm_seek_hack && priv->pcm_seek_hack_packet_size && @@ -1322,6 +1436,8 @@ static void demux_close_lavf(demuxer_t *demuxer) } if (priv->own_stream) free_stream(priv->stream); + if (priv->av_opts) + av_dict_free(&priv->av_opts); talloc_free(priv); demuxer->priv = NULL; } |