Fix 3D support.
[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 /** A wrapper for an Image which contains some pending operations; these may
79  *  not be necessary if the receiver of the PlayerImage throws it away.
80  */
81 class PlayerImage
82 {
83 public:
84         PlayerImage (boost::shared_ptr<const Image>, Crop, dcp::Size, dcp::Size, Scaler const *);
85
86         void set_subtitle (boost::shared_ptr<const Image>, Position<int>);
87         
88         boost::shared_ptr<Image> image ();
89         
90 private:
91         boost::shared_ptr<const Image> _in;
92         Crop _crop;
93         dcp::Size _inter_size;
94         dcp::Size _out_size;
95         Scaler const * _scaler;
96         boost::shared_ptr<const Image> _subtitle_image;
97         Position<int> _subtitle_position;
98 };
99
100 /** @class Player
101  *  @brief A class which can `play' a Playlist.
102  */
103 class Player : public boost::enable_shared_from_this<Player>, public boost::noncopyable
104 {
105 public:
106         Player (boost::shared_ptr<const Film>, boost::shared_ptr<const Playlist>);
107
108         std::list<boost::shared_ptr<DCPVideo> > get_video (DCPTime time, bool accurate);
109         boost::shared_ptr<AudioBuffers> get_audio (DCPTime time, DCPTime length, bool accurate);
110
111         void set_video_container_size (dcp::Size);
112         void set_approximate_size ();
113         void set_burn_subtitles (bool burn) {
114                 _burn_subtitles = burn;
115         }
116
117         PlayerStatistics const & statistics () const;
118         
119         /** Emitted when something has changed such that if we went back and emitted
120          *  the last frame again it would look different.  This is not emitted after
121          *  a seek.
122          *
123          *  The parameter is true if these signals are currently likely to be frequent.
124          */
125         boost::signals2::signal<void (bool)> Changed;
126
127 private:
128         friend class PlayerWrapper;
129         friend class Piece;
130         friend class player_overlaps_test;
131
132         void setup_pieces ();
133         void playlist_changed ();
134         void content_changed (boost::weak_ptr<Content>, int, bool);
135         void flush ();
136         void film_changed (Film::Property);
137         std::list<PositionImage> process_content_image_subtitles (
138                 boost::shared_ptr<SubtitleContent>, std::list<boost::shared_ptr<ContentImageSubtitle> >
139                 ) const;
140         std::list<PositionImage> process_content_text_subtitles (std::list<boost::shared_ptr<ContentTextSubtitle> >) const;
141         void update_subtitle_from_text ();
142         VideoFrame dcp_to_content_video (boost::shared_ptr<const Piece> piece, DCPTime t) const;
143         AudioFrame dcp_to_content_audio (boost::shared_ptr<const Piece> piece, DCPTime t) const;
144         ContentTime dcp_to_content_subtitle (boost::shared_ptr<const Piece> piece, DCPTime t) const;
145         boost::shared_ptr<DCPVideo> black_dcp_video (DCPTime) const;
146         boost::shared_ptr<DCPVideo> content_to_dcp (
147                 boost::shared_ptr<VideoContent> content,
148                 ContentVideo content_video,
149                 std::list<boost::shared_ptr<Piece> > subs,
150                 DCPTime time,
151                 dcp::Size image_size
152                 ) const;
153
154         /** @return Pieces of content type C that overlap a specified time range in the DCP */
155         template<class C>
156         std::list<boost::shared_ptr<Piece> >
157         overlaps (DCPTime from, DCPTime to)
158         {
159                 if (!_have_valid_pieces) {
160                         setup_pieces ();
161                 }
162
163                 std::list<boost::shared_ptr<Piece> > overlaps;
164                 for (typename std::list<boost::shared_ptr<Piece> >::const_iterator i = _pieces.begin(); i != _pieces.end(); ++i) {
165                         if (!boost::dynamic_pointer_cast<C> ((*i)->content)) {
166                                 continue;
167                         }
168
169                         if ((*i)->content->position() <= to && (*i)->content->end() >= from) {
170                                 overlaps.push_back (*i);
171                         }
172                 }
173                 
174                 return overlaps;
175         }
176         
177         boost::shared_ptr<const Film> _film;
178         boost::shared_ptr<const Playlist> _playlist;
179
180         /** Our pieces are ready to go; if this is false the pieces must be (re-)created before they are used */
181         bool _have_valid_pieces;
182         std::list<boost::shared_ptr<Piece> > _pieces;
183
184         dcp::Size _video_container_size;
185         boost::shared_ptr<Image> _black_image;
186
187         bool _approximate_size;
188         bool _burn_subtitles;
189
190         PlayerStatistics _statistics;
191
192         boost::signals2::scoped_connection _playlist_changed_connection;
193         boost::signals2::scoped_connection _playlist_content_changed_connection;
194         boost::signals2::scoped_connection _film_changed_connection;
195 };
196
197 #endif