Untested external audio support; AB transcodes still broken.
authorCarl Hetherington <cth@carlh.net>
Thu, 15 Nov 2012 22:26:16 +0000 (22:26 +0000)
committerCarl Hetherington <cth@carlh.net>
Thu, 15 Nov 2012 22:26:16 +0000 (22:26 +0000)
25 files changed:
ChangeLog
src/lib/ab_transcoder.cc
src/lib/ab_transcoder.h
src/lib/audio_decoder.cc [new file with mode: 0644]
src/lib/audio_decoder.h [new file with mode: 0644]
src/lib/decoder.cc
src/lib/decoder.h
src/lib/decoder_factory.cc
src/lib/decoder_factory.h
src/lib/examine_content_job.cc
src/lib/examine_content_job.h
src/lib/external_audio_decoder.cc [new file with mode: 0644]
src/lib/external_audio_decoder.h [new file with mode: 0644]
src/lib/ffmpeg_decoder.cc
src/lib/ffmpeg_decoder.h
src/lib/film.cc
src/lib/imagemagick_decoder.cc
src/lib/imagemagick_decoder.h
src/lib/transcoder.cc
src/lib/transcoder.h
src/lib/util.cc
src/lib/util.h
src/lib/video_decoder.cc [new file with mode: 0644]
src/lib/video_decoder.h [new file with mode: 0644]
src/lib/wscript

index 167536a881ccd26da9b404aa79c2a10e63ff1be7..7d73e186f894a577cc6ec9791f27727790c0bd2d 100644 (file)
--- a/ChangeLog
+++ b/ChangeLog
@@ -2,6 +2,9 @@
 
        * Default to using a DCI name.
 
+       * Support for using external sound files instead
+       of the ones in the video source.
+
 2012-11-14  Carl Hetherington  <cth@carlh.net>
 
        * Rearrange the GUI a bit to tidy things up.
index 868ce90799b9e1340e5396aa37f91a00d607f777..9999eda90a853fd68ca6fce341541cc4d50bbff1 100644 (file)
@@ -21,7 +21,8 @@
 #include <boost/shared_ptr.hpp>
 #include "ab_transcoder.h"
 #include "film.h"
-#include "decoder.h"
+#include "video_decoder.h"
+#include "audio_decoder.h"
 #include "encoder.h"
 #include "job.h"
 #include "options.h"
@@ -54,9 +55,11 @@ ABTranscoder::ABTranscoder (
        _da = decoder_factory (_film_a, o, j);
        _db = decoder_factory (_film_b, o, j);
 
-       _da->Video.connect (bind (&ABTranscoder::process_video, this, _1, _2, 0));
-       _db->Video.connect (bind (&ABTranscoder::process_video, this, _1, _2, 1));
-       _da->Audio.connect (bind (&Encoder::process_audio, e, _1));
+       /* XXX */
+
+//     _da->Video.connect (bind (&ABTranscoder::process_video, this, _1, _2, 0));
+//     _db->Video.connect (bind (&ABTranscoder::process_video, this, _1, _2, 1));
+//     _da->Audio.connect (bind (&Encoder::process_audio, e, _1));
 }
 
 ABTranscoder::~ABTranscoder ()
@@ -100,10 +103,11 @@ ABTranscoder::go ()
        _encoder->process_begin ();
        
        while (1) {
-               bool const a = _da->pass ();
-               bool const b = _db->pass ();
+               bool const va = _da.first->pass ();
+               bool const vb = _db.first->pass ();
+               bool const a = _da.first->pass ();
 
-               if (a && b) {
+               if (va && vb && a) {
                        break;
                }
        }
index c75398b5c7013dca8e1613c80f305edb12209515..c951329f2bfc6eeefdc00687a13980f60da7db73 100644 (file)
@@ -28,7 +28,8 @@
 
 class Job;
 class Encoder;
-class Decoder;
+class VideoDecoder;
+class AudioDecoder;
 class Options;
 class Image;
 class Log;
@@ -62,7 +63,7 @@ private:
        boost::shared_ptr<const Options> _opt;
        Job* _job;
        boost::shared_ptr<Encoder> _encoder;
-       boost::shared_ptr<Decoder> _da;
-       boost::shared_ptr<Decoder> _db;
+       std::pair<boost::shared_ptr<VideoDecoder>, boost::shared_ptr<AudioDecoder> > _da;
+       std::pair<boost::shared_ptr<VideoDecoder>, boost::shared_ptr<AudioDecoder> > _db;
        boost::shared_ptr<Image> _image;
 };
