Tests of Player::dcp_to_content_video, content_video_to_dcp and
[dcpomatic.git] / src / lib / player.cc
index 32892054918ee412961a792e69688d87bb66665a..83131e2008997588fb2ea1f3b6a9f91f7f71f76d 100644 (file)
@@ -361,38 +361,57 @@ Player::get_video (DCPTime time, bool accurate)
                /* No video content at this time */
                pvf.push_back (black_player_video_frame (time));
        } else {
-               /* Create a PlayerVideo from the content's video at this time */
-
-               shared_ptr<Piece> piece = ov.back ();
-               shared_ptr<VideoDecoder> decoder = dynamic_pointer_cast<VideoDecoder> (piece->decoder);
-               DCPOMATIC_ASSERT (decoder);
-               shared_ptr<VideoContent> video_content = dynamic_pointer_cast<VideoContent> (piece->content);
-               DCPOMATIC_ASSERT (video_content);
-
-               list<ContentVideo> content_video = decoder->get_video (dcp_to_content_video (piece, time), accurate);
-               if (content_video.empty ()) {
-                       pvf.push_back (black_player_video_frame (time));
-                       return pvf;
+               /* Decide which pieces of content to use */
+               list<shared_ptr<Piece> > ov_to_use;
+
+               /* Always use the last one */
+               list<shared_ptr<Piece> >::reverse_iterator i = ov.rbegin ();
+               ov_to_use.push_back (*i);
+               VideoFrameType const first_type = dynamic_pointer_cast<VideoContent> ((*i)->content)->video_frame_type ();
+
+               ++i;
+               if (i != ov.rend ()) {
+                       shared_ptr<VideoContent> vc = dynamic_pointer_cast<VideoContent> ((*i)->content);
+                       /* Use the second to last if it's the other part of a 3D content pair */
+                       if (
+                               (first_type == VIDEO_FRAME_TYPE_3D_LEFT && vc->video_frame_type() == VIDEO_FRAME_TYPE_3D_RIGHT) ||
+                               (first_type == VIDEO_FRAME_TYPE_3D_RIGHT && vc->video_frame_type() == VIDEO_FRAME_TYPE_3D_LEFT)
+                               ) {
+                               /* Other part of a pair of 3D content */
+                               ov_to_use.push_back (*i);
+                       }
                }
 
-               dcp::Size image_size = video_content->scale().size (video_content, _video_container_size, _film->frame_size ());
-
-               for (list<ContentVideo>::const_iterator i = content_video.begin(); i != content_video.end(); ++i) {
-                       pvf.push_back (
-                               shared_ptr<PlayerVideo> (
-                                       new PlayerVideo (
-                                               i->image,
-                                               content_video_to_dcp (piece, i->frame),
-                                               video_content->crop (),
-                                               video_content->fade (i->frame),
-                                               image_size,
-                                               _video_container_size,
-                                               i->eyes,
-                                               i->part,
-                                               video_content->colour_conversion ()
-                                               )
-                                       )
-                               );
+               BOOST_FOREACH (shared_ptr<Piece> piece, ov_to_use) {
+                       shared_ptr<VideoDecoder> decoder = dynamic_pointer_cast<VideoDecoder> (piece->decoder);
+                       DCPOMATIC_ASSERT (decoder);
+                       shared_ptr<VideoContent> video_content = dynamic_pointer_cast<VideoContent> (piece->content);
+                       DCPOMATIC_ASSERT (video_content);
+
+                       list<ContentVideo> content_video = decoder->get_video (dcp_to_content_video (piece, time), accurate);
+                       if (content_video.empty ()) {
+                               pvf.push_back (black_player_video_frame (time));
+                       } else {
+                               dcp::Size image_size = video_content->scale().size (video_content, _video_container_size, _film->frame_size ());
+
+                               for (list<ContentVideo>::const_iterator i = content_video.begin(); i != content_video.end(); ++i) {
+                                       pvf.push_back (
+                                               shared_ptr<PlayerVideo> (
+                                                       new PlayerVideo (
+                                                               i->image,
+                                                               content_video_to_dcp (piece, i->frame),
+                                                               video_content->crop (),
+                                                               video_content->fade (i->frame),
+                                                               image_size,
+                                                               _video_container_size,
+                                                               i->eyes,
+                                                               i->part,
+                                                               video_content->colour_conversion ()
+                                                               )
+                                                       )
+                                               );
+                               }
+                       }
                }
        }
 
@@ -445,10 +464,10 @@ Player::get_audio (DCPTime time, DCPTime length, bool accurate)
                        request = DCPTime ();
                }
 
-               Frame const content_frame = dcp_to_content_audio (*i, request);
-
                BOOST_FOREACH (AudioStreamPtr j, content->audio_streams ()) {
 
+                       Frame const content_frame = dcp_to_content_audio (*i, j, request);
+
                        if (j->channels() == 0) {
                                /* Some content (e.g. DCPs) can have streams with no channels */
                                continue;
@@ -502,13 +521,12 @@ Player::get_audio (DCPTime time, DCPTime length, bool accurate)
 Frame
 Player::dcp_to_content_video (shared_ptr<const Piece> piece, DCPTime t) const
 {
-       /* s is the offset of t from the start position of this content */
-       DCPTime s = t - piece->content->position ();
+       DCPTime s = t - piece->content->position () + piece->content->trim_start ();
        s = DCPTime (max (DCPTime::Type (0), s.get ()));
        s = DCPTime (min (piece->content->length_after_trim().get(), s.get()));
 
        /* Convert this to the content frame */
-       return DCPTime (s + piece->content->trim_start()).frames (_film->video_frame_rate()) / piece->frc.factor ();
+       return s.frames (_film->video_frame_rate()) / piece->frc.factor ();
 }
 
 DCPTime
@@ -523,15 +541,13 @@ Player::content_video_to_dcp (shared_ptr<const Piece> piece, Frame f) const
 }
 
 Frame
-Player::dcp_to_content_audio (shared_ptr<const Piece> piece, DCPTime t) const
+Player::dcp_to_content_audio (shared_ptr<const Piece> piece, AudioStreamPtr stream, DCPTime t) const
 {
-       /* s is the offset of t from the start position of this content */
-       DCPTime s = t - piece->content->position ();
+       DCPTime s = t - piece->content->position () + piece->content->trim_start ();
        s = DCPTime (max (DCPTime::Type (0), s.get ()));
        s = DCPTime (min (piece->content->length_after_trim().get(), s.get()));
 
-       /* Convert this to the content frame */
-       return DCPTime (s + piece->content->trim_start()).frames (_film->audio_frame_rate());
+       return ContentTime (s, piece->frc).frames (stream->frame_rate ());
 }
 
 ContentTime