summaryrefslogtreecommitdiff
path: root/src/lib
diff options
context:
space:
mode:
Diffstat (limited to 'src/lib')
-rw-r--r--src/lib/ab_transcode_job.cc7
-rw-r--r--src/lib/ab_transcode_job.h12
-rw-r--r--src/lib/ab_transcoder.cc25
-rw-r--r--src/lib/ab_transcoder.h10
-rw-r--r--src/lib/audio_decoder.cc2
-rw-r--r--src/lib/audio_decoder.h2
-rw-r--r--src/lib/check_hashes_job.cc13
-rw-r--r--src/lib/check_hashes_job.h13
-rw-r--r--src/lib/dcp_video_frame.cc2
-rw-r--r--src/lib/dcp_video_frame.h5
-rw-r--r--src/lib/decoder.cc8
-rw-r--r--src/lib/decoder.h12
-rw-r--r--src/lib/decoder_factory.cc11
-rw-r--r--src/lib/decoder_factory.h23
-rw-r--r--src/lib/encoder.cc12
-rw-r--r--src/lib/encoder.h6
-rw-r--r--src/lib/encoder_factory.cc2
-rw-r--r--src/lib/encoder_factory.h4
-rw-r--r--src/lib/examine_content_job.cc86
-rw-r--r--src/lib/external_audio_decoder.cc2
-rw-r--r--src/lib/external_audio_decoder.h2
-rw-r--r--src/lib/ffmpeg_decoder.cc132
-rw-r--r--src/lib/ffmpeg_decoder.h11
-rw-r--r--src/lib/film.cc174
-rw-r--r--src/lib/film.h16
-rw-r--r--src/lib/filter_graph.cc9
-rw-r--r--src/lib/filter_graph.h2
-rw-r--r--src/lib/image.cc2
-rw-r--r--src/lib/imagemagick_decoder.cc4
-rw-r--r--src/lib/imagemagick_decoder.h2
-rw-r--r--src/lib/imagemagick_encoder.cc91
-rw-r--r--src/lib/imagemagick_encoder.h42
-rw-r--r--src/lib/j2k_still_encoder.cc2
-rw-r--r--src/lib/j2k_still_encoder.h3
-rw-r--r--src/lib/j2k_wav_encoder.cc2
-rw-r--r--src/lib/j2k_wav_encoder.h2
-rw-r--r--src/lib/job.h1
-rw-r--r--src/lib/make_dcp_job.cc2
-rw-r--r--src/lib/make_dcp_job.h6
-rw-r--r--src/lib/options.h40
-rw-r--r--src/lib/transcode_job.cc9
-rw-r--r--src/lib/transcode_job.h7
-rw-r--r--src/lib/transcoder.cc26
-rw-r--r--src/lib/transcoder.h16
-rw-r--r--src/lib/video_decoder.cc10
-rw-r--r--src/lib/video_decoder.h11
-rw-r--r--src/lib/wscript1
47 files changed, 336 insertions, 546 deletions
diff --git a/src/lib/ab_transcode_job.cc b/src/lib/ab_transcode_job.cc
index c9fd5bc97..b9538ce2e 100644
--- a/src/lib/ab_transcode_job.cc
+++ b/src/lib/ab_transcode_job.cc
@@ -33,9 +33,10 @@ using boost::shared_ptr;
/** @param f Film to compare.
* @param o Options.
*/
-ABTranscodeJob::ABTranscodeJob (shared_ptr<Film> f, shared_ptr<const Options> o, shared_ptr<Job> req)
+ABTranscodeJob::ABTranscodeJob (shared_ptr<Film> f, shared_ptr<const DecodeOptions> od, shared_ptr<const EncodeOptions> oe, shared_ptr<Job> req)
: Job (f, req)
- , _opt (o)
+ , _decode_opt (od)
+ , _encode_opt (oe)
{
_film_b.reset (new Film (*_film));
_film_b->set_scaler (Config::instance()->reference_scaler ());
@@ -53,7 +54,7 @@ ABTranscodeJob::run ()
{
try {
/* _film_b is the one with reference filters */
- ABTranscoder w (_film_b, _film, _opt, this, encoder_factory (_film, _opt));
+ ABTranscoder w (_film_b, _film, _decode_opt, this, encoder_factory (_film, _encode_opt));
w.go ();
set_progress (1);
set_state (FINISHED_OK);
diff --git a/src/lib/ab_transcode_job.h b/src/lib/ab_transcode_job.h
index 8331edf76..86a2a81b8 100644
--- a/src/lib/ab_transcode_job.h
+++ b/src/lib/ab_transcode_job.h
@@ -25,6 +25,8 @@
#include "job.h"
class Film;
+class DecodeOptions;
+class EncodeOptions;
/** @class ABTranscodeJob
* @brief Job to run a transcoder which produces output for A/B comparison of various settings.
@@ -36,13 +38,19 @@ class Film;
class ABTranscodeJob : public Job
{
public:
- ABTranscodeJob (boost::shared_ptr<Film> f, boost::shared_ptr<const Options> o, boost::shared_ptr<Job> req);
+ ABTranscodeJob (
+ boost::shared_ptr<Film> f,
+ boost::shared_ptr<const DecodeOptions> od,
+ boost::shared_ptr<const EncodeOptions> oe,
+ boost::shared_ptr<Job> req
+ );
std::string name () const;
void run ();
private:
- boost::shared_ptr<const Options> _opt;
+ boost::shared_ptr<const DecodeOptions> _decode_opt;
+ boost::shared_ptr<const EncodeOptions> _encode_opt;
/** Copy of our Film using the reference filters and scaler */
boost::shared_ptr<Film> _film_b;
diff --git a/src/lib/ab_transcoder.cc b/src/lib/ab_transcoder.cc
index 537cb4dd7..d85f078a5 100644
--- a/src/lib/ab_transcoder.cc
+++ b/src/lib/ab_transcoder.cc
@@ -43,16 +43,15 @@ using boost::shared_ptr;
/** @param a Film to use for the left half of the screen.
* @param b Film to use for the right half of the screen.
- * @param o Options.
+ * @param o Decoder options.
* @param j Job that we are associated with.
* @param e Encoder to use.
*/
ABTranscoder::ABTranscoder (
- shared_ptr<Film> a, shared_ptr<Film> b, shared_ptr<const Options> o, Job* j, shared_ptr<Encoder> e)
+ shared_ptr<Film> a, shared_ptr<Film> b, shared_ptr<const DecodeOptions> o, Job* j, shared_ptr<Encoder> e)
: _film_a (a)
, _film_b (b)
- , _opt (o)
, _job (j)
, _encoder (e)
{
@@ -67,12 +66,12 @@ ABTranscoder::ABTranscoder (
}
/* Set up the decoder to use the film's set streams */
- _da.first->set_subtitle_stream (_film_a->subtitle_stream ());
- _db.first->set_subtitle_stream (_film_a->subtitle_stream ());
- _da.second->set_audio_stream (_film_a->audio_stream ());
+ _da.video->set_subtitle_stream (_film_a->subtitle_stream ());
+ _db.video->set_subtitle_stream (_film_a->subtitle_stream ());
+ _da.audio->set_audio_stream (_film_a->audio_stream ());
- _da.first->Video.connect (bind (&Combiner::process_video, _combiner, _1, _2));
- _db.first->Video.connect (bind (&Combiner::process_video_b, _combiner, _1, _2));
+ _da.video->Video.connect (bind (&Combiner::process_video, _combiner, _1, _2));
+ _db.video->Video.connect (bind (&Combiner::process_video_b, _combiner, _1, _2));
if (_matcher) {
_combiner->connect_video (_matcher);
@@ -82,7 +81,7 @@ ABTranscoder::ABTranscoder (
}
if (_matcher && _delay_line) {
- _da.second->connect_audio (_delay_line);
+ _da.audio->connect_audio (_delay_line);
_delay_line->connect_audio (_matcher);
_matcher->connect_audio (_gain);
_gain->connect_audio (_encoder);
@@ -95,11 +94,11 @@ ABTranscoder::go ()
_encoder->process_begin ();
while (1) {
- bool const va = _da.first->pass ();
- bool const vb = _db.first->pass ();
- bool const a = _da.first->pass ();
+ bool const va = _da.video->pass ();
+ bool const vb = _db.video->pass ();
+ bool const a = _da.audio->pass ();
- _da.first->set_progress ();
+ _da.video->set_progress ();
if (va && vb && a) {
break;
diff --git a/src/lib/ab_transcoder.h b/src/lib/ab_transcoder.h
index 9b57e4f73..7bfcb393c 100644
--- a/src/lib/ab_transcoder.h
+++ b/src/lib/ab_transcoder.h
@@ -25,12 +25,13 @@
#include <boost/shared_ptr.hpp>
#include <stdint.h>
#include "util.h"
+#include "decoder_factory.h"
class Job;
class Encoder;
class VideoDecoder;
class AudioDecoder;
-class Options;
+class DecodeOptions;
class Image;
class Log;
class Subtitle;
@@ -50,7 +51,7 @@ public:
ABTranscoder (
boost::shared_ptr<Film> a,
boost::shared_ptr<Film> b,
- boost::shared_ptr<const Options> o,
+ boost::shared_ptr<const DecodeOptions> o,
Job* j,
boost::shared_ptr<Encoder> e
);
@@ -60,11 +61,10 @@ public:
private:
boost::shared_ptr<Film> _film_a;
boost::shared_ptr<Film> _film_b;
- boost::shared_ptr<const Options> _opt;
Job* _job;
boost::shared_ptr<Encoder> _encoder;
- std::pair<boost::shared_ptr<VideoDecoder>, boost::shared_ptr<AudioDecoder> > _da;
- std::pair<boost::shared_ptr<VideoDecoder>, boost::shared_ptr<AudioDecoder> > _db;
+ Decoders _da;
+ Decoders _db;
boost::shared_ptr<Combiner> _combiner;
boost::shared_ptr<Matcher> _matcher;
boost::shared_ptr<DelayLine> _delay_line;
diff --git a/src/lib/audio_decoder.cc b/src/lib/audio_decoder.cc
index 70f0effd9..9d8de971c 100644
--- a/src/lib/audio_decoder.cc
+++ b/src/lib/audio_decoder.cc
@@ -23,7 +23,7 @@
using boost::optional;
using boost::shared_ptr;
-AudioDecoder::AudioDecoder (shared_ptr<Film> f, shared_ptr<const Options> o, Job* j)
+AudioDecoder::AudioDecoder (shared_ptr<Film> f, shared_ptr<const DecodeOptions> o, Job* j)
: Decoder (f, o, j)
{
diff --git a/src/lib/audio_decoder.h b/src/lib/audio_decoder.h
index 1570fe3b0..013a6327f 100644
--- a/src/lib/audio_decoder.h
+++ b/src/lib/audio_decoder.h
@@ -34,7 +34,7 @@
class AudioDecoder : public AudioSource, public virtual Decoder
{
public:
- AudioDecoder (boost::shared_ptr<Film>, boost::shared_ptr<const Options>, Job *);
+ AudioDecoder (boost::shared_ptr<Film>, boost::shared_ptr<const DecodeOptions>, Job *);
virtual void set_audio_stream (boost::shared_ptr<AudioStream>);
diff --git a/src/lib/check_hashes_job.cc b/src/lib/check_hashes_job.cc
index 3967d0d70..50d86c523 100644
--- a/src/lib/check_hashes_job.cc
+++ b/src/lib/check_hashes_job.cc
@@ -34,9 +34,10 @@ using std::stringstream;
using std::ifstream;
using boost::shared_ptr;
-CheckHashesJob::CheckHashesJob (shared_ptr<Film> f, shared_ptr<const Options> o, shared_ptr<Job> req)
+CheckHashesJob::CheckHashesJob (shared_ptr<Film> f, shared_ptr<const DecodeOptions> od, shared_ptr<const EncodeOptions> oe, shared_ptr<Job> req)
: Job (f, req)
- , _opt (o)
+ , _decode_opt (od)
+ , _encode_opt (oe)
, _bad (0)
{
@@ -61,7 +62,7 @@ CheckHashesJob::run ()
DCPFrameRate const dfr = dcp_frame_rate (_film->frames_per_second ());
for (SourceFrame i = _film->dcp_trim_start(); i < N; i += dfr.skip) {
- string const j2k_file = _opt->frame_out_path (i, false);
+ string const j2k_file = _encode_opt->frame_out_path (i, false);
string const hash_file = j2k_file + ".md5";
if (!boost::filesystem::exists (j2k_file)) {
@@ -91,13 +92,13 @@ CheckHashesJob::run ()
shared_ptr<Job> tc;
if (_film->dcp_ab()) {
- tc.reset (new ABTranscodeJob (_film, _opt, shared_from_this()));
+ tc.reset (new ABTranscodeJob (_film, _decode_opt, _encode_opt, shared_from_this()));
} else {
- tc.reset (new TranscodeJob (_film, _opt, shared_from_this()));
+ tc.reset (new TranscodeJob (_film, _decode_opt, _encode_opt, shared_from_this()));
}
JobManager::instance()->add_after (shared_from_this(), tc);
- JobManager::instance()->add_after (tc, shared_ptr<Job> (new CheckHashesJob (_film, _opt, tc)));
+ JobManager::instance()->add_after (tc, shared_ptr<Job> (new CheckHashesJob (_film, _decode_opt, _encode_opt, tc)));
}
set_progress (1);
diff --git a/src/lib/check_hashes_job.h b/src/lib/check_hashes_job.h
index e0ed6a64a..c41af9d3f 100644
--- a/src/lib/check_hashes_job.h
+++ b/src/lib/check_hashes_job.h
@@ -19,16 +19,25 @@
#include "job.h"
+class DecodeOptions;
+class EncodeOptions;
+
class CheckHashesJob : public Job
{
public:
- CheckHashesJob (boost::shared_ptr<Film> f, boost::shared_ptr<const Options> o, boost::shared_ptr<Job> req);
+ CheckHashesJob (
+ boost::shared_ptr<Film> f,
+ boost::shared_ptr<const DecodeOptions> od,
+ boost::shared_ptr<const EncodeOptions> oe,
+ boost::shared_ptr<Job> req
+ );
std::string name () const;
void run ();
std::string status () const;
private:
- boost::shared_ptr<const Options> _opt;
+ boost::shared_ptr<const DecodeOptions> _decode_opt;
+ boost::shared_ptr<const EncodeOptions> _encode_opt;
int _bad;
};
diff --git a/src/lib/dcp_video_frame.cc b/src/lib/dcp_video_frame.cc
index c185de0f4..996aff33f 100644
--- a/src/lib/dcp_video_frame.cc
+++ b/src/lib/dcp_video_frame.cc
@@ -376,7 +376,7 @@ DCPVideoFrame::encode_remotely (ServerDescription const * serv)
* @param frame Frame index.
*/
void
-EncodedData::write (shared_ptr<const Options> opt, SourceFrame frame)
+EncodedData::write (shared_ptr<const EncodeOptions> opt, SourceFrame frame)
{
string const tmp_j2k = opt->frame_out_path (frame, true);
diff --git a/src/lib/dcp_video_frame.h b/src/lib/dcp_video_frame.h
index 5ae53f1e8..57e7e6203 100644
--- a/src/lib/dcp_video_frame.h
+++ b/src/lib/dcp_video_frame.h
@@ -26,7 +26,7 @@
*/
class FilmState;
-class Options;
+class EncodeOptions;
class ServerDescription;
class Scaler;
class Image;
@@ -50,7 +50,7 @@ public:
virtual ~EncodedData () {}
void send (boost::shared_ptr<Socket> socket);
- void write (boost::shared_ptr<const Options>, SourceFrame);
+ void write (boost::shared_ptr<const EncodeOptions>, SourceFrame);
/** @return data */
uint8_t* data () const {
@@ -122,7 +122,6 @@ public:
private:
void create_openjpeg_container ();
- void write_encoded (boost::shared_ptr<const Options>, uint8_t *, int);
boost::shared_ptr<const Image> _input; ///< the input image
boost::shared_ptr<Subtitle> _subtitle; ///< any subtitle that should be on the image
diff --git a/src/lib/decoder.cc b/src/lib/decoder.cc
index 2bacf58e7..507708345 100644
--- a/src/lib/decoder.cc
+++ b/src/lib/decoder.cc
@@ -49,10 +49,16 @@ using boost::optional;
* @param o Options.
* @param j Job that we are running within, or 0
*/
-Decoder::Decoder (boost::shared_ptr<Film> f, boost::shared_ptr<const Options> o, Job* j)
+Decoder::Decoder (boost::shared_ptr<Film> f, boost::shared_ptr<const DecodeOptions> o, Job* j)
: _film (f)
, _opt (o)
, _job (j)
{
}
+
+bool
+Decoder::seek (SourceFrame f)
+{
+ throw DecodeError ("decoder does not support seek");
+}
diff --git a/src/lib/decoder.h b/src/lib/decoder.h
index e757e5401..0d35ebb3a 100644
--- a/src/lib/decoder.h
+++ b/src/lib/decoder.h
@@ -35,7 +35,7 @@
#include "audio_source.h"
class Job;
-class Options;
+class DecodeOptions;
class Image;
class Log;
class DelayLine;
@@ -54,16 +54,22 @@ class FilterGraph;
class Decoder
{
public:
- Decoder (boost::shared_ptr<Film>, boost::shared_ptr<const Options>, Job *);
+ Decoder (boost::shared_ptr<Film>, boost::shared_ptr<const DecodeOptions>, Job *);
virtual ~Decoder () {}
virtual bool pass () = 0;
+ /** Seek.
+ * @return true on error.
+ */
+ virtual bool seek (SourceFrame);
+
+ boost::signals2::signal<void()> OutputChanged;
protected:
/** our Film */
boost::shared_ptr<Film> _film;
/** our options */
- boost::shared_ptr<const Options> _opt;
+ boost::shared_ptr<const DecodeOptions> _opt;
/** associated Job, or 0 */
Job* _job;
};
diff --git a/src/lib/decoder_factory.cc b/src/lib/decoder_factory.cc
index b2118ef74..1d8d12cd5 100644
--- a/src/lib/decoder_factory.cc
+++ b/src/lib/decoder_factory.cc
@@ -26,6 +26,7 @@
#include "imagemagick_decoder.h"
#include "film.h"
#include "external_audio_decoder.h"
+#include "decoder_factory.h"
using std::string;
using std::pair;
@@ -33,14 +34,14 @@ using std::make_pair;
using boost::shared_ptr;
using boost::dynamic_pointer_cast;
-pair<shared_ptr<VideoDecoder>, shared_ptr<AudioDecoder> >
+Decoders
decoder_factory (
- shared_ptr<Film> f, shared_ptr<const Options> o, Job* j
+ shared_ptr<Film> f, shared_ptr<const DecodeOptions> o, Job* j
)
{
if (boost::filesystem::is_directory (f->content_path()) || f->content_type() == STILL) {
/* A single image file, or a directory of them */
- return make_pair (
+ return Decoders (
shared_ptr<VideoDecoder> (new ImageMagickDecoder (f, o, j)),
shared_ptr<AudioDecoder> ()
);
@@ -48,8 +49,8 @@ decoder_factory (
shared_ptr<FFmpegDecoder> fd (new FFmpegDecoder (f, o, j));
if (f->use_content_audio()) {
- return make_pair (fd, fd);
+ return Decoders (fd, fd);
}
- return make_pair (fd, shared_ptr<AudioDecoder> (new ExternalAudioDecoder (f, o, j)));
+ return Decoders (fd, shared_ptr<AudioDecoder> (new ExternalAudioDecoder (f, o, j)));
}
diff --git a/src/lib/decoder_factory.h b/src/lib/decoder_factory.h
index 1f3690611..47d977ce7 100644
--- a/src/lib/decoder_factory.h
+++ b/src/lib/decoder_factory.h
@@ -17,16 +17,33 @@
*/
+#ifndef DVDOMATIC_DECODER_FACTORY_H
+#define DVDOMATIC_DECODER_FACTORY_H
+
/** @file src/decoder_factory.h
* @brief A method to create appropriate decoders for some content.
*/
class Film;
-class Options;
+class DecodeOptions;
class Job;
class VideoDecoder;
class AudioDecoder;
-extern std::pair<boost::shared_ptr<VideoDecoder>, boost::shared_ptr<AudioDecoder> > decoder_factory (
- boost::shared_ptr<Film>, boost::shared_ptr<const Options>, Job *
+struct Decoders {
+ Decoders () {}
+
+ Decoders (boost::shared_ptr<VideoDecoder> v, boost::shared_ptr<AudioDecoder> a)
+ : video (v)
+ , audio (a)
+ {}
+
+ boost::shared_ptr<VideoDecoder> video;
+ boost::shared_ptr<AudioDecoder> audio;
+};
+
+extern Decoders decoder_factory (
+ boost::shared_ptr<Film>, boost::shared_ptr<const DecodeOptions>, Job *
);
+
+#endif
diff --git a/src/lib/encoder.cc b/src/lib/encoder.cc
index 17a6726a6..1fc7d5997 100644
--- a/src/lib/encoder.cc
+++ b/src/lib/encoder.cc
@@ -33,7 +33,7 @@ int const Encoder::_history_size = 25;
/** @param f Film that we are encoding.
* @param o Options.
*/
-Encoder::Encoder (shared_ptr<const Film> f, shared_ptr<const Options> o)
+Encoder::Encoder (shared_ptr<const Film> f, shared_ptr<const EncodeOptions> o)
: _film (f)
, _opt (o)
, _just_skipped (false)
@@ -107,13 +107,13 @@ Encoder::frame_skipped ()
void
Encoder::process_video (shared_ptr<Image> i, boost::shared_ptr<Subtitle> s)
{
- if (_opt->decode_video_skip != 0 && (_video_frame % _opt->decode_video_skip) != 0) {
+ if (_opt->video_skip != 0 && (_video_frame % _opt->video_skip) != 0) {
++_video_frame;
return;
}
- if (_opt->video_decode_range) {
- pair<SourceFrame, SourceFrame> const r = _opt->video_decode_range.get();
+ if (_opt->video_range) {
+ pair<SourceFrame, SourceFrame> const r = _opt->video_range.get();
if (_video_frame < r.first || _video_frame >= r.second) {
++_video_frame;
return;
@@ -127,12 +127,12 @@ Encoder::process_video (shared_ptr<Image> i, boost::shared_ptr<Subtitle> s)
void
Encoder::process_audio (shared_ptr<AudioBuffers> data)
{
- if (_opt->audio_decode_range) {
+ if (_opt->audio_range) {
shared_ptr<AudioBuffers> trimmed (new AudioBuffers (*data.get ()));
/* Range that we are encoding */
- pair<int64_t, int64_t> required_range = _opt->audio_decode_range.get();
+ pair<int64_t, int64_t> required_range = _opt->audio_range.get();
/* Range of this block of data */
pair<int64_t, int64_t> this_range (_audio_frame, _audio_frame + trimmed->frames());
diff --git a/src/lib/encoder.h b/src/lib/encoder.h
index b12bd0d48..64f113d74 100644
--- a/src/lib/encoder.h
+++ b/src/lib/encoder.h
@@ -35,7 +35,7 @@ extern "C" {
#include "video_sink.h"
#include "audio_sink.h"
-class Options;
+class EncodeOptions;
class Image;
class Subtitle;
class AudioBuffers;
@@ -54,7 +54,7 @@ class Film;
class Encoder : public VideoSink, public AudioSink
{
public:
- Encoder (boost::shared_ptr<const Film> f, boost::shared_ptr<const Options> o);
+ Encoder (boost::shared_ptr<const Film> f, boost::shared_ptr<const EncodeOptions> o);
virtual ~Encoder () {}
/** Called to indicate that a processing run is about to begin */
@@ -93,7 +93,7 @@ protected:
/** Film that we are encoding */
boost::shared_ptr<const Film> _film;
/** Options */
- boost::shared_ptr<const Options> _opt;
+ boost::shared_ptr<const EncodeOptions> _opt;
/** Mutex for _time_history, _just_skipped and _last_frame */
mutable boost::mutex _history_mutex;
diff --git a/src/lib/encoder_factory.cc b/src/lib/encoder_factory.cc
index 2da021ad8..fe4d50ef3 100644
--- a/src/lib/encoder_factory.cc
+++ b/src/lib/encoder_factory.cc
@@ -29,7 +29,7 @@
using boost::shared_ptr;
shared_ptr<Encoder>
-encoder_factory (shared_ptr<const Film> f, shared_ptr<const Options> o)
+encoder_factory (shared_ptr<const Film> f, shared_ptr<const EncodeOptions> o)
{
if (!boost::filesystem::is_directory (f->content_path()) && f->content_type() == STILL) {
return shared_ptr<Encoder> (new J2KStillEncoder (f, o));
diff --git a/src/lib/encoder_factory.h b/src/lib/encoder_factory.h
index 1bc4e18df..5ac5c9559 100644
--- a/src/lib/encoder_factory.h
+++ b/src/lib/encoder_factory.h
@@ -22,9 +22,9 @@
*/
class Encoder;
-class Options;
+class EncodeOptions;
class Job;
class Log;
class Film;
-extern boost::shared_ptr<Encoder> encoder_factory (boost::shared_ptr<const Film>, boost::shared_ptr<const Options>);
+extern boost::shared_ptr<Encoder> encoder_factory (boost::shared_ptr<const Film>, boost::shared_ptr<const EncodeOptions>);
diff --git a/src/lib/examine_content_job.cc b/src/lib/examine_content_job.cc
index 93333605b..70a04b825 100644
--- a/src/lib/examine_content_job.cc
+++ b/src/lib/examine_content_job.cc
@@ -26,7 +26,6 @@
#include "options.h"
#include "decoder_factory.h"
#include "decoder.h"
-#include "imagemagick_encoder.h"
#include "transcoder.h"
#include "log.h"
#include "film.h"
@@ -60,13 +59,12 @@ ExamineContentJob::name () const
void
ExamineContentJob::run ()
{
- float progress_remaining = 1;
+ descend (1);
/* Set the film's length to either
a) a length judged by running through the content or
b) the length from a decoder's header.
*/
-
if (!_film->trust_content_header()) {
/* Decode the content to get an accurate length */
@@ -74,97 +72,33 @@ ExamineContentJob::run ()
will be messed up.
*/
_film->unset_length ();
+ _film->set_crop (Crop ());
- shared_ptr<Options> o (new Options ("", "", ""));
- o->out_size = Size (512, 512);
- o->apply_crop = false;
+ shared_ptr<DecodeOptions> o (new DecodeOptions);
o->decode_audio = false;
- descend (0.5);
-
- pair<shared_ptr<VideoDecoder>, shared_ptr<AudioDecoder> > decoders = decoder_factory (_film, o, this);
+ Decoders decoders = decoder_factory (_film, o, this);
set_progress_unknown ();
- while (!decoders.first->pass()) {
+ while (!decoders.video->pass()) {
/* keep going */
}
- _film->set_length (decoders.first->video_frame());
+ _film->set_length (decoders.video->video_frame());
_film->log()->log (String::compose ("Video length examined as %1 frames", _film->length().get()));
- ascend ();
-
- progress_remaining -= 0.5;
-
} else {
- /* Get a quick decoder to get the content's length from its header.
- It would have been nice to just use the thumbnail transcoder's decoder,
- but that's a bit fiddly, and this isn't too expensive.
- */
+ /* Get a quick decoder to get the content's length from its header */
- shared_ptr<Options> o (new Options ("", "", ""));
- o->out_size = Size (1024, 1024);
- pair<shared_ptr<VideoDecoder>, shared_ptr<AudioDecoder> > d = decoder_factory (_film, o, 0);
- _film->set_length (d.first->length());
+ shared_ptr<DecodeOptions> o (new DecodeOptions);
+ Decoders d = decoder_factory (_film, o, 0);
+ _film->set_length (d.video->length());
_film->log()->log (String::compose ("Video length obtained from header as %1 frames", _film->length().get()));
}
- /* Now make thumbnails for it */
-
- descend (progress_remaining);
-
- try {
- shared_ptr<Options> o (new Options (_film->dir ("thumbs"), ".png", ""));
- o->out_size = _film->size ();
- o->apply_crop = false;
- o->decode_audio = false;
- o->decode_video_skip = _film->length().get() / 128;
- o->decode_subtitles = true;
- shared_ptr<ImageMagickEncoder> e (new ImageMagickEncoder (_film, o));
- Transcoder w (_film, o, this, e);
- w.go ();
-
- /* Now set the film's length from the transcoder's decoder, since we
- went to all the trouble of going through the content.
- */
-
- _film->set_length (w.video_decoder()->video_frame());
-
- } catch (std::exception& e) {
-
- ascend ();
- set_progress (1);
- set_error (e.what ());
- set_state (FINISHED_ERROR);
- return;
-
- }
-
- string const tdir = _film->dir ("thumbs");
- vector<SourceFrame> thumbs;
-
- for (boost::filesystem::directory_iterator i = boost::filesystem::directory_iterator (tdir); i != boost::filesystem::directory_iterator(); ++i) {
-
- /* Aah, the sweet smell of progress */
-#if BOOST_FILESYSTEM_VERSION == 3
- string const l = boost::filesystem::path(*i).leaf().generic_string();
-#else
- string const l = i->leaf ();
-#endif
-
- size_t const d = l.find (".png");
- size_t const t = l.find (".tmp");
- if (d != string::npos && t == string::npos) {
- thumbs.push_back (atoi (l.substr (0, d).c_str()));
- }
- }
-
- sort (thumbs.begin(), thumbs.end());
- _film->set_thumbs (thumbs);
-
ascend ();
set_progress (1);
set_state (FINISHED_OK);
diff --git a/src/lib/external_audio_decoder.cc b/src/lib/external_audio_decoder.cc
index 9b121235a..25c8068b6 100644
--- a/src/lib/external_audio_decoder.cc
+++ b/src/lib/external_audio_decoder.cc
@@ -31,7 +31,7 @@ using std::cout;
using boost::shared_ptr;
using boost::optional;
-ExternalAudioDecoder::ExternalAudioDecoder (shared_ptr<Film> f, shared_ptr<const Options> o, Job* j)
+ExternalAudioDecoder::ExternalAudioDecoder (shared_ptr<Film> f, shared_ptr<const DecodeOptions> o, Job* j)
: Decoder (f, o, j)
, AudioDecoder (f, o, j)
{
diff --git a/src/lib/external_audio_decoder.h b/src/lib/external_audio_decoder.h
index 45a2a809c..2558955eb 100644
--- a/src/lib/external_audio_decoder.h
+++ b/src/lib/external_audio_decoder.h
@@ -44,7 +44,7 @@ private:
class ExternalAudioDecoder : public AudioDecoder
{
public:
- ExternalAudioDecoder (boost::shared_ptr<Film>, boost::shared_ptr<const Options>, Job *);
+ ExternalAudioDecoder (boost::shared_ptr<Film>, boost::shared_ptr<const DecodeOptions>, Job *);
bool pass ();
diff --git a/src/lib/ffmpeg_decoder.cc b/src/lib/ffmpeg_decoder.cc
index acaf149f4..136843190 100644
--- a/src/lib/ffmpeg_decoder.cc
+++ b/src/lib/ffmpeg_decoder.cc
@@ -59,7 +59,7 @@ using boost::shared_ptr;
using boost::optional;
using boost::dynamic_pointer_cast;
-FFmpegDecoder::FFmpegDecoder (shared_ptr<Film> f, shared_ptr<const Options> o, Job* j)
+FFmpegDecoder::FFmpegDecoder (shared_ptr<Film> f, shared_ptr<const DecodeOptions> o, Job* j)
: Decoder (f, o, j)
, VideoDecoder (f, o, j)
, AudioDecoder (f, o, j)
@@ -77,6 +77,8 @@ FFmpegDecoder::FFmpegDecoder (shared_ptr<Film> f, shared_ptr<const Options> o, J
setup_video ();
setup_audio ();
setup_subtitle ();
+
+ _film_connection = f->Changed.connect (bind (&FFmpegDecoder::film_changed, this, _1));
}
FFmpegDecoder::~FFmpegDecoder ()
@@ -101,11 +103,9 @@ FFmpegDecoder::~FFmpegDecoder ()
void
FFmpegDecoder::setup_general ()
{
- int r;
-
av_register_all ();
- if ((r = avformat_open_input (&_format_context, _film->content_path().c_str(), 0, 0)) != 0) {
+ if (avformat_open_input (&_format_context, _film->content_path().c_str(), 0, 0) < 0) {
throw OpenFileError (_film->content_path ());
}
@@ -265,46 +265,10 @@ FFmpegDecoder::pass ()
_film->log()->log (String::compose ("Used only %1 bytes of %2 in packet", r, _packet.size));
}
- /* Where we are in the output, in seconds */
- double const out_pts_seconds = video_frame() / frames_per_second();
-
- /* Where we are in the source, in seconds */
- double const source_pts_seconds = av_q2d (_format_context->streams[_packet.stream_index]->time_base)
- * av_frame_get_best_effort_timestamp(_frame);
-
- _film->log()->log (
- String::compose ("Source video frame ready; source at %1, output at %2", source_pts_seconds, out_pts_seconds),
- Log::VERBOSE
- );
-
- if (!_first_video) {
- _first_video = source_pts_seconds;
- }
-
- /* 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();
-
- /* 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 ();
- _film->log()->log (
- String::compose (
- "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()
- )
- );
- }
- }
-
- if (delta > -one_frame) {
- /* Process this frame */
- filter_and_emit_video (_frame);
+ if (_opt->video_sync) {
+ out_with_sync ();
} else {
- /* Otherwise we are omitting a frame to keep things right */
- _film->log()->log (String::compose ("Frame removed at %1s", out_pts_seconds));
+ filter_and_emit_video (_frame);
}
}
@@ -557,6 +521,8 @@ FFmpegDecoder::set_subtitle_stream (shared_ptr<SubtitleStream> s)
void
FFmpegDecoder::filter_and_emit_video (AVFrame* frame)
{
+ boost::mutex::scoped_lock lm (_filter_graphs_mutex);
+
shared_ptr<FilterGraph> graph;
list<shared_ptr<FilterGraph> >::iterator i = _filter_graphs.begin();
@@ -565,7 +531,7 @@ FFmpegDecoder::filter_and_emit_video (AVFrame* frame)
}
if (i == _filter_graphs.end ()) {
- graph.reset (new FilterGraph (_film, this, _opt->apply_crop, Size (frame->width, frame->height), (AVPixelFormat) frame->format));
+ graph.reset (new FilterGraph (_film, this, Size (frame->width, frame->height), (AVPixelFormat) frame->format));
_filter_graphs.push_back (graph);
_film->log()->log (String::compose ("New graph for %1x%2, pixel format %3", frame->width, frame->height, frame->format));
} else {
@@ -574,11 +540,23 @@ FFmpegDecoder::filter_and_emit_video (AVFrame* frame)
list<shared_ptr<Image> > images = graph->process (frame);
+ SourceFrame const sf = av_q2d (_format_context->streams[_video_stream]->time_base)
+ * av_frame_get_best_effort_timestamp(_frame) * frames_per_second();
+
for (list<shared_ptr<Image> >::iterator i = images.begin(); i != images.end(); ++i) {
- emit_video (*i);
+ emit_video (*i, sf);
}
}
+bool
+FFmpegDecoder::seek (SourceFrame f)
+{
+ int64_t const t = static_cast<int64_t>(f) / (av_q2d (_format_context->streams[_video_stream]->time_base) * frames_per_second());
+ int const r = av_seek_frame (_format_context, _video_stream, t, 0);
+ avcodec_flush_buffers (_video_codec_context);
+ return r < 0;
+}
+
shared_ptr<FFmpegAudioStream>
FFmpegAudioStream::create (string t, optional<int> v)
{
@@ -631,9 +609,73 @@ FFmpegAudioStream::to_string () const
return String::compose ("ffmpeg %1 %2 %3 %4", _id, _sample_rate, _channel_layout, _name);
}
+void
+FFmpegDecoder::out_with_sync ()
+{
+ /* Where we are in the output, in seconds */
+ double const out_pts_seconds = video_frame() / frames_per_second();
+
+ /* Where we are in the source, in seconds */
+ double const source_pts_seconds = av_q2d (_format_context->streams[_packet.stream_index]->time_base)
+ * av_frame_get_best_effort_timestamp(_frame);
+
+ _film->log()->log (
+ String::compose ("Source video frame ready; source at %1, output at %2", source_pts_seconds, out_pts_seconds),
+ Log::VERBOSE
+ );
+
+ if (!_first_video) {
+ _first_video = source_pts_seconds;
+ }
+
+ /* 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();
+
+ /* 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 ();
+ _film->log()->log (
+ String::compose (
+ "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()
+ )
+ );
+ }
+ }
+
+ if (delta > -one_frame) {
+ /* Process this frame */
+ filter_and_emit_video (_frame);
+ } else {
+ /* Otherwise we are omitting a frame to keep things right */
+ _film->log()->log (String::compose ("Frame removed at %1s", out_pts_seconds));
+ }
+}
+
+void
+FFmpegDecoder::film_changed (Film::Property p)
+{
+ switch (p) {
+ case Film::CROP:
+ {
+ boost::mutex::scoped_lock lm (_filter_graphs_mutex);
+ _filter_graphs.clear ();
+ }
+ OutputChanged ();
+ break;
+
+ default:
+ break;
+ }
+}
+
/** @return Length (in video frames) according to our content's header */
SourceFrame
FFmpegDecoder::length () const
{
return (double(_format_context->duration) / AV_TIME_BASE) * frames_per_second();
}
+
diff --git a/src/lib/ffmpeg_decoder.h b/src/lib/ffmpeg_decoder.h
index 1771551fc..35688003e 100644
--- a/src/lib/ffmpeg_decoder.h
+++ b/src/lib/ffmpeg_decoder.h
@@ -26,6 +26,7 @@
#include <stdint.h>
#include <boost/shared_ptr.hpp>
#include <boost/optional.hpp>
+#include <boost/thread/mutex.hpp>
extern "C" {
#include <libavcodec/avcodec.h>
#include <libpostproc/postprocess.h>
@@ -34,6 +35,7 @@ extern "C" {
#include "decoder.h"
#include "video_decoder.h"
#include "audio_decoder.h"
+#include "film.h"
struct AVFilterGraph;
struct AVCodecContext;
@@ -84,7 +86,7 @@ private:
class FFmpegDecoder : public VideoDecoder, public AudioDecoder
{
public:
- FFmpegDecoder (boost::shared_ptr<Film>, boost::shared_ptr<const Options>, Job *);
+ FFmpegDecoder (boost::shared_ptr<Film>, boost::shared_ptr<const DecodeOptions>, Job *);
~FFmpegDecoder ();
float frames_per_second () const;
@@ -98,6 +100,8 @@ public:
void set_audio_stream (boost::shared_ptr<AudioStream>);
void set_subtitle_stream (boost::shared_ptr<SubtitleStream>);
+ bool seek (SourceFrame);
+
private:
bool pass ();
@@ -105,6 +109,7 @@ private:
AVSampleFormat audio_sample_format () const;
int bytes_per_audio_sample () const;
+ void out_with_sync ();
void filter_and_emit_video (AVFrame *);
void setup_general ();
@@ -115,6 +120,9 @@ private:
void maybe_add_subtitle ();
boost::shared_ptr<AudioBuffers> deinterleave_audio (uint8_t* data, int size);
+ void film_changed (Film::Property);
+ boost::signals2::scoped_connection _film_connection;
+
std::string stream_name (AVStream* s) const;
AVFormatContext* _format_context;
@@ -135,4 +143,5 @@ private:
boost::optional<double> _first_audio;
std::list<boost::shared_ptr<FilterGraph> > _filter_graphs;
+ boost::mutex _filter_graphs_mutex;
};
diff --git a/src/lib/film.cc b/src/lib/film.cc
index e2a4cbeda..4cfe7de0a 100644
--- a/src/lib/film.cc
+++ b/src/lib/film.cc
@@ -31,7 +31,6 @@
#include <boost/date_time.hpp>
#include "film.h"
#include "format.h"
-#include "imagemagick_encoder.h"
#include "job.h"
#include "filter.h"
#include "transcoder.h"
@@ -171,7 +170,6 @@ Film::Film (Film const & o)
, _studio (o._studio)
, _facility (o._facility)
, _package_type (o._package_type)
- , _thumbs (o._thumbs)
, _size (o._size)
, _length (o._length)
, _content_digest (o._content_digest)
@@ -262,35 +260,37 @@ Film::make_dcp (bool transcode)
throw MissingSettingError ("name");
}
- shared_ptr<Options> o (new Options (j2k_dir(), ".j2c", dir ("wavs")));
- o->out_size = format()->dcp_size ();
- o->padding = format()->dcp_padding (shared_from_this ());
- o->ratio = format()->ratio_as_float (shared_from_this ());
+ shared_ptr<EncodeOptions> oe (new EncodeOptions (j2k_dir(), ".j2c", dir ("wavs")));
+ oe->out_size = format()->dcp_size ();
+ oe->padding = format()->dcp_padding (shared_from_this ());
if (dcp_length ()) {
- o->video_decode_range = make_pair (dcp_trim_start(), dcp_trim_start() + dcp_length().get());
+ oe->video_range = make_pair (dcp_trim_start(), dcp_trim_start() + dcp_length().get());
if (audio_stream()) {
- o->audio_decode_range = make_pair (
- video_frames_to_audio_frames (o->video_decode_range.get().first, audio_stream()->sample_rate(), frames_per_second()),
- video_frames_to_audio_frames (o->video_decode_range.get().second, audio_stream()->sample_rate(), frames_per_second())
+ oe->audio_range = make_pair (
+ video_frames_to_audio_frames (oe->video_range.get().first, audio_stream()->sample_rate(), frames_per_second()),
+ video_frames_to_audio_frames (oe->video_range.get().second, audio_stream()->sample_rate(), frames_per_second())
);
}
}
- o->decode_subtitles = with_subtitles ();
- o->decode_video_skip = dcp_frame_rate (frames_per_second()).skip;
+
+ oe->video_skip = dcp_frame_rate (frames_per_second()).skip;
+
+ shared_ptr<DecodeOptions> od (new DecodeOptions);
+ od->decode_subtitles = with_subtitles ();
shared_ptr<Job> r;
if (transcode) {
if (dcp_ab()) {
- r = JobManager::instance()->add (shared_ptr<Job> (new ABTranscodeJob (shared_from_this(), o, shared_ptr<Job> ())));
+ r = JobManager::instance()->add (shared_ptr<Job> (new ABTranscodeJob (shared_from_this(), od, oe, shared_ptr<Job> ())));
} else {
- r = JobManager::instance()->add (shared_ptr<Job> (new TranscodeJob (shared_from_this(), o, shared_ptr<Job> ())));
+ r = JobManager::instance()->add (shared_ptr<Job> (new TranscodeJob (shared_from_this(), od, oe, shared_ptr<Job> ())));
}
}
- r = JobManager::instance()->add (shared_ptr<Job> (new CheckHashesJob (shared_from_this(), o, r)));
- JobManager::instance()->add (shared_ptr<Job> (new MakeDCPJob (shared_from_this(), o, r)));
+ r = JobManager::instance()->add (shared_ptr<Job> (new CheckHashesJob (shared_from_this(), od, oe, r)));
+ JobManager::instance()->add (shared_ptr<Job> (new MakeDCPJob (shared_from_this(), oe, r)));
}
/** Start a job to examine our content file */
@@ -301,12 +301,6 @@ Film::examine_content ()
return;
}
- set_thumbs (vector<SourceFrame> ());
- boost::filesystem::remove_all (dir ("thumbs"));
-
- /* This call will recreate the directory */
- dir ("thumbs");
-
_examine_content_job.reset (new ExamineContentJob (shared_from_this(), shared_ptr<Job> ()));
_examine_content_job->Finished.connect (bind (&Film::examine_content_finished, this));
JobManager::instance()->add (_examine_content_job);
@@ -357,35 +351,6 @@ Film::encoded_frames () const
return N;
}
-/** Return the filename of a subtitle image if one exists for a given thumb index.
- * @param Thumbnail index.
- * @return Position of the image within the source frame, and the image filename, if one exists.
- * Otherwise the filename will be empty.
- */
-pair<Position, string>
-Film::thumb_subtitle (int n) const
-{
- string sub_file = thumb_base(n) + ".sub";
- if (!boost::filesystem::exists (sub_file)) {
- return pair<Position, string> ();
- }
-
- pair<Position, string> sub;
-
- ifstream f (sub_file.c_str ());
- multimap<string, string> kv = read_key_value (f);
- for (map<string, string>::const_iterator i = kv.begin(); i != kv.end(); ++i) {
- if (i->first == "x") {
- sub.first.x = lexical_cast<int> (i->second);
- } else if (i->first == "y") {
- sub.first.y = lexical_cast<int> (i->second);
- sub.second = String::compose ("%1.sub.png", thumb_base(n));
- }
- }
-
- return sub;
-}
-
/** Write state to our `metadata' file */
void
Film::write_metadata () const
@@ -448,12 +413,6 @@ Film::write_metadata () const
f << "facility " << _facility << "\n";
f << "package_type " << _package_type << "\n";
- /* Cached stuff; this is information about our content; we could
- look it up each time, but that's slow.
- */
- for (vector<SourceFrame>::const_iterator i = _thumbs.begin(); i != _thumbs.end(); ++i) {
- f << "thumb " << *i << "\n";
- }
f << "width " << _size.width << "\n";
f << "height " << _size.height << "\n";
f << "length " << _length.get_value_or(0) << "\n";
@@ -481,7 +440,6 @@ Film::read_metadata ()
boost::mutex::scoped_lock lm (_state_mutex);
_external_audio.clear ();
- _thumbs.clear ();
_content_audio_streams.clear ();
_subtitle_streams.clear ();
@@ -585,13 +543,7 @@ Film::read_metadata ()
}
/* Cached stuff */
- if (k == "thumb") {
- int const n = atoi (v.c_str ());
- /* Only add it to the list if it still exists */
- if (boost::filesystem::exists (thumb_file_for_frame (n))) {
- _thumbs.push_back (n);
- }
- } else if (k == "width") {
+ if (k == "width") {
_size.width = atoi (v.c_str ());
} else if (k == "height") {
_size.height = atoi (v.c_str ());
@@ -635,61 +587,6 @@ Film::read_metadata ()
_dirty = false;
}
-/** @param n A thumb index.
- * @return The path to the thumb's image file.
- */
-string
-Film::thumb_file (int n) const
-{
- return thumb_file_for_frame (thumb_frame (n));
-}
-
-/** @param n A frame index within the Film's source.
- * @return The path to the thumb's image file for this frame;
- * we assume that it exists.
- */
-string
-Film::thumb_file_for_frame (SourceFrame n) const
-{
- return thumb_base_for_frame(n) + ".png";
-}
-
-/** @param n Thumb index.
- * Must not be called with the _state_mutex locked.
- */
-string
-Film::thumb_base (int n) const
-{
- return thumb_base_for_frame (thumb_frame (n));
-}
-
-string
-Film::thumb_base_for_frame (SourceFrame n) const
-{
- stringstream s;
- s.width (8);
- s << setfill('0') << n;
-
- boost::filesystem::path p;
- p /= dir ("thumbs");
- p /= s.str ();
-
- return p.string ();
-}
-
-/** @param n A thumb index.
- * @return The frame within the Film's source that it is for.
- *
- * Must not be called with the _state_mutex locked.
- */
-SourceFrame
-Film::thumb_frame (int n) const
-{
- boost::mutex::scoped_lock lm (_state_mutex);
- assert (n < int (_thumbs.size ()));
- return _thumbs[n];
-}
-
Size
Film::cropped_size (Size s) const
{
@@ -954,23 +851,21 @@ Film::set_content (string c)
*/
try {
- shared_ptr<Options> o (new Options ("", "", ""));
- o->out_size = Size (1024, 1024);
-
- pair<shared_ptr<VideoDecoder>, shared_ptr<AudioDecoder> > d = decoder_factory (shared_from_this(), o, 0);
+ shared_ptr<DecodeOptions> o (new DecodeOptions);
+ Decoders d = decoder_factory (shared_from_this(), o, 0);
- set_size (d.first->native_size ());
- set_frames_per_second (d.first->frames_per_second ());
- set_subtitle_streams (d.first->subtitle_streams ());
- set_content_audio_streams (d.second->audio_streams ());
+ set_size (d.video->native_size ());
+ set_frames_per_second (d.video->frames_per_second ());
+ set_subtitle_streams (d.video->subtitle_streams ());
+ set_content_audio_streams (d.audio->audio_streams ());
/* Start off with the first audio and subtitle streams */
- if (!d.second->audio_streams().empty()) {
- set_content_audio_stream (d.second->audio_streams().front());
+ if (!d.audio->audio_streams().empty()) {
+ set_content_audio_stream (d.audio->audio_streams().front());
}
- if (!d.first->subtitle_streams().empty()) {
- set_subtitle_stream (d.first->subtitle_streams().front());
+ if (!d.video->subtitle_streams().empty()) {
+ set_subtitle_stream (d.video->subtitle_streams().front());
}
{
@@ -1003,7 +898,7 @@ Film::set_trust_content_header (bool t)
signal_changed (TRUST_CONTENT_HEADER);
- if (!_trust_content_header) && !content().empty()) {
+ if (!_trust_content_header && !content().empty()) {
/* We just said that we don't trust the content's header */
examine_content ();
}
@@ -1164,8 +1059,7 @@ Film::set_external_audio (vector<string> a)
_external_audio = a;
}
- shared_ptr<Options> o (new Options ("", "", ""));
- o->decode_audio = true;
+ shared_ptr<DecodeOptions> o (new DecodeOptions);
shared_ptr<ExternalAudioDecoder> decoder (new ExternalAudioDecoder (shared_from_this(), o, 0));
if (decoder->audio_stream()) {
_external_audio_stream = decoder->audio_stream ();
@@ -1326,16 +1220,6 @@ Film::set_package_type (string p)
}
void
-Film::set_thumbs (vector<SourceFrame> t)
-{
- {
- boost::mutex::scoped_lock lm (_state_mutex);
- _thumbs = t;
- }
- signal_changed (THUMBS);
-}
-
-void
Film::set_size (Size s)
{
{
diff --git a/src/lib/film.h b/src/lib/film.h
index 8cd55a227..642f2d7da 100644
--- a/src/lib/film.h
+++ b/src/lib/film.h
@@ -61,7 +61,6 @@ public:
std::string j2k_dir () const;
std::vector<std::string> audio_files () const;
- std::pair<Position, std::string> thumb_subtitle (int) const;
void examine_content ();
void send_dcp_to_tms ();
@@ -83,10 +82,6 @@ public:
std::string content_path () const;
ContentType content_type () const;
- std::string thumb_file (int) const;
- std::string thumb_base (int) const;
- SourceFrame thumb_frame (int) const;
-
int target_audio_sample_rate () const;
void write_metadata () const;
@@ -130,7 +125,6 @@ public:
SUBTITLE_OFFSET,
SUBTITLE_SCALE,
DCI_METADATA,
- THUMBS,
SIZE,
LENGTH,
CONTENT_AUDIO_STREAMS,
@@ -291,11 +285,6 @@ public:
return _package_type;
}
- std::vector<SourceFrame> thumbs () const {
- boost::mutex::scoped_lock lm (_state_mutex);
- return _thumbs;
- }
-
Size size () const {
boost::mutex::scoped_lock lm (_state_mutex);
return _size;
@@ -365,7 +354,6 @@ public:
void set_studio (std::string);
void set_facility (std::string);
void set_package_type (std::string);
- void set_thumbs (std::vector<SourceFrame>);
void set_size (Size);
void set_length (SourceFrame);
void unset_length ();
@@ -391,8 +379,6 @@ private:
/** The date that we should use in a DCI name */
boost::gregorian::date _dci_date;
- std::string thumb_file_for_frame (SourceFrame) const;
- std::string thumb_base_for_frame (SourceFrame) const;
void signal_changed (Property);
void examine_content_finished ();
@@ -466,8 +452,6 @@ private:
/* Data which are cached to speed things up */
- /** Vector of frame indices for each of our `thumbnails' */
- std::vector<SourceFrame> _thumbs;
/** Size, in pixels, of the source (ignoring cropping) */
Size _size;
/** Actual length of the source (in video frames) from examining it */
diff --git a/src/lib/filter_graph.cc b/src/lib/filter_graph.cc
index 7320070fe..17107a05b 100644
--- a/src/lib/filter_graph.cc
+++ b/src/lib/filter_graph.cc
@@ -49,11 +49,10 @@ using boost::shared_ptr;
/** Construct a FilterGraph for the settings in a film.
* @param film Film.
* @param decoder Decoder that we are using.
- * @param crop true to apply crop, otherwise false.
* @param s Size of the images to process.
* @param p Pixel format of the images to process.
*/
-FilterGraph::FilterGraph (shared_ptr<Film> film, FFmpegDecoder* decoder, bool crop, Size s, AVPixelFormat p)
+FilterGraph::FilterGraph (shared_ptr<Film> film, FFmpegDecoder* decoder, Size s, AVPixelFormat p)
: _buffer_src_context (0)
, _buffer_sink_context (0)
, _size (s)
@@ -64,11 +63,7 @@ FilterGraph::FilterGraph (shared_ptr<Film> film, FFmpegDecoder* decoder, bool cr
filters += ",";
}
- if (crop) {
- filters += crop_string (Position (film->crop().left, film->crop().top), film->cropped_size (decoder->native_size()));
- } else {
- filters += crop_string (Position (0, 0), decoder->native_size());
- }
+ filters += crop_string (Position (film->crop().left, film->crop().top), film->cropped_size (decoder->native_size()));
avfilter_register_all ();
diff --git a/src/lib/filter_graph.h b/src/lib/filter_graph.h
index 3842e9f7d..a4b9ef75f 100644
--- a/src/lib/filter_graph.h
+++ b/src/lib/filter_graph.h
@@ -36,7 +36,7 @@ class FFmpegDecoder;
class FilterGraph
{
public:
- FilterGraph (boost::shared_ptr<Film> film, FFmpegDecoder* decoder, bool crop, Size s, AVPixelFormat p);
+ FilterGraph (boost::shared_ptr<Film> film, FFmpegDecoder* decoder, Size s, AVPixelFormat p);
bool can_process (Size s, AVPixelFormat p) const;
std::list<boost::shared_ptr<Image> > process (AVFrame const * frame);
diff --git a/src/lib/image.cc b/src/lib/image.cc
index 72828ed46..748e9ae4b 100644
--- a/src/lib/image.cc
+++ b/src/lib/image.cc
@@ -125,7 +125,7 @@ Image::scale_and_convert_to_rgb (Size out_size, int padding, Scaler const * scal
Size content_size = out_size;
content_size.width -= (padding * 2);
- shared_ptr<Image> rgb (new AlignedImage (PIX_FMT_RGB24, content_size));
+ shared_ptr<Image> rgb (new CompactImage (PIX_FMT_RGB24, content_size));
struct SwsContext* scale_context = sws_getContext (
size().width, size().height, pixel_format(),
diff --git a/src/lib/imagemagick_decoder.cc b/src/lib/imagemagick_decoder.cc
index d68c1648f..9d11e043f 100644
--- a/src/lib/imagemagick_decoder.cc
+++ b/src/lib/imagemagick_decoder.cc
@@ -29,7 +29,7 @@ using std::cout;
using boost::shared_ptr;
ImageMagickDecoder::ImageMagickDecoder (
- boost::shared_ptr<Film> f, boost::shared_ptr<const Options> o, Job* j)
+ boost::shared_ptr<Film> f, boost::shared_ptr<const DecodeOptions> o, Job* j)
: Decoder (f, o, j)
, VideoDecoder (f, o, j)
{
@@ -92,7 +92,7 @@ ImageMagickDecoder::pass ()
delete magick_image;
- emit_video (image);
+ emit_video (image, 0);
++_iter;
return false;
diff --git a/src/lib/imagemagick_decoder.h b/src/lib/imagemagick_decoder.h
index de49c1b56..cfcf4b4f6 100644
--- a/src/lib/imagemagick_decoder.h
+++ b/src/lib/imagemagick_decoder.h
@@ -26,7 +26,7 @@ namespace Magick {
class ImageMagickDecoder : public VideoDecoder
{
public:
- ImageMagickDecoder (boost::shared_ptr<Film>, boost::shared_ptr<const Options>, Job *);
+ ImageMagickDecoder (boost::shared_ptr<Film>, boost::shared_ptr<const DecodeOptions>, Job *);
float frames_per_second () const {
/* We don't know */
diff --git a/src/lib/imagemagick_encoder.cc b/src/lib/imagemagick_encoder.cc
deleted file mode 100644
index 480dec8bc..000000000
--- a/src/lib/imagemagick_encoder.cc
+++ /dev/null
@@ -1,91 +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/imagemagick_encoder.cc
- * @brief An encoder that writes image files using ImageMagick (and does nothing with audio).
- */
-
-#include <stdexcept>
-#include <vector>
-#include <sstream>
-#include <iomanip>
-#include <iostream>
-#include <fstream>
-#include <boost/filesystem.hpp>
-#include <Magick++/Image.h>
-#include "imagemagick_encoder.h"
-#include "film.h"
-#include "options.h"
-#include "exceptions.h"
-#include "image.h"
-#include "subtitle.h"
-
-using std::string;
-using std::ofstream;
-using boost::shared_ptr;
-
-/** @param f Film that we are encoding.
- * @param o Options.
- */
-ImageMagickEncoder::ImageMagickEncoder (shared_ptr<const Film> f, shared_ptr<const Options> o)
- : Encoder (f, o)
-{
-
-}
-
-void
-ImageMagickEncoder::do_process_video (shared_ptr<Image> image, shared_ptr<Subtitle> sub)
-{
- shared_ptr<Image> scaled = image->scale_and_convert_to_rgb (_opt->out_size, _opt->padding, _film->scaler());
- shared_ptr<Image> compact (new CompactImage (scaled));
-
- string tmp_file = _opt->frame_out_path (_video_frame, true);
- Magick::Image thumb (compact->size().width, compact->size().height, "RGB", MagickCore::CharPixel, compact->data()[0]);
- thumb.magick ("PNG");
- thumb.write (tmp_file);
- boost::filesystem::rename (tmp_file, _opt->frame_out_path (_video_frame, false));
-
- if (sub) {
- float const x_scale = float (_opt->out_size.width) / _film->size().width;
- float const y_scale = float (_opt->out_size.height) / _film->size().height;
-
- string tmp_metadata_file = _opt->frame_out_path (_video_frame, false, ".sub");
- ofstream metadata (tmp_metadata_file.c_str ());
-
- Size new_size = sub->image()->size ();
- new_size.width *= x_scale;
- new_size.height *= y_scale;
- shared_ptr<Image> scaled = sub->image()->scale (new_size, _film->scaler());
- shared_ptr<Image> compact (new CompactImage (scaled));
-
- string tmp_sub_file = _opt->frame_out_path (_video_frame, true, ".sub.png");
- Magick::Image sub_thumb (compact->size().width, compact->size().height, "RGBA", MagickCore::CharPixel, compact->data()[0]);
- sub_thumb.magick ("PNG");
- sub_thumb.write (tmp_sub_file);
- boost::filesystem::rename (tmp_sub_file, _opt->frame_out_path (_video_frame, false, ".sub.png"));
-
- metadata << "x " << sub->position().x << "\n"
- << "y " << sub->position().y << "\n";
-
- metadata.close ();
- boost::filesystem::rename (tmp_metadata_file, _opt->frame_out_path (_video_frame, false, ".sub"));
- }
-
- frame_done ();
-}
diff --git a/src/lib/imagemagick_encoder.h b/src/lib/imagemagick_encoder.h
deleted file mode 100644
index dfc741cb2..000000000
--- a/src/lib/imagemagick_encoder.h
+++ /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.
-
-*/
-
-/** @file src/imagemagick_encoder.h
- * @brief An encoder that writes image files using ImageMagick (and does nothing with audio).
- */
-
-#include <string>
-#include <sndfile.h>
-#include "encoder.h"
-
-class FilmState;
-class Log;
-
-/** @class ImageMagickEncoder
- * @brief An encoder that writes image files using ImageMagick files (and does nothing with audio).
- */
-class ImageMagickEncoder : public Encoder
-{
-public:
- ImageMagickEncoder (boost::shared_ptr<const Film> f, boost::shared_ptr<const Options> o);
-
-private:
- void do_process_video (boost::shared_ptr<Image>, boost::shared_ptr<Subtitle>);
- void do_process_audio (boost::shared_ptr<AudioBuffers>) {}
-};
diff --git a/src/lib/j2k_still_encoder.cc b/src/lib/j2k_still_encoder.cc
index dd6ef49b2..68088377b 100644
--- a/src/lib/j2k_still_encoder.cc
+++ b/src/lib/j2k_still_encoder.cc
@@ -42,7 +42,7 @@ using std::string;
using std::pair;
using boost::shared_ptr;
-J2KStillEncoder::J2KStillEncoder (shared_ptr<const Film> f, shared_ptr<const Options> o)
+J2KStillEncoder::J2KStillEncoder (shared_ptr<const Film> f, shared_ptr<const EncodeOptions> o)
: Encoder (f, o)
{
diff --git a/src/lib/j2k_still_encoder.h b/src/lib/j2k_still_encoder.h
index 4ffe876af..6069637d0 100644
--- a/src/lib/j2k_still_encoder.h
+++ b/src/lib/j2k_still_encoder.h
@@ -27,6 +27,7 @@
class Image;
class Log;
+class EncodeOptions;
/** @class J2KStillEncoder
* @brief An encoder which writes repeated JPEG2000 files from a single decoded input.
@@ -34,7 +35,7 @@ class Log;
class J2KStillEncoder : public Encoder
{
public:
- J2KStillEncoder (boost::shared_ptr<const Film>, boost::shared_ptr<const Options>);
+ J2KStillEncoder (boost::shared_ptr<const Film>, boost::shared_ptr<const EncodeOptions>);
private:
void do_process_video (boost::shared_ptr<Image>, boost::shared_ptr<Subtitle>);
diff --git a/src/lib/j2k_wav_encoder.cc b/src/lib/j2k_wav_encoder.cc
index 134d74623..e76591552 100644
--- a/src/lib/j2k_wav_encoder.cc
+++ b/src/lib/j2k_wav_encoder.cc
@@ -51,7 +51,7 @@ using boost::shared_ptr;
using boost::thread;
using boost::lexical_cast;
-J2KWAVEncoder::J2KWAVEncoder (shared_ptr<const Film> f, shared_ptr<const Options> o)
+J2KWAVEncoder::J2KWAVEncoder (shared_ptr<const Film> f, shared_ptr<const EncodeOptions> o)
: Encoder (f, o)
#ifdef HAVE_SWRESAMPLE
, _swr_context (0)
diff --git a/src/lib/j2k_wav_encoder.h b/src/lib/j2k_wav_encoder.h
index f3340ba72..064f4221e 100644
--- a/src/lib/j2k_wav_encoder.h
+++ b/src/lib/j2k_wav_encoder.h
@@ -47,7 +47,7 @@ class AudioBuffers;
class J2KWAVEncoder : public Encoder
{
public:
- J2KWAVEncoder (boost::shared_ptr<const Film>, boost::shared_ptr<const Options>);
+ J2KWAVEncoder (boost::shared_ptr<const Film>, boost::shared_ptr<const EncodeOptions>);
~J2KWAVEncoder ();
void process_begin ();
diff --git a/src/lib/job.h b/src/lib/job.h
index 41cefb9be..f32cfa811 100644
--- a/src/lib/job.h
+++ b/src/lib/job.h
@@ -30,7 +30,6 @@
#include <boost/signals2.hpp>
class Film;
-class Options;
/** @class Job
* @brief A parent class to represent long-running tasks which are run in their own thread.
diff --git a/src/lib/make_dcp_job.cc b/src/lib/make_dcp_job.cc
index 65cd272e7..4605d1724 100644
--- a/src/lib/make_dcp_job.cc
+++ b/src/lib/make_dcp_job.cc
@@ -42,7 +42,7 @@ using boost::shared_ptr;
/** @param f Film we are making the DCP for.
* @param o Options.
*/
-MakeDCPJob::MakeDCPJob (shared_ptr<Film> f, shared_ptr<const Options> o, shared_ptr<Job> req)
+MakeDCPJob::MakeDCPJob (shared_ptr<Film> f, shared_ptr<const EncodeOptions> o, shared_ptr<Job> req)
: Job (f, req)
, _opt (o)
{
diff --git a/src/lib/make_dcp_job.h b/src/lib/make_dcp_job.h
index 442bb55f5..1aa906b0a 100644
--- a/src/lib/make_dcp_job.h
+++ b/src/lib/make_dcp_job.h
@@ -23,13 +23,15 @@
#include "job.h"
+class EncodeOptions;
+
/** @class MakeDCPJob
* @brief A job to create DCPs
*/
class MakeDCPJob : public Job
{
public:
- MakeDCPJob (boost::shared_ptr<Film>, boost::shared_ptr<const Options>, boost::shared_ptr<Job> req);
+ MakeDCPJob (boost::shared_ptr<Film>, boost::shared_ptr<const EncodeOptions>, boost::shared_ptr<Job> req);
std::string name () const;
void run ();
@@ -39,6 +41,6 @@ private:
std::string j2c_path (int) const;
std::string wav_path (libdcp::Channel) const;
- boost::shared_ptr<const Options> _opt;
+ boost::shared_ptr<const EncodeOptions> _opt;
};
diff --git a/src/lib/options.h b/src/lib/options.h
index 29b3b71cd..4457969f3 100644
--- a/src/lib/options.h
+++ b/src/lib/options.h
@@ -27,22 +27,19 @@
#include <boost/optional.hpp>
#include "util.h"
-/** @class Options
- * @brief Options for a transcoding operation.
+/** @class EncodeOptions
+ * @brief EncodeOptions for an encoding operation.
*
* These are settings which may be different, in different circumstances, for
- * the same film; ie they are options for a particular transcode operation.
+ * the same film; ie they are options for a particular operation.
*/
-class Options
+class EncodeOptions
{
public:
- Options (std::string f, std::string e, std::string m)
+ EncodeOptions (std::string f, std::string e, std::string m)
: padding (0)
- , apply_crop (true)
- , decode_video_skip (0)
- , decode_audio (true)
- , decode_subtitles (false)
+ , video_skip (0)
, _frame_out_path (f)
, _frame_out_extension (e)
, _multichannel_audio_out_path (m)
@@ -94,21 +91,17 @@ public:
}
Size out_size; ///< size of output images
- float ratio; ///< ratio of the wanted output image (not considering padding)
int padding; ///< number of pixels of padding (in terms of the output size) each side of the image
- bool apply_crop; ///< true to apply cropping
/** Range of video frames to decode */
- boost::optional<std::pair<SourceFrame, SourceFrame> > video_decode_range;
+ boost::optional<std::pair<SourceFrame, SourceFrame> > video_range;
/** Range of audio frames to decode */
- boost::optional<std::pair<int64_t, int64_t> > audio_decode_range;
+ boost::optional<std::pair<int64_t, int64_t> > audio_range;
/** Skip frames such that we don't decode any frame where (index % decode_video_skip) != 0; e.g.
* 1 for every frame, 2 for every other frame, etc.
*/
- SourceFrame decode_video_skip;
- bool decode_audio; ///< true to decode audio, otherwise false
- bool decode_subtitles;
+ SourceFrame video_skip;
private:
/** Path of the directory to write video frames to */
@@ -118,3 +111,18 @@ private:
/** Path of the directory to write audio files to */
std::string _multichannel_audio_out_path;
};
+
+
+class DecodeOptions
+{
+public:
+ DecodeOptions ()
+ : decode_audio (true)
+ , decode_subtitles (false)
+ , video_sync (true)
+ {}
+
+ bool decode_audio;
+ bool decode_subtitles;
+ bool video_sync;
+};
diff --git a/src/lib/transcode_job.cc b/src/lib/transcode_job.cc
index 081e04252..54619c39f 100644
--- a/src/lib/transcode_job.cc
+++ b/src/lib/transcode_job.cc
@@ -41,9 +41,10 @@ using boost::shared_ptr;
* @param o Options.
* @param req Job that must be completed before this job is run.
*/
-TranscodeJob::TranscodeJob (shared_ptr<Film> f, shared_ptr<const Options> o, shared_ptr<Job> req)
+TranscodeJob::TranscodeJob (shared_ptr<Film> f, shared_ptr<const DecodeOptions> od, shared_ptr<const EncodeOptions> oe, shared_ptr<Job> req)
: Job (f, req)
- , _opt (o)
+ , _decode_opt (od)
+ , _encode_opt (oe)
{
}
@@ -62,8 +63,8 @@ TranscodeJob::run ()
_film->log()->log ("Transcode job starting");
_film->log()->log (String::compose ("Audio delay is %1ms", _film->audio_delay()));
- _encoder = encoder_factory (_film, _opt);
- Transcoder w (_film, _opt, this, _encoder);
+ _encoder = encoder_factory (_film, _encode_opt);
+ Transcoder w (_film, _decode_opt, this, _encoder);
w.go ();
set_progress (1);
set_state (FINISHED_OK);
diff --git a/src/lib/transcode_job.h b/src/lib/transcode_job.h
index 1decea070..97f655e15 100644
--- a/src/lib/transcode_job.h
+++ b/src/lib/transcode_job.h
@@ -25,6 +25,8 @@
#include "job.h"
class Encoder;
+class DecodeOptions;
+class EncodeOptions;
/** @class TranscodeJob
* @brief A job which transcodes from one format to another.
@@ -32,7 +34,7 @@ class Encoder;
class TranscodeJob : public Job
{
public:
- TranscodeJob (boost::shared_ptr<Film> f, boost::shared_ptr<const Options> o, boost::shared_ptr<Job> req);
+ TranscodeJob (boost::shared_ptr<Film> f, boost::shared_ptr<const DecodeOptions> od, boost::shared_ptr<const EncodeOptions> oe, boost::shared_ptr<Job> req);
std::string name () const;
void run ();
@@ -42,6 +44,7 @@ protected:
int remaining_time () const;
private:
- boost::shared_ptr<const Options> _opt;
+ boost::shared_ptr<const DecodeOptions> _decode_opt;
+ boost::shared_ptr<const EncodeOptions> _encode_opt;
boost::shared_ptr<Encoder> _encoder;
};
diff --git a/src/lib/transcoder.cc b/src/lib/transcoder.cc
index a7e79b05f..87a1fb3f2 100644
--- a/src/lib/transcoder.cc
+++ b/src/lib/transcoder.cc
@@ -44,11 +44,11 @@ using boost::dynamic_pointer_cast;
/** Construct a transcoder using a Decoder that we create and a supplied Encoder.
* @param f Film that we are transcoding.
- * @param o Options.
+ * @param o Decode options.
* @param j Job that we are running under, or 0.
* @param e Encoder to use.
*/
-Transcoder::Transcoder (shared_ptr<Film> f, shared_ptr<const Options> o, Job* j, shared_ptr<Encoder> e)
+Transcoder::Transcoder (shared_ptr<Film> f, shared_ptr<const DecodeOptions> o, Job* j, shared_ptr<Encoder> e)
: _job (j)
, _encoder (e)
, _decoders (decoder_factory (f, o, j))
@@ -63,20 +63,20 @@ Transcoder::Transcoder (shared_ptr<Film> f, shared_ptr<const Options> o, Job* j,
}
/* Set up the decoder to use the film's set streams */
- _decoders.first->set_subtitle_stream (f->subtitle_stream ());
- if (_decoders.second) {
- _decoders.second->set_audio_stream (f->audio_stream ());
+ _decoders.video->set_subtitle_stream (f->subtitle_stream ());
+ if (_decoders.audio) {
+ _decoders.audio->set_audio_stream (f->audio_stream ());
}
if (_matcher) {
- _decoders.first->connect_video (_matcher);
+ _decoders.video->connect_video (_matcher);
_matcher->connect_video (_encoder);
} else {
- _decoders.first->connect_video (_encoder);
+ _decoders.video->connect_video (_encoder);
}
- if (_matcher && _delay_line && _decoders.second) {
- _decoders.second->connect_audio (_delay_line);
+ if (_matcher && _delay_line && _decoders.audio) {
+ _decoders.audio->connect_audio (_delay_line);
_delay_line->connect_audio (_matcher);
_matcher->connect_audio (_gain);
_gain->connect_audio (_encoder);
@@ -95,12 +95,12 @@ Transcoder::go ()
while (1) {
if (!done[0]) {
- done[0] = _decoders.first->pass ();
- _decoders.first->set_progress ();
+ done[0] = _decoders.video->pass ();
+ _decoders.video->set_progress ();
}
- if (!done[1] && _decoders.second && dynamic_pointer_cast<Decoder> (_decoders.second) != dynamic_pointer_cast<Decoder> (_decoders.first)) {
- done[1] = _decoders.second->pass ();
+ if (!done[1] && _decoders.audio && dynamic_pointer_cast<Decoder> (_decoders.audio) != dynamic_pointer_cast<Decoder> (_decoders.video)) {
+ done[1] = _decoders.audio->pass ();
} else {
done[1] = true;
}
diff --git a/src/lib/transcoder.h b/src/lib/transcoder.h
index 4a9667b3c..b50113742 100644
--- a/src/lib/transcoder.h
+++ b/src/lib/transcoder.h
@@ -24,6 +24,8 @@
* as a parameter to the constructor.
*/
+#include "decoder_factory.h"
+
class Film;
class Job;
class Encoder;
@@ -34,7 +36,8 @@ class Gain;
class VideoDecoder;
class AudioDecoder;
class DelayLine;
-class Options;
+class EncodeOptions;
+class DecodeOptions;
/** @class Transcoder
* @brief A class which takes a FilmState and some Options, then uses those to transcode a Film.
@@ -45,12 +48,17 @@ class Options;
class Transcoder
{
public:
- Transcoder (boost::shared_ptr<Film> f, boost::shared_ptr<const Options> o, Job* j, boost::shared_ptr<Encoder> e);
+ Transcoder (
+ boost::shared_ptr<Film> f,
+ boost::shared_ptr<const DecodeOptions> o,
+ Job* j,
+ boost::shared_ptr<Encoder> e
+ );
void go ();
boost::shared_ptr<VideoDecoder> video_decoder () const {
- return _decoders.first;
+ return _decoders.video;
}
protected:
@@ -59,7 +67,7 @@ protected:
/** The encoder that we will use */
boost::shared_ptr<Encoder> _encoder;
/** The decoders that we will use */
- std::pair<boost::shared_ptr<VideoDecoder>, boost::shared_ptr<AudioDecoder> > _decoders;
+ Decoders _decoders;
boost::shared_ptr<Matcher> _matcher;
boost::shared_ptr<DelayLine> _delay_line;
boost::shared_ptr<Gain> _gain;
diff --git a/src/lib/video_decoder.cc b/src/lib/video_decoder.cc
index 23a69f958..d3b441fbf 100644
--- a/src/lib/video_decoder.cc
+++ b/src/lib/video_decoder.cc
@@ -28,19 +28,20 @@
using boost::shared_ptr;
using boost::optional;
-VideoDecoder::VideoDecoder (shared_ptr<Film> f, shared_ptr<const Options> o, Job* j)
+VideoDecoder::VideoDecoder (shared_ptr<Film> f, shared_ptr<const DecodeOptions> o, Job* j)
: Decoder (f, o, j)
, _video_frame (0)
+ , _last_source_frame (0)
{
}
/** Called by subclasses to tell the world that some video data is ready.
* We find a subtitle then emit it for listeners.
- * @param frame to decode; caller manages memory.
+ * @param frame to emit.
*/
void
-VideoDecoder::emit_video (shared_ptr<Image> image)
+VideoDecoder::emit_video (shared_ptr<Image> image, SourceFrame f)
{
shared_ptr<Subtitle> sub;
if (_timed_subtitle && _timed_subtitle->displayed_at (double (video_frame()) / _film->frames_per_second())) {
@@ -48,6 +49,7 @@ VideoDecoder::emit_video (shared_ptr<Image> image)
}
signal_video (image, sub);
+ _last_source_frame = f;
}
void
@@ -77,7 +79,7 @@ VideoDecoder::emit_subtitle (shared_ptr<TimedSubtitle> s)
{
_timed_subtitle = s;
- if (_timed_subtitle && _opt->apply_crop) {
+ if (_timed_subtitle) {
Position const p = _timed_subtitle->subtitle()->position ();
_timed_subtitle->subtitle()->set_position (Position (p.x - _film->crop().left, p.y - _film->crop().top));
}
diff --git a/src/lib/video_decoder.h b/src/lib/video_decoder.h
index 685138a58..f682941d1 100644
--- a/src/lib/video_decoder.h
+++ b/src/lib/video_decoder.h
@@ -27,7 +27,7 @@
class VideoDecoder : public VideoSource, public virtual Decoder
{
public:
- VideoDecoder (boost::shared_ptr<Film>, boost::shared_ptr<const Options>, Job *);
+ VideoDecoder (boost::shared_ptr<Film>, boost::shared_ptr<const DecodeOptions>, Job *);
/** @return video frames per second, or 0 if unknown */
virtual float frames_per_second () const = 0;
@@ -57,11 +57,15 @@ public:
return _subtitle_streams;
}
+ SourceFrame last_source_frame () const {
+ return _last_source_frame;
+ }
+
protected:
virtual PixelFormat pixel_format () const = 0;
- void emit_video (boost::shared_ptr<Image>);
+ void emit_video (boost::shared_ptr<Image>, SourceFrame);
void emit_subtitle (boost::shared_ptr<TimedSubtitle>);
void repeat_last_video ();
@@ -74,7 +78,8 @@ private:
void signal_video (boost::shared_ptr<Image>, boost::shared_ptr<Subtitle>);
SourceFrame _video_frame;
-
+ SourceFrame _last_source_frame;
+
boost::shared_ptr<TimedSubtitle> _timed_subtitle;
boost::shared_ptr<Image> _last_image;
diff --git a/src/lib/wscript b/src/lib/wscript
index c1786bb81..5d3fbb906 100644
--- a/src/lib/wscript
+++ b/src/lib/wscript
@@ -37,7 +37,6 @@ def build(bld):
gain.cc
image.cc
imagemagick_decoder.cc
- imagemagick_encoder.cc
j2k_still_encoder.cc
j2k_wav_encoder.cc
job.cc