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