From d217a16d41dd71c921fa2155e068df7cca11f457 Mon Sep 17 00:00:00 2001 From: Carl Hetherington Date: Sun, 24 Jan 2016 23:40:32 +0000 Subject: [PATCH] Stop trying to get frames from a video source when an attempt to get an earlier frame has already failed because the decoder said it has no more data. Before this the VideoDecoder would repeatedly seek to try to get a frame which does not exist. This happens when the header of a file is wrong, it would seem; in the file that triggered the bug the header (as read by DoM or ffprobe) has a length of 137275 frames but the last frame in the file (according to DoM or ffprobe -show_frames) is 136207 (44.5s earlier). --- ChangeLog | 4 ++++ src/lib/video_decoder.cc | 11 ++++++++--- src/lib/video_decoder.h | 5 ++++- 3 files changed, 16 insertions(+), 4 deletions(-) diff --git a/ChangeLog b/ChangeLog index 427c36294..c2d05c5eb 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,7 @@ +2016-01-24 Carl Hetherington + + * Fix encodes getting stuck in some cases (#783). + 2016-01-23 Carl Hetherington * Fix estimate of required disk space to take referencing diff --git a/src/lib/video_decoder.cc b/src/lib/video_decoder.cc index fd5779a65..1de2cd806 100644 --- a/src/lib/video_decoder.cc +++ b/src/lib/video_decoder.cc @@ -1,5 +1,5 @@ /* - Copyright (C) 2012-2015 Carl Hetherington + Copyright (C) 2012-2016 Carl Hetherington This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -70,6 +70,10 @@ VideoDecoder::decoded_video (Frame frame) list VideoDecoder::get_video (Frame frame, bool accurate) { + if (_no_data_frame && frame >= _no_data_frame.get()) { + return list (); + } + /* At this stage, if we have get_video()ed before, _decoded_video will contain the last frame that this method returned (and possibly a few more). If the requested frame is not in _decoded_video and it is not the next one after the end of _decoded_video we need to seek. @@ -100,6 +104,7 @@ VideoDecoder::get_video (Frame frame, bool accurate) if (pass (PASS_REASON_VIDEO, accurate)) { /* The decoder has nothing more for us */ + _no_data_frame = frame; break; } @@ -121,9 +126,9 @@ VideoDecoder::get_video (Frame frame, bool accurate) } } - /* Clean up _decoded_video; keep the frame we are returning (which may have two images + /* Clean up _decoded_video; keep the frame we are returning, if any (which may have two images for 3D), but nothing before that */ - while (!_decoded_video.empty() && _decoded_video.front().frame < dec.front().frame) { + while (!_decoded_video.empty() && !dec.empty() && _decoded_video.front().frame < dec.front().frame) { _decoded_video.pop_front (); } diff --git a/src/lib/video_decoder.h b/src/lib/video_decoder.h index 42cfc4906..af24b93bc 100644 --- a/src/lib/video_decoder.h +++ b/src/lib/video_decoder.h @@ -70,9 +70,12 @@ protected: boost::shared_ptr _black_image; boost::optional _last_seek_time; bool _last_seek_accurate; - /** true if this decoder should ignore all video; i.e. never produce any */ bool _ignore_video; + /** if set, this is a frame for which we got no data because the Decoder said + * it has no more to give. + */ + boost::optional _no_data_frame; }; #endif -- 2.30.2