[FFmpeg-devel] [PATCH] ffmpeg: Add threshold to discard crazy/damaged timestamps.
Michael Niedermayer
michaelni at gmx.at
Wed Feb 8 00:50:11 CET 2012
The added tests are limited to the case where timestamp discontinuities
are not allowed. The default is 30 hours which is arbitrarily picked and
quite conservative.
This prevents a out of memory condition due to duplicating a frame
millions of times.
Found-by: Mateusz "j00ru" Jurczyk and Gynvael Coldwind
Signed-off-by: Michael Niedermayer <michaelni at gmx.at>
---
ffmpeg.c | 27 +++++++++++++++++++++++----
1 files changed, 23 insertions(+), 4 deletions(-)
diff --git a/ffmpeg.c b/ffmpeg.c
index 9b6c19d..8d4e9dd 100644
--- a/ffmpeg.c
+++ b/ffmpeg.c
@@ -171,6 +171,7 @@ static int nb_frames_drop = 0;
static int input_sync;
static float dts_delta_threshold = 10;
+static float dts_error_threshold = 3600*30;
static int print_stats = 1;
@@ -3021,14 +3022,14 @@ static int transcode(OutputFile *output_files, int nb_output_files,
// ist->next_pts,
// pkt.dts, input_files[ist->file_index].ts_offset,
// ist->st->codec->codec_type);
- if (pkt.dts != AV_NOPTS_VALUE && ist->next_pts != AV_NOPTS_VALUE
- && (is->iformat->flags & AVFMT_TS_DISCONT)) {
+ if (pkt.dts != AV_NOPTS_VALUE && ist->next_pts != AV_NOPTS_VALUE && !copy_ts) {
int64_t pkt_dts = av_rescale_q(pkt.dts, ist->st->time_base, AV_TIME_BASE_Q);
int64_t delta = pkt_dts - ist->next_pts;
- if((delta < -1LL*dts_delta_threshold*AV_TIME_BASE ||
+ if (is->iformat->flags & AVFMT_TS_DISCONT) {
+ if(delta < -1LL*dts_delta_threshold*AV_TIME_BASE ||
(delta > 1LL*dts_delta_threshold*AV_TIME_BASE &&
ist->st->codec->codec_type != AVMEDIA_TYPE_SUBTITLE) ||
- pkt_dts+1<ist->pts)&& !copy_ts){
+ pkt_dts+1<ist->pts){
input_files[ist->file_index].ts_offset -= delta;
av_log(NULL, AV_LOG_DEBUG,
"timestamp discontinuity %"PRId64", new offset= %"PRId64"\n",
@@ -3037,6 +3038,23 @@ static int transcode(OutputFile *output_files, int nb_output_files,
if (pkt.pts != AV_NOPTS_VALUE)
pkt.pts-= av_rescale_q(delta, AV_TIME_BASE_Q, ist->st->time_base);
}
+ } else {
+ if ( delta < -1LL*dts_error_threshold*AV_TIME_BASE ||
+ (delta > 1LL*dts_error_threshold*AV_TIME_BASE && ist->st->codec->codec_type != AVMEDIA_TYPE_SUBTITLE) ||
+ pkt_dts+1<ist->pts){
+ av_log(NULL, AV_LOG_WARNING, "DTS %"PRId64", %"PRId64" invalid droping\n", pkt.dts, ist->next_pts);
+ pkt.dts = AV_NOPTS_VALUE;
+ }
+ if (pkt.pts != AV_NOPTS_VALUE){
+ int64_t pkt_pts = av_rescale_q(pkt.pts, ist->st->time_base, AV_TIME_BASE_Q);
+ delta = pkt_pts - ist->next_pts;
+ if ( delta < -1LL*dts_error_threshold*AV_TIME_BASE ||
+ (delta > 1LL*dts_error_threshold*AV_TIME_BASE && ist->st->codec->codec_type != AVMEDIA_TYPE_SUBTITLE)) {
+ av_log(NULL, AV_LOG_WARNING, "PTS %"PRId64", %"PRId64" invalid droping\n", pkt.pts, ist->next_pts);
+ pkt.pts = AV_NOPTS_VALUE;
+ }
+ }
+ }
}
// fprintf(stderr,"read #%d.%d size=%d\n", ist->file_index, ist->st->index, pkt.size);
@@ -4962,6 +4980,7 @@ static const OptionDef options[] = {
{ "copytb", HAS_ARG | OPT_INT | OPT_EXPERT, {(void*)©_tb}, "copy input stream time base when stream copying", "source" },
{ "shortest", OPT_BOOL | OPT_EXPERT, {(void*)&opt_shortest}, "finish encoding within shortest input" }, //
{ "dts_delta_threshold", HAS_ARG | OPT_FLOAT | OPT_EXPERT, {(void*)&dts_delta_threshold}, "timestamp discontinuity delta threshold", "threshold" },
+ { "dts_error_threshold", HAS_ARG | OPT_FLOAT | OPT_EXPERT, {(void*)&dts_error_threshold}, "timestamp error delta threshold", "threshold" },
{ "xerror", OPT_BOOL, {(void*)&exit_on_error}, "exit on error", "error" },
{ "copyinkf", OPT_BOOL | OPT_EXPERT | OPT_SPEC, {.off = OFFSET(copy_initial_nonkeyframes)}, "copy initial non-keyframes" },
{ "frames", OPT_INT64 | HAS_ARG | OPT_SPEC, {.off = OFFSET(max_frames)}, "set the number of frames to record", "number" },
--
1.7.5.4
More information about the ffmpeg-devel
mailing list