diff --git a/src/lib/audio_decoder.cc b/src/lib/audio_decoder.cc
new file mode 100644 (file)
index 0000000..b34bf1e
--- /dev/null
@@ -0,0 +1,17 @@
+#include "audio_decoder.h"
+#include "stream.h"
+
+using boost::optional;
+using boost::shared_ptr;
+
+AudioDecoder::AudioDecoder (shared_ptr<Film> f, shared_ptr<const Options> o, Job* j)
+       : Decoder (f, o, j)
+{
+
+}
+
+void
+AudioDecoder::set_audio_stream (optional<AudioStream> s)
+{
+       _audio_stream = s;
+}
diff --git a/src/lib/audio_decoder.h b/src/lib/audio_decoder.h
new file mode 100644 (file)
index 0000000..f9948f5
--- /dev/null
@@ -0,0 +1,28 @@
+#ifndef DVDOMATIC_AUDIO_DECODER_H
+#define DVDOMATIC_AUDIO_DECODER_H
+
+#include "audio_source.h"
+#include "stream.h"
+#include "decoder.h"
+
+class AudioDecoder : public AudioSource, public virtual Decoder
+{
+public:
+       AudioDecoder (boost::shared_ptr<Film>, boost::shared_ptr<const Options>, Job *);
+
+       virtual void set_audio_stream (boost::optional<AudioStream>);
+
+       boost::optional<AudioStream> audio_stream () const {
+               return _audio_stream;
+       }
+
+       std::vector<AudioStream> audio_streams () const {
+               return _audio_streams;
+       }
+
+protected:
+       boost::optional<AudioStream> _audio_stream;
+       std::vector<AudioStream> _audio_streams;
+};
+
+#endif
index 8d087b6ee00c338413948d5f6b499d132a15775e..2bacf58e73b929a57948a6097465fd90d4cd15e8 100644 (file)
@@ -53,82 +53,6 @@ Decoder::Decoder (boost::shared_ptr<Film> f, boost::shared_ptr<const Options> o,
        : _film (f)
        , _opt (o)
        , _job (j)
-       , _video_frame (0)
 {
        
 }
-
-/** Start decoding */
-void
-Decoder::go ()
-{
-       if (_job && !_film->dcp_length()) {
-               _job->set_progress_unknown ();
-       }
-
-       while (pass () == false) {
-               if (_job && _film->dcp_length()) {
-                       _job->set_progress (float (_video_frame) / _film->length().get());
-               }
-       }
-}
-
-/** 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.
- */
-void
-Decoder::emit_video (shared_ptr<Image> image)
-{
-       shared_ptr<Subtitle> sub;
-       if (_timed_subtitle && _timed_subtitle->displayed_at (double (video_frame()) / _film->frames_per_second())) {
-               sub = _timed_subtitle->subtitle ();
-       }
-
-       signal_video (image, sub);
-}
-
-void
-Decoder::repeat_last_video ()
-{
-       if (!_last_image) {
-               _last_image.reset (new CompactImage (pixel_format(), native_size()));
-               _last_image->make_black ();
-       }
-
-       signal_video (_last_image, _last_subtitle);
-}
-
-void
-Decoder::signal_video (shared_ptr<Image> image, shared_ptr<Subtitle> sub)
-{
-       TIMING ("Decoder emits %1", _video_frame);
-       Video (image, sub);
-       ++_video_frame;
-
-       _last_image = image;
-       _last_subtitle = sub;
-}
-
-void
-Decoder::emit_subtitle (shared_ptr<TimedSubtitle> s)
-{
-       _timed_subtitle = s;
-       
-       if (_timed_subtitle && _opt->apply_crop) {
-               Position const p = _timed_subtitle->subtitle()->position ();
-               _timed_subtitle->subtitle()->set_position (Position (p.x - _film->crop().left, p.y - _film->crop().top));
-       }
-}
-
-void
-Decoder::set_audio_stream (optional<AudioStream> s)
-{
-       _audio_stream = s;
-}
-
-void
-Decoder::set_subtitle_stream (optional<SubtitleStream> s)
-{
-       _subtitle_stream = s;
-}
index 805f6e521326bd9902f8b6bcace5495f7335fdcb..cd033b5f9ccb9fe39f02ee80b16bac53cbb6eb57 100644 (file)
@@ -47,84 +47,27 @@ class FilterGraph;
 /** @class Decoder.
  *  @brief Parent class for decoders of content.
  *
- *  These classes can be instructed run through their content
- *  (by calling ::go), and they emit signals when video or audio data is ready for something else
- *  to process.
+ *  These classes can be instructed run through their content (by
+ *  calling ::go), and they emit signals when video or audio data is
+ *  ready for something else to process.
  */
-class Decoder : public VideoSource, public AudioSource
+class Decoder
 {
 public:
        Decoder (boost::shared_ptr<Film>, boost::shared_ptr<const Options>, Job *);
        virtual ~Decoder () {}
 
-       /* Methods to query our input video */
-
-       /** @return video frames per second, or 0 if unknown */
-       virtual float frames_per_second () const = 0;
-       /** @return native size in pixels */
-       virtual Size native_size () const = 0;
-
-       virtual int time_base_numerator () const = 0;
-       virtual int time_base_denominator () const = 0;
-       virtual int sample_aspect_ratio_numerator () const = 0;
-       virtual int sample_aspect_ratio_denominator () const = 0;
-       
        virtual bool pass () = 0;
-       void go ();
-
-       SourceFrame video_frame () const {
-               return _video_frame;
-       }
-
-       virtual void set_audio_stream (boost::optional<AudioStream>);
-       virtual void set_subtitle_stream (boost::optional<SubtitleStream>);
-
-       boost::optional<AudioStream> audio_stream () const {
-               return _audio_stream;
-       }
-
-       boost::optional<SubtitleStream> subtitle_stream () const {
-               return _subtitle_stream;
-       }
-
-       std::vector<AudioStream> audio_streams () const {
-               return _audio_streams;
-       }
-       
-       std::vector<SubtitleStream> subtitle_streams () const {
-               return _subtitle_streams;
-       }
 
 protected:
+       virtual void set_progress () const {}
        
-       virtual PixelFormat pixel_format () const = 0;
-       
-       void emit_video (boost::shared_ptr<Image>);
-       void emit_subtitle (boost::shared_ptr<TimedSubtitle>);
-       void repeat_last_video ();
-
        /** our Film */
        boost::shared_ptr<Film> _film;
        /** our options */
        boost::shared_ptr<const Options> _opt;
        /** associated Job, or 0 */
        Job* _job;
-
-       boost::optional<AudioStream> _audio_stream;
-       boost::optional<SubtitleStream> _subtitle_stream;
-
-       std::vector<AudioStream> _audio_streams;
-       std::vector<SubtitleStream> _subtitle_streams;
-       
-private:
-       void signal_video (boost::shared_ptr<Image>, boost::shared_ptr<Subtitle>);
-
-       SourceFrame _video_frame;
-
-       boost::shared_ptr<TimedSubtitle> _timed_subtitle;
-
-       boost::shared_ptr<Image> _last_image;
-       boost::shared_ptr<Subtitle> _last_subtitle;
 };
 
 #endif
index bb6eff97140edd27328ef957b2793d998466728e..e9b5bfa9e755682f5d4bf72e1dba2b5c31dbadea 100644 (file)
 #include "ffmpeg_decoder.h"
 #include "imagemagick_decoder.h"
 #include "film.h"
+#include "external_audio_decoder.h"
 
 using std::string;
+using std::pair;
+using std::make_pair;
 using boost::shared_ptr;
 
-shared_ptr<Decoder>
+pair<shared_ptr<VideoDecoder>, shared_ptr<AudioDecoder> >
 decoder_factory (
        shared_ptr<Film> f, shared_ptr<const Options> 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 shared_ptr<Decoder> (new ImageMagickDecoder (f, o, j));
+               return make_pair (
+                       shared_ptr<VideoDecoder> (new ImageMagickDecoder (f, o, j)),
+                       shared_ptr<AudioDecoder> ()
+                       );
+       }
+
+       shared_ptr<FFmpegDecoder> fd (new FFmpegDecoder (f, o, j));
+       if (f->use_content_audio()) {
+               return make_pair (fd, fd);
        }
        
-       return shared_ptr<Decoder> (new FFmpegDecoder (f, o, j));
+       return make_pair (fd, shared_ptr<AudioDecoder> (new ExternalAudioDecoder (f, o, j)));
 }
