This is a replacement in ffmpeg for the deprecated avcodec flag AV_CODEC_FLAG_DROPCHANGED. This option is meant to be used when the filtergraph should not be reinited upon input parameter changes as that leads to loss of state in the filtergraph potentially leading to broken or aborted output, e.g. inserting of silence with first_pts specified in aresample. Generally useful to avoid corrupted yet decodable packets in live streaming inputs. This option when enabled takes precedence over reinit_filters
Unified · Split
| @@ -1373,6 +1373,12 @@ The properties where a change triggers reinitialization are, · 1372 unmodified lines | |||
| 1373 | for video, frame resolution or pixel format; | 1373 | for video, frame resolution or pixel format; |
| 1374 | for audio, sample format, sample rate, channel count or channel layout. | 1374 | for audio, sample format, sample rate, channel count or channel layout. |
| 1375 | 1375 | ||
| 1376 | @item -drop_changed[:@var{stream_specifier}] @var{integer} (@emph{input,per-stream}) | ||
| 1377 | This boolean option determines whether a frame with differing frame parameters mid-stream | ||
| 1378 | gets dropped instead of leading to filtergraph reinitialization, as that would lead to loss | ||
| 1379 | of filter state. Generally useful to avoid corrupted yet decodable packets in live streaming | ||
| 1380 | inputs. Default is false. | ||
| 1381 | |||
| 1376 | @item -filter_threads @var{nb_threads} (@emph{global}) | 1382 | @item -filter_threads @var{nb_threads} (@emph{global}) |
| 1377 | Defines how many threads are used to process a filter pipeline. Each pipeline | 1383 | Defines how many threads are used to process a filter pipeline. Each pipeline |
| 1378 | will produce a thread pool with this many threads available for parallel processing. | 1384 | will produce a thread pool with this many threads available for parallel processing. |
| @@ -232,6 +232,7 @@ typedef struct OptionsContext { · 231 unmodified lines | |||
| 232 | SpecifierOptList filter_scripts; | 232 | SpecifierOptList filter_scripts; |
| 233 | #endif | 233 | #endif |
| 234 | SpecifierOptList reinit_filters; | 234 | SpecifierOptList reinit_filters; |
| 235 | SpecifierOptList drop_changed; | ||
| 235 | SpecifierOptList fix_sub_duration; | 236 | SpecifierOptList fix_sub_duration; |
| 236 | SpecifierOptList fix_sub_duration_heartbeat; | 237 | SpecifierOptList fix_sub_duration_heartbeat; |
| 237 | SpecifierOptList canvas_sizes; | 238 | SpecifierOptList canvas_sizes; |
| @@ -262,6 +263,7 @@ enum IFilterFlags { · 24 unmodified lines | |||
| 262 | IFILTER_FLAG_REINIT = (1 << 1), | 263 | IFILTER_FLAG_REINIT = (1 << 1), |
| 263 | IFILTER_FLAG_CFR = (1 << 2), | 264 | IFILTER_FLAG_CFR = (1 << 2), |
| 264 | IFILTER_FLAG_CROP = (1 << 3), | 265 | IFILTER_FLAG_CROP = (1 << 3), |
| 266 | IFILTER_FLAG_DROPCHANGED = (1 << 4), | ||
| 265 | }; | 267 | }; |
| 266 | 268 | ||
| 267 | typedef struct InputFilterOptions { | 269 | typedef struct InputFilterOptions { |
| @@ -67,6 +67,7 @@ typedef struct DemuxStream { · 66 unmodified lines | |||
| 67 | int reinit_filters; | 67 | int reinit_filters; |
| 68 | int autorotate; | 68 | int autorotate; |
| 69 | int apply_cropping; | 69 | int apply_cropping; |
| 70 | int drop_changed; | ||
| 70 | 71 | ||
| 71 | 72 | ||
| 72 | int wrap_correction_done; | 73 | int wrap_correction_done; |
| @@ -1099,7 +1100,8 @@ int ist_filter_add(InputStream *ist, InputFilter *ifilter, int is_simple, · 1026 unmodified lines | |||
| 1099 | return AVERROR(ENOMEM); | 1100 | return AVERROR(ENOMEM); |
| 1100 | 1101 | ||
| 1101 | opts->flags |= IFILTER_FLAG_AUTOROTATE * !!(ds->autorotate) | | 1102 | opts->flags |= IFILTER_FLAG_AUTOROTATE * !!(ds->autorotate) | |
| 1102 | IFILTER_FLAG_REINIT * !!(ds->reinit_filters); | 1103 | IFILTER_FLAG_REINIT * !!(ds->reinit_filters) | |
| 1104 | IFILTER_FLAG_DROPCHANGED* !!(ds->drop_changed); | ||
| 1103 | 1105 | ||
| 1104 | return 0; | 1106 | return 0; |
| 1105 | } | 1107 | } |
| @@ -1410,6 +1412,17 @@ static int ist_add(const OptionsContext *o, Demuxer *d, AVStream *st, AVDictiona · 304 unmodified lines | |||
| 1410 | ds->reinit_filters = -1; | 1412 | ds->reinit_filters = -1; |
| 1411 | opt_match_per_stream_int(ist, &o->reinit_filters, ic, st, &ds->reinit_filters); | 1413 | opt_match_per_stream_int(ist, &o->reinit_filters, ic, st, &ds->reinit_filters); |
| 1412 | 1414 | ||
| 1415 | ds->drop_changed = 0; | ||
| 1416 | opt_match_per_stream_int(ist, &o->drop_changed, ic, st, &ds->drop_changed); | ||
| 1417 | |||
| 1418 | if (ds->drop_changed && ds->reinit_filters) { | ||
| 1419 | if (ds->reinit_filters > 0) { | ||
| 1420 | av_log(ist, AV_LOG_ERROR, "drop_changed and reinit_filters both enabled. These are mutually exclusive.\n"); | ||
| 1421 | return AVERROR(EINVAL); | ||
| 1422 | } | ||
| 1423 | ds->reinit_filters = 0; | ||
| 1424 | } | ||
| 1425 | |||
| 1413 | ist->user_set_discard = AVDISCARD_NONE; | 1426 | ist->user_set_discard = AVDISCARD_NONE; |
| 1414 | 1427 | ||
| 1415 | if ((o->video_disable && ist->st->codecpar->codec_type == AVMEDIA_TYPE_VIDEO) || | 1428 | if ((o->video_disable && ist->st->codecpar->codec_type == AVMEDIA_TYPE_VIDEO) || |
| @@ -126,6 +126,8 @@ typedef struct InputFilterPriv { · 125 unmodified lines | |||
| 126 | 126 | ||
| 127 | int eof; | 127 | int eof; |
| 128 | int bound; | 128 | int bound; |
| 129 | int drop_warned; | ||
| 130 | uint64_t nb_dropped; | ||
| 129 | 131 | ||
| 130 | // parameters configured for this input | 132 | // parameters configured for this input |
| 131 | int format; | 133 | int format; |
| @@ -2898,6 +2900,13 @@ static int send_frame(FilterGraph *fg, FilterGraphThread *fgt, · 2766 unmodified lines | |||
| 2898 | } else if (ifp->downmixinfo_present) | 2900 | } else if (ifp->downmixinfo_present) |
| 2899 | need_reinit |= DOWNMIX_CHANGED; | 2901 | need_reinit |= DOWNMIX_CHANGED; |
| 2900 | 2902 | ||
| 2903 | if (need_reinit && (ifp->opts.flags & IFILTER_FLAG_DROPCHANGED)) { | ||
| 2904 | ifp->nb_dropped++; | ||
| 2905 | av_log_once(fg, AV_LOG_WARNING, AV_LOG_DEBUG, &ifp->drop_warned, "Avoiding reinit; dropping frame pts: %s bound for %s\n", av_ts2str(frame->pts), ifilter->name); | ||
| 2906 | av_frame_unref(frame); | ||
| 2907 | return 0; | ||
| 2908 | } | ||
| 2909 | |||
| 2901 | if (!(ifp->opts.flags & IFILTER_FLAG_REINIT) && fgt->graph) | 2910 | if (!(ifp->opts.flags & IFILTER_FLAG_REINIT) && fgt->graph) |
| 2902 | need_reinit = 0; | 2911 | need_reinit = 0; |
| 2903 | 2912 | ||
| @@ -3140,6 +3149,8 @@ read_frames: · 236 unmodified lines | |||
| 3140 | ret = read_frames(fg, &fgt, fgt.frame); | 3149 | ret = read_frames(fg, &fgt, fgt.frame); |
| 3141 | if (ret == AVERROR_EOF) { | 3150 | if (ret == AVERROR_EOF) { |
| 3142 | av_log(fg, AV_LOG_VERBOSE, "All consumers returned EOF\n"); | 3151 | av_log(fg, AV_LOG_VERBOSE, "All consumers returned EOF\n"); |
| 3152 | if (ifp->opts.flags & IFILTER_FLAG_DROPCHANGED) | ||
| 3153 | av_log(fg, AV_LOG_INFO, "Total changed input frames dropped : %"PRId64"\n", ifp->nb_dropped); | ||
| 3143 | break; | 3154 | break; |
| 3144 | } else if (ret < 0) { | 3155 | } else if (ret < 0) { |
| 3145 | av_log(fg, AV_LOG_ERROR, "Error sending frames to consumers: %s\n", | 3156 | av_log(fg, AV_LOG_ERROR, "Error sending frames to consumers: %s\n", |
| @@ -1718,6 +1718,9 @@ const OptionDef options[] = { · 1717 unmodified lines | |||
| 1718 | { "reinit_filter", OPT_TYPE_INT, OPT_PERSTREAM | OPT_INPUT | OPT_EXPERT, | 1718 | { "reinit_filter", OPT_TYPE_INT, OPT_PERSTREAM | OPT_INPUT | OPT_EXPERT, |
| 1719 | { .off = OFFSET(reinit_filters) }, | 1719 | { .off = OFFSET(reinit_filters) }, |
| 1720 | "reinit filtergraph on input parameter changes", "" }, | 1720 | "reinit filtergraph on input parameter changes", "" }, |
| 1721 | { "drop_changed", OPT_TYPE_INT, OPT_PERSTREAM | OPT_INPUT | OPT_EXPERT, | ||
| 1722 | { .off = OFFSET(drop_changed) }, | ||
| 1723 | "drop frame instead of reiniting filtergraph on input parameter changes", "" }, | ||
| 1721 | { "filter_complex", OPT_TYPE_FUNC, OPT_FUNC_ARG | OPT_EXPERT, | 1724 | { "filter_complex", OPT_TYPE_FUNC, OPT_FUNC_ARG | OPT_EXPERT, |
| 1722 | { .func_arg = opt_filter_complex }, | 1725 | { .func_arg = opt_filter_complex }, |
| 1723 | "create a complex filtergraph", "graph_description" }, | 1726 | "create a complex filtergraph", "graph_description" }, |