Try to tidy up frame indexing; use DCP length obtained from the transcode to make...
[dcpomatic.git] / src / lib / make_dcp_job.cc
1 /*
2     Copyright (C) 2012 Carl Hetherington <cth@carlh.net>
3
4     This program is free software; you can redistribute it and/or modify
5     it under the terms of the GNU General Public License as published by
6     the Free Software Foundation; either version 2 of the License, or
7     (at your option) any later version.
8
9     This program is distributed in the hope that it will be useful,
10     but WITHOUT ANY WARRANTY; without even the implied warranty of
11     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12     GNU General Public License for more details.
13
14     You should have received a copy of the GNU General Public License
15     along with this program; if not, write to the Free Software
16     Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
17
18 */
19
20 /** @file src/make_dcp_job.cc
21  *  @brief A job to create DCPs.
22  */
23
24 #include <iostream>
25 #include <boost/filesystem.hpp>
26 #include <libdcp/dcp.h>
27 #include <libdcp/picture_asset.h>
28 #include <libdcp/sound_asset.h>
29 #include <libdcp/reel.h>
30 extern "C" {
31 #include <libavutil/pixdesc.h>
32 }
33 #include "make_dcp_job.h"
34 #include "dcp_content_type.h"
35 #include "exceptions.h"
36 #include "options.h"
37 #include "imagemagick_decoder.h"
38 #include "film.h"
39 #include "format.h"
40
41 using std::string;
42 using std::cout;
43 using boost::shared_ptr;
44
45 /** @param f Film we are making the DCP for.
46  *  @param o Options.
47  */
48 MakeDCPJob::MakeDCPJob (shared_ptr<Film> f, shared_ptr<Job> req)
49         : Job (f, req)
50 {
51         
52 }
53
54 string
55 MakeDCPJob::name () const
56 {
57         return String::compose ("Make DCP for %1", _film->name());
58 }
59
60 /** @param f DCP frame index */
61 string
62 MakeDCPJob::j2c_path (int f, int offset) const
63 {
64         return _film->frame_out_path (f, false);
65 }
66
67 string
68 MakeDCPJob::wav_path (libdcp::Channel c) const
69 {
70         return _film->multichannel_audio_out_path (int (c), false);
71 }
72
73 void
74 MakeDCPJob::run ()
75 {
76         if (!_film->dcp_intrinsic_duration()) {
77                 throw EncodeError ("cannot make a DCP when its intrinsic duration is not known");
78         }
79
80         descend (0.9);
81         
82         string const dcp_path = _film->dir (_film->dcp_name());
83
84         /* Remove any old DCP */
85         boost::filesystem::remove_all (dcp_path);
86
87         int const frames = _film->dcp_intrinsic_duration().get();
88         int const duration = frames - _film->trim_start() - _film->trim_end();
89         DCPFrameRate const dfr (_film->frames_per_second ());
90
91         libdcp::DCP dcp (_film->dir (_film->dcp_name()));
92         dcp.Progress.connect (boost::bind (&MakeDCPJob::dcp_progress, this, _1));
93
94         shared_ptr<libdcp::CPL> cpl (
95                 new libdcp::CPL (_film->dir (_film->dcp_name()), _film->dcp_name(), _film->dcp_content_type()->libdcp_kind (), frames, dfr.frames_per_second)
96                 );
97         
98         dcp.add_cpl (cpl);
99
100         int frames_per_reel = 0;
101         if (_film->reel_size()) {
102                 frames_per_reel = (_film->reel_size().get() / (_film->j2k_bandwidth() / 8)) * dfr.frames_per_second;
103         } else {
104                 frames_per_reel = frames;
105         }
106
107         int frames_done = 0;
108         int reel = 0;
109
110         while (frames_done < frames) {
111
112                 descend (float (frames_per_reel) / frames);
113
114                 int this_time = std::min (frames_per_reel, (frames - frames_done));
115
116                 descend (0.8);
117
118                 shared_ptr<libdcp::MonoPictureAsset> pa (
119                         new libdcp::MonoPictureAsset (
120                                 boost::bind (&MakeDCPJob::j2c_path, this, _1, frames_done),
121                                 _film->dir (_film->dcp_name()),
122                                 String::compose ("video_%1.mxf", reel),
123                                 &dcp.Progress,
124                                 dfr.frames_per_second,
125                                 this_time,
126                                 _film->format()->dcp_size()
127                                 )
128                         );
129
130                 pa->set_entry_point (_film->trim_start ());
131                 pa->set_duration (duration);
132         
133                 ascend ();
134                 
135                 shared_ptr<libdcp::SoundAsset> sa;
136                 
137                 if (_film->audio_channels() > 0) {
138                         descend (0.1);
139                         sa.reset (
140                                 new libdcp::SoundAsset (
141                                         boost::bind (&MakeDCPJob::wav_path, this, _1),
142                                         _film->dir (_film->dcp_name()),
143                                         String::compose ("audio_%1.mxf", reel),
144                                         &dcp.Progress,
145                                         dfr.frames_per_second,
146                                         this_time,
147                                         frames_done,
148                                         dcp_audio_channels (_film->audio_channels())
149                                         )
150                                 );
151
152                         sa->set_entry_point (_film->trim_start ());
153                         sa->set_duration (duration);
154                         
155                         ascend ();
156                 }
157
158                 descend (0.1);
159                 cpl->add_reel (shared_ptr<libdcp::Reel> (new libdcp::Reel (pa, sa, shared_ptr<libdcp::SubtitleAsset> ())));
160                 ascend ();
161                 
162                 frames_done += frames_per_reel;
163                 ++reel;
164
165                 ascend ();
166         }
167
168         ascend ();
169
170         descend (0.1);
171         dcp.write_xml ();
172         ascend ();
173                 
174         set_progress (1);
175         set_state (FINISHED_OK);
176 }
177
178 void
179 MakeDCPJob::dcp_progress (float p)
180 {
181         set_progress (p);
182 }