From 14f5424e2bd0f933965901f18b5b1673993e0045 Mon Sep 17 00:00:00 2001 From: Carl Hetherington Date: Mon, 10 Sep 2018 02:39:34 +0100 Subject: [PATCH] Basics of export of multiple reels to multiple files. --- ChangeLog | 4 +++ src/lib/ffmpeg_encoder.cc | 71 +++++++++++++++++++++++++++++-------- src/lib/ffmpeg_encoder.h | 12 +++++-- src/tools/dcpomatic.cc | 6 +++- src/wx/export_dialog.cc | 9 +++++ src/wx/export_dialog.h | 2 ++ test/ffmpeg_encoder_test.cc | 16 ++++----- 7 files changed, 94 insertions(+), 26 deletions(-) diff --git a/ChangeLog b/ChangeLog index 1e9c46f5e..4420c78a8 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,7 @@ +2018-09-10 Carl Hetherington + + * Basic export of multiple reels to multiple files. + 2018-09-09 Carl Hetherington * Updated fr_FR translation from Thierry Journet. diff --git a/src/lib/ffmpeg_encoder.cc b/src/lib/ffmpeg_encoder.cc index 2d7d41997..24ce22270 100644 --- a/src/lib/ffmpeg_encoder.cc +++ b/src/lib/ffmpeg_encoder.cc @@ -36,25 +36,52 @@ using std::string; using std::runtime_error; using std::cout; using std::pair; +using std::list; using boost::shared_ptr; using boost::bind; using boost::weak_ptr; - -FFmpegEncoder::FFmpegEncoder (shared_ptr film, weak_ptr job, boost::filesystem::path output, ExportFormat format, bool mixdown_to_stereo, int x264_crf) +FFmpegEncoder::FFmpegEncoder ( + shared_ptr film, + weak_ptr job, + boost::filesystem::path output, + ExportFormat format, + bool mixdown_to_stereo, + bool split_reels, + int x264_crf + ) : Encoder (film, job) - , _file_encoder ( - _film->frame_size(), - _film->video_frame_rate(), - _film->audio_frame_rate(), - mixdown_to_stereo ? 2 : film->audio_channels(), - _film->log(), - format, - x264_crf, - output - ) , _history (1000) { + int const files = split_reels ? film->reels().size() : 1; + for (int i = 0; i < files; ++i) { + + boost::filesystem::path filename = output; + if (files > 1) { + string extension = boost::filesystem::extension (filename); + filename = boost::filesystem::change_extension (filename, ""); + /// TRANSLATORS: _reel%1.%2 here is to be added to an export filename to indicate + /// which reel it is. Preserve the %1 and %2; %1 will be replaced with the reel number + /// and %2 with the file extension. + filename = filename.string() + String::compose(_("_reel%1%2"), i + 1, extension); + } + + _file_encoders.push_back ( + shared_ptr( + new FFmpegFileEncoder( + _film->frame_size(), + _film->video_frame_rate(), + _film->audio_frame_rate(), + mixdown_to_stereo ? 2 : film->audio_channels(), + _film->log(), + format, + x264_crf, + filename + ) + ) + ); + } + _player->set_always_burn_open_subtitles (); _player->set_play_referenced (); @@ -92,13 +119,25 @@ FFmpegEncoder::go () job->sub (_("Encoding")); } + list reel_periods = _film->reels (); + list::const_iterator reel = reel_periods.begin (); + list >::iterator encoder = _file_encoders.begin (); + 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 deinterleaved (new AudioBuffers (_output_audio_channels, audio_frames)); for (DCPTime i; i < _film->length(); i += video_frame) { + + if (!reel->contains(i)) { + ++reel; + ++encoder; + DCPOMATIC_ASSERT (reel != reel_periods.end()); + DCPOMATIC_ASSERT (encoder != _file_encoders.end()); + } + pair, DCPTime> v = _butler->get_video (); - _file_encoder.video (v.first, v.second); + (*encoder)->video (v.first, v.second); _history.event (); @@ -120,11 +159,13 @@ FFmpegEncoder::go () deinterleaved->data(k)[j] = *p++; } } - _file_encoder.audio (deinterleaved); + (*encoder)->audio (deinterleaved); } delete[] interleaved; - _file_encoder.flush (); + BOOST_FOREACH (shared_ptr i, _file_encoders) { + i->flush (); + } } float diff --git a/src/lib/ffmpeg_encoder.h b/src/lib/ffmpeg_encoder.h index 98c4704e2..9af284e6e 100644 --- a/src/lib/ffmpeg_encoder.h +++ b/src/lib/ffmpeg_encoder.h @@ -31,7 +31,15 @@ class Butler; class FFmpegEncoder : public Encoder { public: - FFmpegEncoder (boost::shared_ptr film, boost::weak_ptr job, boost::filesystem::path output, ExportFormat format, bool mixdown_to_stereo, int x264_crf); + FFmpegEncoder ( + boost::shared_ptr film, + boost::weak_ptr job, + boost::filesystem::path output, + ExportFormat format, + bool mixdown_to_stereo, + bool split_reels, + int x264_crf + ); void go (); @@ -42,7 +50,7 @@ public: } private: - FFmpegFileEncoder _file_encoder; + std::list > _file_encoders; int _output_audio_channels; mutable boost::mutex _mutex; diff --git a/src/tools/dcpomatic.cc b/src/tools/dcpomatic.cc index ded95eb44..330935ba2 100644 --- a/src/tools/dcpomatic.cc +++ b/src/tools/dcpomatic.cc @@ -835,7 +835,11 @@ private: ExportDialog* d = new ExportDialog (this); if (d->ShowModal() == wxID_OK) { shared_ptr job (new TranscodeJob (_film)); - job->set_encoder (shared_ptr (new FFmpegEncoder (_film, job, d->path(), d->format(), d->mixdown_to_stereo(), d->x264_crf()))); + job->set_encoder ( + shared_ptr ( + new FFmpegEncoder (_film, job, d->path(), d->format(), d->mixdown_to_stereo(), d->split_reels(), d->x264_crf()) + ) + ); JobManager::instance()->add (job); } d->Destroy (); diff --git a/src/wx/export_dialog.cc b/src/wx/export_dialog.cc index f75150e45..3c08da1b7 100644 --- a/src/wx/export_dialog.cc +++ b/src/wx/export_dialog.cc @@ -57,6 +57,9 @@ ExportDialog::ExportDialog (wxWindow* parent) add_spacer (); _mixdown = new wxCheckBox (this, wxID_ANY, _("Mix audio down to stereo")); add (_mixdown, false); + add_spacer (); + _split_reels = new wxCheckBox (this, wxID_ANY, _("Write reels into separate files")); + add (_split_reels, false); _x264_crf_label[0] = add (_("Quality"), true); _x264_crf = new wxSlider (this, wxID_ANY, 23, 0, 51, wxDefaultPosition, wxDefaultSize, wxSL_HORIZONTAL | wxSL_LABELS); add (_x264_crf, false); @@ -123,6 +126,12 @@ ExportDialog::mixdown_to_stereo () const return _mixdown->GetValue (); } +bool +ExportDialog::split_reels () const +{ + return _split_reels->GetValue (); +} + int ExportDialog::x264_crf () const { diff --git a/src/wx/export_dialog.h b/src/wx/export_dialog.h index d6e3bdbb6..509cd60e9 100644 --- a/src/wx/export_dialog.h +++ b/src/wx/export_dialog.h @@ -33,6 +33,7 @@ public: boost::filesystem::path path () const; ExportFormat format () const; bool mixdown_to_stereo () const; + bool split_reels () const; int x264_crf () const; private: @@ -41,6 +42,7 @@ private: wxChoice* _format; wxCheckBox* _mixdown; + wxCheckBox* _split_reels; wxSlider* _x264_crf; wxStaticText* _x264_crf_label[2]; FilePickerCtrl* _file; diff --git a/test/ffmpeg_encoder_test.cc b/test/ffmpeg_encoder_test.cc index d7bb6c29b..4b323c5bf 100644 --- a/test/ffmpeg_encoder_test.cc +++ b/test/ffmpeg_encoder_test.cc @@ -65,7 +65,7 @@ ffmpeg_content_test (int number, boost::filesystem::path content, ExportFormat f film->write_metadata (); shared_ptr job (new TranscodeJob (film)); - FFmpegEncoder encoder (film, job, String::compose("build/test/%1.%2", name, extension), format, false, 23); + FFmpegEncoder encoder (film, job, String::compose("build/test/%1.%2", name, extension), format, false, false, 23); encoder.go (); } @@ -109,7 +109,7 @@ BOOST_AUTO_TEST_CASE (ffmpeg_encoder_prores_test5) film->write_metadata (); shared_ptr job (new TranscodeJob (film)); - FFmpegEncoder encoder (film, job, "build/test/ffmpeg_encoder_prores_test5.mov", EXPORT_FORMAT_PRORES, false, 23); + FFmpegEncoder encoder (film, job, "build/test/ffmpeg_encoder_prores_test5.mov", EXPORT_FORMAT_PRORES, false, false, 23); encoder.go (); } @@ -130,7 +130,7 @@ BOOST_AUTO_TEST_CASE (ffmpeg_encoder_prores_test6) film->write_metadata(); shared_ptr job (new TranscodeJob (film)); - FFmpegEncoder encoder (film, job, "build/test/ffmpeg_encoder_prores_test6.mov", EXPORT_FORMAT_PRORES, false, 23); + FFmpegEncoder encoder (film, job, "build/test/ffmpeg_encoder_prores_test6.mov", EXPORT_FORMAT_PRORES, false, false, 23); encoder.go (); } @@ -154,7 +154,7 @@ BOOST_AUTO_TEST_CASE (ffmpeg_encoder_prores_test7) s->only_text()->set_effect_colour (dcp::Colour (0, 255, 255)); shared_ptr job (new TranscodeJob (film)); - FFmpegEncoder encoder (film, job, "build/test/ffmpeg_encoder_prores_test7.mov", EXPORT_FORMAT_PRORES, false, 23); + FFmpegEncoder encoder (film, job, "build/test/ffmpeg_encoder_prores_test7.mov", EXPORT_FORMAT_PRORES, false, false, 23); encoder.go (); } @@ -181,7 +181,7 @@ BOOST_AUTO_TEST_CASE (ffmpeg_encoder_h264_test2) film->write_metadata(); shared_ptr job (new TranscodeJob (film)); - FFmpegEncoder encoder (film, job, "build/test/ffmpeg_encoder_h264_test2.mp4", EXPORT_FORMAT_H264, false, 23); + FFmpegEncoder encoder (film, job, "build/test/ffmpeg_encoder_h264_test2.mp4", EXPORT_FORMAT_H264, false, false, 23); encoder.go (); } @@ -206,7 +206,7 @@ BOOST_AUTO_TEST_CASE (ffmpeg_encoder_h264_test3) film->write_metadata(); shared_ptr job (new TranscodeJob (film)); - FFmpegEncoder encoder (film, job, "build/test/ffmpeg_encoder_h264_test3.mp4", EXPORT_FORMAT_H264, false, 23); + FFmpegEncoder encoder (film, job, "build/test/ffmpeg_encoder_h264_test3.mp4", EXPORT_FORMAT_H264, false, false, 23); encoder.go (); } @@ -220,7 +220,7 @@ BOOST_AUTO_TEST_CASE (ffmpeg_encoder_h264_test4) film->set_container(Ratio::from_id("185")); shared_ptr job(new TranscodeJob(film)); - FFmpegEncoder encoder(film, job, "build/test/ffmpeg_encoder_h264_test4.mp4", EXPORT_FORMAT_H264, false, 23); + FFmpegEncoder encoder(film, job, "build/test/ffmpeg_encoder_h264_test4.mp4", EXPORT_FORMAT_H264, false, false, 23); encoder.go(); } @@ -274,7 +274,7 @@ BOOST_AUTO_TEST_CASE (ffmpeg_encoder_h264_test5) Rs->audio->set_mapping (map); shared_ptr job (new TranscodeJob (film)); - FFmpegEncoder encoder (film, job, "build/test/ffmpeg_encoder_h264_test5.mp4", EXPORT_FORMAT_H264, true, 23); + FFmpegEncoder encoder (film, job, "build/test/ffmpeg_encoder_h264_test5.mp4", EXPORT_FORMAT_H264, true, false, 23); encoder.go (); check_ffmpeg ("build/test/ffmpeg_encoder_h264_test5.mp4", "test/data/ffmpeg_encoder_h264_test5.mp4", 1); -- 2.30.2