index 765b38816d83beca0f8aae311fd7c7c29f7de106..1f369061192e3e7c0050b5ef8f5f0c9d9a778ac0 100644 (file)
 */
 
 /** @file  src/decoder_factory.h
- *  @brief A method to create an appropriate decoder for some content.
+ *  @brief A method to create appropriate decoders for some content.
  */
 
-class Decoder;
 class Film;
 class Options;
 class Job;
-class Log;
+class VideoDecoder;
+class AudioDecoder;
 
-extern boost::shared_ptr<Decoder> decoder_factory (
+extern std::pair<boost::shared_ptr<VideoDecoder>, boost::shared_ptr<AudioDecoder> > decoder_factory (
        boost::shared_ptr<Film>, boost::shared_ptr<const Options>, Job *
        );
index b13e9d9d59a901f83d5c2b0c22973117af85fb15..8db74801fdd634feed5e2a822c4d4f97691884b6 100644 (file)
 #include "transcoder.h"
 #include "log.h"
 #include "film.h"
+#include "video_decoder.h"
 
 using std::string;
 using std::vector;
+using std::pair;
 using boost::shared_ptr;
 
 ExamineContentJob::ExamineContentJob (shared_ptr<Film> f, shared_ptr<Job> req)
@@ -72,10 +74,14 @@ ExamineContentJob::run ()
 
        descend (0.5);
 
-       _decoder = decoder_factory (_film, o, this);
-       _decoder->go ();
+       pair<shared_ptr<VideoDecoder>, shared_ptr<AudioDecoder> > decoders = decoder_factory (_film, o, this);
 
-       _film->set_length (_decoder->video_frame());
+       set_progress_unknown ();
+       while (!decoders.first->pass()) {
+               /* keep going */
+       }
+
+       _film->set_length (decoders.first->video_frame());
 
        _film->log()->log (String::compose ("Video length is %1 frames", _film->length()));
 
index d87bd0876b23b160c346643dc29768689aa7d11c..2004aca8318225e2b2f33da0c6b70f1c959b0c59 100644 (file)
@@ -23,8 +23,6 @@
 
 #include "job.h"
 
-class Decoder;
-
 /** @class ExamineContentJob
  *  @brief A class to run through content at high speed to find its length.
  */
@@ -36,8 +34,5 @@ public:
 
        std::string name () const;
        void run ();
-
-private:
-       boost::shared_ptr<Decoder> _decoder;
 };
 
