Fix 3D support.
authorCarl Hetherington <cth@carlh.net>
Thu, 1 May 2014 13:32:45 +0000 (14:32 +0100)
committerCarl Hetherington <cth@carlh.net>
Thu, 1 May 2014 13:32:45 +0000 (14:32 +0100)
src/lib/player.cc
src/lib/player.h
src/lib/transcoder.cc
src/lib/video_decoder.cc
src/lib/video_decoder.h
src/tools/server_test.cc
src/wx/film_viewer.cc
test/ffmpeg_decoder_seek_test.cc
test/ffmpeg_decoder_sequential_test.cc
test/recover_test.cc
test/seek_zero_test.cc

index 817a390d6fcabf44db00a8633a79ec36d8d89ead..5fe35e34d736ed455cada873eac294d925c5f6fa 100644 (file)
@@ -218,7 +218,7 @@ Player::film_changed (Film::Property p)
 }
 
 list<PositionImage>
-Player::process_content_image_subtitles (shared_ptr<SubtitleContent> content, list<shared_ptr<ContentImageSubtitle> > subs)
+Player::process_content_image_subtitles (shared_ptr<SubtitleContent> content, list<shared_ptr<ContentImageSubtitle> > subs) const
 {
        list<PositionImage> all;
        
@@ -269,7 +269,7 @@ Player::process_content_image_subtitles (shared_ptr<SubtitleContent> content, li
 }
 
 list<PositionImage>
-Player::process_content_text_subtitles (list<shared_ptr<ContentTextSubtitle> > sub)
+Player::process_content_text_subtitles (list<shared_ptr<ContentTextSubtitle> > sub) const
 {
        list<PositionImage> all;
        for (list<shared_ptr<ContentTextSubtitle> >::const_iterator i = sub.begin(); i != sub.end(); ++i) {
@@ -305,45 +305,17 @@ Player::black_dcp_video (DCPTime time) const
 }
 
 shared_ptr<DCPVideo>
-Player::get_video (DCPTime time, bool accurate)
+Player::content_to_dcp (
+       shared_ptr<VideoContent> content,
+       ContentVideo content_video,
+       list<shared_ptr<Piece> > subs,
+       DCPTime time,
+       dcp::Size image_size) const
 {
-       if (!_have_valid_pieces) {
-               setup_pieces ();
-       }
-       
-       list<shared_ptr<Piece> > ov = overlaps<VideoContent> (
-               time,
-               time + DCPTime::from_frames (1, _film->video_frame_rate ())
-               );
-               
-       if (ov.empty ()) {
-               /* No video content at this time */
-               return black_dcp_video (time);
-       }
-
-       /* Create a DCPVideo from the content's video at this time */
-
-       shared_ptr<Piece> piece = ov.back ();
-       shared_ptr<VideoDecoder> decoder = dynamic_pointer_cast<VideoDecoder> (piece->decoder);
-       assert (decoder);
-       shared_ptr<VideoContent> content = dynamic_pointer_cast<VideoContent> (piece->content);
-       assert (content);
-
-       optional<ContentVideo> dec = decoder->get_video (dcp_to_content_video (piece, time), accurate);
-       if (!dec) {
-               return black_dcp_video (time);
-       }
-
-       dcp::Size image_size = content->scale().size (content, _video_container_size, _film->frame_size ());
-       if (_approximate_size) {
-               image_size.width &= ~3;
-               image_size.height &= ~3;
-       }
-
        shared_ptr<DCPVideo> dcp_video (
                new DCPVideo (
-                       dec->image,
-                       dec->eyes,
+                       content_video.image,
+                       content_video.eyes,
                        content->crop (),
                        image_size,
                        _video_container_size,
@@ -352,17 +324,13 @@ Player::get_video (DCPTime time, bool accurate)
                        time
                        )
                );
-
+       
+       
        /* Add subtitles */
-
-       ov = overlaps<SubtitleContent> (
-               time,
-               time + DCPTime::from_frames (1, _film->video_frame_rate ())
-               );
        
        list<PositionImage> sub_images;
        
-       for (list<shared_ptr<Piece> >::const_iterator i = ov.begin(); i != ov.end(); ++i) {
+       for (list<shared_ptr<Piece> >::const_iterator i = subs.begin(); i != subs.end(); ++i) {
                shared_ptr<SubtitleDecoder> subtitle_decoder = dynamic_pointer_cast<SubtitleDecoder> ((*i)->decoder);
                shared_ptr<SubtitleContent> subtitle_content = dynamic_pointer_cast<SubtitleContent> ((*i)->content);
                ContentTime const from = dcp_to_content_subtitle (*i, time);
@@ -374,10 +342,10 @@ Player::get_video (DCPTime time, bool accurate)
                                subtitle_content,
                                image_subtitles
                                );
-
+                       
                        copy (im.begin(), im.end(), back_inserter (sub_images));
                }
-
+               
                if (_burn_subtitles) {
                        list<shared_ptr<ContentTextSubtitle> > text_subtitles = subtitle_decoder->get_text_subtitles (from, to);
                        if (!text_subtitles.empty ()) {
@@ -386,7 +354,7 @@ Player::get_video (DCPTime time, bool accurate)
                        }
                }
        }
-
+       
        if (!sub_images.empty ()) {
                dcp_video->set_subtitle (merge (sub_images));
        }
@@ -394,6 +362,59 @@ Player::get_video (DCPTime time, bool accurate)
        return dcp_video;
 }
 
+/** @return All DCPVideo at the given time (there may be two frames for 3D) */
+list<shared_ptr<DCPVideo> >
+Player::get_video (DCPTime time, bool accurate)
+{
+       if (!_have_valid_pieces) {
+               setup_pieces ();
+       }
+       
+       list<shared_ptr<Piece> > ov = overlaps<VideoContent> (
+               time,
+               time + DCPTime::from_frames (1, _film->video_frame_rate ())
+               );
+
+       list<shared_ptr<DCPVideo> > dcp_video;
+               
+       if (ov.empty ()) {
+               /* No video content at this time */
+               dcp_video.push_back (black_dcp_video (time));
+               return dcp_video;
+       }
+
+       /* Create a DCPVideo from the content's video at this time */
+
+       shared_ptr<Piece> piece = ov.back ();
+       shared_ptr<VideoDecoder> decoder = dynamic_pointer_cast<VideoDecoder> (piece->decoder);
+       assert (decoder);
+       shared_ptr<VideoContent> content = dynamic_pointer_cast<VideoContent> (piece->content);
+       assert (content);
+
+       list<ContentVideo> content_video = decoder->get_video (dcp_to_content_video (piece, time), accurate);
+       if (content_video.empty ()) {
+               dcp_video.push_back (black_dcp_video (time));
+               return dcp_video;
+       }
+
+       dcp::Size image_size = content->scale().size (content, _video_container_size, _film->frame_size ());
+       if (_approximate_size) {
+               image_size.width &= ~3;
+               image_size.height &= ~3;
+       }
+
+       for (list<ContentVideo>::const_iterator i = content_video.begin(); i != content_video.end(); ++i) {
+               list<shared_ptr<Piece> > subs = overlaps<SubtitleContent> (
+                       time,
+                       time + DCPTime::from_frames (1, _film->video_frame_rate ())
+                       );
+               
+               dcp_video.push_back (content_to_dcp (content, *i, subs, time, image_size));
+       }
+               
+       return dcp_video;
+}
+
 shared_ptr<AudioBuffers>
 Player::get_audio (DCPTime time, DCPTime length, bool accurate)
 {
index b70bd3f64325bb3f67d8a8d04cee21d66860b9df..9151d20c5ac163d4a1ed882374782af96cd2eb2a 100644 (file)
@@ -32,6 +32,7 @@
 #include "content_subtitle.h"
 #include "position_image.h"
 #include "piece.h"
+#include "content_video.h"
 
 class Job;
 class Film;
@@ -104,7 +105,7 @@ class Player : public boost::enable_shared_from_this<Player>, public boost::nonc
 public:
        Player (boost::shared_ptr<const Film>, boost::shared_ptr<const Playlist>);
 
-       boost::shared_ptr<DCPVideo> get_video (DCPTime time, bool accurate);
+       std::list<boost::shared_ptr<DCPVideo> > get_video (DCPTime time, bool accurate);
        boost::shared_ptr<AudioBuffers> get_audio (DCPTime time, DCPTime length, bool accurate);
 
        void set_video_container_size (dcp::Size);
@@ -135,13 +136,20 @@ private:
        void film_changed (Film::Property);
        std::list<PositionImage> process_content_image_subtitles (
                boost::shared_ptr<SubtitleContent>, std::list<boost::shared_ptr<ContentImageSubtitle> >
-               );
-       std::list<PositionImage> process_content_text_subtitles (std::list<boost::shared_ptr<ContentTextSubtitle> >);
+               ) const;
+       std::list<PositionImage> process_content_text_subtitles (std::list<boost::shared_ptr<ContentTextSubtitle> >) const;
        void update_subtitle_from_text ();
        VideoFrame dcp_to_content_video (boost::shared_ptr<const Piece> piece, DCPTime t) const;
        AudioFrame dcp_to_content_audio (boost::shared_ptr<const Piece> piece, DCPTime t) const;
        ContentTime dcp_to_content_subtitle (boost::shared_ptr<const Piece> piece, DCPTime t) const;
        boost::shared_ptr<DCPVideo> black_dcp_video (DCPTime) const;
+       boost::shared_ptr<DCPVideo> content_to_dcp (
+               boost::shared_ptr<VideoContent> content,
+               ContentVideo content_video,
+               std::list<boost::shared_ptr<Piece> > subs,
+               DCPTime time,
+               dcp::Size image_size
+               ) const;
 
        /** @return Pieces of content type C that overlap a specified time range in the DCP */
        template<class C>
index 810606391b18381883f0117829d802dbbc2590f1..cc41b4256e2861630a312bd968fec4137e1dd9e9 100644 (file)
@@ -36,6 +36,7 @@
 
 using std::string;
 using std::cout;
+using std::list;
 using boost::shared_ptr;
 using boost::weak_ptr;
 using boost::dynamic_pointer_cast;
@@ -60,7 +61,10 @@ Transcoder::go ()
 
        DCPTime const frame = DCPTime::from_frames (1, _film->video_frame_rate ());
        for (DCPTime t; t < _film->length(); t += frame) {
-               _encoder->process_video (_player->get_video (t, true));
+               list<shared_ptr<DCPVideo> > v = _player->get_video (t, true);
+               for (list<shared_ptr<DCPVideo> >::const_iterator i = v.begin(); i != v.end(); ++i) {
+                       _encoder->process_video (*i);
+               }
                _encoder->process_audio (_player->get_audio (t, frame, true));
        }
 
index bd609d1683ddd0fca0ee82ca9da8bd7eeaed725b..146120fe1adda6c930e04cd44968fed493bc4a1a 100644 (file)
@@ -39,19 +39,21 @@ VideoDecoder::VideoDecoder (shared_ptr<const VideoContent> c)
 
 }
 
