summaryrefslogtreecommitdiff
path: root/src/lib
diff options
context:
space:
mode:
authorCarl Hetherington <cth@carlh.net>2013-12-11 10:31:18 +0000
committerCarl Hetherington <cth@carlh.net>2013-12-11 10:31:18 +0000
commitea910e250a0fb3b0ad3ce0cf32dd27b24c17cd1d (patch)
tree32119d2a04532d3162c656df7c7e715b289c6e61 /src/lib
parent3e5df964ada49e10a880a200c985cc309ccecb64 (diff)
Various work on better seeking (and seeking of audio).
Diffstat (limited to 'src/lib')
-rw-r--r--src/lib/audio_content.cc24
-rw-r--r--src/lib/audio_content.h2
-rw-r--r--src/lib/audio_merger.h9
-rw-r--r--src/lib/decoder.h9
-rw-r--r--src/lib/ffmpeg.cc4
-rw-r--r--src/lib/ffmpeg_content.cc7
-rw-r--r--src/lib/ffmpeg_decoder.cc151
-rw-r--r--src/lib/ffmpeg_decoder.h7
-rw-r--r--src/lib/film.cc6
-rw-r--r--src/lib/film.h1
-rw-r--r--src/lib/image_content.cc2
-rw-r--r--src/lib/image_decoder.cc4
-rw-r--r--src/lib/image_decoder.h2
-rw-r--r--src/lib/player.cc14
-rw-r--r--src/lib/playlist.cc17
-rw-r--r--src/lib/playlist.h2
-rw-r--r--src/lib/sndfile_decoder.cc6
-rw-r--r--src/lib/sndfile_decoder.h1
-rw-r--r--src/lib/util.cc5
-rw-r--r--src/lib/util.h9
-rw-r--r--src/lib/video_content.cc12
-rw-r--r--src/lib/video_decoder.h5
22 files changed, 222 insertions, 77 deletions
diff --git a/src/lib/audio_content.cc b/src/lib/audio_content.cc
index 97372b962..0c4586681 100644
--- a/src/lib/audio_content.cc
+++ b/src/lib/audio_content.cc
@@ -148,3 +148,27 @@ AudioContent::technical_summary () const
{
return String::compose ("audio: channels %1, length %2, raw rate %3, out rate %4", audio_channels(), audio_length(), content_audio_frame_rate(), output_audio_frame_rate());
}
+
+/** Note: this is not particularly fast, as the FrameRateChange lookup
+ * is not very intelligent.
+ *
+ * @param t Some duration to convert.
+ * @param at The time within the DCP to get the active frame rate change from; i.e. a point at which
+ * the `controlling' video content is active.
+ */
+AudioContent::Frame
+AudioContent::time_to_content_audio_frames (Time t, Time at) const
+{
+ shared_ptr<const Film> film = _film.lock ();
+ assert (film);
+
+ /* Consider the case where we're running a 25fps video at 24fps (i.e. slow)
+ Our audio is at 44.1kHz. We will resample it to 48000 * 25 / 24 and then
+ run it at 48kHz (i.e. slow, to match).
+
+ After 1 second, we'll have run the equivalent of 44.1kHz * 24 / 25 samples
+ in the source.
+ */
+
+ return rint (t * content_audio_frame_rate() * film->active_frame_rate_change(at).speed_up / TIME_HZ);
+}
diff --git a/src/lib/audio_content.h b/src/lib/audio_content.h
index ca4a1f234..10114e10d 100644
--- a/src/lib/audio_content.h
+++ b/src/lib/audio_content.h
@@ -74,6 +74,8 @@ public:
return _audio_delay;
}
+ Frame time_to_content_audio_frames (Time, Time) const;
+
private:
/** Gain to apply to audio in dB */
float _audio_gain;
diff --git a/src/lib/audio_merger.h b/src/lib/audio_merger.h
index 226601e0e..6ad33fb37 100644
--- a/src/lib/audio_merger.h
+++ b/src/lib/audio_merger.h
@@ -97,9 +97,16 @@ public:
if (_buffers->frames() == 0) {
return TimedAudioBuffers<T> ();
}
-
+
return TimedAudioBuffers<T> (_buffers, _last_pull);
}
+
+ void
+ clear (Time t)
+ {
+ _last_pull = t;
+ _buffers.reset (new AudioBuffers (_buffers->channels(), 0));
+ }
private:
boost::shared_ptr<AudioBuffers> _buffers;
diff --git a/src/lib/decoder.h b/src/lib/decoder.h
index d67592ed8..908d3aae5 100644
--- a/src/lib/decoder.h
+++ b/src/lib/decoder.h
@@ -27,6 +27,7 @@
#include <boost/shared_ptr.hpp>
#include <boost/weak_ptr.hpp>
#include <boost/utility.hpp>
+#include "types.h"
class Film;
@@ -43,6 +44,14 @@ public:
* cause the object to emit some data.
*/
virtual void pass () = 0;
+
+ /** Seek so that the next pass() will yield the next thing
+ * (video/sound frame, subtitle etc.) at or after the requested
+ * time. Pass accurate = true to try harder to get close to
+ * the request.
+ */
+ virtual void seek (Time time, bool accurate) = 0;
+
virtual bool done () const = 0;
protected:
diff --git a/src/lib/ffmpeg.cc b/src/lib/ffmpeg.cc
index e5e5f317a..53d12419a 100644
--- a/src/lib/ffmpeg.cc
+++ b/src/lib/ffmpeg.cc
@@ -191,6 +191,10 @@ FFmpeg::video_codec_context () const
AVCodecContext *
FFmpeg::audio_codec_context () const
{
+ if (!_ffmpeg_content->audio_stream ()) {
+ return 0;
+ }
+
return _ffmpeg_content->audio_stream()->stream(_format_context)->codec;
}
diff --git a/src/lib/ffmpeg_content.cc b/src/lib/ffmpeg_content.cc
index 9533315a5..b6df2e929 100644
--- a/src/lib/ffmpeg_content.cc
+++ b/src/lib/ffmpeg_content.cc
@@ -310,16 +310,15 @@ FFmpegContent::output_audio_frame_rate () const
/* Resample to a DCI-approved sample rate */
double t = dcp_audio_frame_rate (content_audio_frame_rate ());
- FrameRateConversion frc (video_frame_rate(), film->video_frame_rate());
+ FrameRateChange frc (video_frame_rate(), film->video_frame_rate());
/* Compensate if the DCP is being run at a different frame rate
to the source; that is, if the video is run such that it will
look different in the DCP compared to the source (slower or faster).
- skip/repeat doesn't come into effect here.
*/
if (frc.change_speed) {
- t *= video_frame_rate() * frc.factor() / film->video_frame_rate();
+ t /= frc.speed_up;
}
return rint (t);
@@ -452,7 +451,7 @@ FFmpegContent::full_length () const
shared_ptr<const Film> film = _film.lock ();
assert (film);
- FrameRateConversion frc (video_frame_rate (), film->video_frame_rate ());
+ FrameRateChange frc (video_frame_rate (), film->video_frame_rate ());
return video_length() * frc.factor() * TIME_HZ / film->video_frame_rate ();
}
diff --git a/src/lib/ffmpeg_decoder.cc b/src/lib/ffmpeg_decoder.cc
index 5a1b78762..ed0574c61 100644
--- a/src/lib/ffmpeg_decoder.cc
+++ b/src/lib/ffmpeg_decoder.cc
@@ -297,70 +297,132 @@ FFmpegDecoder::bytes_per_audio_sample () const
return av_get_bytes_per_sample (audio_sample_format ());
}
-void
-FFmpegDecoder::seek (VideoContent::Frame frame, bool accurate)
+int
+FFmpegDecoder::minimal_run (boost::function<bool (int)> finished)
{
- double const time_base = av_q2d (_format_context->streams[_video_stream]->time_base);
+ int frames_read = 0;
+
+ while (!finished (frames_read)) {
+ int r = av_read_frame (_format_context, &_packet);
+ if (r < 0) {
+ return -1;
+ }
- /* If we are doing an accurate seek, our initial shot will be 5 frames (5 being
- a number plucked from the air) earlier than we want to end up. The loop below
- will hopefully then step through to where we want to be.
- */
- int initial = frame;
+ ++frames_read;
- if (accurate) {
- initial -= 5;
- }
+ double const time_base = av_q2d (_format_context->streams[_packet.stream_index]->time_base);
+
+ if (_packet.stream_index == _video_stream) {
+
+ avcodec_get_frame_defaults (_frame);
+
+ int finished = 0;
+ r = avcodec_decode_video2 (video_codec_context(), _frame, &finished, &_packet);
+ if (r >= 0 && finished) {
+ _video_position = rint (
+ (av_frame_get_best_effort_timestamp (_frame) * time_base + _video_pts_offset) * _ffmpeg_content->video_frame_rate()
+ );
+ }
+
+ } else if (_ffmpeg_content->audio_stream() && _packet.stream_index == _ffmpeg_content->audio_stream()->index (_format_context)) {
+
+ AVPacket copy_packet = _packet;
- if (initial < 0) {
- initial = 0;
+ while (copy_packet.size > 0) {
+
+ int finished;
+ r = avcodec_decode_audio4 (audio_codec_context(), _frame, &finished, &copy_packet);
+ if (r >= 0 && finished) {
+ _audio_position = rint (
+ (av_frame_get_best_effort_timestamp (_frame) * time_base + _audio_pts_offset) *
+ _ffmpeg_content->audio_stream()->frame_rate
+ );
+ }
+
+ copy_packet.data += r;
+ copy_packet.size -= r;
+ }
+ }
+
+ av_free_packet (&_packet);
}
- /* Initial seek time in the stream's timebase */
- int64_t const initial_vt = ((initial / _ffmpeg_content->video_frame_rate()) - _video_pts_offset) / time_base;
+ return frames_read;
+}
+
+bool
+FFmpegDecoder::seek_overrun_finished (Time seek) const
+{
+ return (
+ _video_position >= _ffmpeg_content->time_to_content_video_frames (seek) ||
+ _audio_position >= _ffmpeg_content->time_to_content_audio_frames (seek, _ffmpeg_content->position())
+ );
+}
+
+bool
+FFmpegDecoder::seek_final_finished (int n, int done) const
+{
+ return n == done;
+}
+
+void
+FFmpegDecoder::seek_and_flush (Time t)
+{
+ int64_t const initial_v = ((_ffmpeg_content->time_to_content_video_frames (t) / _ffmpeg_content->video_frame_rate()) - _video_pts_offset) /
+ av_q2d (_format_context->streams[_video_stream]->time_base);
+
+ av_seek_frame (_format_context, _video_stream, initial_v, AVSEEK_FLAG_BACKWARD);
- av_seek_frame (_format_context, _video_stream, initial_vt, AVSEEK_FLAG_BACKWARD);
+ shared_ptr<FFmpegAudioStream> as = _ffmpeg_content->audio_stream ();
+ if (as) {
+ int64_t initial_a = ((_ffmpeg_content->time_to_content_audio_frames (t, t) / as->frame_rate) - _audio_pts_offset) /
+ av_q2d (as->stream(_format_context)->time_base);
+
+ av_seek_frame (_format_context, as->index (_format_context), initial_a, AVSEEK_FLAG_BACKWARD);
+ }
avcodec_flush_buffers (video_codec_context());
+ if (audio_codec_context ()) {
+ avcodec_flush_buffers (audio_codec_context ());
+ }
if (_subtitle_codec_context) {
avcodec_flush_buffers (_subtitle_codec_context);
}
+ _video_position = _ffmpeg_content->time_to_content_video_frames (t);
+ _audio_position = _ffmpeg_content->time_to_content_audio_frames (t, t);
+}
+
+void
+FFmpegDecoder::seek (Time time, bool accurate)
+{
+ /* If we are doing an accurate seek, our initial shot will be 200ms (200 being
+ a number plucked from the air) earlier than we want to end up. The loop below
+ will hopefully then step through to where we want to be.
+ */
+
+ Time pre_roll = accurate ? (0.2 * TIME_HZ) : 0;
+ Time initial_seek = time - pre_roll;
+ if (initial_seek < 0) {
+ initial_seek = 0;
+ }
+
+ /* Initial seek time in the video stream's timebase */
+
+ seek_and_flush (initial_seek);
+
_just_sought = true;
- _video_position = frame;
- if (frame == 0 || !accurate) {
+ if (time == 0 || !accurate) {
/* We're already there, or we're as close as we need to be */
return;
}
- while (1) {
- int r = av_read_frame (_format_context, &_packet);
- if (r < 0) {
- return;
- }
+ int const N = minimal_run (boost::bind (&FFmpegDecoder::seek_overrun_finished, this, time));
- if (_packet.stream_index != _video_stream) {
- av_free_packet (&_packet);
- continue;
- }
-
- avcodec_get_frame_defaults (_frame);
-
- int finished = 0;
- r = avcodec_decode_video2 (video_codec_context(), _frame, &finished, &_packet);
- if (r >= 0 && finished) {
- _video_position = rint (
- (av_frame_get_best_effort_timestamp (_frame) * time_base + _video_pts_offset) * _ffmpeg_content->video_frame_rate()
- );
-
- if (_video_position >= (frame - 1)) {
- av_free_packet (&_packet);
- break;
- }
- }
-
- av_free_packet (&_packet);
+ seek_and_flush (initial_seek);
+ if (N > 0) {
+ minimal_run (boost::bind (&FFmpegDecoder::seek_final_finished, this, N - 1, _1));
}
}
@@ -377,6 +439,7 @@ FFmpegDecoder::decode_audio_packet ()
int frame_finished;
int const decode_result = avcodec_decode_audio4 (audio_codec_context(), _frame, &frame_finished, &copy_packet);
+
if (decode_result < 0) {
shared_ptr<const Film> film = _film.lock ();
assert (film);
diff --git a/src/lib/ffmpeg_decoder.h b/src/lib/ffmpeg_decoder.h
index 11f83ed97..f54ee2496 100644
--- a/src/lib/ffmpeg_decoder.h
+++ b/src/lib/ffmpeg_decoder.h
@@ -52,7 +52,7 @@ public:
~FFmpegDecoder ();
void pass ();
- void seek (VideoContent::Frame, bool);
+ void seek (Time time, bool);
bool done () const;
private:
@@ -74,6 +74,11 @@ private:
void maybe_add_subtitle ();
boost::shared_ptr<AudioBuffers> deinterleave_audio (uint8_t** data, int size);
+ bool seek_overrun_finished (Time) const;
+ bool seek_final_finished (int, int) const;
+ int minimal_run (boost::function<bool (int)>);
+ void seek_and_flush (int64_t);
+
AVCodecContext* _subtitle_codec_context; ///< may be 0 if there is no subtitle
AVCodec* _subtitle_codec; ///< may be 0 if there is no subtitle
diff --git a/src/lib/film.cc b/src/lib/film.cc
index 5946d5bec..b61991a45 100644
--- a/src/lib/film.cc
+++ b/src/lib/film.cc
@@ -866,6 +866,12 @@ Film::content_paths_valid () const
return _playlist->content_paths_valid ();
}
+FrameRateChange
+Film::active_frame_rate_change (Time t) const
+{
+ return _playlist->active_frame_rate_change (t, video_frame_rate ());
+}
+
void
Film::playlist_content_changed (boost::weak_ptr<Content> c, int p)
{
diff --git a/src/lib/film.h b/src/lib/film.h
index 4b07f84a9..6573bd5b7 100644
--- a/src/lib/film.h
+++ b/src/lib/film.h
@@ -115,6 +115,7 @@ public:
bool has_subtitles () const;
OutputVideoFrame best_video_frame_rate () const;
bool content_paths_valid () const;
+ FrameRateChange active_frame_rate_change (Time) const;
libdcp::KDM
make_kdm (
diff --git a/src/lib/image_content.cc b/src/lib/image_content.cc
index b05fa6b8d..8eba33f3a 100644
--- a/src/lib/image_content.cc
+++ b/src/lib/image_content.cc
@@ -126,7 +126,7 @@ ImageContent::full_length () const
shared_ptr<const Film> film = _film.lock ();
assert (film);
- FrameRateConversion frc (video_frame_rate(), film->video_frame_rate ());
+ FrameRateChange frc (video_frame_rate(), film->video_frame_rate ());
return video_length() * frc.factor() * TIME_HZ / video_frame_rate();
}
diff --git a/src/lib/image_decoder.cc b/src/lib/image_decoder.cc
index fb6053ae5..bf3bc344b 100644
--- a/src/lib/image_decoder.cc
+++ b/src/lib/image_decoder.cc
@@ -77,9 +77,9 @@ ImageDecoder::pass ()
}
void
-ImageDecoder::seek (VideoContent::Frame frame, bool)
+ImageDecoder::seek (Time time, bool)
{
- _video_position = frame;
+ _video_position = _video_content->time_to_content_video_frames (time);
}
bool
diff --git a/src/lib/image_decoder.h b/src/lib/image_decoder.h
index c7500243e..1f5f0b9d2 100644
--- a/src/lib/image_decoder.h
+++ b/src/lib/image_decoder.h
@@ -37,7 +37,7 @@ public:
/* Decoder */
void pass ();
- void seek (VideoContent::Frame, bool);
+ void seek (Time, bool);
bool done () const;
private:
diff --git a/src/lib/player.cc b/src/lib/player.cc
index 7f500b3d6..184c9811f 100644
--- a/src/lib/player.cc
+++ b/src/lib/player.cc
@@ -235,7 +235,7 @@ Player::pass ()
_audio_position += _film->audio_frames_to_time (tb.audio->frames ());
}
}
-
+
return false;
}
@@ -259,7 +259,7 @@ Player::process_video (weak_ptr<Piece> weak_piece, shared_ptr<const Image> image
shared_ptr<VideoContent> content = dynamic_pointer_cast<VideoContent> (piece->content);
assert (content);
- FrameRateConversion frc (content->video_frame_rate(), _film->video_frame_rate());
+ FrameRateChange frc (content->video_frame_rate(), _film->video_frame_rate());
if (frc.skip && (frame % 2) == 1) {
return;
}
@@ -420,16 +420,12 @@ Player::seek (Time t, bool accurate)
(*i)->video_position = (*i)->audio_position = vc->position() + s;
/* And seek the decoder */
- dynamic_pointer_cast<VideoDecoder>((*i)->decoder)->seek (
- vc->time_to_content_video_frames (s + vc->trim_start ()), accurate
- );
-
+ dynamic_pointer_cast<VideoDecoder>((*i)->decoder)->seek (s + vc->trim_start (), accurate);
(*i)->reset_repeat ();
}
_video_position = _audio_position = t;
-
- /* XXX: don't seek audio because we don't need to... */
+ _audio_merger.clear (t);
}
void
@@ -456,7 +452,7 @@ Player::setup_pieces ()
fd->Audio.connect (bind (&Player::process_audio, this, weak_ptr<Piece> (piece), _1, _2));
fd->Subtitle.connect (bind (&Player::process_subtitle, this, weak_ptr<Piece> (piece), _1, _2, _3, _4));
- fd->seek (fc->time_to_content_video_frames (fc->trim_start ()), true);
+ fd->seek (fc->trim_start (), true);
piece->decoder = fd;
}
diff --git a/src/lib/playlist.cc b/src/lib/playlist.cc
index 37b290218..581235adc 100644
--- a/src/lib/playlist.cc
+++ b/src/lib/playlist.cc
@@ -292,6 +292,23 @@ Playlist::video_end () const
return end;
}
+FrameRateChange
+Playlist::active_frame_rate_change (Time t, int dcp_video_frame_rate) const
+{
+ for (ContentList::const_iterator i = _content.begin(); i != _content.end(); ++i) {
+ shared_ptr<const VideoContent> vc = dynamic_pointer_cast<const VideoContent> (*i);
+ if (!vc) {
+ break;
+ }
+
+ if (vc->position() >= t && t < vc->end()) {
+ return FrameRateChange (vc->video_frame_rate(), dcp_video_frame_rate);
+ }
+ }
+
+ return FrameRateChange (dcp_video_frame_rate, dcp_video_frame_rate);
+}
+
void
Playlist::set_sequence_video (bool s)
{
diff --git a/src/lib/playlist.h b/src/lib/playlist.h
index f87b3397b..d3cf50a27 100644
--- a/src/lib/playlist.h
+++ b/src/lib/playlist.h
@@ -25,6 +25,7 @@
#include <boost/enable_shared_from_this.hpp>
#include "ffmpeg_content.h"
#include "audio_mapping.h"
+#include "util.h"
class Content;
class FFmpegContent;
@@ -74,6 +75,7 @@ public:
int best_dcp_frame_rate () const;
Time video_end () const;
+ FrameRateChange active_frame_rate_change (Time, int dcp_frame_rate) const;
void set_sequence_video (bool);
void maybe_sequence_video ();
diff --git a/src/lib/sndfile_decoder.cc b/src/lib/sndfile_decoder.cc
index e10f4f568..0cca25257 100644
--- a/src/lib/sndfile_decoder.cc
+++ b/src/lib/sndfile_decoder.cc
@@ -118,3 +118,9 @@ SndfileDecoder::done () const
{
return _audio_position >= _sndfile_content->audio_length ();
}
+
+void
+SndfileDecoder::seek (Time t, bool accurate)
+{
+ /* XXX */
+}
diff --git a/src/lib/sndfile_decoder.h b/src/lib/sndfile_decoder.h
index 77fa6d177..c3db1c294 100644
--- a/src/lib/sndfile_decoder.h
+++ b/src/lib/sndfile_decoder.h
@@ -30,6 +30,7 @@ public:
~SndfileDecoder ();
void pass ();
+ void seek (Time, bool);
bool done () const;
int audio_channels () const;
diff --git a/src/lib/util.cc b/src/lib/util.cc
index ddc0a2974..d5a07192c 100644
--- a/src/lib/util.cc
+++ b/src/lib/util.cc
@@ -772,7 +772,7 @@ audio_channel_name (int c)
return channels[c];
}
-FrameRateConversion::FrameRateConversion (float source, int dcp)
+FrameRateChange::FrameRateChange (float source, int dcp)
: skip (false)
, repeat (1)
, change_speed (false)
@@ -790,7 +790,8 @@ FrameRateConversion::FrameRateConversion (float source, int dcp)
repeat = round (dcp / source);
}
- change_speed = !about_equal (source * factor(), dcp);
+ speed_up = dcp / (source * factor());
+ change_speed = !about_equal (speed_up, 1.0);
if (!skip && repeat == 1 && !change_speed) {
description = _("Content and DCP have the same rate.\n");
diff --git a/src/lib/util.h b/src/lib/util.h
index 7dcd920b7..9b201a50e 100644
--- a/src/lib/util.h
+++ b/src/lib/util.h
@@ -79,9 +79,9 @@ extern std::string tidy_for_filename (std::string);
extern boost::shared_ptr<const libdcp::Signer> make_signer ();
extern libdcp::Size fit_ratio_within (float ratio, libdcp::Size);
-struct FrameRateConversion
+struct FrameRateChange
{
- FrameRateConversion (float, int);
+ FrameRateChange (float, int);
/** @return factor by which to multiply a source frame rate
to get the effective rate after any skip or repeat has happened.
@@ -109,6 +109,11 @@ struct FrameRateConversion
*/
bool change_speed;
+ /** Amount by which the video is being sped-up in the DCP; e.g. for a
+ * 24fps source in a 25fps DCP this would be 25/24.
+ */
+ float speed_up;
+
std::string description;
};
diff --git a/src/lib/video_content.cc b/src/lib/video_content.cc
index 0a19ffd69..c61a2455f 100644
--- a/src/lib/video_content.cc
+++ b/src/lib/video_content.cc
@@ -351,7 +351,8 @@ VideoContent::video_size_after_crop () const
}
/** @param t A time offset from the start of this piece of content.
- * @return Corresponding frame index.
+ * @return Corresponding frame index, rounded up so that the frame index
+ * is that of the next complete frame which starts after `t'.
*/
VideoContent::Frame
VideoContent::time_to_content_video_frames (Time t) const
@@ -359,11 +360,12 @@ VideoContent::time_to_content_video_frames (Time t) const
shared_ptr<const Film> film = _film.lock ();
assert (film);
- FrameRateConversion frc (video_frame_rate(), film->video_frame_rate());
-
/* Here we are converting from time (in the DCP) to a frame number in the content.
Hence we need to use the DCP's frame rate and the double/skip correction, not
- the source's rate.
+ the source's rate; source rate will be equal to DCP rate if we ignore
+ double/skip. There's no need to call Film::active_frame_rate_change() here
+ as we know that we are it (since we're video).
*/
- return t * film->video_frame_rate() / (frc.factor() * TIME_HZ);
+ FrameRateChange frc (video_frame_rate(), film->video_frame_rate());
+ return ceil (t * film->video_frame_rate() / (frc.factor() * TIME_HZ));
}
diff --git a/src/lib/video_decoder.h b/src/lib/video_decoder.h
index 142320a04..01319e481 100644
--- a/src/lib/video_decoder.h
+++ b/src/lib/video_decoder.h
@@ -34,11 +34,6 @@ class VideoDecoder : public virtual Decoder
public:
VideoDecoder (boost::shared_ptr<const Film>, boost::shared_ptr<const VideoContent>);
- /** Seek so that the next pass() will yield (approximately) the requested frame.
- * Pass accurate = true to try harder to get close to the request.
- */
- virtual void seek (VideoContent::Frame frame, bool accurate) = 0;
-
/** Emitted when a video frame is ready.
* First parameter is the video image.
* Second parameter is the eye(s) which should see this image.