summaryrefslogtreecommitdiff
path: root/src/lib
diff options
context:
space:
mode:
authorCarl Hetherington <cth@carlh.net>2013-06-26 01:21:21 +0100
committerCarl Hetherington <cth@carlh.net>2013-06-26 01:21:21 +0100
commitd0d584a7dde6de383302615634fdee17e9724fe8 (patch)
tree884bda89f740ab69a86fa4fe1691e787629f8b29 /src/lib
parent46cd0fe7b5b514f0d9456b25f670679cc584a218 (diff)
Hacks.
Diffstat (limited to 'src/lib')
-rw-r--r--src/lib/audio_content.h4
-rw-r--r--src/lib/audio_decoder.cc101
-rw-r--r--src/lib/audio_decoder.h25
-rw-r--r--src/lib/audio_sink.h32
-rw-r--r--src/lib/audio_source.cc42
-rw-r--r--src/lib/audio_source.h43
-rw-r--r--src/lib/black_decoder.cc45
-rw-r--r--src/lib/black_decoder.h9
-rw-r--r--src/lib/combiner.cc65
-rw-r--r--src/lib/combiner.h43
-rw-r--r--src/lib/decoder.h20
-rw-r--r--src/lib/encoder.cc4
-rw-r--r--src/lib/encoder.h8
-rw-r--r--src/lib/ffmpeg_content.cc6
-rw-r--r--src/lib/ffmpeg_content.h2
-rw-r--r--src/lib/ffmpeg_decoder.cc97
-rw-r--r--src/lib/ffmpeg_decoder.h6
-rw-r--r--src/lib/ffmpeg_examiner.cc2
-rw-r--r--src/lib/ffmpeg_examiner.h2
-rw-r--r--src/lib/image.cc5
-rw-r--r--src/lib/imagemagick_content.cc2
-rw-r--r--src/lib/imagemagick_content.h2
-rw-r--r--src/lib/imagemagick_decoder.cc41
-rw-r--r--src/lib/imagemagick_decoder.h4
-rw-r--r--src/lib/imagemagick_examiner.h2
-rw-r--r--src/lib/matcher.cc224
-rw-r--r--src/lib/matcher.h77
-rw-r--r--src/lib/null_content.h4
-rw-r--r--src/lib/player.cc159
-rw-r--r--src/lib/player.h26
-rw-r--r--src/lib/playlist.h4
-rw-r--r--src/lib/resampler.cc61
-rw-r--r--src/lib/resampler.h21
-rw-r--r--src/lib/silence_decoder.cc47
-rw-r--r--src/lib/silence_decoder.h7
-rw-r--r--src/lib/sndfile_content.cc2
-rw-r--r--src/lib/sndfile_content.h4
-rw-r--r--src/lib/sndfile_decoder.cc12
-rw-r--r--src/lib/sndfile_decoder.h10
-rw-r--r--src/lib/subtitle.cc3
-rw-r--r--src/lib/transcoder.cc23
-rw-r--r--src/lib/types.h2
-rw-r--r--src/lib/util.cc2
-rw-r--r--src/lib/util.h3
-rw-r--r--src/lib/video_content.cc5
-rw-r--r--src/lib/video_content.h9
-rw-r--r--src/lib/video_decoder.cc107
-rw-r--r--src/lib/video_decoder.h35
-rw-r--r--src/lib/video_examiner.h3
-rw-r--r--src/lib/video_sink.h39
-rw-r--r--src/lib/video_source.cc44
-rw-r--r--src/lib/video_source.h52
-rw-r--r--src/lib/wscript4
53 files changed, 405 insertions, 1196 deletions
diff --git a/src/lib/audio_content.h b/src/lib/audio_content.h
index 73a00ca7d..9bf53e0ab 100644
--- a/src/lib/audio_content.h
+++ b/src/lib/audio_content.h
@@ -41,6 +41,8 @@ public:
class AudioContent : public virtual Content
{
public:
+ typedef int64_t Frame;
+
AudioContent (boost::shared_ptr<const Film>, Time);
AudioContent (boost::shared_ptr<const Film>, boost::filesystem::path);
AudioContent (boost::shared_ptr<const Film>, boost::shared_ptr<const cxml::Node>);
@@ -49,7 +51,7 @@ public:
void as_xml (xmlpp::Node *) const;
virtual int audio_channels () const = 0;
- virtual ContentAudioFrame audio_length () const = 0;
+ virtual AudioContent::Frame audio_length () const = 0;
virtual int content_audio_frame_rate () const = 0;
virtual int output_audio_frame_rate () const = 0;
virtual AudioMapping audio_mapping () const = 0;
diff --git a/src/lib/audio_decoder.cc b/src/lib/audio_decoder.cc
index a9e01908c..396471910 100644
--- a/src/lib/audio_decoder.cc
+++ b/src/lib/audio_decoder.cc
@@ -31,57 +31,12 @@ using std::cout;
using boost::optional;
using boost::shared_ptr;
-AudioDecoder::AudioDecoder (shared_ptr<const Film> f, shared_ptr<const AudioContent> c)
+AudioDecoder::AudioDecoder (shared_ptr<const Film> f)
: Decoder (f)
- , _next_audio (0)
- , _audio_content (c)
+ , _next_audio_frame (0)
{
- if (_audio_content->content_audio_frame_rate() != _audio_content->output_audio_frame_rate()) {
-
- shared_ptr<const Film> film = _film.lock ();
- assert (film);
-
- stringstream s;
- s << String::compose (
- "Will resample audio from %1 to %2",
- _audio_content->content_audio_frame_rate(), _audio_content->output_audio_frame_rate()
- );
-
- film->log()->log (s.str ());
-
- /* We will be using planar float data when we call the
- resampler. As far as I can see, the audio channel
- layout is not necessary for our purposes; it seems
- only to be used get the number of channels and
- decide if rematrixing is needed. It won't be, since
- input and output layouts are the same.
- */
-
- _swr_context = swr_alloc_set_opts (
- 0,
- av_get_default_channel_layout (_audio_content->audio_channels ()),
- AV_SAMPLE_FMT_FLTP,
- _audio_content->output_audio_frame_rate(),
- av_get_default_channel_layout (_audio_content->audio_channels ()),
- AV_SAMPLE_FMT_FLTP,
- _audio_content->content_audio_frame_rate(),
- 0, 0
- );
-
- swr_init (_swr_context);
- } else {
- _swr_context = 0;
- }
}
-AudioDecoder::~AudioDecoder ()
-{
- if (_swr_context) {
- swr_free (&_swr_context);
- }
-}
-
-
#if 0
void
AudioDecoder::process_end ()
@@ -113,54 +68,8 @@ AudioDecoder::process_end ()
#endif
void
-AudioDecoder::audio (shared_ptr<const AudioBuffers> data, Time time)
-{
- /* Maybe resample */
- if (_swr_context) {
-
- /* Compute the resampled frames count and add 32 for luck */
- int const max_resampled_frames = ceil (
- (int64_t) data->frames() * _audio_content->output_audio_frame_rate() / _audio_content->content_audio_frame_rate()
- ) + 32;
-
- shared_ptr<AudioBuffers> resampled (new AudioBuffers (data->channels(), max_resampled_frames));
-
- /* Resample audio */
- int const resampled_frames = swr_convert (
- _swr_context, (uint8_t **) resampled->data(), max_resampled_frames, (uint8_t const **) data->data(), data->frames()
- );
-
- if (resampled_frames < 0) {
- throw EncodeError (_("could not run sample-rate converter"));
- }
-
- resampled->set_frames (resampled_frames);
-
- /* And point our variables at the resampled audio */
- data = resampled;
- }
-
- shared_ptr<const Film> film = _film.lock ();
- assert (film);
-
- /* Remap channels */
- shared_ptr<AudioBuffers> dcp_mapped (new AudioBuffers (film->dcp_audio_channels(), data->frames()));
- dcp_mapped->make_silent ();
- list<pair<int, libdcp::Channel> > map = _audio_content->audio_mapping().content_to_dcp ();
- for (list<pair<int, libdcp::Channel> >::iterator i = map.begin(); i != map.end(); ++i) {
- dcp_mapped->accumulate_channel (data.get(), i->first, i->second);
- }
-
- Audio (dcp_mapped, time);
- _next_audio = time + film->audio_frames_to_time (data->frames());
-}
-
-bool
-AudioDecoder::audio_done () const
+AudioDecoder::audio (shared_ptr<const AudioBuffers> data, AudioContent::Frame frame)
{
- shared_ptr<const Film> film = _film.lock ();
- assert (film);
-
- return (_audio_content->length() - _next_audio) < film->audio_frames_to_time (1);
+ Audio (data, frame);
+ _next_audio_frame = frame + data->frames ();
}
-
diff --git a/src/lib/audio_decoder.h b/src/lib/audio_decoder.h
index 1da8a676f..168348c2e 100644
--- a/src/lib/audio_decoder.h
+++ b/src/lib/audio_decoder.h
@@ -24,33 +24,26 @@
#ifndef DCPOMATIC_AUDIO_DECODER_H
#define DCPOMATIC_AUDIO_DECODER_H
-#include "audio_source.h"
#include "decoder.h"
-extern "C" {
-#include <libswresample/swresample.h>
-}
+#include "content.h"
-class AudioContent;
+class AudioBuffers;
/** @class AudioDecoder.
* @brief Parent class for audio decoders.
*/
-class AudioDecoder : public AudioSource, public virtual Decoder
+class AudioDecoder : public virtual Decoder
{
public:
- AudioDecoder (boost::shared_ptr<const Film>, boost::shared_ptr<const AudioContent>);
- ~AudioDecoder ();
+ AudioDecoder (boost::shared_ptr<const Film>);
-protected:
-
- void audio (boost::shared_ptr<const AudioBuffers>, Time);
- bool audio_done () const;
+ /** Emitted when some audio data is ready */
+ boost::signals2::signal<void (boost::shared_ptr<const AudioBuffers>, AudioContent::Frame)> Audio;
- Time _next_audio;
- boost::shared_ptr<const AudioContent> _audio_content;
+protected:
-private:
- SwrContext* _swr_context;
+ void audio (boost::shared_ptr<const AudioBuffers>, AudioContent::Frame);
+ AudioContent::Frame _next_audio_frame;
};
#endif
diff --git a/src/lib/audio_sink.h b/src/lib/audio_sink.h
deleted file mode 100644
index 1aad5edf9..000000000
--- a/src/lib/audio_sink.h
+++ /dev/null
@@ -1,32 +0,0 @@
-/*
- Copyright (C) 2012 Carl Hetherington <cth@carlh.net>
-
- 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
- the Free Software Foundation; either version 2 of the License, or
- (at your option) any later version.
-
- This program is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU General Public License for more details.
-
- You should have received a copy of the GNU General Public License
- along with this program; if not, write to the Free Software
- Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
-
-*/
-
-#ifndef DCPOMATIC_AUDIO_SINK_H
-#define DCPOMATIC_AUDIO_SINK_H
-
-class AudioBuffers;
-
-class AudioSink
-{
-public:
- /** Call with some audio data */
- virtual void process_audio (boost::shared_ptr<const AudioBuffers>, Time) = 0;
-};
-
-#endif
diff --git a/src/lib/audio_source.cc b/src/lib/audio_source.cc
deleted file mode 100644
index e61721646..000000000
--- a/src/lib/audio_source.cc
+++ /dev/null
@@ -1,42 +0,0 @@
-/*
- Copyright (C) 2012 Carl Hetherington <cth@carlh.net>
-
- 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
- the Free Software Foundation; either version 2 of the License, or
- (at your option) any later version.
-
- This program is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU General Public License for more details.
-
- You should have received a copy of the GNU General Public License
- along with this program; if not, write to the Free Software
- Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
-
-*/
-
-#include "audio_source.h"
-#include "audio_sink.h"
-
-using boost::shared_ptr;
-using boost::weak_ptr;
-using boost::bind;
-
-static void
-process_audio_proxy (weak_ptr<AudioSink> sink, shared_ptr<const AudioBuffers> audio, Time time)
-{
- shared_ptr<AudioSink> p = sink.lock ();
- if (p) {
- p->process_audio (audio, time);
- }
-}
-
-void
-AudioSource::connect_audio (shared_ptr<AudioSink> s)
-{
- Audio.connect (bind (process_audio_proxy, weak_ptr<AudioSink> (s), _1, _2));
-}
-
-
diff --git a/src/lib/audio_source.h b/src/lib/audio_source.h
deleted file mode 100644
index ef47e969b..000000000
--- a/src/lib/audio_source.h
+++ /dev/null
@@ -1,43 +0,0 @@
-/*
- Copyright (C) 2012 Carl Hetherington <cth@carlh.net>
-
- 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
- the Free Software Foundation; either version 2 of the License, or
- (at your option) any later version.
-
- This program is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU General Public License for more details.
-
- You should have received a copy of the GNU General Public License
- along with this program; if not, write to the Free Software
- Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
-
-*/
-
-/** @file src/audio_source.h
- * @brief Parent class for classes which emit audio data.
- */
-
-#ifndef DCPOMATIC_AUDIO_SOURCE_H
-#define DCPOMATIC_AUDIO_SOURCE_H
-
-#include <boost/signals2.hpp>
-#include "types.h"
-
-class AudioBuffers;
-class AudioSink;
-
-/** A class that emits audio data */
-class AudioSource
-{
-public:
- /** Emitted when some audio data is ready */
- boost::signals2::signal<void (boost::shared_ptr<const AudioBuffers>, Time)> Audio;
-
- void connect_audio (boost::shared_ptr<AudioSink>);
-};
-
-#endif
diff --git a/src/lib/black_decoder.cc b/src/lib/black_decoder.cc
index 0b231edd3..beb6bfef3 100644
--- a/src/lib/black_decoder.cc
+++ b/src/lib/black_decoder.cc
@@ -25,7 +25,8 @@ using boost::shared_ptr;
BlackDecoder::BlackDecoder (shared_ptr<const Film> f, shared_ptr<NullContent> c)
: Decoder (f)
- , VideoDecoder (f, c)
+ , VideoDecoder (f)
+ , _null_content (c)
{
}
@@ -36,9 +37,9 @@ BlackDecoder::pass ()
if (!_image) {
_image.reset (new SimpleImage (AV_PIX_FMT_RGB24, video_size(), true));
_image->make_black ();
- video (_image, false, _next_video);
+ video (_image, false, _next_video_frame);
} else {
- video (_image, true, _next_video);
+ video (_image, true, _next_video_frame);
}
}
@@ -53,50 +54,28 @@ BlackDecoder::video_frame_rate () const
return f->dcp_video_frame_rate ();
}
-ContentVideoFrame
+VideoContent::Frame
BlackDecoder::video_length () const
{
- return _video_content->length() * video_frame_rate() / TIME_HZ;
-}
-
-Time
-BlackDecoder::position () const
-{
- return _next_video;
+ return _null_content->length() * video_frame_rate() / TIME_HZ;
}
void
-BlackDecoder::seek (Time t)
+BlackDecoder::seek (VideoContent::Frame frame)
{
- _next_video = t;
+ _next_video_frame = frame;
}
void
BlackDecoder::seek_back ()
{
- boost::shared_ptr<const Film> f = _film.lock ();
- if (!f) {
- return;
- }
-
- _next_video -= f->video_frames_to_time (2);
-}
-
-void
-BlackDecoder::seek_forward ()
-{
- boost::shared_ptr<const Film> f = _film.lock ();
- if (!f) {
- return;
+ if (_next_video_frame > 0) {
+ --_next_video_frame;
}
-
- _next_video += f->video_frames_to_time (1);
}
-
+
bool
BlackDecoder::done () const
{
- return video_done ();
+ return _next_video_frame >= _null_content->video_length ();
}
-
-
diff --git a/src/lib/black_decoder.h b/src/lib/black_decoder.h
index 4591881a1..40aa73d72 100644
--- a/src/lib/black_decoder.h
+++ b/src/lib/black_decoder.h
@@ -29,20 +29,19 @@ public:
/* Decoder */
void pass ();
- void seek (Time);
- void seek_back ();
- void seek_forward ();
- Time position () const;
bool done () const;
/* VideoDecoder */
+ void seek (VideoContent::Frame);
+ void seek_back ();
float video_frame_rate () const;
libdcp::Size video_size () const {
return libdcp::Size (256, 256);
}
- ContentVideoFrame video_length () const;
+ VideoContent::Frame video_length () const;
private:
+ boost::shared_ptr<NullContent> _null_content;
boost::shared_ptr<Image> _image;
};
diff --git a/src/lib/combiner.cc b/src/lib/combiner.cc
deleted file mode 100644
index 44971d135..000000000
--- a/src/lib/combiner.cc
+++ /dev/null
@@ -1,65 +0,0 @@
-/*
- Copyright (C) 2012 Carl Hetherington <cth@carlh.net>
-
- 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
- the Free Software Foundation; either version 2 of the License, or
- (at your option) any later version.
-
- This program is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU General Public License for more details.
-
- You should have received a copy of the GNU General Public License
- along with this program; if not, write to the Free Software
- Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
-
-*/
-
-#include "combiner.h"
-#include "image.h"
-
-using boost::shared_ptr;
-
-Combiner::Combiner ()
-{
-
-}
-
-/** Process video for the left half of the frame.
- * Subtitle parameter will be ignored.
- * @param image Frame image.
- */
-void
-Combiner::process_video (shared_ptr<const Image> image, bool, Time)
-{
- _image.reset (new SimpleImage (image, true));
-}
-
-/** Process video for the right half of the frame.
- * @param image Frame image.
- * @param sub Subtitle (which will be put onto the whole frame)
- */
-void
-Combiner::process_video_b (shared_ptr<const Image> image, bool, Time t)
-{
- /* Copy the right half of this image into our _image */
- /* XXX: this should probably be in the Image class */
- for (int i = 0; i < image->components(); ++i) {
- int const line_size = image->line_size()[i];
- int const half_line_size = line_size / 2;
-
- uint8_t* p = _image->data()[i];
- uint8_t* q = image->data()[i];
-
- for (int j = 0; j < image->lines (i); ++j) {
- memcpy (p + half_line_size, q + half_line_size, half_line_size);
- p += _image->stride()[i];
- q += image->stride()[i];
- }
- }
-
- Video (_image, false, t);
- _image.reset ();
-}
diff --git a/src/lib/combiner.h b/src/lib/combiner.h
deleted file mode 100644
index 46c90b4d8..000000000
--- a/src/lib/combiner.h
+++ /dev/null
@@ -1,43 +0,0 @@
-/*
- Copyright (C) 2012 Carl Hetherington <cth@carlh.net>
-
- 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
- the Free Software Foundation; either version 2 of the License, or
- (at your option) any later version.
-
- This program is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU General Public License for more details.
-
- You should have received a copy of the GNU General Public License
- along with this program; if not, write to the Free Software
- Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
-
-*/
-
-/** @file src/lib/combiner.h
- * @brief Class for combining two video streams.
- */
-
-#include "video_source.h"
-#include "video_sink.h"
-
-/** @class Combiner
- * @brief A class which can combine two video streams into one, with
- * one image used for the left half of the screen and the other for
- * the right.
- */
-class Combiner : public VideoSource, public VideoSink
-{
-public:
- Combiner ();
-
- void process_video (boost::shared_ptr<const Image> i, bool, Time);
- void process_video_b (boost::shared_ptr<const Image> i, bool, Time);
-
-private:
- /** The image that we are currently working on */
- boost::shared_ptr<Image> _image;
-};
diff --git a/src/lib/decoder.h b/src/lib/decoder.h
index 391b9d19a..cfca6867f 100644
--- a/src/lib/decoder.h
+++ b/src/lib/decoder.h
@@ -29,8 +29,6 @@
#include <stdint.h>
#include <boost/shared_ptr.hpp>
#include <boost/signals2.hpp>
-#include "video_source.h"
-#include "audio_source.h"
#include "film.h"
class Image;
@@ -54,24 +52,6 @@ public:
*/
virtual void pass () = 0;
- /** Seek this decoder to as close as possible to some time,
- * expressed relative to our source's start.
- * @param t Time.
- * @param a true to try hard to be accurate, otherwise false.
- */
- virtual void seek (Time) = 0;
-
- /** Seek back one video frame */
- virtual void seek_back () = 0;
-
- /** Seek forward one video frame */
- virtual void seek_forward () = 0;
-
- /** @return Approximate time of the next content that we will emit,
- * expressed relative to the start of our source.
- */
- virtual Time position () const = 0;
-
virtual bool done () const = 0;
protected:
diff --git a/src/lib/encoder.cc b/src/lib/encoder.cc
index 8b2db0eb3..c3865d2c1 100644
--- a/src/lib/encoder.cc
+++ b/src/lib/encoder.cc
@@ -169,7 +169,7 @@ Encoder::frame_done ()
}
void
-Encoder::process_video (shared_ptr<const Image> image, bool same, Time)
+Encoder::process_video (shared_ptr<const Image> image, bool same)
{
boost::mutex::scoped_lock lock (_mutex);
@@ -215,7 +215,7 @@ Encoder::process_video (shared_ptr<const Image> image, bool same, Time)
}
void
-Encoder::process_audio (shared_ptr<const AudioBuffers> data, Time)
+Encoder::process_audio (shared_ptr<const AudioBuffers> data)
{
_writer->write (data);
}
diff --git a/src/lib/encoder.h b/src/lib/encoder.h
index 3fe707b51..b5a641f50 100644
--- a/src/lib/encoder.h
+++ b/src/lib/encoder.h
@@ -36,8 +36,6 @@ extern "C" {
#include <libswresample/swresample.h>
}
#include "util.h"
-#include "video_sink.h"
-#include "audio_sink.h"
class Image;
class AudioBuffers;
@@ -55,7 +53,7 @@ class Job;
* is supplied as uncompressed PCM in blocks of various sizes.
*/
-class Encoder : public VideoSink, public AudioSink
+class Encoder
{
public:
Encoder (boost::shared_ptr<const Film> f, boost::shared_ptr<Job>);
@@ -68,10 +66,10 @@ public:
* @param i Video frame image.
* @param same true if i is the same as the last time we were called.
*/
- void process_video (boost::shared_ptr<const Image> i, bool same, Time);
+ void process_video (boost::shared_ptr<const Image> i, bool same);
/** Call with some audio data */
- void process_audio (boost::shared_ptr<const AudioBuffers>, Time);
+ void process_audio (boost::shared_ptr<const AudioBuffers>);
/** Called when a processing run has finished */
void process_end ();
diff --git a/src/lib/ffmpeg_content.cc b/src/lib/ffmpeg_content.cc
index 68132c5ab..378bd98cb 100644
--- a/src/lib/ffmpeg_content.cc
+++ b/src/lib/ffmpeg_content.cc
@@ -139,7 +139,7 @@ FFmpegContent::examine (shared_ptr<Job> job)
shared_ptr<FFmpegExaminer> examiner (new FFmpegExaminer (shared_from_this ()));
- ContentVideoFrame video_length = 0;
+ VideoContent::Frame video_length = 0;
video_length = examiner->video_length ();
film->log()->log (String::compose ("Video length obtained from header as %1 frames", video_length));
@@ -214,12 +214,12 @@ FFmpegContent::set_audio_stream (shared_ptr<FFmpegAudioStream> s)
signal_changed (FFmpegContentProperty::AUDIO_STREAM);
}
-ContentAudioFrame
+AudioContent::Frame
FFmpegContent::audio_length () const
{
int const cafr = content_audio_frame_rate ();
int const vfr = video_frame_rate ();
- ContentVideoFrame const vl = video_length ();
+ VideoContent::Frame const vl = video_length ();
boost::mutex::scoped_lock lm (_mutex);
if (!_audio_stream) {
diff --git a/src/lib/ffmpeg_content.h b/src/lib/ffmpeg_content.h
index 36c24c2b3..fc45267ee 100644
--- a/src/lib/ffmpeg_content.h
+++ b/src/lib/ffmpeg_content.h
@@ -99,7 +99,7 @@ public:
/* AudioContent */
int audio_channels () const;
- ContentAudioFrame audio_length () const;
+ AudioContent::Frame audio_length () const;
int content_audio_frame_rate () const;
int output_audio_frame_rate () const;
AudioMapping audio_mapping () const;
diff --git a/src/lib/ffmpeg_decoder.cc b/src/lib/ffmpeg_decoder.cc
index f1d984ee1..d897aef9d 100644
--- a/src/lib/ffmpeg_decoder.cc
+++ b/src/lib/ffmpeg_decoder.cc
@@ -59,8 +59,8 @@ using libdcp::Size;
FFmpegDecoder::FFmpegDecoder (shared_ptr<const Film> f, shared_ptr<const FFmpegContent> c, bool video, bool audio)
: Decoder (f)
- , VideoDecoder (f, c)
- , AudioDecoder (f, c)
+ , VideoDecoder (f)
+ , AudioDecoder (f)
, FFmpeg (c)
, _subtitle_codec_context (0)
, _subtitle_codec (0)
@@ -108,7 +108,8 @@ FFmpegDecoder::pass ()
}
/* Stop us being asked for any more data */
- _next_video = _next_audio = _ffmpeg_content->length ();
+ _next_video_frame = _ffmpeg_content->video_length ();
+ _next_audio_frame = _ffmpeg_content->audio_length ();
return;
}
@@ -119,6 +120,7 @@ FFmpegDecoder::pass ()
} else if (_ffmpeg_content->audio_stream() && _packet.stream_index == _ffmpeg_content->audio_stream()->id && _decode_audio) {
decode_audio_packet ();
} else if (_ffmpeg_content->subtitle_stream() && _packet.stream_index == _ffmpeg_content->subtitle_stream()->id) {
+#if 0
int got_subtitle;
AVSubtitle sub;
@@ -138,6 +140,7 @@ FFmpegDecoder::pass ()
}
avsubtitle_free (&sub);
}
+#endif
}
av_free_packet (&_packet);
@@ -256,38 +259,26 @@ FFmpegDecoder::bytes_per_audio_sample () const
}
void
-FFmpegDecoder::seek (Time t)
+FFmpegDecoder::seek (VideoContent::Frame frame)
{
- do_seek (t, false, false);
- VideoDecoder::seek (t);
+ do_seek (frame, false, false);
}
void
FFmpegDecoder::seek_back ()
{
- if (position() < (2.5 * TIME_HZ / _ffmpeg_content->video_frame_rate())) {
+ if (_next_video_frame == 0) {
return;
}
- do_seek (position() - 2.5 * TIME_HZ / _ffmpeg_content->video_frame_rate(), true, true);
+ do_seek (_next_video_frame - 1, true, true);
VideoDecoder::seek_back ();
}
void
-FFmpegDecoder::seek_forward ()
+FFmpegDecoder::do_seek (VideoContent::Frame frame, bool backwards, bool accurate)
{
- if (position() >= (_ffmpeg_content->length() - 0.5 * TIME_HZ / _ffmpeg_content->video_frame_rate())) {
- return;
- }
-
- do_seek (position() - 0.5 * TIME_HZ / _ffmpeg_content->video_frame_rate(), true, true);
- VideoDecoder::seek_forward ();
-}
-
-void
-FFmpegDecoder::do_seek (Time t, bool backwards, bool accurate)
-{
- int64_t const vt = t / (av_q2d (_format_context->streams[_video_stream]->time_base) * TIME_HZ);
+ int64_t const vt = frame * _ffmpeg_content->video_frame_rate() / av_q2d (_format_context->streams[_video_stream]->time_base);
av_seek_frame (_format_context, _video_stream, vt, backwards ? AVSEEK_FLAG_BACKWARD : 0);
avcodec_flush_buffers (video_codec_context());
@@ -347,7 +338,7 @@ FFmpegDecoder::decode_audio_packet ()
);
assert (audio_codec_context()->channels == _ffmpeg_content->audio_channels());
- audio (deinterleave_audio (_frame->data, data_size), source_pts_seconds * TIME_HZ);
+ Audio (deinterleave_audio (_frame->data, data_size), source_pts_seconds * _ffmpeg_content->content_audio_frame_rate());
}
copy_packet.data += decode_result;
@@ -398,11 +389,33 @@ FFmpegDecoder::decode_video_packet ()
int64_t const bet = av_frame_get_best_effort_timestamp (_frame);
if (bet != AV_NOPTS_VALUE) {
- /* XXX: may need to insert extra frames / remove frames here ...
- (as per old Matcher)
- */
- Time const t = bet * av_q2d (_format_context->streams[_video_stream]->time_base) * TIME_HZ;
- video (image, false, t);
+
+ double const pts = bet * av_q2d (_format_context->streams[_video_stream]->time_base);
+ double const next = _next_video_frame / _ffmpeg_content->video_frame_rate();
+ double const one_frame = 1 / _ffmpeg_content->video_frame_rate ();
+ double delta = pts - next;
+
+ while (delta > one_frame) {
+ /* This PTS is more than one frame forward in time of where we think we should be; emit
+ a black frame.
+ */
+ boost::shared_ptr<Image> black (
+ new SimpleImage (
+ static_cast<AVPixelFormat> (_frame->format),
+ libdcp::Size (video_codec_context()->width, video_codec_context()->height),
+ true
+ )
+ );
+
+ black->make_black ();
+ video (image, false, _next_video_frame);
+ delta -= one_frame;
+ }
+
+ if (delta > -one_frame) {
+ /* This PTS is within a frame of being right; emit this (otherwise it will be dropped) */
+ video (image, false, _next_video_frame);
+ }
} else {
shared_ptr<const Film> film = _film.lock ();
assert (film);
@@ -413,27 +426,6 @@ FFmpegDecoder::decode_video_packet ()
return true;
}
-Time
-FFmpegDecoder::position () const
-{
- if (_decode_video && _decode_audio && _ffmpeg_content->audio_stream()) {
- return min (_next_video, _next_audio);
- }
-
- if (_decode_audio && _ffmpeg_content->audio_stream()) {
- return _next_audio;
- }
-
- return _next_video;
-}
-
-bool
-FFmpegDecoder::done () const
-{
- bool const ad = !_decode_audio || !_ffmpeg_content->audio_stream() || audio_done();
- bool const vd = !_decode_video || video_done();
- return ad && vd;
-}
void
FFmpegDecoder::setup_subtitle ()
@@ -455,3 +447,12 @@ FFmpegDecoder::setup_subtitle ()
throw DecodeError (N_("could not open subtitle decoder"));
}
}
+
+bool
+FFmpegDecoder::done () const
+{
+ bool const vd = !_decode_video || (_next_video_frame >= _ffmpeg_content->video_length());
+ bool const ad = !_decode_audio || !_ffmpeg_content->audio_stream() || (_next_audio_frame >= _ffmpeg_content->audio_length());
+ return vd && ad;
+}
+
diff --git a/src/lib/ffmpeg_decoder.h b/src/lib/ffmpeg_decoder.h
index 331d9be70..a8eabb972 100644
--- a/src/lib/ffmpeg_decoder.h
+++ b/src/lib/ffmpeg_decoder.h
@@ -49,10 +49,8 @@ public:
~FFmpegDecoder ();
void pass ();
- void seek (Time);
+ void seek (VideoContent::Frame);
void seek_back ();
- void seek_forward ();
- Time position () const;
bool done () const;
private:
@@ -65,7 +63,7 @@ private:
AVSampleFormat audio_sample_format () const;
int bytes_per_audio_sample () const;
- void do_seek (Time, bool, bool);
+ void do_seek (VideoContent::Frame, bool, bool);
bool decode_video_packet ();
void decode_audio_packet ();
diff --git a/src/lib/ffmpeg_examiner.cc b/src/lib/ffmpeg_examiner.cc
index c09395e76..6f1524f50 100644
--- a/src/lib/ffmpeg_examiner.cc
+++ b/src/lib/ffmpeg_examiner.cc
@@ -134,7 +134,7 @@ FFmpegExaminer::video_size () const
}
/** @return Length (in video frames) according to our content's header */
-ContentVideoFrame
+VideoContent::Frame
FFmpegExaminer::video_length () const
{
return (double (_format_context->duration) / AV_TIME_BASE) * video_frame_rate();
diff --git a/src/lib/ffmpeg_examiner.h b/src/lib/ffmpeg_examiner.h
index 57b7775d4..5cf9c2d0a 100644
--- a/src/lib/ffmpeg_examiner.h
+++ b/src/lib/ffmpeg_examiner.h
@@ -31,7 +31,7 @@ public:
float video_frame_rate () const;
libdcp::Size video_size () const;
- ContentVideoFrame video_length () const;
+ VideoContent::Frame video_length () const;
std::vector<boost::shared_ptr<FFmpegSubtitleStream> > subtitle_streams () const {
return _subtitle_streams;
diff --git a/src/lib/image.cc b/src/lib/image.cc
index 0bff1a7cc..722ff5d3c 100644
--- a/src/lib/image.cc
+++ b/src/lib/image.cc
@@ -43,8 +43,9 @@ extern "C" {
#include "i18n.h"
-using namespace std;
-using namespace boost;
+using std::string;
+using std::min;
+using boost::shared_ptr;
using libdcp::Size;
void
diff --git a/src/lib/imagemagick_content.cc b/src/lib/imagemagick_content.cc
index f9ee8cc84..2fd65ffa0 100644
--- a/src/lib/imagemagick_content.cc
+++ b/src/lib/imagemagick_content.cc
@@ -87,7 +87,7 @@ ImageMagickContent::clone () const
}
void
-ImageMagickContent::set_video_length (ContentVideoFrame len)
+ImageMagickContent::set_video_length (VideoContent::Frame len)
{
{
boost::mutex::scoped_lock lm (_mutex);
diff --git a/src/lib/imagemagick_content.h b/src/lib/imagemagick_content.h
index d7673d870..04425af08 100644
--- a/src/lib/imagemagick_content.h
+++ b/src/lib/imagemagick_content.h
@@ -43,7 +43,7 @@ public:
boost::shared_ptr<Content> clone () const;
Time length () const;
- void set_video_length (ContentVideoFrame);
+ void set_video_length (VideoContent::Frame);
static bool valid_file (boost::filesystem::path);
};
diff --git a/src/lib/imagemagick_decoder.cc b/src/lib/imagemagick_decoder.cc
index c9123c77c..acc34421c 100644
--- a/src/lib/imagemagick_decoder.cc
+++ b/src/lib/imagemagick_decoder.cc
@@ -34,7 +34,7 @@ using libdcp::Size;
ImageMagickDecoder::ImageMagickDecoder (shared_ptr<const Film> f, shared_ptr<const ImageMagickContent> c)
: Decoder (f)
- , VideoDecoder (f, c)
+ , VideoDecoder (f)
, ImageMagick (c)
{
@@ -43,12 +43,12 @@ ImageMagickDecoder::ImageMagickDecoder (shared_ptr<const Film> f, shared_ptr<con
void
ImageMagickDecoder::pass ()
{
- if (_next_video >= _imagemagick_content->length ()) {
+ if (_next_video_frame >= _imagemagick_content->video_length ()) {
return;
}
if (_image) {
- video (_image, true, _next_video);
+ video (_image, true, _next_video_frame);
return;
}
@@ -71,48 +71,25 @@ ImageMagickDecoder::pass ()
delete magick_image;
- _image = _image->crop (_imagemagick_content->crop(), true);
- video (_image, false, _next_video);
+ video (_image, false, _next_video_frame);
}
void
-ImageMagickDecoder::seek (Time t)
+ImageMagickDecoder::seek (VideoContent::Frame frame)
{
- _next_video = t;
+ _next_video_frame = frame;
}
void
ImageMagickDecoder::seek_back ()
{
- boost::shared_ptr<const Film> f = _film.lock ();
- if (!f) {
- return;
- }
-
- _next_video -= f->video_frames_to_time (2);
-}
-
-void
-ImageMagickDecoder::seek_forward ()
-{
- boost::shared_ptr<const Film> f = _film.lock ();
- if (!f) {
- return;
+ if (_next_video_frame > 0) {
+ _next_video_frame--;
}
-
- _next_video += f->video_frames_to_time (1);
}
-Time
-ImageMagickDecoder::position () const
-{
- return _next_video;
-}
-
-
bool
ImageMagickDecoder::done () const
{
- return video_done ();
+ return _next_video_frame > _imagemagick_content->video_length ();
}
-
diff --git a/src/lib/imagemagick_decoder.h b/src/lib/imagemagick_decoder.h
index e169f9bc3..286f47337 100644
--- a/src/lib/imagemagick_decoder.h
+++ b/src/lib/imagemagick_decoder.h
@@ -34,10 +34,8 @@ public:
/* Decoder */
void pass ();
- void seek (Time);
+ void seek (VideoContent::Frame);
void seek_back ();
- void seek_forward ();
- Time position () const;
bool done () const;
private:
diff --git a/src/lib/imagemagick_examiner.h b/src/lib/imagemagick_examiner.h
index 827dad67e..801ede442 100644
--- a/src/lib/imagemagick_examiner.h
+++ b/src/lib/imagemagick_examiner.h
@@ -33,7 +33,7 @@ public:
float video_frame_rate () const;
libdcp::Size video_size () const;
- ContentVideoFrame video_length () const;
+ VideoContent::Frame video_length () const;
private:
boost::weak_ptr<const Film> _film;
diff --git a/src/lib/matcher.cc b/src/lib/matcher.cc
deleted file mode 100644
index 4acb82afa..000000000
--- a/src/lib/matcher.cc
+++ /dev/null
@@ -1,224 +0,0 @@
-/*
- Copyright (C) 2012 Carl Hetherington <cth@carlh.net>
-
- 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
- the Free Software Foundation; either version 2 of the License, or
- (at your option) any later version.
-
- This program is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU General Public License for more details.
-
- You should have received a copy of the GNU General Public License
- along with this program; if not, write to the Free Software
- Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
-
-*/
-
-#include "matcher.h"
-#include "image.h"
-#include "log.h"
-
-#include "i18n.h"
-
-using std::min;
-using std::cout;
-using std::list;
-using boost::shared_ptr;
-
-Matcher::Matcher (shared_ptr<Log> log, int sample_rate, float frames_per_second)
- : Processor (log)
- , _sample_rate (sample_rate)
- , _frames_per_second (frames_per_second)
- , _video_frames (0)
- , _audio_frames (0)
- , _had_first_video (false)
- , _had_first_audio (false)
-{
-
-}
-
-void
-Matcher::process_video (boost::shared_ptr<const Image> image, bool same, boost::shared_ptr<Subtitle> sub, double t)
-{
- _pixel_format = image->pixel_format ();
- _size = image->size ();
-
- _log->log(String::compose("Matcher video @ %1 [audio=%2, video=%3, pending_audio=%4]", t, _audio_frames, _video_frames, _pending_audio.size()));
-
- if (!_first_input || t < _first_input.get()) {
- _first_input = t;
- }
-
- bool const this_is_first_video = !_had_first_video;
- _had_first_video = true;
-
- if (!_had_first_audio) {
- /* No audio yet; we must postpone these data until we have some */
- _pending_video.push_back (VideoRecord (image, same, sub, t));
- } else if (this_is_first_video && _had_first_audio) {
- /* First video since we got audio */
- _pending_video.push_back (VideoRecord (image, same, sub, t));
- fix_start ();
- } else {
- /* Normal running */
-
- /* Difference between where this video is and where it should be */
- double const delta = t - _first_input.get() - _video_frames / _frames_per_second;
- double const one_frame = 1 / _frames_per_second;
-
- if (delta > one_frame) {
- /* Insert frames to make up the difference */
- int const extra = rint (delta / one_frame);
- for (int i = 0; i < extra; ++i) {
- repeat_last_video ();
- _log->log (String::compose ("Extra video frame inserted at %1s", _video_frames / _frames_per_second));
- }
- }
-
- if (delta > -one_frame) {
- Video (image, same, sub);
- ++_video_frames;
- } else {
- /* We are omitting a frame to keep things right */
- _log->log (String::compose ("Frame removed at %1s; delta %2; first input was at %3", t, delta, _first_input.get()));
- }
-
- _last_image = image;
- _last_subtitle = sub;
- }
-}
-
-void
-Matcher::process_audio (boost::shared_ptr<const AudioBuffers> b, double t)
-{
- _channels = b->channels ();
-
- _log->log (String::compose (
- "Matcher audio (%1 frames) @ %2 [video=%3, audio=%4, pending_video=%5, pending_audio=%6]",
- b->frames(), t, _video_frames, _audio_frames, _pending_video.size(), _pending_audio.size()
- )
- );
-
- if (!_first_input || t < _first_input.get()) {
- _first_input = t;
- }
-
- bool const this_is_first_audio = !_had_first_audio;
- _had_first_audio = true;
-
- if (!_had_first_video) {
- /* No video yet; we must postpone these data until we have some */
- _pending_audio.push_back (AudioRecord (b, t));
- } else if (this_is_first_audio && _had_first_video) {
- /* First audio since we got video */
- _pending_audio.push_back (AudioRecord (b, t));
- fix_start ();
- } else {
- /* Normal running. We assume audio time stamps are consecutive, so there's no equivalent of
- the checking / insertion of repeat frames that there is for video.
- */
- Audio (b);
- _audio_frames += b->frames ();
- }
-}
-
-void
-Matcher::process_end ()
-{
- if (_audio_frames == 0 || !_pixel_format || !_size || !_channels) {
- /* We won't do anything */
- return;
- }
-
- _log->log (String::compose ("Matcher has seen %1 video frames (which equals %2 audio frames) and %3 audio frames",
- _video_frames, video_frames_to_audio_frames (_video_frames, _sample_rate, _frames_per_second), _audio_frames));
-
- match ((double (_audio_frames) / _sample_rate) - (double (_video_frames) / _frames_per_second));
-}
-
-void
-Matcher::fix_start ()
-{
- assert (!_pending_video.empty ());
- assert (!_pending_audio.empty ());
-
- _log->log (String::compose ("Fixing start; video at %1, audio at %2", _pending_video.front().time, _pending_audio.front().time));
-
- match (_pending_video.front().time - _pending_audio.front().time);
-
- for (list<VideoRecord>::iterator i = _pending_video.begin(); i != _pending_video.end(); ++i) {
- process_video (i->image, i->same, i->subtitle, i->time);
- }
-
- _pending_video.clear ();
-
- for (list<AudioRecord>::iterator i = _pending_audio.begin(); i != _pending_audio.end(); ++i) {
- process_audio (i->audio, i->time);
- }
-
- _pending_audio.clear ();
-}
-
-void
-Matcher::match (double extra_video_needed)
-{
- _log->log (String::compose ("Match %1", extra_video_needed));
-
- if (extra_video_needed > 0) {
-
- /* Emit black video frames */
-
- int const black_video_frames = ceil (extra_video_needed * _frames_per_second);
-
- _log->log (String::compose (N_("Emitting %1 frames of black video"), black_video_frames));
-
- shared_ptr<Image> black (new SimpleImage (_pixel_format.get(), _size.get(), true));
- black->make_black ();
- for (int i = 0; i < black_video_frames; ++i) {
- Video (black, i != 0, shared_ptr<Subtitle>());
- ++_video_frames;
- }
-
- extra_video_needed -= black_video_frames / _frames_per_second;
- }
-
- if (extra_video_needed < 0) {
-
- /* Emit silence */
-
- int64_t to_do = -extra_video_needed * _sample_rate;
- _log->log (String::compose (N_("Emitting %1 frames of silence"), to_do));
-
- /* Do things in half second blocks as I think there may be limits
- to what FFmpeg (and in particular the resampler) can cope with.
- */
- int64_t const block = _sample_rate / 2;
- shared_ptr<AudioBuffers> b (new AudioBuffers (_channels.get(), block));
- b->make_silent ();
-
- while (to_do > 0) {
- int64_t const this_time = min (to_do, block);
- b->set_frames (this_time);
- Audio (b);
- _audio_frames += b->frames ();
- to_do -= this_time;
- }
- }
-}
-
-void
-Matcher::repeat_last_video ()
-{
- if (!_last_image) {
- shared_ptr<Image> im (new SimpleImage (_pixel_format.get(), _size.get(), true));
- im->make_black ();
- _last_image = im;
- }
-
- Video (_last_image, true, _last_subtitle);
- ++_video_frames;
-}
-
diff --git a/src/lib/matcher.h b/src/lib/matcher.h
deleted file mode 100644
index 61fd81436..000000000
--- a/src/lib/matcher.h
+++ /dev/null
@@ -1,77 +0,0 @@
-/*
- Copyright (C) 2012 Carl Hetherington <cth@carlh.net>
-
- 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
- the Free Software Foundation; either version 2 of the License, or
- (at your option) any later version.
-
- This program is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU General Public License for more details.
-
- You should have received a copy of the GNU General Public License
- along with this program; if not, write to the Free Software
- Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
-
-*/
-
-#include <boost/optional.hpp>
-#include "processor.h"
-
-class Matcher : public Processor, public TimedAudioSink, public TimedVideoSink, public AudioSource, public VideoSource
-{
-public:
- Matcher (boost::shared_ptr<Log> log, int sample_rate, float frames_per_second);
- void process_video (boost::shared_ptr<const Image> i, bool, boost::shared_ptr<Subtitle> s, double);
- void process_audio (boost::shared_ptr<const AudioBuffers>, double);
- void process_end ();
-
-private:
- void fix_start ();
- void match (double);
- void repeat_last_video ();
-
- int _sample_rate;
- float _frames_per_second;
- int _video_frames;
- int64_t _audio_frames;
- boost::optional<AVPixelFormat> _pixel_format;
- boost::optional<libdcp::Size> _size;
- boost::optional<int> _channels;
-
- struct VideoRecord {
- VideoRecord (boost::shared_ptr<const Image> i, bool s, boost::shared_ptr<Subtitle> u, double t)
- : image (i)
- , same (s)
- , subtitle (u)
- , time (t)
- {}
-
- boost::shared_ptr<const Image> image;
- bool same;
- boost::shared_ptr<Subtitle> subtitle;
- double time;
- };
-
- struct AudioRecord {
- AudioRecord (boost::shared_ptr<const AudioBuffers> a, double t)
- : audio (a)
- , time (t)
- {}
-
- boost::shared_ptr<const AudioBuffers> audio;
- double time;
- };
-
- std::list<VideoRecord> _pending_video;
- std::list<AudioRecord> _pending_audio;
-
- boost::optional<double> _first_input;
- boost::shared_ptr<const Image> _last_image;
- boost::shared_ptr<Subtitle> _last_subtitle;
-
- bool _had_first_video;
- bool _had_first_audio;
-};
diff --git a/src/lib/null_content.h b/src/lib/null_content.h
index 889ff7a0d..44bfffa49 100644
--- a/src/lib/null_content.h
+++ b/src/lib/null_content.h
@@ -43,7 +43,7 @@ public:
int audio_channels () const;
- ContentAudioFrame audio_length () const {
+ AudioContent::Frame audio_length () const {
return _audio_length;
}
@@ -62,6 +62,6 @@ public:
}
private:
- ContentAudioFrame _audio_length;
+ AudioContent::Frame _audio_length;
Time _length;
};
diff --git a/src/lib/player.cc b/src/lib/player.cc
index cd1c54d5b..79f1c3b97 100644
--- a/src/lib/player.cc
+++ b/src/lib/player.cc
@@ -32,12 +32,16 @@
#include "null_content.h"
#include "black_decoder.h"
#include "silence_decoder.h"
+#include "ratio.h"
+#include "resampler.h"
using std::list;
using std::cout;
using std::min;
using std::max;
using std::vector;
+using std::pair;
+using std::map;
using boost::shared_ptr;
using boost::weak_ptr;
using boost::dynamic_pointer_cast;
@@ -49,10 +53,12 @@ struct Piece
Piece (shared_ptr<Content> c, shared_ptr<Decoder> d)
: content (c)
, decoder (d)
+ , last_emission (0)
{}
shared_ptr<Content> content;
shared_ptr<Decoder> decoder;
+ Time last_emission;
};
@@ -125,13 +131,8 @@ Player::pass ()
continue;
}
- if (!_audio && dynamic_pointer_cast<AudioDecoder> ((*i)->decoder) && !dynamic_pointer_cast<VideoDecoder> ((*i)->decoder)) {
- continue;
- }
-
- Time const t = (*i)->content->start() + (*i)->decoder->position();
- if (t < earliest_t) {
- earliest_t = t;
+ if ((*i)->last_emission < earliest_t) {
+ earliest_t = (*i)->last_emission;
earliest = *i;
}
}
@@ -142,39 +143,106 @@ Player::pass ()
}
earliest->decoder->pass ();
- _position = earliest->content->start() + earliest->decoder->position ();
+ _position = earliest->last_emission;
return false;
}
void
-Player::process_video (weak_ptr<Content> weak_content, shared_ptr<const Image> image, bool same, Time time)
+Player::process_video (weak_ptr<Piece> weak_piece, shared_ptr<const Image> image, bool same, VideoContent::Frame frame)
{
- shared_ptr<Content> content = weak_content.lock ();
- if (!content) {
+ shared_ptr<Piece> piece = weak_piece.lock ();
+ if (!piece) {
+ return;
+ }
+
+ shared_ptr<VideoContent> content = dynamic_pointer_cast<VideoContent> (piece->content);
+ assert (content);
+
+ FrameRateConversion frc (content->video_frame_rate(), _film->dcp_video_frame_rate());
+ if (frc.skip && (frame % 2) == 1) {
return;
}
+
+ image = image->crop (content->crop(), true);
+
+ libdcp::Size const container_size = _video_container_size.get_value_or (_film->container()->size (_film->full_frame ()));
+ libdcp::Size const image_size = content->ratio()->size (container_size);
- time += content->start ();
+ image = image->scale_and_convert_to_rgb (image_size, _film->scaler(), true);
+
+#if 0
+ if (film->with_subtitles ()) {
+ shared_ptr<Subtitle> sub;
+ if (_timed_subtitle && _timed_subtitle->displayed_at (t)) {
+ sub = _timed_subtitle->subtitle ();
+ }
+
+ if (sub) {
+ dcpomatic::Rect const tx = subtitle_transformed_area (
+ float (image_size.width) / content->video_size().width,
+ float (image_size.height) / content->video_size().height,
+ sub->area(), film->subtitle_offset(), film->subtitle_scale()
+ );
+
+ shared_ptr<Image> im = sub->image()->scale (tx.size(), film->scaler(), true);
+ image->alpha_blend (im, tx.position());
+ }
+ }
+#endif
+
+ if (image_size != container_size) {
+ assert (image_size.width <= container_size.width);
+ assert (image_size.height <= container_size.height);
+ shared_ptr<Image> im (new SimpleImage (PIX_FMT_RGB24, container_size, true));
+ im->make_black ();
+ im->copy (image, Position ((container_size.width - image_size.width) / 2, (container_size.height - image_size.height) / 2));
+ image = im;
+ }
+
+ Time time = content->start() + (frame * frc.factor() * TIME_HZ / _film->dcp_video_frame_rate());
Video (image, same, time);
+
+ if (frc.repeat) {
+ time += TIME_HZ / _film->dcp_video_frame_rate();
+ Video (image, true, time);
+ }
+
+ piece->last_emission = min (piece->last_emission, time);
}
void
-Player::process_audio (weak_ptr<Content> weak_content, shared_ptr<const AudioBuffers> audio, Time time)
+Player::process_audio (weak_ptr<Piece> weak_piece, shared_ptr<const AudioBuffers> audio, AudioContent::Frame frame)
{
- shared_ptr<Content> content = weak_content.lock ();
- if (!content) {
+ shared_ptr<Piece> piece = weak_piece.lock ();
+ if (!piece) {
return;
}
-
+
+ shared_ptr<AudioContent> content = dynamic_pointer_cast<AudioContent> (piece->content);
+ assert (content);
+
+ if (content->content_audio_frame_rate() != content->output_audio_frame_rate()) {
+ audio = resampler(content)->run (audio);
+ }
+
+ /* Remap channels */
+ shared_ptr<AudioBuffers> dcp_mapped (new AudioBuffers (_film->dcp_audio_channels(), audio->frames()));
+ dcp_mapped->make_silent ();
+ list<pair<int, libdcp::Channel> > map = content->audio_mapping().content_to_dcp ();
+ for (list<pair<int, libdcp::Channel> >::iterator i = map.begin(); i != map.end(); ++i) {
+ dcp_mapped->accumulate_channel (audio.get(), i->first, i->second);
+ }
+
/* The time of this audio may indicate that some of our buffered audio is not going to
be added to any more, so it can be emitted.
*/
- time += content->start ();
+ Time const time = content->start() + (frame * TIME_HZ / _film->dcp_audio_frame_rate());
+ piece->last_emission = min (piece->last_emission, time);
- cout << "Player gets " << audio->frames() << " @ " << time << " cf " << _next_audio << "\n";
+ cout << "Player gets " << dcp_mapped->frames() << " @ " << time << " cf " << _next_audio << "\n";
if (time > _next_audio) {
/* We can emit some audio from our buffers */
@@ -224,10 +292,18 @@ Player::seek (Time t)
}
for (list<shared_ptr<Piece> >::iterator i = _pieces.begin(); i != _pieces.end(); ++i) {
- Time s = t - (*i)->content->start ();
+ shared_ptr<VideoContent> vc = dynamic_pointer_cast<VideoContent> ((*i)->content);
+ if (!vc) {
+ continue;
+ }
+
+ Time s = t - vc->start ();
s = max (static_cast<Time> (0), s);
- s = min ((*i)->content->length(), s);
- (*i)->decoder->seek (s);
+ s = min (vc->length(), s);
+
+ FrameRateConversion frc (vc->video_frame_rate(), _film->dcp_video_frame_rate());
+ VideoContent::Frame f = s * _film->dcp_video_frame_rate() / (frc.factor() * TIME_HZ);
+ dynamic_pointer_cast<VideoDecoder>((*i)->decoder)->seek (f);
}
/* XXX: don't seek audio because we don't need to... */
@@ -241,19 +317,14 @@ Player::seek_back ()
}
void
-Player::seek_forward ()
-{
-
-}
-
-void
Player::add_black_piece (Time s, Time len)
{
shared_ptr<NullContent> nc (new NullContent (_film, s, len));
nc->set_ratio (_film->container ());
shared_ptr<BlackDecoder> bd (new BlackDecoder (_film, nc));
- bd->Video.connect (bind (&Player::process_video, this, nc, _1, _2, _3));
- _pieces.push_back (shared_ptr<Piece> (new Piece (nc, bd)));
+ shared_ptr<Piece> p (new Piece (nc, bd));
+ _pieces.push_back (p);
+ bd->Video.connect (bind (&Player::process_video, this, p, _1, _2, _3));
}
void
@@ -261,8 +332,9 @@ Player::add_silent_piece (Time s, Time len)
{
shared_ptr<NullContent> nc (new NullContent (_film, s, len));
shared_ptr<SilenceDecoder> sd (new SilenceDecoder (_film, nc));
- sd->Audio.connect (bind (&Player::process_audio, this, nc, _1, _2));
- _pieces.push_back (shared_ptr<Piece> (new Piece (nc, sd)));
+ shared_ptr<Piece> p (new Piece (nc, sd));
+ _pieces.push_back (p);
+ sd->Audio.connect (bind (&Player::process_audio, this, p, _1, _2));
}
@@ -279,7 +351,7 @@ Player::setup_pieces ()
for (Playlist::ContentList::iterator i = content.begin(); i != content.end(); ++i) {
shared_ptr<Decoder> decoder;
-
+
/* XXX: into content? */
shared_ptr<const FFmpegContent> fc = dynamic_pointer_cast<const FFmpegContent> (*i);
@@ -288,9 +360,6 @@ Player::setup_pieces ()
fd->Video.connect (bind (&Player::process_video, this, *i, _1, _2, _3));
fd->Audio.connect (bind (&Player::process_audio, this, *i, _1, _2));
- if (_video_container_size) {
- fd->set_video_container_size (_video_container_size.get ());
- }
decoder = fd;
}
@@ -310,9 +379,6 @@ Player::setup_pieces ()
if (!id) {
id.reset (new ImageMagickDecoder (_film, ic));
id->Video.connect (bind (&Player::process_video, this, *i, _1, _2, _3));
- if (_video_container_size) {
- id->set_video_container_size (_video_container_size.get ());
- }
}
decoder = id;
@@ -390,10 +456,17 @@ void
Player::set_video_container_size (libdcp::Size s)
{
_video_container_size = s;
- for (list<shared_ptr<Piece> >::iterator i = _pieces.begin(); i != _pieces.end(); ++i) {
- shared_ptr<VideoDecoder> vd = dynamic_pointer_cast<VideoDecoder> ((*i)->decoder);
- if (vd) {
- vd->set_video_container_size (s);
- }
+}
+
+shared_ptr<Resampler>
+Player::resampler (shared_ptr<AudioContent> c)
+{
+ map<shared_ptr<AudioContent>, shared_ptr<Resampler> >::iterator i = _resamplers.find (c);
+ if (i != _resamplers.end ()) {
+ return i->second;
}
+
+ shared_ptr<Resampler> r (new Resampler (c->content_audio_frame_rate(), c->output_audio_frame_rate(), c->audio_channels()));
+ _resamplers[c] = r;
+ return r;
}
diff --git a/src/lib/player.h b/src/lib/player.h
index e4fb83220..903d011d0 100644
--- a/src/lib/player.h
+++ b/src/lib/player.h
@@ -23,24 +23,23 @@
#include <list>
#include <boost/shared_ptr.hpp>
#include <boost/enable_shared_from_this.hpp>
-#include "video_source.h"
-#include "audio_source.h"
-#include "video_sink.h"
-#include "audio_sink.h"
#include "playlist.h"
#include "audio_buffers.h"
+#include "content.h"
class Job;
class Film;
class Playlist;
class AudioContent;
class Piece;
+class Image;
+class Resampler;
/** @class Player
* @brief A class which can `play' a Playlist; emitting its audio and video.
*/
-class Player : public VideoSource, public AudioSource, public boost::enable_shared_from_this<Player>
+class Player : public boost::enable_shared_from_this<Player>
{
public:
Player (boost::shared_ptr<const Film>, boost::shared_ptr<const Playlist>);
@@ -51,7 +50,6 @@ public:
bool pass ();
void seek (Time);
void seek_back ();
- void seek_forward ();
/** @return position that we are at; ie the time of the next thing we will emit on pass() */
Time position () const {
@@ -60,10 +58,20 @@ public:
void set_video_container_size (libdcp::Size);
+ /** Emitted when a video frame is ready.
+ * First parameter is the video image.
+ * Second parameter is true if the image is the same as the last one that was emitted.
+ * Third parameter is the time.
+ */
+ boost::signals2::signal<void (boost::shared_ptr<const Image>, bool, Time)> Video;
+
+ /** Emitted when some audio data is ready */
+ boost::signals2::signal<void (boost::shared_ptr<const AudioBuffers>, Time)> Audio;
+
private:
- void process_video (boost::weak_ptr<Content>, boost::shared_ptr<const Image>, bool, Time);
- void process_audio (boost::weak_ptr<Content>, boost::shared_ptr<const AudioBuffers>, Time);
+ void process_video (boost::weak_ptr<Piece>, boost::shared_ptr<const Image>, bool, VideoContent::Frame);
+ void process_audio (boost::weak_ptr<Piece>, boost::shared_ptr<const AudioBuffers>, AudioContent::Frame);
void setup_pieces ();
void playlist_changed ();
void content_changed (boost::weak_ptr<Content>, int);
@@ -71,6 +79,7 @@ private:
void add_black_piece (Time, Time);
void add_silent_piece (Time, Time);
void flush ();
+ boost::shared_ptr<Resampler> resampler (boost::shared_ptr<AudioContent>);
boost::shared_ptr<const Film> _film;
boost::shared_ptr<const Playlist> _playlist;
@@ -85,6 +94,7 @@ private:
AudioBuffers _audio_buffers;
Time _next_audio;
boost::optional<libdcp::Size> _video_container_size;
+ std::map<boost::shared_ptr<AudioContent>, boost::shared_ptr<Resampler> > _resamplers;
};
#endif
diff --git a/src/lib/playlist.h b/src/lib/playlist.h
index e4f4c79f0..2d243fe8f 100644
--- a/src/lib/playlist.h
+++ b/src/lib/playlist.h
@@ -23,10 +23,6 @@
#include <list>
#include <boost/shared_ptr.hpp>
#include <boost/enable_shared_from_this.hpp>
-#include "video_source.h"
-#include "audio_source.h"
-#include "video_sink.h"
-#include "audio_sink.h"
#include "ffmpeg_content.h"
#include "audio_mapping.h"
diff --git a/src/lib/resampler.cc b/src/lib/resampler.cc
new file mode 100644
index 000000000..1235b9038
--- /dev/null
+++ b/src/lib/resampler.cc
@@ -0,0 +1,61 @@
+extern "C" {
+#include "libavutil/channel_layout.h"
+}
+#include "resampler.h"
+#include "audio_buffers.h"
+#include "exceptions.h"
+
+#include "i18n.h"
+
+using boost::shared_ptr;
+
+Resampler::Resampler (int in, int out, int channels)
+ : _in_rate (in)
+ , _out_rate (out)
+ , _channels (channels)
+{
+ /* We will be using planar float data when we call the
+ resampler. As far as I can see, the audio channel
+ layout is not necessary for our purposes; it seems
+ only to be used get the number of channels and
+ decide if rematrixing is needed. It won't be, since
+ input and output layouts are the same.
+ */
+
+ _swr_context = swr_alloc_set_opts (
+ 0,
+ av_get_default_channel_layout (_channels),
+ AV_SAMPLE_FMT_FLTP,
+ _out_rate,
+ av_get_default_channel_layout (_channels),
+ AV_SAMPLE_FMT_FLTP,
+ _in_rate,
+ 0, 0
+ );
+
+ swr_init (_swr_context);
+}
+
+Resampler::~Resampler ()
+{
+ swr_free (&_swr_context);
+}
+
+shared_ptr<const AudioBuffers>
+Resampler::run (shared_ptr<const AudioBuffers> in)
+{
+ /* Compute the resampled frames count and add 32 for luck */
+ int const max_resampled_frames = ceil ((double) in->frames() * _out_rate / _in_rate) + 32;
+ shared_ptr<AudioBuffers> resampled (new AudioBuffers (_channels, max_resampled_frames));
+
+ int const resampled_frames = swr_convert (
+ _swr_context, (uint8_t **) resampled->data(), max_resampled_frames, (uint8_t const **) in->data(), in->frames()
+ );
+
+ if (resampled_frames < 0) {
+ throw EncodeError (_("could not run sample-rate converter"));
+ }
+
+ resampled->set_frames (resampled_frames);
+ return resampled;
+}
diff --git a/src/lib/resampler.h b/src/lib/resampler.h
new file mode 100644
index 000000000..cda718934
--- /dev/null
+++ b/src/lib/resampler.h
@@ -0,0 +1,21 @@
+#include <boost/shared_ptr.hpp>
+extern "C" {
+#include <libswresample/swresample.h>
+}
+
+class AudioBuffers;
+
+class Resampler
+{
+public:
+ Resampler (int, int, int);
+ ~Resampler ();
+
+ boost::shared_ptr<const AudioBuffers> run (boost::shared_ptr<const AudioBuffers>);
+
+private:
+ SwrContext* _swr_context;
+ int _in_rate;
+ int _out_rate;
+ int _channels;
+};
diff --git a/src/lib/silence_decoder.cc b/src/lib/silence_decoder.cc
index 0380117ce..8cff80ed2 100644
--- a/src/lib/silence_decoder.cc
+++ b/src/lib/silence_decoder.cc
@@ -27,7 +27,8 @@ using boost::shared_ptr;
SilenceDecoder::SilenceDecoder (shared_ptr<const Film> f, shared_ptr<NullContent> c)
: Decoder (f)
- , AudioDecoder (f, c)
+ , AudioDecoder (f)
+ , _null_content (c)
{
}
@@ -38,50 +39,14 @@ SilenceDecoder::pass ()
shared_ptr<const Film> film = _film.lock ();
assert (film);
- Time const this_time = min (_audio_content->length() - _next_audio, TIME_HZ / 2);
- cout << "silence emit " << this_time << " from " << _audio_content->length() << "\n";
- shared_ptr<AudioBuffers> data (new AudioBuffers (film->dcp_audio_channels(), film->time_to_audio_frames (this_time)));
+ AudioContent::Frame const this_time = min (_null_content->audio_length() - _next_audio_frame, int64_t (_null_content->output_audio_frame_rate() / 2));
+ shared_ptr<AudioBuffers> data (new AudioBuffers (film->dcp_audio_channels(), this_time));
data->make_silent ();
- audio (data, _next_audio);
-}
-
-void
-SilenceDecoder::seek (Time t)
-{
- _next_audio = t;
-}
-
-void
-SilenceDecoder::seek_back ()
-{
- boost::shared_ptr<const Film> f = _film.lock ();
- if (!f) {
- return;
- }
-
- _next_audio -= f->video_frames_to_time (2);
-}
-
-void
-SilenceDecoder::seek_forward ()
-{
- boost::shared_ptr<const Film> f = _film.lock ();
- if (!f) {
- return;
- }
-
- _next_audio += f->video_frames_to_time (1);
-}
-
-Time
-SilenceDecoder::position () const
-{
- return _next_audio;
+ audio (data, _next_audio_frame);
}
bool
SilenceDecoder::done () const
{
- return audio_done ();
+ return _next_audio_frame > _null_content->audio_length ();
}
-
diff --git a/src/lib/silence_decoder.h b/src/lib/silence_decoder.h
index a8a335d39..10c18c69f 100644
--- a/src/lib/silence_decoder.h
+++ b/src/lib/silence_decoder.h
@@ -29,9 +29,8 @@ public:
SilenceDecoder (boost::shared_ptr<const Film>, boost::shared_ptr<NullContent>);
void pass ();
- void seek (Time);
- void seek_back ();
- void seek_forward ();
- Time position () const;
bool done () const;
+
+private:
+ boost::shared_ptr<NullContent> _null_content;
};
diff --git a/src/lib/sndfile_content.cc b/src/lib/sndfile_content.cc
index 8eede89f4..beee7cd9d 100644
--- a/src/lib/sndfile_content.cc
+++ b/src/lib/sndfile_content.cc
@@ -46,7 +46,7 @@ SndfileContent::SndfileContent (shared_ptr<const Film> f, shared_ptr<const cxml:
, AudioContent (f, node)
{
_audio_channels = node->number_child<int> ("AudioChannels");
- _audio_length = node->number_child<ContentAudioFrame> ("AudioLength");
+ _audio_length = node->number_child<AudioContent::Frame> ("AudioLength");
_audio_frame_rate = node->number_child<int> ("AudioFrameRate");
_audio_mapping = AudioMapping (node->node_child ("AudioMapping"));
}
diff --git a/src/lib/sndfile_content.h b/src/lib/sndfile_content.h
index 30eb23a4e..876d66088 100644
--- a/src/lib/sndfile_content.h
+++ b/src/lib/sndfile_content.h
@@ -49,7 +49,7 @@ public:
return _audio_channels;
}
- ContentAudioFrame audio_length () const {
+ AudioContent::Frame audio_length () const {
boost::mutex::scoped_lock lm (_mutex);
return _audio_length;
}
@@ -72,7 +72,7 @@ public:
private:
int _audio_channels;
- ContentAudioFrame _audio_length;
+ AudioContent::Frame _audio_length;
int _audio_frame_rate;
AudioMapping _audio_mapping;
};
diff --git a/src/lib/sndfile_decoder.cc b/src/lib/sndfile_decoder.cc
index ff56f1062..9030021e7 100644
--- a/src/lib/sndfile_decoder.cc
+++ b/src/lib/sndfile_decoder.cc
@@ -35,7 +35,7 @@ using boost::shared_ptr;
SndfileDecoder::SndfileDecoder (shared_ptr<const Film> f, shared_ptr<const SndfileContent> c)
: Decoder (f)
- , AudioDecoder (f, c)
+ , AudioDecoder (f)
, _sndfile_content (c)
, _deinterleave_buffer (0)
{
@@ -100,7 +100,7 @@ SndfileDecoder::audio_channels () const
return _info.channels;
}
-ContentAudioFrame
+AudioContent::Frame
SndfileDecoder::audio_length () const
{
return _info.frames;
@@ -112,14 +112,8 @@ SndfileDecoder::audio_frame_rate () const
return _info.samplerate;
}
-Time
-SndfileDecoder::position () const
-{
- return _next_audio;
-}
-
bool
SndfileDecoder::done () const
{
- return audio_done ();
+ return _next_audio_frame > _sndfile_content->audio_length ();
}
diff --git a/src/lib/sndfile_decoder.h b/src/lib/sndfile_decoder.h
index e904340b3..77fa6d177 100644
--- a/src/lib/sndfile_decoder.h
+++ b/src/lib/sndfile_decoder.h
@@ -30,21 +30,17 @@ public:
~SndfileDecoder ();
void pass ();
- void seek (Time) {}
- void seek_back () {}
- void seek_forward () {}
- Time position () const;
bool done () const;
int audio_channels () const;
- ContentAudioFrame audio_length () const;
+ AudioContent::Frame audio_length () const;
int audio_frame_rate () const;
private:
boost::shared_ptr<const SndfileContent> _sndfile_content;
SNDFILE* _sndfile;
SF_INFO _info;
- ContentAudioFrame _done;
- ContentAudioFrame _remaining;
+ AudioContent::Frame _done;
+ AudioContent::Frame _remaining;
float* _deinterleave_buffer;
};
diff --git a/src/lib/subtitle.cc b/src/lib/subtitle.cc
index 5e719f977..7013f1d7d 100644
--- a/src/lib/subtitle.cc
+++ b/src/lib/subtitle.cc
@@ -27,8 +27,7 @@
#include "i18n.h"
-using namespace std;
-using namespace boost;
+using boost::shared_ptr;
using libdcp::Size;
/** Construct a TimedSubtitle. This is a subtitle image, position,
diff --git a/src/lib/transcoder.cc b/src/lib/transcoder.cc
index f4637a05c..f4a52639a 100644
--- a/src/lib/transcoder.cc
+++ b/src/lib/transcoder.cc
@@ -36,8 +36,27 @@
using std::string;
using boost::shared_ptr;
+using boost::weak_ptr;
using boost::dynamic_pointer_cast;
+static void
+video_proxy (weak_ptr<Encoder> encoder, shared_ptr<const Image> image, bool same)
+{
+ shared_ptr<Encoder> e = encoder.lock ();
+ if (e) {
+ e->process_video (image, same);
+ }
+}
+
+static void
+audio_proxy (weak_ptr<Encoder> encoder, shared_ptr<const AudioBuffers> audio)
+{
+ shared_ptr<Encoder> e = encoder.lock ();
+ if (e) {
+ e->process_audio (audio);
+ }
+}
+
/** Construct a transcoder using a Decoder that we create and a supplied Encoder.
* @param f Film that we are transcoding.
* @param j Job that we are running under, or 0.
@@ -48,8 +67,8 @@ Transcoder::Transcoder (shared_ptr<const Film> f, shared_ptr<Job> j)
, _player (f->player ())
, _encoder (new Encoder (f, j))
{
- _player->connect_video (_encoder);
- _player->connect_audio (_encoder);
+ _player->Video.connect (bind (video_proxy, _encoder, _1, _2));
+ _player->Audio.connect (bind (audio_proxy, _encoder, _1));
}
void
diff --git a/src/lib/types.h b/src/lib/types.h
index 70262afb0..33f8239d8 100644
--- a/src/lib/types.h
+++ b/src/lib/types.h
@@ -27,8 +27,6 @@
class Content;
-typedef int64_t ContentAudioFrame;
-typedef int ContentVideoFrame;
typedef int64_t Time;
#define TIME_MAX INT64_MAX
#define TIME_HZ ((Time) 96000)
diff --git a/src/lib/util.cc b/src/lib/util.cc
index eda0d0236..d425fc8fe 100644
--- a/src/lib/util.cc
+++ b/src/lib/util.cc
@@ -710,7 +710,7 @@ ensure_ui_thread ()
* @return Equivalent number of audio frames for `v'.
*/
int64_t
-video_frames_to_audio_frames (ContentVideoFrame v, float audio_sample_rate, float frames_per_second)
+video_frames_to_audio_frames (VideoContent::Frame v, float audio_sample_rate, float frames_per_second)
{
return ((int64_t) v * audio_sample_rate / frames_per_second);
}
diff --git a/src/lib/util.h b/src/lib/util.h
index 42514a12c..c68bb4f16 100644
--- a/src/lib/util.h
+++ b/src/lib/util.h
@@ -38,6 +38,7 @@ extern "C" {
}
#include "compose.hpp"
#include "types.h"
+#include "video_content.h"
#ifdef DCPOMATIC_DEBUG
#define TIMING(...) _film->log()->microsecond_log (String::compose (__VA_ARGS__), Log::TIMING);
@@ -152,7 +153,7 @@ private:
int _timeout;
};
-extern int64_t video_frames_to_audio_frames (ContentVideoFrame v, float audio_sample_rate, float frames_per_second);
+extern int64_t video_frames_to_audio_frames (VideoContent::Frame v, float audio_sample_rate, float frames_per_second);
class LocaleGuard
{
diff --git a/src/lib/video_content.cc b/src/lib/video_content.cc
index f9de6aa21..3818fa792 100644
--- a/src/lib/video_content.cc
+++ b/src/lib/video_content.cc
@@ -22,6 +22,7 @@
#include "video_content.h"
#include "video_examiner.h"
#include "ratio.h"
+#include "compose.hpp"
#include "i18n.h"
@@ -37,7 +38,7 @@ using boost::shared_ptr;
using boost::lexical_cast;
using boost::optional;
-VideoContent::VideoContent (shared_ptr<const Film> f, Time s, ContentVideoFrame len)
+VideoContent::VideoContent (shared_ptr<const Film> f, Time s, VideoContent::Frame len)
: Content (f, s)
, _video_length (len)
, _video_frame_rate (0)
@@ -58,7 +59,7 @@ VideoContent::VideoContent (shared_ptr<const Film> f, boost::filesystem::path p)
VideoContent::VideoContent (shared_ptr<const Film> f, shared_ptr<const cxml::Node> node)
: Content (f, node)
{
- _video_length = node->number_child<ContentVideoFrame> ("VideoLength");
+ _video_length = node->number_child<VideoContent::Frame> ("VideoLength");
_video_size.width = node->number_child<int> ("VideoWidth");
_video_size.height = node->number_child<int> ("VideoHeight");
_video_frame_rate = node->number_child<float> ("VideoFrameRate");
diff --git a/src/lib/video_content.h b/src/lib/video_content.h
index 23bcaa89b..372cab3bd 100644
--- a/src/lib/video_content.h
+++ b/src/lib/video_content.h
@@ -21,7 +21,6 @@
#define DCPOMATIC_VIDEO_CONTENT_H
#include "content.h"
-#include "util.h"
class VideoExaminer;
class Ratio;
@@ -38,7 +37,9 @@ public:
class VideoContent : public virtual Content
{
public:
- VideoContent (boost::shared_ptr<const Film>, Time, ContentVideoFrame);
+ typedef int Frame;
+
+ VideoContent (boost::shared_ptr<const Film>, Time, VideoContent::Frame);
VideoContent (boost::shared_ptr<const Film>, boost::filesystem::path);
VideoContent (boost::shared_ptr<const Film>, boost::shared_ptr<const cxml::Node>);
VideoContent (VideoContent const &);
@@ -46,7 +47,7 @@ public:
void as_xml (xmlpp::Node *) const;
virtual std::string information () const;
- ContentVideoFrame video_length () const {
+ VideoContent::Frame video_length () const {
boost::mutex::scoped_lock lm (_mutex);
return _video_length;
}
@@ -82,7 +83,7 @@ public:
protected:
void take_from_video_examiner (boost::shared_ptr<VideoExaminer>);
- ContentVideoFrame _video_length;
+ VideoContent::Frame _video_length;
private:
libdcp::Size _video_size;
diff --git a/src/lib/video_decoder.cc b/src/lib/video_decoder.cc
index fcc0ccf41..b5cc7d158 100644
--- a/src/lib/video_decoder.cc
+++ b/src/lib/video_decoder.cc
@@ -28,78 +28,22 @@
using std::cout;
using boost::shared_ptr;
-VideoDecoder::VideoDecoder (shared_ptr<const Film> f, shared_ptr<const VideoContent> c)
+VideoDecoder::VideoDecoder (shared_ptr<const Film> f)
: Decoder (f)
- , _next_video (0)
- , _video_content (c)
- , _frame_rate_conversion (c->video_frame_rate(), f->dcp_video_frame_rate())
- , _odd (false)
+ , _next_video_frame (0)
{
}
-/** Called by subclasses when some video is ready.
- * @param image frame to emit.
- * @param same true if this frame is the same as the last one passed to this call.
- * @param t Time of the frame within the source.
- */
void
-VideoDecoder::video (shared_ptr<Image> image, bool same, Time t)
+VideoDecoder::video (shared_ptr<const Image> image, bool same, VideoContent::Frame frame)
{
- if (_frame_rate_conversion.skip && _odd) {
- _odd = !_odd;
- return;
- }
-
- image = image->crop (_video_content->crop(), true);
-
- shared_ptr<const Film> film = _film.lock ();
- assert (film);
-
- libdcp::Size const container_size = _video_container_size.get_value_or (film->container()->size (film->full_frame ()));
- libdcp::Size const image_size = _video_content->ratio()->size (container_size);
-
- shared_ptr<Image> out = image->scale_and_convert_to_rgb (image_size, film->scaler(), true);
-
- if (film->with_subtitles ()) {
- shared_ptr<Subtitle> sub;
- if (_timed_subtitle && _timed_subtitle->displayed_at (t)) {
- sub = _timed_subtitle->subtitle ();
- }
-
- if (sub) {
- dcpomatic::Rect const tx = subtitle_transformed_area (
- float (image_size.width) / _video_content->video_size().width,
- float (image_size.height) / _video_content->video_size().height,
- sub->area(), film->subtitle_offset(), film->subtitle_scale()
- );
-
- shared_ptr<Image> im = sub->image()->scale (tx.size(), film->scaler(), true);
- out->alpha_blend (im, tx.position());
- }
- }
-
- if (image_size != container_size) {
- assert (image_size.width <= container_size.width);
- assert (image_size.height <= container_size.height);
- shared_ptr<Image> im (new SimpleImage (PIX_FMT_RGB24, container_size, true));
- im->make_black ();
- im->copy (out, Position ((container_size.width - image_size.width) / 2, (container_size.height - image_size.height) / 2));
- out = im;
- }
-
- Video (out, same, t);
-
- if (_frame_rate_conversion.repeat) {
- Video (image, true, t + film->video_frames_to_time (1));
- _next_video = t + film->video_frames_to_time (2);
- } else {
- _next_video = t + film->video_frames_to_time (1);
- }
-
- _odd = !_odd;
+ Video (image, same, frame);
+ _next_video_frame = frame + 1;
}
+#if 0
+
/** Called by subclasses when a subtitle is ready.
* s may be 0 to say that there is no current subtitle.
* @param s New current subtitle, or 0.
@@ -114,40 +58,5 @@ VideoDecoder::subtitle (shared_ptr<TimedSubtitle> s)
_timed_subtitle->subtitle()->set_position (Position (p.x - _video_content->crop().left, p.y - _video_content->crop().top));
}
}
+#endif
-bool
-VideoDecoder::video_done () const
-{
- shared_ptr<const Film> film = _film.lock ();
- assert (film);
-
- return (_video_content->length() - _next_video) < film->video_frames_to_time (1);
-}
-
-void
-VideoDecoder::seek (Time t)
-{
- _next_video = t;
-}
-
-void
-VideoDecoder::seek_back ()
-{
- shared_ptr<const Film> film = _film.lock ();
- assert (film);
- _next_video -= film->video_frames_to_time (1);
-}
-
-void
-VideoDecoder::seek_forward ()
-{
- shared_ptr<const Film> film = _film.lock ();
- assert (film);
- _next_video += film->video_frames_to_time (1);
-}
-
-void
-VideoDecoder::set_video_container_size (libdcp::Size s)
-{
- _video_container_size = s;
-}
diff --git a/src/lib/video_decoder.h b/src/lib/video_decoder.h
index 8de76c10f..c86248417 100644
--- a/src/lib/video_decoder.h
+++ b/src/lib/video_decoder.h
@@ -20,37 +20,30 @@
#ifndef DCPOMATIC_VIDEO_DECODER_H
#define DCPOMATIC_VIDEO_DECODER_H
-#include "video_source.h"
#include "decoder.h"
#include "util.h"
class VideoContent;
-class VideoDecoder : public VideoSource, public virtual Decoder
+class VideoDecoder : public virtual Decoder
{
public:
- VideoDecoder (boost::shared_ptr<const Film>, boost::shared_ptr<const VideoContent>);
+ VideoDecoder (boost::shared_ptr<const Film>);
- virtual void seek (Time);
- virtual void seek_back ();
- virtual void seek_forward ();
-
- void set_video_container_size (libdcp::Size);
+ virtual void seek (VideoContent::Frame) = 0;
+ virtual void seek_back () = 0;
-protected:
+ /** Emitted when a video frame is ready.
+ * First parameter is the video image.
+ * Second parameter is true if the image is the same as the last one that was emitted.
+ * Third parameter is the frame within our source.
+ */
+ boost::signals2::signal<void (boost::shared_ptr<const Image>, bool, VideoContent::Frame)> Video;
- void video (boost::shared_ptr<Image>, bool, Time);
- void subtitle (boost::shared_ptr<TimedSubtitle>);
- bool video_done () const;
-
- Time _next_video;
- boost::shared_ptr<const VideoContent> _video_content;
-
-private:
- boost::shared_ptr<TimedSubtitle> _timed_subtitle;
- FrameRateConversion _frame_rate_conversion;
- bool _odd;
- boost::optional<libdcp::Size> _video_container_size;
+protected:
+
+ void video (boost::shared_ptr<const Image>, bool, VideoContent::Frame);
+ VideoContent::Frame _next_video_frame;
};
#endif
diff --git a/src/lib/video_examiner.h b/src/lib/video_examiner.h
index 2f713291b..72f6ccc12 100644
--- a/src/lib/video_examiner.h
+++ b/src/lib/video_examiner.h
@@ -19,11 +19,12 @@
#include <libdcp/types.h>
#include "types.h"
+#include "video_content.h"
class VideoExaminer
{
public:
virtual float video_frame_rate () const = 0;
virtual libdcp::Size video_size () const = 0;
- virtual ContentVideoFrame video_length () const = 0;
+ virtual VideoContent::Frame video_length () const = 0;
};
diff --git a/src/lib/video_sink.h b/src/lib/video_sink.h
deleted file mode 100644
index 957aeb4b4..000000000
--- a/src/lib/video_sink.h
+++ /dev/null
@@ -1,39 +0,0 @@
-/*
- Copyright (C) 2012 Carl Hetherington <cth@carlh.net>
-
- 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
- the Free Software Foundation; either version 2 of the License, or
- (at your option) any later version.
-
- This program is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU General Public License for more details.
-
- You should have received a copy of the GNU General Public License
- along with this program; if not, write to the Free Software
- Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
-
-*/
-
-#ifndef DCPOMATIC_VIDEO_SINK_H
-#define DCPOMATIC_VIDEO_SINK_H
-
-#include <boost/shared_ptr.hpp>
-#include "util.h"
-
-class Subtitle;
-class Image;
-
-class VideoSink
-{
-public:
- /** Call with a frame of video.
- * @param i Video frame image.
- * @param same true if i is the same as last time we were called.
- */
- virtual void process_video (boost::shared_ptr<const Image> i, bool same, Time) = 0;
-};
-
-#endif
diff --git a/src/lib/video_source.cc b/src/lib/video_source.cc
deleted file mode 100644
index 824587bcb..000000000
--- a/src/lib/video_source.cc
+++ /dev/null
@@ -1,44 +0,0 @@
-/*
- Copyright (C) 2012 Carl Hetherington <cth@carlh.net>
-
- 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
- the Free Software Foundation; either version 2 of the License, or
- (at your option) any later version.
-
- This program is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU General Public License for more details.
-
- You should have received a copy of the GNU General Public License
- along with this program; if not, write to the Free Software
- Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
-
-*/
-
-#include "video_source.h"
-#include "video_sink.h"
-
-using boost::shared_ptr;
-using boost::weak_ptr;
-using boost::bind;
-
-static void
-process_video_proxy (weak_ptr<VideoSink> sink, shared_ptr<const Image> image, bool same, Time time)
-{
- shared_ptr<VideoSink> p = sink.lock ();
- if (p) {
- p->process_video (image, same, time);
- }
-}
-
-void
-VideoSource::connect_video (shared_ptr<VideoSink> s)
-{
- /* If we bind, say, a Player (as the VideoSink) to a Decoder (which is owned
- by the Player) we create a cycle. Use a weak_ptr to break it.
- */
- Video.connect (bind (process_video_proxy, weak_ptr<VideoSink> (s), _1, _2, _3));
-}
-
diff --git a/src/lib/video_source.h b/src/lib/video_source.h
deleted file mode 100644
index 9242af444..000000000
--- a/src/lib/video_source.h
+++ /dev/null
@@ -1,52 +0,0 @@
-/*
- Copyright (C) 2012 Carl Hetherington <cth@carlh.net>
-
- 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
- the Free Software Foundation; either version 2 of the License, or
- (at your option) any later version.
-
- This program is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU General Public License for more details.
-
- You should have received a copy of the GNU General Public License
- along with this program; if not, write to the Free Software
- Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
-
-*/
-
-/** @file src/video_source.h
- * @brief Parent class for classes which emit video data.
- */
-
-#ifndef DCPOMATIC_VIDEO_SOURCE_H
-#define DCPOMATIC_VIDEO_SOURCE_H
-
-#include <boost/shared_ptr.hpp>
-#include <boost/signals2.hpp>
-#include "util.h"
-
-class VideoSink;
-class Subtitle;
-class Image;
-
-/** @class VideoSource
- * @param A class that emits video data.
- */
-class VideoSource
-{
-public:
-
- /** Emitted when a video frame is ready.
- * First parameter is the video image.
- * Second parameter is true if the image is the same as the last one that was emitted.
- * Third parameter is the time relative to the start of this source's content.
- */
- boost::signals2::signal<void (boost::shared_ptr<const Image>, bool, Time)> Video;
-
- void connect_video (boost::shared_ptr<VideoSink>);
-};
-
-#endif
diff --git a/src/lib/wscript b/src/lib/wscript
index d0f102998..bffc2d5e6 100644
--- a/src/lib/wscript
+++ b/src/lib/wscript
@@ -8,10 +8,8 @@ sources = """
audio_content.cc
audio_decoder.cc
audio_mapping.cc
- audio_source.cc
black_decoder.cc
config.cc
- combiner.cc
content.cc
cross.cc
dci_metadata.cc
@@ -41,6 +39,7 @@ sources = """
player.cc
playlist.cc
ratio.cc
+ resampler.cc
scp_dcp_job.cc
scaler.cc
server.cc
@@ -57,7 +56,6 @@ sources = """
util.cc
video_content.cc
video_decoder.cc
- video_source.cc
writer.cc
"""