-optional<ContentVideo>
+list<ContentVideo>
 VideoDecoder::decoded_video (VideoFrame frame)
 {
+       list<ContentVideo> output;
+       
        for (list<ContentVideo>::const_iterator i = _decoded_video.begin(); i != _decoded_video.end(); ++i) {
                if (i->frame == frame) {
-                       return *i;
+                       output.push_back (*i);
                }
        }
 
-       return optional<ContentVideo> ();
+       return output;
 }
 
-optional<ContentVideo>
+list<ContentVideo>
 VideoDecoder::get_video (VideoFrame frame, bool accurate)
 {
        if (_decoded_video.empty() || (frame < _decoded_video.front().frame || frame > (_decoded_video.back().frame + 1))) {
@@ -59,7 +61,7 @@ VideoDecoder::get_video (VideoFrame frame, bool accurate)
                seek (ContentTime::from_frames (frame, _video_content->video_frame_rate()), accurate);
        }
 
-       optional<ContentVideo> dec;
+       list<ContentVideo> dec;
 
        /* Now enough pass() calls should either:
         *  (a) give us what we want, or
@@ -70,7 +72,7 @@ VideoDecoder::get_video (VideoFrame frame, bool accurate)
                 * This could all be one statement but it's split up for clarity.
                 */
                while (true) {
-                       if (decoded_video (frame)) {
+                       if (!decoded_video(frame).empty ()) {
                                /* We got what we want */
                                break;
                        }
@@ -94,7 +96,7 @@ VideoDecoder::get_video (VideoFrame frame, bool accurate)
                /* Any frame will do: use the first one that comes out of pass() */
                while (_decoded_video.empty() && !pass ()) {}
                if (!_decoded_video.empty ()) {
-                       dec = _decoded_video.front ();
+                       dec.push_back (_decoded_video.front ());
                }
        }
 
index 8715b9714cfefadcbc37c1a53016202153fb51af..685b72bc8683ad72b8b3b96feca365899eeeb779 100644 (file)
@@ -35,7 +35,7 @@ class VideoDecoder : public virtual Decoder
 public:
        VideoDecoder (boost::shared_ptr<const VideoContent> c);
 
-       boost::optional<ContentVideo> get_video (VideoFrame frame, bool accurate);
+       std::list<ContentVideo> get_video (VideoFrame frame, bool accurate);
 
        boost::shared_ptr<const VideoContent> video_content () const {
                return _video_content;
@@ -49,7 +49,7 @@ protected:
 
        void seek (ContentTime time, bool accurate);
        void video (boost::shared_ptr<const Image>, VideoFrame frame);
-       boost::optional<ContentVideo> decoded_video (VideoFrame frame);
+       std::list<ContentVideo> decoded_video (VideoFrame frame);
 
        boost::shared_ptr<const VideoContent> _video_content;
        std::list<ContentVideo> _decoded_video;
index ad3cf94819be44dff7dd0a0c3ed49df9390473e8..ba16697564705fe25afe03dc2458522e4de9899a 100644 (file)
@@ -156,7 +156,7 @@ main (int argc, char* argv[])
 
                DCPTime const frame = DCPTime::from_frames (1, film->video_frame_rate ());
                for (DCPTime t; t < film->length(); t += frame) {
-                       process_video (player->get_video (t, true));
+                       process_video (player->get_video(t, true).front ());
                }
        } catch (std::exception& e) {
                cerr << "Error: " << e.what() << "\n";
index 33af202bc7164c31efd650fd8c854ad30b697f16..e517c9ccaf55c2cc79c293b7a8211bbc3453271a 100644 (file)
@@ -150,9 +150,9 @@ FilmViewer::get (DCPTime p, bool accurate)
                return;
        }
 
-       shared_ptr<DCPVideo> dcp_video = _player->get_video (p, accurate);
-       if (dcp_video) {
-               _frame = dcp_video->image (PIX_FMT_BGRA, true);
+       list<shared_ptr<DCPVideo> > dcp_video = _player->get_video (p, accurate);
+       if (!dcp_video.empty ()) {
+               _frame = dcp_video.front()->image (PIX_FMT_BGRA, true);
                _frame = _frame->scale (_frame->size(), Scaler::from_id ("fastbilinear"), PIX_FMT_RGB24, false);
        } else {
                _frame.reset ();
index dd80765f419e6e4e3bc9995fd602271f9e934758..968c3bdf910eb0265441739ae4b07a7783cfb172 100644 (file)
 
 using std::cerr;
 using std::vector;
+using std::list;
 using boost::shared_ptr;
 using boost::optional;
 
 static void
 check (FFmpegDecoder& decoder, int frame)
 {
-       optional<ContentVideo> v;
+       list<ContentVideo> v;
        v = decoder.get_video (frame, true);
-       BOOST_CHECK (v);
-       BOOST_CHECK_EQUAL (v->frame, frame);
+       BOOST_CHECK (v.size() == 1);
+       BOOST_CHECK_EQUAL (v.front().frame, frame);
 }
 
 static void
index 48b9b6b3bb27d8e140c706baa1dc37ebdf38fb0a..b4ff36e6eed0848624fcd8aabb019023252f056b 100644 (file)
@@ -32,6 +32,7 @@
 
 using std::cout;
 using std::cerr;
+using std::list;
 using boost::shared_ptr;
 using boost::optional;
 
@@ -57,13 +58,13 @@ test (boost::filesystem::path file, float fps, int first)
        VideoFrame const N = decoder.video_content()->video_length().frames (decoder.video_content()->video_frame_rate ());
        decoder.test_gaps = 0;
        for (VideoFrame i = 0; i < N; ++i) {
-               optional<ContentVideo> v;
+               list<ContentVideo> v;
                v = decoder.get_video (i, true);
                if (i < first) {
-                       BOOST_CHECK (!v);
+                       BOOST_CHECK (v.empty ());
                } else {
-                       BOOST_CHECK (v);
-                       BOOST_CHECK_EQUAL (v->frame, i);
+                       BOOST_CHECK (v.size() == 1);
+                       BOOST_CHECK_EQUAL (v.front().frame, i);
                }
        }
        BOOST_CHECK_EQUAL (decoder.test_gaps, 0);
index dfbc9f60d9537e9baba3369e99a9aa1a074df45f..31b882a2eaeeeb81ca4e99450c594f96fad73798 100644 (file)
@@ -34,9 +34,11 @@ using std::string;
 using boost::shared_ptr;
 
 static void
-note (dcp::NoteType, string n)
+note (dcp::NoteType t, string n)
 {
-       cout << n << "\n";
+       if (t == dcp::ERROR) {
+               cout << n << "\n";
+       }
 }
 
 BOOST_AUTO_TEST_CASE (recover_test)
@@ -55,7 +57,7 @@ BOOST_AUTO_TEST_CASE (recover_test)
        film->make_dcp ();
        wait_for_jobs ();
 
-       boost::filesystem::path const video = "build/test/recover_test/video/185_2K_aa7e8a4665281568bbe11645a3d4ba4e_24_bicubic_200000000_P_S_3D.mxf";
+       boost::filesystem::path const video = "build/test/recover_test/video/185_2K_3651eded785682b85f4baca4b1d3b7a9_24_bicubic_200000000_P_S_3D.mxf";
 
        boost::filesystem::copy_file (
                video,
index 03968ae5cb1c54ea11284b8c2d3bcaa8217cd2b9..77e95c28c11b5d11d42977ec2dfc02b6d26eca27 100644 (file)
@@ -32,6 +32,7 @@
 #include "test.h"
 
 using std::cout;
+using std::list;
 using boost::shared_ptr;
 using boost::dynamic_pointer_cast;
 using boost::optional;
@@ -58,7 +59,7 @@ BOOST_AUTO_TEST_CASE (seek_zero_test)
        VideoFrame const first_frame = video_delay.round_up (content->video_frame_rate ()).frames (content->video_frame_rate ());
 
        FFmpegDecoder decoder (content, film->log());
-       optional<ContentVideo> a = decoder.get_video (first_frame, true);
-       BOOST_CHECK (a);
-       BOOST_CHECK_EQUAL (a->frame, first_frame);
+       list<ContentVideo> a = decoder.get_video (first_frame, true);
+       BOOST_CHECK (a.size() == 1);
+       BOOST_CHECK_EQUAL (a.front().frame, first_frame);
 }