/* Copyright (C) 2012 Carl Hetherington 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/make_dcp_job.cc * @brief A job to create DCPs. */ #include #include #include #include #include #include extern "C" { #include } #include "make_dcp_job.h" #include "dcp_content_type.h" #include "exceptions.h" #include "options.h" #include "imagemagick_decoder.h" #include "film.h" using std::string; using std::cout; using boost::shared_ptr; /** @param f Film we are making the DCP for. * @param o Options. */ MakeDCPJob::MakeDCPJob (shared_ptr f, shared_ptr o, shared_ptr req) : Job (f, req) , _opt (o) { } string MakeDCPJob::name () const { return String::compose ("Make DCP for %1", _film->name()); } /** @param f DCP frame index */ string MakeDCPJob::j2c_path (int f, int offset) const { SourceFrame const s = ((f + offset) * dcp_frame_rate(_film->frames_per_second()).skip) + _film->dcp_trim_start(); return _opt->frame_out_path (s, false); } string MakeDCPJob::wav_path (libdcp::Channel c) const { return _opt->multichannel_audio_out_path (int (c), false); } void MakeDCPJob::run () { if (!_film->dcp_length()) { throw EncodeError ("cannot make a DCP when the source length is not known"); } descend (0.9); string const dcp_path = _film->dir (_film->dcp_name()); /* Remove any old DCP */ boost::filesystem::remove_all (dcp_path); DCPFrameRate const dfr = dcp_frame_rate (_film->frames_per_second ()); int frames = 0; switch (_film->content_type ()) { case VIDEO: /* Source frames -> DCP frames */ frames = _film->dcp_length().get() / dfr.skip; break; case STILL: frames = _film->still_duration() * 24; break; } libdcp::DCP dcp (_film->dir (_film->dcp_name())); dcp.Progress.connect (boost::bind (&MakeDCPJob::dcp_progress, this, _1)); shared_ptr cpl ( new libdcp::CPL (_film->dir (_film->dcp_name()), _film->dcp_name(), _film->dcp_content_type()->libdcp_kind (), frames, dfr.frames_per_second) ); dcp.add_cpl (cpl); int frames_per_reel = 0; if (_film->reel_size()) { frames_per_reel = (_film->reel_size().get() / (_film->j2k_bandwidth() / 8)) * dfr.frames_per_second; } else { frames_per_reel = frames; } int frames_done = 0; int reel = 0; while (frames_done < frames) { descend (float (frames_per_reel) / frames); int this_time = std::min (frames_per_reel, (frames - frames_done)); descend (0.8); shared_ptr pa ( new libdcp::MonoPictureAsset ( boost::bind (&MakeDCPJob::j2c_path, this, _1, frames_done), _film->dir (_film->dcp_name()), String::compose ("video_%1.mxf", reel), &dcp.Progress, dfr.frames_per_second, this_time, _opt->out_size.width, _opt->out_size.height, _film->encrypted() ) ); ascend (); shared_ptr sa; if (_film->audio_channels() > 0) { descend (0.1); sa.reset ( new libdcp::SoundAsset ( boost::bind (&MakeDCPJob::wav_path, this, _1), _film->dir (_film->dcp_name()), String::compose ("audio_%1.mxf", reel), &dcp.Progress, dfr.frames_per_second, this_time, frames_done, dcp_audio_channels (_film->audio_channels()), _film->encrypted() ) ); ascend (); } descend (0.1); cpl->add_reel (shared_ptr (new libdcp::Reel (pa, sa, shared_ptr ()))); ascend (); frames_done += frames_per_reel; ++reel; ascend (); } ascend (); descend (0.1); dcp.write_xml (); ascend (); set_progress (1); set_state (FINISHED_OK); } void MakeDCPJob::dcp_progress (float p) { set_progress (p); }