Basic multithread of DCP decryption during export.
authorCarl Hetherington <cth@carlh.net>
Wed, 26 Jul 2017 16:08:00 +0000 (17:08 +0100)
committerCarl Hetherington <cth@carlh.net>
Wed, 26 Jul 2017 16:08:00 +0000 (17:08 +0100)
src/lib/dcp_encoder.cc
src/lib/dcp_encoder.h
src/lib/encoder.cc
src/lib/encoder.h
src/lib/ffmpeg_encoder.cc
src/lib/ffmpeg_encoder.h

index 67235e5968e419c3c08a70c5301afeef5c955587..5ee6cca982a596b5bc1728c5390bf2c5409a28f1 100644 (file)
@@ -61,6 +61,10 @@ DCPEncoder::DCPEncoder (shared_ptr<const Film> film, weak_ptr<Job> job)
        , _finishing (false)
        , _non_burnt_subtitles (false)
 {
+       _player_video_connection = _player->Video.connect (bind (&DCPEncoder::video, this, _1, _2));
+       _player_audio_connection = _player->Audio.connect (bind (&DCPEncoder::audio, this, _1, _2));
+       _player_subtitle_connection = _player->Subtitle.connect (bind (&DCPEncoder::subtitle, this, _1, _2));
+
        BOOST_FOREACH (shared_ptr<const Content> c, film->content ()) {
                if (c->subtitle && c->subtitle->use() && !c->subtitle->burn()) {
                        _non_burnt_subtitles = true;
index b1514efdc7d0715070c76445dee8ecae32ec528b..0fa20c2c9c9fa19276c1bf7af8733e30127583ce 100644 (file)
@@ -60,4 +60,8 @@ private:
        boost::shared_ptr<J2KEncoder> _j2k_encoder;
        bool _finishing;
        bool _non_burnt_subtitles;
+
+       boost::signals2::scoped_connection _player_video_connection;
+       boost::signals2::scoped_connection _player_audio_connection;
+       boost::signals2::scoped_connection _player_subtitle_connection;
 };
index 16d9923141080fc42bc0aacbcee039e6e1585db2..535389a94932b4ab4eb5b466f9dfaedb7831f293 100644 (file)
@@ -43,7 +43,5 @@ Encoder::Encoder (shared_ptr<const Film> film, weak_ptr<Job> job)
        , _job (job)
        , _player (new Player (film, film->playlist ()))
 {
-       _player_video_connection = _player->Video.connect (bind (&Encoder::video, this, _1, _2));
-       _player_audio_connection = _player->Audio.connect (bind (&Encoder::audio, this, _1, _2));
-       _player_subtitle_connection = _player->Subtitle.connect (bind (&Encoder::subtitle, this, _1, _2));
+
 }
index 64540195278ea0970f8b7e87d297fd937aa66e23..4907ed7c5a906f7a3dcc3ca2c31339139fbc9219 100644 (file)
@@ -49,17 +49,9 @@ public:
        virtual bool finishing () const = 0;
 
 protected:
-       virtual void video (boost::shared_ptr<PlayerVideo>, DCPTime) = 0;
-       virtual void audio (boost::shared_ptr<AudioBuffers>, DCPTime) = 0;
-       virtual void subtitle (PlayerSubtitles, DCPTimePeriod) = 0;
-
        boost::shared_ptr<const Film> _film;
        boost::weak_ptr<Job> _job;
        boost::shared_ptr<Player> _player;
-
-       boost::signals2::scoped_connection _player_video_connection;
-       boost::signals2::scoped_connection _player_audio_connection;
-       boost::signals2::scoped_connection _player_subtitle_connection;
 };
 
 #endif
index 9dba02dd5588c72ef9d57cc38d9a4e774893cc2a..2a9146f116520b6bffaabdd5ad7c58166ca329d1 100644 (file)
@@ -26,6 +26,7 @@
 #include "log.h"
 #include "image.h"
 #include "cross.h"
+#include "butler.h"
 #include "compose.hpp"
 #include <iostream>
 
@@ -34,6 +35,7 @@
 using std::string;
 using std::runtime_error;
 using std::cout;
+using std::pair;
 using boost::shared_ptr;
 using boost::bind;
 using boost::weak_ptr;
@@ -75,24 +77,29 @@ FFmpegEncoder::FFmpegEncoder (shared_ptr<const Film> film, weak_ptr<Job> job, bo
 
        int const ch = film->audio_channels ();
 
+       AudioMapping map;
        if (mixdown_to_stereo) {
-               _audio_mapping = AudioMapping (ch, 2);
+               _output_audio_channels = 2;
+               map = AudioMapping (ch, 2);
                float const overall_gain = 2 / (4 + sqrt(2));
                float const minus_3dB = 1 / sqrt(2);
-               _audio_mapping.set (dcp::LEFT,   0, overall_gain);
-               _audio_mapping.set (dcp::RIGHT,  1, overall_gain);
-               _audio_mapping.set (dcp::CENTRE, 0, overall_gain * minus_3dB);
-               _audio_mapping.set (dcp::CENTRE, 1, overall_gain * minus_3dB);
-               _audio_mapping.set (dcp::LS,     0, overall_gain);
-               _audio_mapping.set (dcp::RS,     1, overall_gain);
+               map.set (dcp::LEFT,   0, overall_gain);
+               map.set (dcp::RIGHT,  1, overall_gain);
+               map.set (dcp::CENTRE, 0, overall_gain * minus_3dB);
+               map.set (dcp::CENTRE, 1, overall_gain * minus_3dB);
+               map.set (dcp::LS,     0, overall_gain);
+               map.set (dcp::RS,     1, overall_gain);
                _pending_audio.reset (new AudioBuffers (2, 0));
        } else {
-               _audio_mapping = AudioMapping (ch, ch);
+               _output_audio_channels = ch;
+               map = AudioMapping (ch, ch);
                _pending_audio.reset (new AudioBuffers (ch, 0));
                for (int i = 0; i < ch; ++i) {
-                       _audio_mapping.set (i, i, 1);
+                       map.set (i, i, 1);
                }
        }
+
+       _butler.reset (new Butler (film, _player, map, _output_audio_channels));
 }
 
 void
@@ -138,8 +145,8 @@ FFmpegEncoder::setup_audio ()
        _audio_codec_context->bit_rate = 256 * 1024;
        _audio_codec_context->sample_fmt = _sample_format;
        _audio_codec_context->sample_rate = _film->audio_frame_rate ();
-       _audio_codec_context->channel_layout = av_get_default_channel_layout (_audio_mapping.output_channels ());
-       _audio_codec_context->channels = _audio_mapping.output_channels ();
+       _audio_codec_context->channel_layout = av_get_default_channel_layout (_output_audio_channels);
+       _audio_codec_context->channels = _output_audio_channels;
 }
 
 void
