Add interface to set up still image lengths.
[dcpomatic.git] / src / lib / playlist.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 <boost/shared_ptr.hpp>
21 #include "playlist.h"
22 #include "sndfile_content.h"
23 #include "sndfile_decoder.h"
24 #include "ffmpeg_content.h"
25 #include "ffmpeg_decoder.h"
26 #include "imagemagick_content.h"
27 #include "imagemagick_decoder.h"
28 #include "job.h"
29
30 using std::list;
31 using std::cout;
32 using std::vector;
33 using boost::shared_ptr;
34 using boost::weak_ptr;
35 using boost::dynamic_pointer_cast;
36
37 Playlist::Playlist ()
38         : _video_from (VIDEO_NONE)
39         , _audio_from (AUDIO_NONE)
40 {
41
42 }
43
44 void
45 Playlist::setup (ContentList content)
46 {
47         _video_from = VIDEO_NONE;
48         _audio_from = AUDIO_NONE;
49
50         _ffmpeg.reset ();
51         _imagemagick.clear ();
52         _sndfile.clear ();
53
54         for (list<boost::signals2::connection>::iterator i = _content_connections.begin(); i != _content_connections.end(); ++i) {
55                 i->disconnect ();
56         }
57         
58         _content_connections.clear ();
59
60         for (ContentList::const_iterator i = content.begin(); i != content.end(); ++i) {
61                 shared_ptr<FFmpegContent> fc = dynamic_pointer_cast<FFmpegContent> (*i);
62                 if (fc) {
63                         assert (!_ffmpeg);
64                         _ffmpeg = fc;
65                         _video_from = VIDEO_FFMPEG;
66                         if (_audio_from == AUDIO_NONE) {
67                                 _audio_from = AUDIO_FFMPEG;
68                         }
69                 }
70                 
71                 shared_ptr<ImageMagickContent> ic = dynamic_pointer_cast<ImageMagickContent> (*i);
72                 if (ic) {
73                         _imagemagick.push_back (ic);
74                         if (_video_from == VIDEO_NONE) {
75                                 _video_from = VIDEO_IMAGEMAGICK;
76                         }
77                 }
78
79                 shared_ptr<SndfileContent> sc = dynamic_pointer_cast<SndfileContent> (*i);
80                 if (sc) {
81                         _sndfile.push_back (sc);
82                         _audio_from = AUDIO_SNDFILE;
83                 }
84
85                 _content_connections.push_back ((*i)->Changed.connect (bind (&Playlist::content_changed, this, _1, _2)));
86         }
87
88         Changed ();
89 }
90
91 ContentAudioFrame
92 Playlist::audio_length () const
93 {
94         switch (_audio_from) {
95         case AUDIO_NONE:
96                 return 0;
97         case AUDIO_FFMPEG:
98                 return _ffmpeg->audio_length ();
99         case AUDIO_SNDFILE:
100         {
101                 ContentAudioFrame l = 0;
102                 for (list<shared_ptr<const SndfileContent> >::const_iterator i = _sndfile.begin(); i != _sndfile.end(); ++i) {
103                         l += (*i)->audio_length ();
104                 }
105                 return l;
106         }
107         }
108
109         return 0;
110 }
111
112 int
113 Playlist::audio_channels () const
114 {
115         switch (_audio_from) {
116         case AUDIO_NONE:
117                 return 0;
118         case AUDIO_FFMPEG:
119                 return _ffmpeg->audio_channels ();
120         case AUDIO_SNDFILE:
121         {
122                 int c = 0;
123                 for (list<shared_ptr<const SndfileContent> >::const_iterator i = _sndfile.begin(); i != _sndfile.end(); ++i) {
124                         c += (*i)->audio_channels ();
125                 }
126                 return c;
127         }
128         }
129
130         return 0;
131 }
132
133 int
134 Playlist::audio_frame_rate () const
135 {
136         switch (_audio_from) {
137         case AUDIO_NONE:
138                 return 0;
139         case AUDIO_FFMPEG:
140                 return _ffmpeg->audio_frame_rate ();
141         case AUDIO_SNDFILE:
142                 return _sndfile.front()->audio_frame_rate ();
143         }
144
145         return 0;
146 }
147
148 int64_t
149 Playlist::audio_channel_layout () const
150 {
151         switch (_audio_from) {
152         case AUDIO_NONE:
153                 return 0;
154         case AUDIO_FFMPEG:
155                 return _ffmpeg->audio_channel_layout ();
156         case AUDIO_SNDFILE:
157                 /* XXX */
158                 return 0;
159         }
160
161         return 0;
162 }
163
164 float
165 Playlist::video_frame_rate () const
166 {
167         switch (_video_from) {
168         case VIDEO_NONE:
169                 return 0;
170         case VIDEO_FFMPEG:
171                 return _ffmpeg->video_frame_rate ();
172         case VIDEO_IMAGEMAGICK:
173                 return 24;
174         }
175
176         return 0;
177 }
178
179 libdcp::Size
180 Playlist::video_size () const
181 {
182         switch (_video_from) {
183         case VIDEO_NONE:
184                 return libdcp::Size ();
185         case VIDEO_FFMPEG:
186                 return _ffmpeg->video_size ();
187         case VIDEO_IMAGEMAGICK:
188                 /* XXX */
189                 return _imagemagick.front()->video_size ();
190         }
191
192         return libdcp::Size ();
193 }
194
195 ContentVideoFrame
196 Playlist::video_length () const
197 {
198         switch (_video_from) {
199         case VIDEO_NONE:
200                 return 0;
201         case VIDEO_FFMPEG:
202                 return _ffmpeg->video_length ();
203         case VIDEO_IMAGEMAGICK:
204         {
205                 ContentVideoFrame l = 0;
206                 for (list<shared_ptr<const ImageMagickContent> >::const_iterator i = _imagemagick.begin(); i != _imagemagick.end(); ++i) {
207                         l += (*i)->video_length ();
208                 }
209                 return l;
210         }
211         }
212
213         return 0;
214 }
215
216 bool
217 Playlist::has_audio () const
218 {
219         return _audio_from != AUDIO_NONE;
220 }
221
222 void
223 Playlist::content_changed (weak_ptr<Content> c, int p)
224 {
225         ContentChanged (c, p);
226 }