Use cxml::ConstNodePtr.
[dcpomatic.git] / src / lib / player.h
1 /*
2     Copyright (C) 2013-2014 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 #ifndef DCPOMATIC_PLAYER_H
21 #define DCPOMATIC_PLAYER_H
22
23 #include <list>
24 #include <boost/shared_ptr.hpp>
25 #include <boost/enable_shared_from_this.hpp>
26 #include "playlist.h"
27 #include "content.h"
28 #include "film.h"
29 #include "rect.h"
30 #include "audio_content.h"
31 #include "dcpomatic_time.h"
32 #include "content_subtitle.h"
33 #include "position_image.h"
34 #include "piece.h"
35 #include "content_video.h"
36
37 class Job;
38 class Film;
39 class Playlist;
40 class AudioContent;
41 class Piece;
42 class Image;
43 class DCPVideo;
44 class Decoder;
45
46 class PlayerStatistics
47 {
48 public:
49         struct Video {
50                 Video ()
51                         : black (0)
52                         , repeat (0)
53                         , good (0)
54                         , skip (0)
55                 {}
56                 
57                 int black;
58                 int repeat;
59                 int good;
60                 int skip;
61         } video;
62
63         struct Audio {
64                 Audio ()
65                         : silence (0)
66                         , good (0)
67                         , skip (0)
68                 {}
69                 
70                 DCPTime silence;
71                 int64_t good;
72                 int64_t skip;
73         } audio;
74
75         void dump (boost::shared_ptr<Log>) const;
76 };
77
78 /** @class PlayerImage
79  *  @brief A wrapper for an Image which contains some pending operations; these may
80  *  not be necessary if the receiver of the PlayerImage throws it away.
81  */
82 class PlayerImage
83 {
84 public:
85         PlayerImage (boost::shared_ptr<const Image>, Crop, dcp::Size, dcp::Size, Scaler const *);
86
87         void set_subtitle (boost::shared_ptr<const Image>, Position<int>);
88         
89         boost::shared_ptr<Image> image ();
90         
91 private:
92         boost::shared_ptr<const Image> _in;
93         Crop _crop;
94         dcp::Size _inter_size;
95         dcp::Size _out_size;
96         Scaler const * _scaler;
97         boost::shared_ptr<const Image> _subtitle_image;
98         Position<int> _subtitle_position;
99 };
100
101 /** @class Player
102  *  @brief A class which can `play' a Playlist.
103  */
104 class Player : public boost::enable_shared_from_this<Player>, public boost::noncopyable
105 {
106 public:
107         Player (boost::shared_ptr<const Film>, boost::shared_ptr<const Playlist>);
108
109         std::list<boost::shared_ptr<DCPVideo> > get_video (DCPTime time, bool accurate);
110         boost::shared_ptr<AudioBuffers> get_audio (DCPTime time, DCPTime length, bool accurate);
111
112         void set_video_container_size (dcp::Size);
113         void set_approximate_size ();
114         void set_burn_subtitles (bool burn) {
115                 _burn_subtitles = burn;
116         }
117
118         PlayerStatistics const & statistics () const;
119         
120         /** Emitted when something has changed such that if we went back and emitted
121          *  the last frame again it would look different.  This is not emitted after
122          *  a seek.
123          *
124          *  The parameter is true if these signals are currently likely to be frequent.
125          */
126         boost::signals2::signal<void (bool)> Changed;
127
128 private:
129         friend class PlayerWrapper;
130         friend class Piece;
131         friend class player_overlaps_test;
132
133         void setup_pieces ();
134         void playlist_changed ();
135         void content_changed (boost::weak_ptr<Content>, int, bool);
136         void flush ();
137         void film_changed (Film::Property);
138         std::list<PositionImage> process_content_image_subtitles (
139                 boost::shared_ptr<SubtitleContent>, std::list<boost::shared_ptr<ContentImageSubtitle> >
140                 ) const;
141         std::list<PositionImage> process_content_text_subtitles (std::list<boost::shared_ptr<ContentTextSubtitle> >) const;
142         void update_subtitle_from_text ();
143         VideoFrame dcp_to_content_video (boost::shared_ptr<const Piece> piece, DCPTime t) const;
144         AudioFrame dcp_to_content_audio (boost::shared_ptr<const Piece> piece, DCPTime t) const;
145         ContentTime dcp_to_content_subtitle (boost::shared_ptr<const Piece> piece, DCPTime t) const;
146         boost::shared_ptr<DCPVideo> black_dcp_video (DCPTime) const;
147         boost::shared_ptr<DCPVideo> content_to_dcp (
148                 boost::shared_ptr<VideoContent> content,
149                 ContentVideo content_video,
150                 std::list<boost::shared_ptr<Piece> > subs,
151                 DCPTime time,
152                 dcp::Size image_size
153                 ) const;
154
155         /** @return Pieces of content type C that overlap a specified time range in the DCP */
156         template<class C>
157         std::list<boost::shared_ptr<Piece> >
158         overlaps (DCPTime from, DCPTime to)
159         {
160                 if (!_have_valid_pieces) {
161                         setup_pieces ();
162                 }
163
164                 std::list<boost::shared_ptr<Piece> > overlaps;
165                 for (typename std::list<boost::shared_ptr<Piece> >::const_iterator i = _pieces.begin(); i != _pieces.end(); ++i) {
166                         if (!boost::dynamic_pointer_cast<C> ((*i)->content)) {
167                                 continue;
168                         }
169
170                         if ((*i)->content->position() <= to && (*i)->content->end() >= from) {
171                                 overlaps.push_back (*i);
172                         }
173                 }
174                 
175                 return overlaps;
176         }
177         
178         boost::shared_ptr<const Film> _film;
179         boost::shared_ptr<const Playlist> _playlist;
180
181         /** Our pieces are ready to go; if this is false the pieces must be (re-)created before they are used */
182         bool _have_valid_pieces;
183         std::list<boost::shared_ptr<Piece> > _pieces;
184
185         dcp::Size _video_container_size;
186         boost::shared_ptr<Image> _black_image;
187
188         bool _approximate_size;
189         bool _burn_subtitles;
190
191         PlayerStatistics _statistics;
192
193         boost::signals2::scoped_connection _playlist_changed_connection;
194         boost::signals2::scoped_connection _playlist_content_changed_connection;
195         boost::signals2::scoped_connection _film_changed_connection;
196 };
197
198 #endif