}
float
-FFmpegDecoder::frames_per_second () const
+FFmpegDecoder::video_frame_rate () const
{
AVStream* s = _format_context->streams[_video_stream];
FFmpegDecoder::out_with_sync ()
{
/* Where we are in the output, in seconds */
- double const out_pts_seconds = video_frame() / frames_per_second();
+ double const out_pts_seconds = video_frame() / video_frame_rate();
/* Where we are in the source, in seconds */
double const source_pts_seconds = av_q2d (_format_context->streams[_packet.stream_index]->time_base)
/* Difference between where we are and where we should be */
double const delta = source_pts_seconds - _first_video.get() - out_pts_seconds;
- double const one_frame = 1 / frames_per_second();
+ double const one_frame = 1 / video_frame_rate();
/* Insert frames if required to get out_pts_seconds up to pts_seconds */
if (delta > one_frame) {
int const extra = rint (delta / one_frame);
for (int i = 0; i < extra; ++i) {
- repeat_last_video ();
+ repeat_last_video (frame_time ());
_film->log()->log (
String::compose (
N_("Extra video frame inserted at %1s; source frame %2, source PTS %3 (at %4 fps)"),
- out_pts_seconds, video_frame(), source_pts_seconds, frames_per_second()
+ out_pts_seconds, video_frame(), source_pts_seconds, video_frame_rate()
)
);
}
ContentVideoFrame
FFmpegDecoder::video_length () const
{
- return (double(_format_context->duration) / AV_TIME_BASE) * frames_per_second();
+ return (double(_format_context->duration) / AV_TIME_BASE) * video_frame_rate();
}
double
FFmpegDecoder (boost::shared_ptr<const Film>, boost::shared_ptr<const FFmpegContent>, bool video, bool audio, bool subtitles, bool video_sync);
~FFmpegDecoder ();
- float frames_per_second () const;
+ float video_frame_rate () const;
libdcp::Size native_size () const;
ContentVideoFrame video_length () const;
int time_base_numerator () const;
}
if (have_last_video ()) {
- repeat_last_video ();
+ repeat_last_video (double (_position) / 24);
_position++;
return false;
}
image = image->crop (_film->crop(), true);
- emit_video (image, 0);
+ emit_video (image, double (_position) / 24);
++_position;
return false;
public:
ImageMagickDecoder (boost::shared_ptr<const Film>, boost::shared_ptr<const ImageMagickContent>);
- float frames_per_second () const {
+ float video_frame_rate () const {
return 24;
}
case Playlist::VIDEO_FFMPEG:
return _ffmpeg_decoder->last_source_time ();
case Playlist::VIDEO_IMAGEMAGICK:
- return (*_imagemagick_decoder)->last_source_time ();
+ {
+ double t = 0;
+ for (list<shared_ptr<ImageMagickDecoder> >::const_iterator i = _imagemagick_decoders.begin(); i != _imagemagick_decoder; ++i) {
+ t += (*i)->video_length() / (*i)->video_frame_rate ();
+ }
+
+ return t + (*_imagemagick_decoder)->last_source_time ();
+ }
}
return 0;
{
/* These decoder calls could call other content methods which take a lock on the mutex */
libdcp::Size const vs = d->native_size ();
- float const vfr = d->frames_per_second ();
+ float const vfr = d->video_frame_rate ();
{
boost::mutex::scoped_lock lm (_mutex);
sub = _timed_subtitle->subtitle ();
}
- signal_video (image, false, sub);
- _last_source_time = t;
+ signal_video (image, false, sub, t);
}
bool
* we will generate a black frame.
*/
void
-VideoDecoder::repeat_last_video ()
+VideoDecoder::repeat_last_video (double t)
{
if (!_last_image) {
_last_image.reset (new SimpleImage (pixel_format(), native_size(), true));
_last_image->make_black ();
}
- signal_video (_last_image, true, _last_subtitle);
+ signal_video (_last_image, true, _last_subtitle, t);
}
/** Emit our signal to say that some video data is ready.
* @param sub Subtitle for this frame, or 0.
*/
void
-VideoDecoder::signal_video (shared_ptr<Image> image, bool same, shared_ptr<Subtitle> sub)
+VideoDecoder::signal_video (shared_ptr<Image> image, bool same, shared_ptr<Subtitle> sub, double t)
{
TIMING (N_("Decoder emits %1"), _video_frame);
Video (image, same, sub);
_last_image = image;
_last_subtitle = sub;
+ _last_source_time = t;
}
/** Set up the current subtitle. This will be put onto frames that
public:
VideoDecoder (boost::shared_ptr<const Film>);
- /** @return video frames per second, or 0 if unknown */
- virtual float frames_per_second () const = 0;
+ /** @return video frame rate second, or 0 if unknown */
+ virtual float video_frame_rate () const = 0;
/** @return native size in pixels */
virtual libdcp::Size native_size () const = 0;
/** @return length according to our content's header */
void emit_video (boost::shared_ptr<Image>, double);
void emit_subtitle (boost::shared_ptr<TimedSubtitle>);
bool have_last_video () const;
- void repeat_last_video ();
+ void repeat_last_video (double);
private:
- void signal_video (boost::shared_ptr<Image>, bool, boost::shared_ptr<Subtitle>);
+ void signal_video (boost::shared_ptr<Image>, bool, boost::shared_ptr<Subtitle>, double);
int _video_frame;
double _last_source_time;