History

ffmpeg: add per-stream input option drop_changed

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

Gyan Doshi committed 1 year ago

Commit cbbc9271 parent 323cb8c5 files · +36 −1Browse files

Unified · Split

5 files
  1. doc/ffmpeg.texi +6 −0
  2. fftools/ffmpeg.h +2 −0
  3. fftools/ffmpeg_demux.c +14 −1
  4. fftools/ffmpeg_filter.c +11 −0
  5. fftools/ffmpeg_opt.c +3 −0
doc/ffmpeg.texi+6−0
@@ -1373,6 +1373,12 @@ The properties where a change triggers reinitialization are, · 1372 unmodified lines
1373for video, frame resolution or pixel format;1373for video, frame resolution or pixel format;
1374for audio, sample format, sample rate, channel count or channel layout.1374for 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})
1377This boolean option determines whether a frame with differing frame parameters mid-stream
1378gets dropped instead of leading to filtergraph reinitialization, as that would lead to loss
1379of filter state. Generally useful to avoid corrupted yet decodable packets in live streaming
1380inputs. Default is false.
1381
1376@item -filter_threads @var{nb_threads} (@emph{global})1382@item -filter_threads @var{nb_threads} (@emph{global})
1377Defines how many threads are used to process a filter pipeline. Each pipeline1383Defines how many threads are used to process a filter pipeline. Each pipeline
1378will produce a thread pool with this many threads available for parallel processing.1384will produce a thread pool with this many threads available for parallel processing.
fftools/ffmpeg.h+2−0
@@ -232,6 +232,7 @@ typedef struct OptionsContext { · 231 unmodified lines
232 SpecifierOptList filter_scripts;232 SpecifierOptList filter_scripts;
233#endif233#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
267typedef struct InputFilterOptions {269typedef struct InputFilterOptions {
fftools/ffmpeg_demux.c+14−1
@@ -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) ||
fftools/ffmpeg_filter.c+11−0
@@ -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 input132 // 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",
fftools/ffmpeg_opt.c+3−0
@@ -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" },

Keyboard shortcuts

General

Show keyboard shortcuts
?
Focus the current search
/

Issues and pull requests

Open filters
f

Issues, pull requests and Inbox

Select next item
j↓
Select previous item
k↑
Open selected item
Enter
Dismiss filters or clear selection
Esc

Repository code

Go to file
t