@@ -194,7 +201,24 @@ FFmpegEncoder::go ()
                job->sub (_("Encoding"));
        }
 
-       while (!_player->pass ()) {}
+       DCPTime const video_frame = DCPTime::from_frames (1, _film->video_frame_rate ());
+       int const audio_frames = video_frame.frames_round(_film->audio_frame_rate());
+       float* interleaved = new float[_output_audio_channels * audio_frames];
+       shared_ptr<AudioBuffers> deinterleaved (new AudioBuffers (_output_audio_channels, audio_frames));
+       for (DCPTime i; i < _film->length(); i += video_frame) {
+               pair<shared_ptr<PlayerVideo>, DCPTime> v = _butler->get_video ();
+               video (v.first, v.second);
+               _butler->get_audio (interleaved, audio_frames);
+               /* XXX: inefficient; butler interleaves and we deinterleave again */
+               float* p = interleaved;
+               for (int i = 0; i < audio_frames; ++i) {
+                       for (int j = 0; j < _output_audio_channels; ++j) {
+                               deinterleaved->data(j)[i] = *p++;
+                       }
+               }
+               audio (deinterleaved, i);
+       }
+       delete[] interleaved;
 
        if (_pending_audio->frames() > 0) {
                audio_frame (_pending_audio->frames ());
@@ -308,7 +332,7 @@ FFmpegEncoder::video (shared_ptr<PlayerVideo> video, DCPTime time)
 void
 FFmpegEncoder::audio (shared_ptr<AudioBuffers> audio, DCPTime)
 {
-       _pending_audio->append (remap (audio, _audio_mapping.output_channels(), _audio_mapping));
+       _pending_audio->append (audio);
 
        int frame_size = _audio_codec_context->frame_size;
        if (frame_size == 0) {
index 5ab59c12dcdcfe640ae5bc5902bc7be58a43d348..5e6dcecf75d1ee556314d9ff8cddea1f49d12752 100644 (file)
@@ -28,6 +28,9 @@ extern "C" {
 #include <libavcodec/avcodec.h>
 #include <libavformat/avformat.h>
 }
+#include <boost/thread/condition.hpp>
+
+class Butler;
 
 class FFmpegEncoder : public Encoder
 {
@@ -70,7 +73,7 @@ private:
        AVDictionary* _video_options;
        std::string _video_codec_name;
        std::string _audio_codec_name;
-       AudioMapping _audio_mapping;
+       int _output_audio_channels;
 
        mutable boost::mutex _mutex;
        DCPTime _last_time;
@@ -81,6 +84,12 @@ private:
 
        boost::shared_ptr<AudioBuffers> _pending_audio;
 
+       mutable boost::mutex _queue_mutex;
+       boost::condition _queue_full;
+       std::list<std::pair<boost::shared_ptr<PlayerVideo>, DCPTime> > _queue;
+
+       boost::shared_ptr<Butler> _butler;
+
        static int _video_stream_index;
        static int _audio_stream_index;
 };