6e2e7ed140bd00415d432ee53ce7e21e540b8a2d
[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 "imagemagick_decoder.h"
24 #include "sndfile_decoder.h"
25 #include "playlist.h"
26 #include "job.h"
27
28 using std::list;
29 using boost::shared_ptr;
30
31 Player::Player (shared_ptr<const Film> f, shared_ptr<const Playlist> p)
32         : _film (f)
33         , _playlist (p)
34         , _video (true)
35         , _audio (true)
36         , _subtitles (true)
37         , _have_setup_decoders (false)
38         , _ffmpeg_decoder_done (false)
39         , _video_sync (true)
40 {
41
42 }
43
44 void
45 Player::disable_video ()
46 {
47         _video = false;
48 }
49
50 void
51 Player::disable_audio ()
52 {
53         _audio = false;
54 }
55
56 void
57 Player::disable_subtitles ()
58 {
59         _subtitles = false;
60 }
61
62 bool
63 Player::pass ()
64 {
65         if (!_have_setup_decoders) {
66                 setup_decoders ();
67                 _have_setup_decoders = true;
68         }
69         
70         bool done = true;
71         
72         if (_playlist->video_from() == Playlist::VIDEO_FFMPEG || _playlist->audio_from() == Playlist::AUDIO_FFMPEG) {
73                 if (!_ffmpeg_decoder_done) {
74                         if (_ffmpeg_decoder->pass ()) {
75                                 _ffmpeg_decoder_done = true;
76                         } else {
77                                 done = false;
78                         }
79                 }
80         }
81
82         if (_playlist->video_from() == Playlist::VIDEO_IMAGEMAGICK) {
83                 if (_imagemagick_decoder != _imagemagick_decoders.end ()) {
84                         if ((*_imagemagick_decoder)->pass ()) {
85                                 _imagemagick_decoder++;
86                         }
87
88                         if (_imagemagick_decoder != _imagemagick_decoders.end ()) {
89                                 done = false;
90                         }
91                 }
92         }
93
94         /* XXX: sndfile */
95
96         return done;
97 }
98
99 void
100 Player::set_progress (shared_ptr<Job> job)
101 {
102         /* Assume progress can be divined from how far through the video we are */
103         switch (_playlist->video_from ()) {
104         case Playlist::VIDEO_NONE:
105                 break;
106         case Playlist::VIDEO_FFMPEG:
107                 if (_playlist->video_length ()) {
108                         job->set_progress (float(_ffmpeg_decoder->video_frame()) / _playlist->video_length ());
109                 }
110                 break;
111         case Playlist::VIDEO_IMAGEMAGICK:
112         {
113                 int n = 0;
114                 for (list<shared_ptr<ImageMagickDecoder> >::iterator i = _imagemagick_decoders.begin(); i != _imagemagick_decoders.end(); ++i) {
115                         if (_imagemagick_decoder == i) {
116                                 job->set_progress (float (n) / _imagemagick_decoders.size ());
117                         }
118                         ++n;
119                 }
120                 break;
121         }
122         }
123 }
124
125 void
126 Player::process_video (shared_ptr<Image> i, bool same, shared_ptr<Subtitle> s)
127 {
128         Video (i, same, s);
129 }
130
131 void
132 Player::process_audio (shared_ptr<AudioBuffers> b)
133 {
134         Audio (b);
135 }
136
137 /** @return true on error */
138 bool
139 Player::seek (double t)
140 {
141         if (!_have_setup_decoders) {
142                 setup_decoders ();
143                 _have_setup_decoders = true;
144         }
145         
146         bool r = false;
147
148         switch (_playlist->video_from()) {
149         case Playlist::VIDEO_NONE:
150                 break;
151         case Playlist::VIDEO_FFMPEG:
152                 if (!_ffmpeg_decoder || _ffmpeg_decoder->seek (t)) {
153                         r = true;
154                 }
155                 /* We're seeking, so all `all done' bets are off */
156                 _ffmpeg_decoder_done = false;
157                 break;
158         case Playlist::VIDEO_IMAGEMAGICK:
159                 /* Find the decoder that contains this position */
160                 _imagemagick_decoder = _imagemagick_decoders.begin ();
161                 while (_imagemagick_decoder != _imagemagick_decoders.end ()) {
162                         double const this_length = (*_imagemagick_decoder)->video_length() / _film->video_frame_rate ();
163                         if (t < this_length) {
164                                 break;
165                         }
166                         t -= this_length;
167                         ++_imagemagick_decoder;
168                 }
169
170                 if (_imagemagick_decoder != _imagemagick_decoders.end()) {
171                         (*_imagemagick_decoder)->seek (t);
172                 } else {
173                         r = true;
174                 }
175                 break;
176         }
177
178         /* XXX: don't seek audio because we don't need to... */
179
180         return r;
181 }
182
183 bool
184 Player::seek_to_last ()
185 {
186         if (!_have_setup_decoders) {
187                 setup_decoders ();
188                 _have_setup_decoders = true;
189         }
190
191         bool r = false;
192         
193         switch (_playlist->video_from ()) {
194         case Playlist::VIDEO_NONE:
195                 break;
196         case Playlist::VIDEO_FFMPEG:
197                 if (!_ffmpeg_decoder || _ffmpeg_decoder->seek_to_last ()) {
198                         r = true;
199                 }
200
201                 /* We're seeking, so all `all done' bets are off */
202                 _ffmpeg_decoder_done = false;
203                 break;
204         case Playlist::VIDEO_IMAGEMAGICK:
205                 if ((*_imagemagick_decoder)->seek_to_last ()) {
206                         r = true;
207                 }
208                 break;
209         }
210
211         /* XXX: don't seek audio because we don't need to... */
212
213         return r;
214 }
215
216 void
217 Player::setup_decoders ()
218 {
219         if ((_video && _playlist->video_from() == Playlist::VIDEO_FFMPEG) || (_audio && _playlist->audio_from() == Playlist::AUDIO_FFMPEG)) {
220                 _ffmpeg_decoder.reset (
221                         new FFmpegDecoder (
222                                 _film,
223                                 _playlist->ffmpeg(),
224                                 _video && _playlist->video_from() == Playlist::VIDEO_FFMPEG,
225                                 _audio && _playlist->audio_from() == Playlist::AUDIO_FFMPEG,
226                                 _subtitles && _film->with_subtitles(),
227                                 _video_sync
228                                 )
229                         );
230         }
231         
232         if (_video && _playlist->video_from() == Playlist::VIDEO_FFMPEG) {
233                 _ffmpeg_decoder->connect_video (shared_from_this ());
234         }
235
236         if (_audio && _playlist->audio_from() == Playlist::AUDIO_FFMPEG) {
237                 _ffmpeg_decoder->connect_audio (shared_from_this ());
238         }
239
240         if (_video && _playlist->video_from() == Playlist::VIDEO_IMAGEMAGICK) {
241                 list<shared_ptr<const ImageMagickContent> > ic = _playlist->imagemagick ();
242                 for (list<shared_ptr<const ImageMagickContent> >::iterator i = ic.begin(); i != ic.end(); ++i) {
243                         shared_ptr<ImageMagickDecoder> d (new ImageMagickDecoder (_film, *i));
244                         _imagemagick_decoders.push_back (d);
245                         d->connect_video (shared_from_this ());
246                 }
247
248                 _imagemagick_decoder = _imagemagick_decoders.begin ();
249         }
250
251         if (_audio && _playlist->audio_from() == Playlist::AUDIO_SNDFILE) {
252                 list<shared_ptr<const SndfileContent> > sc = _playlist->sndfile ();
253                 for (list<shared_ptr<const SndfileContent> >::iterator i = sc.begin(); i != sc.end(); ++i) {
254                         shared_ptr<SndfileDecoder> d (new SndfileDecoder (_film, *i));
255                         _sndfile_decoders.push_back (d);
256                         d->connect_audio (shared_from_this ());
257                 }
258         }
259 }
260
261 void
262 Player::disable_video_sync ()
263 {
264         _video_sync = false;
265 }
266
267 double
268 Player::last_video_time () const
269 {
270         switch (_playlist->video_from ()) {
271         case Playlist::VIDEO_NONE:
272                 return 0;
273         case Playlist::VIDEO_FFMPEG:
274                 return _ffmpeg_decoder->last_source_time ();
275         case Playlist::VIDEO_IMAGEMAGICK:
276                 return (*_imagemagick_decoder)->last_source_time ();
277         }
278
279         return 0;
280 }