diff --git a/src/lib/external_audio_decoder.cc b/src/lib/external_audio_decoder.cc
new file mode 100644 (file)
index 0000000..99dd1de
--- /dev/null
@@ -0,0 +1,87 @@
+#include <sndfile.h>
+#include "external_audio_decoder.h"
+#include "film.h"
+#include "exceptions.h"
+
+using std::vector;
+using std::string;
+using std::min;
+using boost::shared_ptr;
+
+ExternalAudioDecoder::ExternalAudioDecoder (shared_ptr<Film> f, shared_ptr<const Options> o, Job* j)
+       : Decoder (f, o, j)
+       , AudioDecoder (f, o, j)
+{
+
+}
+
+bool
+ExternalAudioDecoder::pass ()
+{
+       vector<string> const files = _film->external_audio ();
+
+       int N = 0;
+       for (size_t i = 0; i < files.size(); ++i) {
+               if (!files[i].empty()) {
+                       N = i + 1;
+               }
+       }
+
+       if (N == 0) {
+               return true;
+       }
+
+       bool first = true;
+       sf_count_t frames = 0;
+       
+       vector<SNDFILE*> sndfiles;
+       for (vector<string>::const_iterator i = files.begin(); i != files.end(); ++i) {
+               if (i->empty ()) {
+                       sndfiles.push_back (0);
+               } else {
+                       SF_INFO info;
+                       SNDFILE* s = sf_open (i->c_str(), SFM_READ, &info);
+                       if (!s) {
+                               throw DecodeError ("could not open external audio file for reading");
+                       }
+
+                       if (info.channels != 1) {
+                               throw DecodeError ("external audio files must be mono");
+                       }
+                       
+                       sndfiles.push_back (s);
+
+                       if (first) {
+                               /* XXX: nasty magic value */
+                               AudioStream st ("DVDOMATIC-EXTERNAL", -1, info.samplerate, av_get_default_channel_layout (info.channels));
+                               _audio_streams.push_back (st);
+                               _audio_stream = st;
+                               frames = info.frames;
+                               first = false;
+                       } else {
+                               if (info.frames != frames) {
+                                       throw DecodeError ("external audio files have differing lengths");
+                               }
+                       }
+               }
+       }
+
+       sf_count_t const block = 65536;
+
+       shared_ptr<AudioBuffers> audio (new AudioBuffers (_audio_stream.get().channels(), block));
+       while (frames > 0) {
+               sf_count_t const this_time = min (block, frames);
+               for (size_t i = 0; i < sndfiles.size(); ++i) {
+                       if (!sndfiles[i]) {
+                               audio->make_silent (i);
+                       } else {
+                               sf_read_float (sndfiles[i], audio->data(i), block);
+                       }
+               }
+
+               Audio (audio);
+               frames -= this_time;
+       }
+       
+       return true;
+}
diff --git a/src/lib/external_audio_decoder.h b/src/lib/external_audio_decoder.h
new file mode 100644 (file)
index 0000000..3cc4314
--- /dev/null
@@ -0,0 +1,10 @@
+#include "decoder.h"
+#include "audio_decoder.h"
+
+class ExternalAudioDecoder : public AudioDecoder
+{
+public:
+       ExternalAudioDecoder (boost::shared_ptr<Film>, boost::shared_ptr<const Options>, Job *);
+
+       bool pass ();
+};
index 3767d7c5fd0ce2b8d679600c93f0ed327e86d040..60f192c85213ec7b0d61bc4828c80c1a7cffbb56 100644 (file)
@@ -60,6 +60,8 @@ using boost::optional;
 
 FFmpegDecoder::FFmpegDecoder (shared_ptr<Film> f, shared_ptr<const Options> o, Job* j)
        : Decoder (f, o, j)
