Try to clean up some aspects of video/audio/video-audio content; fixes crash with...
[dcpomatic.git] / src / lib / player.cc
1 /*
2     Copyright (C) 2013 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 #include "player.h"
21 #include "film.h"
22 #include "ffmpeg_decoder.h"
23 #include "ffmpeg_content.h"
24 #include "imagemagick_decoder.h"
25 #include "imagemagick_content.h"
26 #include "sndfile_decoder.h"
27 #include "sndfile_content.h"
28 #include "playlist.h"
29 #include "job.h"
30
31 using std::list;
32 using std::cout;
33 using boost::shared_ptr;
34 using boost::weak_ptr;
35 using boost::dynamic_pointer_cast;
36
37 Player::Player (shared_ptr<const Film> f, shared_ptr<const Playlist> p)
38         : _film (f)
39         , _playlist (p)
40         , _video (true)
41         , _audio (true)
42         , _subtitles (true)
43         , _have_valid_decoders (false)
44 {
45         _playlist->Changed.connect (bind (&Player::playlist_changed, this));
46         _playlist->ContentChanged.connect (bind (&Player::content_changed, this, _1, _2));
47 }
48
49 void
50 Player::disable_video ()
51 {
52         _video = false;
53 }
54
55 void
56 Player::disable_audio ()
57 {
58         _audio = false;
59 }
60
61 void
62 Player::disable_subtitles ()
63 {
64         _subtitles = false;
65 }
66
67 bool
68 Player::pass ()
69 {
70         if (!_have_valid_decoders) {
71                 setup_decoders ();
72                 _have_valid_decoders = true;
73         }
74         
75         bool done = true;
76         
77         if (_video_decoder != _video_decoders.end ()) {
78
79                 /* Run video decoder; this may also produce audio */
80                 
81                 if ((*_video_decoder)->pass ()) {
82                         _video_decoder++;
83                 }
84                 
85                 if (_video_decoder != _video_decoders.end ()) {
86                         done = false;
87                 }
88                 
89         } else if (!_video && _playlist->audio_from() == Playlist::AUDIO_FFMPEG && _sequential_audio_decoder != _audio_decoders.end ()) {
90
91                 /* We're not producing video, so we may need to run FFmpeg content to get the audio */
92                 
93                 if ((*_sequential_audio_decoder)->pass ()) {
94                         _sequential_audio_decoder++;
95                 }
96                 
97                 if (_sequential_audio_decoder != _audio_decoders.end ()) {
98                         done = false;
99                 }
100                 
101         } else if (_playlist->audio_from() == Playlist::AUDIO_SNDFILE) {
102
103                 /* We're getting audio from SndfileContent */
104                 
105                 for (list<shared_ptr<AudioDecoder> >::iterator i = _audio_decoders.begin(); i != _audio_decoders.end(); ++i) {
106                         if (!(*i)->pass ()) {
107                                 done = false;
108                         }
109                 }
110
111                 Audio (_audio_buffers, _audio_time.get());
112                 _audio_buffers.reset ();
113                 _audio_time = boost::none;
114         }
115
116         return done;
117 }
118
119 void
120 Player::set_progress (shared_ptr<Job> job)
121 {
122         /* Assume progress can be divined from how far through the video we are */
123
124         if (_video_decoder == _video_decoders.end() || !_playlist->video_length()) {
125                 return;
126         }
127         
128         ContentVideoFrame p = 0;
129         list<shared_ptr<VideoDecoder> >::iterator i = _video_decoders.begin ();
130         while (i != _video_decoders.end() && i != _video_decoder) {
131                 p += (*i)->video_length ();
132         }
133
134         job->set_progress (float ((*_video_decoder)->video_frame ()) / _playlist->video_length ());
135 }
136
137 void
138 Player::process_video (shared_ptr<Image> i, bool same, shared_ptr<Subtitle> s, double t)
139 {
140         /* XXX: this time will need mangling to add on the offset of the start of the content */
141         Video (i, same, s, t);
142 }
143
144 void
145 Player::process_audio (weak_ptr<const AudioContent> c, shared_ptr<AudioBuffers> b, double t)
146 {
147         /* XXX: this time will need mangling to add on the offset of the start of the content */
148         AudioMapping mapping = _film->audio_mapping ();
149         if (!_audio_buffers) {
150                 _audio_buffers.reset (new AudioBuffers (mapping.dcp_channels(), b->frames ()));
151                 _audio_buffers->make_silent ();
152                 _audio_time = t;
153         }
154
155         for (int i = 0; i < b->channels(); ++i) {
156                 list<libdcp::Channel> dcp = mapping.content_to_dcp (AudioMapping::Channel (c, i));
157                 for (list<libdcp::Channel>::iterator j = dcp.begin(); j != dcp.end(); ++j) {
158                         _audio_buffers->accumulate (b, i, static_cast<int> (*j));
159                 }
160         }
161
162         if (_playlist->audio_from() == Playlist::AUDIO_FFMPEG) {
163                 /* We can just emit this audio now as it will all be here */
164                 Audio (_audio_buffers, t);
165                 _audio_buffers.reset ();
166                 _audio_time = boost::none;
167         }
168 }
169
170 /** @return true on error */
171 bool
172 Player::seek (double t)
173 {
174         if (!_have_valid_decoders) {
175                 setup_decoders ();
176                 _have_valid_decoders = true;
177         }
178
179         /* Find the decoder that contains this position */
180         _video_decoder = _video_decoders.begin ();
181         while (_video_decoder != _video_decoders.end ()) {
182                 double const this_length = double ((*_video_decoder)->video_length()) / _film->video_frame_rate ();
183                 if (t < this_length) {
184                         break;
185                 }
186                 t -= this_length;
187                 ++_video_decoder;
188         }
189         
190         if (_video_decoder != _video_decoders.end()) {
191                 (*_video_decoder)->seek (t);
192         } else {
193                 return true;
194         }
195
196         /* XXX: don't seek audio because we don't need to... */
197
198         return false;
199 }
200
201
202 void
203 Player::seek_back ()
204 {
205         /* XXX */
206 }
207
208 void
209 Player::seek_forward ()
210 {
211         /* XXX */
212 }
213
214
215 void
216 Player::setup_decoders ()
217 {
218         _video_decoders.clear ();
219         _video_decoder = _video_decoders.end ();
220         _audio_decoders.clear ();
221         
222         if (_video) {
223                 list<shared_ptr<const VideoContent> > vc = _playlist->video ();
224                 for (list<shared_ptr<const VideoContent> >::iterator i = vc.begin(); i != vc.end(); ++i) {
225
226                         shared_ptr<VideoDecoder> d;
227                         
228                         /* XXX: into content? */
229                         
230                         shared_ptr<const FFmpegContent> fc = dynamic_pointer_cast<const FFmpegContent> (*i);
231                         if (fc) {
232                                 shared_ptr<FFmpegDecoder> fd (
233                                         new FFmpegDecoder (
234                                                 _film, fc, _video,
235                                                 _audio && _playlist->audio_from() == Playlist::AUDIO_FFMPEG,
236                                                 _subtitles
237                                                 )
238                                         );
239
240                                 if (_playlist->audio_from() == Playlist::AUDIO_FFMPEG) {
241                                         fd->Audio.connect (bind (&Player::process_audio, this, fc, _1, _2));
242                                 }
243
244                                 d = fd;
245                         }
246
247                         shared_ptr<const ImageMagickContent> ic = dynamic_pointer_cast<const ImageMagickContent> (*i);
248                         if (ic) {
249                                 d.reset (new ImageMagickDecoder (_film, ic));
250                         }
251
252                         d->connect_video (shared_from_this ());
253                         _video_decoders.push_back (d);
254                 }
255
256                 _video_decoder = _video_decoders.begin ();
257         }
258
259         if (_playlist->audio_from() == Playlist::AUDIO_FFMPEG && !_video) {
260
261                 /* If we're getting audio from FFmpegContent but not the video, we need a set
262                    of decoders for the audio.
263                 */
264                 
265                 list<shared_ptr<const AudioContent> > ac = _playlist->audio ();
266                 for (list<shared_ptr<const AudioContent> >::iterator i = ac.begin(); i != ac.end(); ++i) {
267
268                         shared_ptr<const FFmpegContent> fc = dynamic_pointer_cast<const FFmpegContent> (*i);
269                         assert (fc);
270                         
271                         shared_ptr<AudioDecoder> d (
272                                 new FFmpegDecoder (
273                                         _film, fc, _video,
274                                         _audio && _playlist->audio_from() == Playlist::AUDIO_FFMPEG,
275                                         _subtitles
276                                         )
277                                 );
278
279                         d->Audio.connect (bind (&Player::process_audio, this, fc, _1, _2));
280                         _audio_decoders.push_back (d);
281                 }
282
283                 _sequential_audio_decoder = _audio_decoders.begin ();
284         }
285
286         if (_playlist->audio_from() == Playlist::AUDIO_SNDFILE) {
287                 
288                 list<shared_ptr<const AudioContent> > ac = _playlist->audio ();
289                 for (list<shared_ptr<const AudioContent> >::iterator i = ac.begin(); i != ac.end(); ++i) {
290                         
291                         shared_ptr<const SndfileContent> sc = dynamic_pointer_cast<const SndfileContent> (*i);
292                         assert (sc);
293                         
294                         shared_ptr<AudioDecoder> d (new SndfileDecoder (_film, sc));
295                         d->Audio.connect (bind (&Player::process_audio, this, sc, _1, _2));
296                         _audio_decoders.push_back (d);
297                 }
298         }
299 }
300
301 double
302 Player::last_video_time () const
303 {
304         double t = 0;
305         for (list<shared_ptr<VideoDecoder> >::const_iterator i = _video_decoders.begin(); i != _video_decoder; ++i) {
306                 t += (*i)->video_length() / (*i)->video_frame_rate ();
307         }
308
309         return t + (*_video_decoder)->last_content_time ();
310 }
311
312 void
313 Player::content_changed (weak_ptr<Content> w, int p)
314 {
315         shared_ptr<Content> c = w.lock ();
316         if (!c) {
317                 return;
318         }
319
320         if (p == VideoContentProperty::VIDEO_LENGTH) {
321                 if (dynamic_pointer_cast<FFmpegContent> (c)) {
322                         /* FFmpeg content length changes are serious; we need new decoders */
323                         _have_valid_decoders = false;
324                 }
325         }
326 }
327
328 void
329 Player::playlist_changed ()
330 {
331         _have_valid_decoders = false;
332 }