Allow export with one audio stream per channel.
[dcpomatic.git] / src / lib / ffmpeg_encoder.cc
index ee49a06461133e8d57dece989e5afb4572cdbc7a..cf91a9fae6ae0b19849347899071bed925e25980 100644 (file)
@@ -52,6 +52,7 @@ FFmpegEncoder::FFmpegEncoder (
        ExportFormat format,
        bool mixdown_to_stereo,
        bool split_reels,
+       bool audio_stream_per_channel,
        int x264_crf
 #ifdef DCPOMATIC_VARIANT_SWAROOP
        , optional<dcp::Key> key
@@ -61,38 +62,6 @@ FFmpegEncoder::FFmpegEncoder (
        : Encoder (film, job)
        , _history (200)
 {
-       int const files = split_reels ? film->reels().size() : 1;
-       for (int i = 0; i < files; ++i) {
-
-               boost::filesystem::path filename = output;
-               string extension = boost::filesystem::extension (filename);
-               filename = boost::filesystem::change_extension (filename, "");
-
-               if (files > 1) {
-                       /// TRANSLATORS: _reel%1 here is to be added to an export filename to indicate
-                       /// which reel it is.  Preserve the %1; it will be replaced with the reel number.
-                       filename = filename.string() + String::compose(_("_reel%1"), i + 1);
-               }
-
-               _file_encoders.push_back (
-                       FileEncoderSet (
-                               _film->frame_size(),
-                               _film->video_frame_rate(),
-                               _film->audio_frame_rate(),
-                               mixdown_to_stereo ? 2 : film->audio_channels(),
-                               format,
-                               x264_crf,
-                               _film->three_d(),
-                               filename,
-                               extension
-#ifdef DCPOMATIC_VARIANT_SWAROOP
-                               , key
-                               , id
-#endif
-                               )
-                       );
-       }
-
        _player->set_always_burn_open_subtitles ();
        _player->set_play_referenced ();
 
@@ -123,16 +92,53 @@ FFmpegEncoder::FFmpegEncoder (
                }
                /* XXX: maybe we should do something better for >6 channel DCPs */
        } else {
-               _output_audio_channels = ch;
-               map = AudioMapping (ch, ch);
+               /* Our encoders don't really want to encode any channel count between 9 and 15 inclusive,
+                * so let's just use 16 channel exports for any project with more than 8 channels.
+                */
+               _output_audio_channels = ch > 8 ? 16 : ch;
+               map = AudioMapping (ch, _output_audio_channels);
                for (int i = 0; i < ch; ++i) {
                        map.set (i, i, 1);
                }
        }
 
        _butler.reset (new Butler(_player, map, _output_audio_channels, bind(&PlayerVideo::force, _1, FFmpegFileEncoder::pixel_format(format)), true, false));
+
+       int const files = split_reels ? film->reels().size() : 1;
+       for (int i = 0; i < files; ++i) {
+
+               boost::filesystem::path filename = output;
+               string extension = boost::filesystem::extension (filename);
+               filename = boost::filesystem::change_extension (filename, "");
+
+               if (files > 1) {
+                       /// TRANSLATORS: _reel%1 here is to be added to an export filename to indicate
+                       /// which reel it is.  Preserve the %1; it will be replaced with the reel number.
+                       filename = filename.string() + String::compose(_("_reel%1"), i + 1);
+               }
+
+               _file_encoders.push_back (
+                       FileEncoderSet (
+                               _film->frame_size(),
+                               _film->video_frame_rate(),
+                               _film->audio_frame_rate(),
+                               _output_audio_channels,
+                               format,
+                               audio_stream_per_channel,
+                               x264_crf,
+                               _film->three_d(),
+                               filename,
+                               extension
+#ifdef DCPOMATIC_VARIANT_SWAROOP
+                               , key
+                               , id
+#endif
+                               )
+                       );
+       }
 }
 
+
 void
 FFmpegEncoder::go ()
 {
@@ -166,6 +172,7 @@ FFmpegEncoder::go ()
                for (int j = 0; j < gets_per_frame; ++j) {
                        Butler::Error e;
                        pair<shared_ptr<PlayerVideo>, DCPTime> v = _butler->get_video (true, &e);
+                       _butler->rethrow ();
                        if (!v.first) {
                                throw ProgrammingError(__FILE__, __LINE__, String::compose("butler returned no video; error was %1", static_cast<int>(e)));
                        }
@@ -225,6 +232,7 @@ FFmpegEncoder::FileEncoderSet::FileEncoderSet (
        int audio_frame_rate,
        int channels,
        ExportFormat format,
+       bool audio_stream_per_channel,
        int x264_crf,
        bool three_d,
        boost::filesystem::path output,
@@ -238,7 +246,9 @@ FFmpegEncoder::FileEncoderSet::FileEncoderSet (
        if (three_d) {
                /// TRANSLATORS: L here is an abbreviation for "left", to indicate the left-eye part of a 3D export
                _encoders[EYES_LEFT] = shared_ptr<FFmpegFileEncoder>(
-                       new FFmpegFileEncoder(video_frame_size, video_frame_rate, audio_frame_rate, channels, format, x264_crf, String::compose("%1_%2%3", output.string(), _("L"), extension)
+                       new FFmpegFileEncoder(
+                               video_frame_size, video_frame_rate, audio_frame_rate, channels, format,
+                               audio_stream_per_channel, x264_crf, String::compose("%1_%2%3", output.string(), _("L"), extension)
 #ifdef DCPOMATIC_VARIANT_SWAROOP
                                              , key, id
 #endif
@@ -246,7 +256,9 @@ FFmpegEncoder::FileEncoderSet::FileEncoderSet (
                        );
                /// TRANSLATORS: R here is an abbreviation for "right", to indicate the right-eye part of a 3D export
                _encoders[EYES_RIGHT] = shared_ptr<FFmpegFileEncoder>(
-                       new FFmpegFileEncoder(video_frame_size, video_frame_rate, audio_frame_rate, channels, format, x264_crf, String::compose("%1_%2%3", output.string(), _("R"), extension)
+                       new FFmpegFileEncoder(
+                               video_frame_size, video_frame_rate, audio_frame_rate, channels, format,
+                               audio_stream_per_channel, x264_crf, String::compose("%1_%2%3", output.string(), _("R"), extension)
 #ifdef DCPOMATIC_VARIANT_SWAROOP
                                              , key, id
 #endif
@@ -254,7 +266,9 @@ FFmpegEncoder::FileEncoderSet::FileEncoderSet (
                        );
        } else {
                _encoders[EYES_BOTH]  = shared_ptr<FFmpegFileEncoder>(
-                       new FFmpegFileEncoder(video_frame_size, video_frame_rate, audio_frame_rate, channels, format, x264_crf, String::compose("%1%2", output.string(), extension)
+                       new FFmpegFileEncoder(
+                               video_frame_size, video_frame_rate, audio_frame_rate, channels, format,
+                               audio_stream_per_channel, x264_crf, String::compose("%1%2", output.string(), extension)
 #ifdef DCPOMATIC_VARIANT_SWAROOP
                                              , key, id
 #endif