Basic grunt-work, untested and unfinished, but it compiles.
[dcpomatic.git] / src / lib / player.cc
1 /*
2     Copyright (C) 2013-2016 Carl Hetherington <cth@carlh.net>
3
4     This file is part of DCP-o-matic.
5
6     DCP-o-matic is free software; you can redistribute it and/or modify
7     it under the terms of the GNU General Public License as published by
8     the Free Software Foundation; either version 2 of the License, or
9     (at your option) any later version.
10
11     DCP-o-matic is distributed in the hope that it will be useful,
12     but WITHOUT ANY WARRANTY; without even the implied warranty of
13     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14     GNU General Public License for more details.
15
16     You should have received a copy of the GNU General Public License
17     along with DCP-o-matic.  If not, see <http://www.gnu.org/licenses/>.
18
19 */
20
21 #include "player.h"
22 #include "film.h"
23 #include "audio_buffers.h"
24 #include "content_audio.h"
25 #include "dcp_content.h"
26 #include "job.h"
27 #include "image.h"
28 #include "raw_image_proxy.h"
29 #include "ratio.h"
30 #include "log.h"
31 #include "render_subtitles.h"
32 #include "config.h"
33 #include "content_video.h"
34 #include "player_video.h"
35 #include "frame_rate_change.h"
36 #include "audio_processor.h"
37 #include "playlist.h"
38 #include "referenced_reel_asset.h"
39 #include "decoder_factory.h"
40 #include "decoder.h"
41 #include "video_decoder.h"
42 #include "audio_decoder.h"
43 #include "subtitle_content.h"
44 #include "subtitle_decoder.h"
45 #include "ffmpeg_content.h"
46 #include "audio_content.h"
47 #include "content_subtitle.h"
48 #include "dcp_decoder.h"
49 #include "image_decoder.h"
50 #include <dcp/reel.h>
51 #include <dcp/reel_sound_asset.h>
52 #include <dcp/reel_subtitle_asset.h>
53 #include <dcp/reel_picture_asset.h>
54 #include <boost/foreach.hpp>
55 #include <stdint.h>
56 #include <algorithm>
57 #include <iostream>
58
59 #include "i18n.h"
60
61 #define LOG_GENERAL(...) _film->log()->log (String::compose (__VA_ARGS__), LogEntry::TYPE_GENERAL);
62
63 using std::list;
64 using std::cout;
65 using std::min;
66 using std::max;
67 using std::min;
68 using std::vector;
69 using std::pair;
70 using std::map;
71 using std::make_pair;
72 using std::copy;
73 using boost::shared_ptr;
74 using boost::weak_ptr;
75 using boost::dynamic_pointer_cast;
76 using boost::optional;
77 using boost::scoped_ptr;
78
79 static bool
80 has_video (Content* c)
81 {
82         return static_cast<bool>(c->video);
83 }
84
85 static bool
86 has_audio (Content* c)
87 {
88         return static_cast<bool>(c->audio);
89 }
90
91 static bool
92 has_subtitle (Content* c)
93 {
94         return static_cast<bool>(c->subtitle);
95 }
96
97 Player::Player (shared_ptr<const Film> film, shared_ptr<const Playlist> playlist)
98         : _film (film)
99         , _playlist (playlist)
100         , _have_valid_pieces (false)
101         , _ignore_video (false)
102         , _ignore_audio (false)
103         , _always_burn_subtitles (false)
104         , _fast (false)
105         , _play_referenced (false)
106 {
107         _film_changed_connection = _film->Changed.connect (bind (&Player::film_changed, this, _1));
108         _playlist_changed_connection = _playlist->Changed.connect (bind (&Player::playlist_changed, this));
109         _playlist_content_changed_connection = _playlist->ContentChanged.connect (bind (&Player::playlist_content_changed, this, _1, _2, _3));
110         set_video_container_size (_film->frame_size ());
111
112         film_changed (Film::AUDIO_PROCESSOR);
113 }
114
115 void
116 Player::setup_pieces ()
117 {
118         _pieces.clear ();
119
120         BOOST_FOREACH (shared_ptr<Content> i, _playlist->content ()) {
121
122                 if (!i->paths_valid ()) {
123                         continue;
124                 }
125
126                 shared_ptr<Decoder> decoder = decoder_factory (i, _film->log());
127                 FrameRateChange frc (i->active_video_frame_rate(), _film->video_frame_rate());
128
129                 if (!decoder) {
130                         /* Not something that we can decode; e.g. Atmos content */
131                         continue;
132                 }
133
134                 if (decoder->video && _ignore_video) {
135                         decoder->video->set_ignore ();
136                 }
137
138                 if (decoder->audio && _ignore_audio) {
139                         decoder->audio->set_ignore ();
140                 }
141
142                 if (decoder->audio && _fast) {
143                         decoder->audio->set_fast ();
144                 }
145
146                 shared_ptr<DCPDecoder> dcp = dynamic_pointer_cast<DCPDecoder> (decoder);
147                 if (dcp && _play_referenced) {
148                         dcp->set_decode_referenced ();
149                 }
150
151                 shared_ptr<Piece> piece (new Piece (i, decoder, frc));
152                 _pieces.push_back (piece);
153
154                 if (decoder->video) {
155                         decoder->video->Data.connect (bind (&Player::video, this, weak_ptr<Piece> (piece), _1));
156                 }
157
158                 if (decoder->audio) {
159                         decoder->audio->Data.connect (bind (&Player::audio, this, weak_ptr<Piece> (piece), _1));
160                 }
161
162                 if (decoder->subtitle) {
163                         decoder->subtitle->ImageData.connect (bind (&Player::image_subtitle, this, weak_ptr<Piece> (piece), _1));
164                         decoder->subtitle->TextData.connect (bind (&Player::text_subtitle, this, weak_ptr<Piece> (piece), _1));
165                 }
166         }
167
168         _have_valid_pieces = true;
169 }
170
171 void
172 Player::playlist_content_changed (weak_ptr<Content> w, int property, bool frequent)
173 {
174         shared_ptr<Content> c = w.lock ();
175         if (!c) {
176                 return;
177         }
178
179         if (
180                 property == ContentProperty::POSITION ||
181                 property == ContentProperty::LENGTH ||
182                 property == ContentProperty::TRIM_START ||
183                 property == ContentProperty::TRIM_END ||
184                 property == ContentProperty::PATH ||
185                 property == VideoContentProperty::FRAME_TYPE ||
186                 property == DCPContentProperty::NEEDS_ASSETS ||
187                 property == DCPContentProperty::NEEDS_KDM ||
188                 property == SubtitleContentProperty::COLOUR ||
189                 property == SubtitleContentProperty::OUTLINE ||
190                 property == SubtitleContentProperty::SHADOW ||
191                 property == SubtitleContentProperty::EFFECT_COLOUR ||
192                 property == FFmpegContentProperty::SUBTITLE_STREAM ||
193                 property == VideoContentProperty::COLOUR_CONVERSION
194                 ) {
195
196                 _have_valid_pieces = false;
197                 Changed (frequent);
198
199         } else if (
200                 property == SubtitleContentProperty::LINE_SPACING ||
201                 property == SubtitleContentProperty::OUTLINE_WIDTH ||
202                 property == SubtitleContentProperty::Y_SCALE ||
203                 property == SubtitleContentProperty::FADE_IN ||
204                 property == SubtitleContentProperty::FADE_OUT ||
205                 property == ContentProperty::VIDEO_FRAME_RATE ||
206                 property == SubtitleContentProperty::USE ||
207                 property == SubtitleContentProperty::X_OFFSET ||
208                 property == SubtitleContentProperty::Y_OFFSET ||
209                 property == SubtitleContentProperty::X_SCALE ||
210                 property == SubtitleContentProperty::FONTS ||
211                 property == VideoContentProperty::CROP ||
212                 property == VideoContentProperty::SCALE ||
213                 property == VideoContentProperty::FADE_IN ||
214                 property == VideoContentProperty::FADE_OUT
215                 ) {
216
217                 Changed (frequent);
218         }
219 }
220
221 void
222 Player::set_video_container_size (dcp::Size s)
223 {
224         _video_container_size = s;
225
226         _black_image.reset (new Image (AV_PIX_FMT_RGB24, _video_container_size, true));
227         _black_image->make_black ();
228 }
229
230 void
231 Player::playlist_changed ()
232 {
233         _have_valid_pieces = false;
234         Changed (false);
235 }
236
237 void
238 Player::film_changed (Film::Property p)
239 {
240         /* Here we should notice Film properties that affect our output, and
241            alert listeners that our output now would be different to how it was
242            last time we were run.
243         */
244
245         if (p == Film::CONTAINER) {
246                 Changed (false);
247         } else if (p == Film::VIDEO_FRAME_RATE) {
248                 /* Pieces contain a FrameRateChange which contains the DCP frame rate,
249                    so we need new pieces here.
250                 */
251                 _have_valid_pieces = false;
252                 Changed (false);
253         } else if (p == Film::AUDIO_PROCESSOR) {
254                 if (_film->audio_processor ()) {
255                         _audio_processor = _film->audio_processor()->clone (_film->audio_frame_rate ());
256                 }
257         }
258 }
259
260 list<PositionImage>
261 Player::transform_image_subtitles (list<ImageSubtitle> subs) const
262 {
263         list<PositionImage> all;
264
265         for (list<ImageSubtitle>::const_iterator i = subs.begin(); i != subs.end(); ++i) {
266                 if (!i->image) {
267                         continue;
268                 }
269
270                 /* We will scale the subtitle up to fit _video_container_size */
271                 dcp::Size scaled_size (i->rectangle.width * _video_container_size.width, i->rectangle.height * _video_container_size.height);
272
273                 /* Then we need a corrective translation, consisting of two parts:
274                  *
275                  * 1.  that which is the result of the scaling of the subtitle by _video_container_size; this will be
276                  *     rect.x * _video_container_size.width and rect.y * _video_container_size.height.
277                  *
278                  * 2.  that to shift the origin of the scale by subtitle_scale to the centre of the subtitle; this will be
279                  *     (width_before_subtitle_scale * (1 - subtitle_x_scale) / 2) and
280                  *     (height_before_subtitle_scale * (1 - subtitle_y_scale) / 2).
281                  *
282                  * Combining these two translations gives these expressions.
283                  */
284
285                 all.push_back (
286                         PositionImage (
287                                 i->image->scale (
288                                         scaled_size,
289                                         dcp::YUV_TO_RGB_REC601,
290                                         i->image->pixel_format (),
291                                         true,
292                                         _fast
293                                         ),
294                                 Position<int> (
295                                         lrint (_video_container_size.width * i->rectangle.x),
296                                         lrint (_video_container_size.height * i->rectangle.y)
297                                         )
298                                 )
299                         );
300         }
301
302         return all;
303 }
304
305 shared_ptr<PlayerVideo>
306 Player::black_player_video_frame (DCPTime time) const
307 {
308         return shared_ptr<PlayerVideo> (
309                 new PlayerVideo (
310                         shared_ptr<const ImageProxy> (new RawImageProxy (_black_image)),
311                         time,
312                         Crop (),
313                         optional<double> (),
314                         _video_container_size,
315                         _video_container_size,
316                         EYES_BOTH,
317                         PART_WHOLE,
318                         PresetColourConversion::all().front().conversion
319                 )
320         );
321 }
322
323 Frame
324 Player::dcp_to_content_video (shared_ptr<const Piece> piece, DCPTime t) const
325 {
326         DCPTime s = t - piece->content->position ();
327         s = min (piece->content->length_after_trim(), s);
328         s = max (DCPTime(), s + DCPTime (piece->content->trim_start(), piece->frc));
329
330         /* It might seem more logical here to convert s to a ContentTime (using the FrameRateChange)
331            then convert that ContentTime to frames at the content's rate.  However this fails for
332            situations like content at 29.9978733fps, DCP at 30fps.  The accuracy of the Time type is not
333            enough to distinguish between the two with low values of time (e.g. 3200 in Time units).
334
335            Instead we convert the DCPTime using the DCP video rate then account for any skip/repeat.
336         */
337         return s.frames_floor (piece->frc.dcp) / piece->frc.factor ();
338 }
339
340 DCPTime
341 Player::content_video_to_dcp (shared_ptr<const Piece> piece, Frame f) const
342 {
343         /* See comment in dcp_to_content_video */
344         DCPTime const d = DCPTime::from_frames (f * piece->frc.factor(), piece->frc.dcp) - DCPTime (piece->content->trim_start (), piece->frc);
345         return max (DCPTime (), d + piece->content->position ());
346 }
347
348 Frame
349 Player::dcp_to_resampled_audio (shared_ptr<const Piece> piece, DCPTime t) const
350 {
351         DCPTime s = t - piece->content->position ();
352         s = min (piece->content->length_after_trim(), s);
353         /* See notes in dcp_to_content_video */
354         return max (DCPTime (), DCPTime (piece->content->trim_start (), piece->frc) + s).frames_floor (_film->audio_frame_rate ());
355 }
356
357 ContentTime
358 Player::dcp_to_content_subtitle (shared_ptr<const Piece> piece, DCPTime t) const
359 {
360         DCPTime s = t - piece->content->position ();
361         s = min (piece->content->length_after_trim(), s);
362         return max (ContentTime (), ContentTime (s, piece->frc) + piece->content->trim_start());
363 }
364
365 DCPTime
366 Player::content_subtitle_to_dcp (shared_ptr<const Piece> piece, ContentTime t) const
367 {
368         return max (DCPTime (), DCPTime (t - piece->content->trim_start(), piece->frc) + piece->content->position());
369 }
370
371 list<shared_ptr<Font> >
372 Player::get_subtitle_fonts ()
373 {
374         if (!_have_valid_pieces) {
375                 setup_pieces ();
376         }
377
378         list<shared_ptr<Font> > fonts;
379         BOOST_FOREACH (shared_ptr<Piece>& p, _pieces) {
380                 if (p->content->subtitle) {
381                         /* XXX: things may go wrong if there are duplicate font IDs
382                            with different font files.
383                         */
384                         list<shared_ptr<Font> > f = p->content->subtitle->fonts ();
385                         copy (f.begin(), f.end(), back_inserter (fonts));
386                 }
387         }
388
389         return fonts;
390 }
391
392 /** Set this player never to produce any video data */
393 void
394 Player::set_ignore_video ()
395 {
396         _ignore_video = true;
397 }
398
399 /** Set this player never to produce any audio data */
400 void
401 Player::set_ignore_audio ()
402 {
403         _ignore_audio = true;
404 }
405
406 /** Set whether or not this player should always burn text subtitles into the image,
407  *  regardless of the content settings.
408  *  @param burn true to always burn subtitles, false to obey content settings.
409  */
410 void
411 Player::set_always_burn_subtitles (bool burn)
412 {
413         _always_burn_subtitles = burn;
414 }
415
416 void
417 Player::set_fast ()
418 {
419         _fast = true;
420         _have_valid_pieces = false;
421 }
422
423 void
424 Player::set_play_referenced ()
425 {
426         _play_referenced = true;
427         _have_valid_pieces = false;
428 }
429
430 list<ReferencedReelAsset>
431 Player::get_reel_assets ()
432 {
433         list<ReferencedReelAsset> a;
434
435         BOOST_FOREACH (shared_ptr<Content> i, _playlist->content ()) {
436                 shared_ptr<DCPContent> j = dynamic_pointer_cast<DCPContent> (i);
437                 if (!j) {
438                         continue;
439                 }
440
441                 scoped_ptr<DCPDecoder> decoder;
442                 try {
443                         decoder.reset (new DCPDecoder (j, _film->log()));
444                 } catch (...) {
445                         return a;
446                 }
447
448                 int64_t offset = 0;
449                 BOOST_FOREACH (shared_ptr<dcp::Reel> k, decoder->reels()) {
450
451                         DCPOMATIC_ASSERT (j->video_frame_rate ());
452                         double const cfr = j->video_frame_rate().get();
453                         Frame const trim_start = j->trim_start().frames_round (cfr);
454                         Frame const trim_end = j->trim_end().frames_round (cfr);
455                         int const ffr = _film->video_frame_rate ();
456
457                         DCPTime const from = i->position() + DCPTime::from_frames (offset, _film->video_frame_rate());
458                         if (j->reference_video ()) {
459                                 shared_ptr<dcp::ReelAsset> ra = k->main_picture ();
460                                 DCPOMATIC_ASSERT (ra);
461                                 ra->set_entry_point (ra->entry_point() + trim_start);
462                                 ra->set_duration (ra->duration() - trim_start - trim_end);
463                                 a.push_back (
464                                         ReferencedReelAsset (ra, DCPTimePeriod (from, from + DCPTime::from_frames (ra->duration(), ffr)))
465                                         );
466                         }
467
468                         if (j->reference_audio ()) {
469                                 shared_ptr<dcp::ReelAsset> ra = k->main_sound ();
470                                 DCPOMATIC_ASSERT (ra);
471                                 ra->set_entry_point (ra->entry_point() + trim_start);
472                                 ra->set_duration (ra->duration() - trim_start - trim_end);
473                                 a.push_back (
474                                         ReferencedReelAsset (ra, DCPTimePeriod (from, from + DCPTime::from_frames (ra->duration(), ffr)))
475                                         );
476                         }
477
478                         if (j->reference_subtitle ()) {
479                                 shared_ptr<dcp::ReelAsset> ra = k->main_subtitle ();
480                                 DCPOMATIC_ASSERT (ra);
481                                 ra->set_entry_point (ra->entry_point() + trim_start);
482                                 ra->set_duration (ra->duration() - trim_start - trim_end);
483                                 a.push_back (
484                                         ReferencedReelAsset (ra, DCPTimePeriod (from, from + DCPTime::from_frames (ra->duration(), ffr)))
485                                         );
486                         }
487
488                         /* Assume that main picture duration is the length of the reel */
489                         offset += k->main_picture()->duration ();
490                 }
491         }
492
493         return a;
494 }
495
496 list<shared_ptr<Piece> >
497 Player::overlaps (DCPTime from, DCPTime to, boost::function<bool (Content *)> valid)
498 {
499         if (!_have_valid_pieces) {
500                 setup_pieces ();
501         }
502
503         list<shared_ptr<Piece> > overlaps;
504         BOOST_FOREACH (shared_ptr<Piece> i, _pieces) {
505                 if (valid (i->content.get ()) && i->content->position() < to && i->content->end() > from) {
506                         overlaps.push_back (i);
507                 }
508         }
509
510         return overlaps;
511 }
512
513 bool
514 Player::pass ()
515 {
516         if (!_have_valid_pieces) {
517                 setup_pieces ();
518         }
519
520         shared_ptr<Piece> earliest;
521         DCPTime earliest_position;
522         BOOST_FOREACH (shared_ptr<Piece> i, _pieces) {
523                 /* Convert i->decoder->position() to DCPTime and work out the earliest */
524         }
525
526         earliest->decoder->pass ();
527
528         /* XXX: collect audio and maybe emit some */
529 }
530
531 void
532 Player::video (weak_ptr<Piece> wp, ContentVideo video)
533 {
534         shared_ptr<Piece> piece = wp.lock ();
535         if (!piece) {
536                 return;
537         }
538
539         /* Get subs to burn in and burn them in */
540
541
542         /* Fill gaps */
543
544         DCPTime time = content_video_to_dcp (piece, video.frame.index());
545
546         dcp::Size image_size = piece->content->video->scale().size (
547                 piece->content->video, _video_container_size, _film->frame_size ()
548                 );
549
550         Video (
551                 shared_ptr<PlayerVideo> (
552                         new PlayerVideo (
553                                 video.image,
554                                 time,
555                                 piece->content->video->crop (),
556                                 piece->content->video->fade (video.frame.index()),
557                                 image_size,
558                                 _video_container_size,
559                                 video.frame.eyes(),
560                                 video.part,
561                                 piece->content->video->colour_conversion ()
562                                 )
563                         )
564                 );
565
566 }
567
568 void
569 Player::audio (weak_ptr<Piece> piece, ContentAudio video)
570 {
571         /* Put into merge buffer */
572 }
573
574 void
575 Player::image_subtitle (weak_ptr<Piece> piece, ContentImageSubtitle subtitle)
576 {
577         /* Store for video to see */
578 }
579
580 void
581 Player::text_subtitle (weak_ptr<Piece> piece, ContentTextSubtitle subtitle)
582 {
583         /* Store for video to see, or emit */
584 }
585
586 void
587 Player::seek (DCPTime time, bool accurate)
588 {
589         if (accurate) {
590                 _last_video = time - DCPTime::from_frames (1, _film->video_frame_rate ());
591         }
592 }