+       , VideoDecoder (f, o, j)
+       , AudioDecoder (f, o, j)
        , _format_context (0)
        , _video_stream (-1)
        , _frame (0)
@@ -519,14 +521,14 @@ FFmpegDecoder::bytes_per_audio_sample () const
 void
 FFmpegDecoder::set_audio_stream (optional<AudioStream> s)
 {
-       Decoder::set_audio_stream (s);
+       AudioDecoder::set_audio_stream (s);
        setup_audio ();
 }
 
 void
 FFmpegDecoder::set_subtitle_stream (optional<SubtitleStream> s)
 {
-       Decoder::set_subtitle_stream (s);
+       VideoDecoder::set_subtitle_stream (s);
        setup_subtitle ();
 }
 
index 5c6f8ab2691c0bcaa7661859d651333c7c4d95ed..a4a9246f0bb16189dd4f30ea63fb79752fa5bff1 100644 (file)
@@ -32,6 +32,8 @@ extern "C" {
 }
 #include "util.h"
 #include "decoder.h"
+#include "video_decoder.h"
+#include "audio_decoder.h"
 
 struct AVFilterGraph;
 struct AVCodecContext;
@@ -49,13 +51,12 @@ class Log;
 /** @class FFmpegDecoder
  *  @brief A decoder using FFmpeg to decode content.
  */
-class FFmpegDecoder : public Decoder
+class FFmpegDecoder : public VideoDecoder, public AudioDecoder
 {
 public:
        FFmpegDecoder (boost::shared_ptr<Film>, boost::shared_ptr<const Options>, Job *);
        ~FFmpegDecoder ();
 
-       /* Methods to query our input video */
        float frames_per_second () const;
        Size native_size () const;
        int time_base_numerator () const;
index 454ac9aa9b809e38cea59ba3ef7330dd494338dc..2330e3c7304ed54728a3b9848cb3e3fc403a57f2 100644 (file)
@@ -52,6 +52,8 @@
 #include "check_hashes_job.h"
 #include "version.h"
 #include "ui_signaller.h"
+#include "video_decoder.h"
+#include "audio_decoder.h"
 
 using std::string;
 using std::stringstream;
@@ -939,20 +941,20 @@ Film::set_content (string c)
                shared_ptr<Options> o (new Options ("", "", ""));
                o->out_size = Size (1024, 1024);
                
-               shared_ptr<Decoder> d = decoder_factory (shared_from_this(), o, 0);
+               pair<shared_ptr<VideoDecoder>, shared_ptr<AudioDecoder> > d = decoder_factory (shared_from_this(), o, 0);
                
-               set_size (d->native_size ());
-               set_frames_per_second (d->frames_per_second ());
-               set_audio_streams (d->audio_streams ());
-               set_subtitle_streams (d->subtitle_streams ());
+               set_size (d.first->native_size ());
+               set_frames_per_second (d.first->frames_per_second ());
+               set_subtitle_streams (d.first->subtitle_streams ());
+               set_audio_streams (d.second->audio_streams ());
 
                /* Start off with the first audio and subtitle streams */
-               if (!d->audio_streams().empty()) {
-                       set_audio_stream (d->audio_streams().front());
+               if (!d.second->audio_streams().empty()) {
+                       set_audio_stream (d.second->audio_streams().front());
                }
                
-               if (!d->subtitle_streams().empty()) {
-                       set_subtitle_stream (d->subtitle_streams().front());
+               if (!d.first->subtitle_streams().empty()) {
+                       set_subtitle_stream (d.first->subtitle_streams().front());
                }
                
                {
index 7faf74c6196c42b72a82356136a303218a8509e3..d68c1648fe1242dcc2ab1d64ca43fcfeb29707ae 100644 (file)
@@ -31,6 +31,7 @@ using boost::shared_ptr;
 ImageMagickDecoder::ImageMagickDecoder (
        boost::shared_ptr<Film> f, boost::shared_ptr<const Options> o, Job* j)
        : Decoder (f, o, j)
+       , VideoDecoder (f, o, j)
 {
        if (boost::filesystem::is_directory (_film->content_path())) {
                for (
index 6506d0177f1196667eccfe7d8eab5dbb6680f3f3..f636191f2e3bdbb6da13d799c13a496cabbd6885 100644 (file)
 
 */
 
-#include "decoder.h"
+#include "video_decoder.h"
 
 namespace Magick {
        class Image;
 }
 
-class ImageMagickDecoder : public Decoder
+class ImageMagickDecoder : public VideoDecoder
 {
 public:
        ImageMagickDecoder (boost::shared_ptr<Film>, boost::shared_ptr<const Options>, Job *);
index 01f54be3fa1381d1ef14a1f3c88520812f3b2f24..32725f77caaca32e5d07b47fe066de4c639f6b50 100644 (file)
 #include "delay_line.h"
 #include "options.h"
 #include "gain.h"
+#include "video_decoder.h"
+#include "audio_decoder.h"
 
 using std::string;
 using boost::shared_ptr;
+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.
@@ -47,7 +50,7 @@ using boost::shared_ptr;
 Transcoder::Transcoder (shared_ptr<Film> f, shared_ptr<const Options> o, Job* j, shared_ptr<Encoder> e)
        : _job (j)
        , _encoder (e)
-       , _decoder (decoder_factory (f, o, j))
+       , _decoders (decoder_factory (f, o, j))
 {
        assert (_encoder);
 
@@ -59,18 +62,18 @@ Transcoder::Transcoder (shared_ptr<Film> f, shared_ptr<const Options> o, Job* j,
        }
 
        /* Set up the decoder to use the film's set streams */
-       _decoder->set_audio_stream (f->audio_stream ());
-       _decoder->set_subtitle_stream (f->subtitle_stream ());
+       _decoders.first->set_subtitle_stream (f->subtitle_stream ());
+       _decoders.second->set_audio_stream (f->audio_stream ());
 
        if (_matcher) {
-               _decoder->connect_video (_matcher);
+               _decoders.first->connect_video (_matcher);
                _matcher->connect_video (_encoder);
        } else {
-               _decoder->connect_video (_encoder);
+               _decoders.first->connect_video (_encoder);
        }
        
        if (_matcher && _delay_line) {
-               _decoder->connect_audio (_delay_line);
+               _decoders.second->connect_audio (_delay_line);
                _delay_line->connect_audio (_matcher);
                _matcher->connect_audio (_gain);
                _gain->connect_audio (_encoder);
@@ -85,7 +88,19 @@ Transcoder::go ()
 {
        _encoder->process_begin ();
        try {
-               _decoder->go ();
+               while (1) {
+                       bool const v = _decoders.first->pass ();
+
+                       bool a = false;
+                       if (dynamic_pointer_cast<Decoder> (_decoders.second) != dynamic_pointer_cast<Decoder> (_decoders.first)) {
+                               a = _decoders.second->pass ();
+                       }
+
+                       if (v && a) {
+                               break;
+                       }
+               }
+               
        } catch (...) {
                /* process_end() is important as the decoder may have worker
                   threads that need to be cleaned up.
index 324a72037752f5bef2f1f07584996c66be803c7a..e3ca2bb32085b128bb0c47673bcab7b55fed804a 100644 (file)
@@ -17,8 +17,6 @@
 
 */
 
-#include "decoder.h"
-
 /** @file  src/transcoder.h
  *  @brief A class which takes a FilmState and some Options, then uses those to transcode a Film.
  *
@@ -33,6 +31,10 @@ class FilmState;
 class Matcher;
 class VideoFilter;
 class Gain;
+class VideoDecoder;
+class AudioDecoder;
+class DelayLine;
+class Options;
 
 /** @class Transcoder
  *  @brief A class which takes a FilmState and some Options, then uses those to transcode a Film.
@@ -47,18 +49,13 @@ public:
 
        void go ();
 
-       /** @return Our decoder */
-       boost::shared_ptr<Decoder> decoder () {
-               return _decoder;
-       }
-
 protected:
        /** A Job that is running this Transcoder, or 0 */
        Job* _job;
        /** The encoder that we will use */
        boost::shared_ptr<Encoder> _encoder;
-       /** The decoder that we will use */
-       boost::shared_ptr<Decoder> _decoder;
+       /** The decoders that we will use */
+       std::pair<boost::shared_ptr<VideoDecoder>, boost::shared_ptr<AudioDecoder> > _decoders;
        boost::shared_ptr<Matcher> _matcher;
        boost::shared_ptr<DelayLine> _delay_line;
        boost::shared_ptr<Gain> _gain;
index 862ddc1112f2672f53ee536780f2fcefab21553e..ed9594692dca40ac3fd8f0afc336859c534f8ef0 100644 (file)
@@ -780,9 +780,15 @@ void
 AudioBuffers::make_silent ()
 {
        for (int i = 0; i < _channels; ++i) {
-               for (int j = 0; j < _frames; ++j) {
-                       _data[i][j] = 0;
-               }
+               make_silent (i);
+       }
+}
+
+void
+AudioBuffers::make_silent (int c)
+{
+       for (int i = 0; i < _frames; ++i) {
+               _data[c][i] = 0;
        }
 }
 
index 301a8bc4e9398dd48babbf84475ba24dd980b77a..53e78e57c8f1d44142bf5e2551812ce63d1b069f 100644 (file)
@@ -243,6 +243,7 @@ public:
        void set_frames (int f);
 
        void make_silent ();
+       void make_silent (int c);
 
        void copy_from (AudioBuffers* from, int frames_to_copy, int read_offset, int write_offset);
        void move (int from, int to, int frames);
diff --git a/src/lib/video_decoder.cc b/src/lib/video_decoder.cc
new file mode 100644 (file)
index 0000000..906f92e
--- /dev/null
@@ -0,0 +1,79 @@
+#include "video_decoder.h"
+#include "subtitle.h"
+#include "film.h"
+#include "image.h"
+#include "log.h"
+#include "options.h"
+#include "job.h"
+
+using boost::shared_ptr;
+using boost::optional;
+
+VideoDecoder::VideoDecoder (shared_ptr<Film> f, shared_ptr<const Options> o, Job* j)
+       : Decoder (f, o, j)
+       , _video_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.
+ */
+void
+VideoDecoder::emit_video (shared_ptr<Image> image)
+{
+       shared_ptr<Subtitle> sub;
+       if (_timed_subtitle && _timed_subtitle->displayed_at (double (video_frame()) / _film->frames_per_second())) {
+               sub = _timed_subtitle->subtitle ();
+       }
+
+       signal_video (image, sub);
+}
+
+void
+VideoDecoder::repeat_last_video ()
+{
+       if (!_last_image) {
+               _last_image.reset (new CompactImage (pixel_format(), native_size()));
+               _last_image->make_black ();
+       }
+
+       signal_video (_last_image, _last_subtitle);
+}
+
+void
+VideoDecoder::signal_video (shared_ptr<Image> image, shared_ptr<Subtitle> sub)
+{
+       TIMING ("Decoder emits %1", _video_frame);
+       Video (image, sub);
+       ++_video_frame;
+
+       _last_image = image;
+       _last_subtitle = sub;
+}
+
+void
+VideoDecoder::emit_subtitle (shared_ptr<TimedSubtitle> s)
+{
+       _timed_subtitle = s;
+       
+       if (_timed_subtitle && _opt->apply_crop) {
+               Position const p = _timed_subtitle->subtitle()->position ();
+               _timed_subtitle->subtitle()->set_position (Position (p.x - _film->crop().left, p.y - _film->crop().top));
+       }
+}
+
+void
+VideoDecoder::set_subtitle_stream (optional<SubtitleStream> s)
+{
+       _subtitle_stream = s;
+}
+
+void
+VideoDecoder::set_progress () const
+{
+       if (_job && _film->dcp_length()) {
+               _job->set_progress (float (_video_frame) / _film->length().get());
+       }
+}
diff --git a/src/lib/video_decoder.h b/src/lib/video_decoder.h
new file mode 100644 (file)
index 0000000..df06b7c
--- /dev/null
@@ -0,0 +1,60 @@
+#ifndef DVDOMATIC_VIDEO_DECODER_H
+#define DVDOMATIC_VIDEO_DECODER_H
+
+#include "video_source.h"
+#include "stream.h"
+#include "decoder.h"
+
+class VideoDecoder : public VideoSource, public virtual Decoder
+{
+public:
+       VideoDecoder (boost::shared_ptr<Film>, boost::shared_ptr<const Options>, Job *);
+
+       /** @return video frames per second, or 0 if unknown */
+       virtual float frames_per_second () const = 0;
+       /** @return native size in pixels */
+       virtual Size native_size () const = 0;
+
+       virtual int time_base_numerator () const = 0;
+       virtual int time_base_denominator () const = 0;
+       virtual int sample_aspect_ratio_numerator () const = 0;
+       virtual int sample_aspect_ratio_denominator () const = 0;
+
+       virtual void set_subtitle_stream (boost::optional<SubtitleStream>);
+
+       SourceFrame video_frame () const {
+               return _video_frame;
+       }
+
+       boost::optional<SubtitleStream> subtitle_stream () const {
+               return _subtitle_stream;
+       }
+
+       std::vector<SubtitleStream> subtitle_streams () const {
+               return _subtitle_streams;
+       }
+
+protected:
+       
+       virtual PixelFormat pixel_format () const = 0;
+       void set_progress () const;
+
+       void emit_video (boost::shared_ptr<Image>);
+       void emit_subtitle (boost::shared_ptr<TimedSubtitle>);
+       void repeat_last_video ();
+
+       boost::optional<SubtitleStream> _subtitle_stream;
+       std::vector<SubtitleStream> _subtitle_streams;
+
+private:
+       void signal_video (boost::shared_ptr<Image>, boost::shared_ptr<Subtitle>);
+
+       SourceFrame _video_frame;
+
+       boost::shared_ptr<TimedSubtitle> _timed_subtitle;
+
+       boost::shared_ptr<Image> _last_image;
+       boost::shared_ptr<Subtitle> _last_subtitle;
+};
+
+#endif
index 6d006f559cc5b578343a0a56f5b7df9ef3d7413f..339c73e4774db3dea15d7cf2cd0792dc3cb15925 100644 (file)
@@ -8,6 +8,7 @@ def build(bld):
     obj.source = """
                 ab_transcode_job.cc
                 ab_transcoder.cc
+                 audio_decoder.cc
                  audio_source.cc
                  check_hashes_job.cc
                 config.cc
@@ -23,6 +24,7 @@ def build(bld):
                 encoder.cc
                  encoder_factory.cc
                 examine_content_job.cc
+                external_audio_decoder.cc
                  filter_graph.cc
                  ffmpeg_compatibility.cc
                  ffmpeg_decoder.cc
@@ -54,6 +56,7 @@ def build(bld):
                  ui_signaller.cc
                 util.cc
                 version.cc
+                 video_decoder.cc
                  video_source.cc
                 """