From c98c87afe29d9ef74bdced8a9c96d7752f3fe80f Mon Sep 17 00:00:00 2001 From: Carl Hetherington Date: Thu, 1 May 2014 14:32:45 +0100 Subject: [PATCH] Fix 3D support. --- src/lib/player.cc | 117 +++++++++++++++---------- src/lib/player.h | 14 ++- src/lib/transcoder.cc | 6 +- src/lib/video_decoder.cc | 16 ++-- src/lib/video_decoder.h | 4 +- src/tools/server_test.cc | 2 +- src/wx/film_viewer.cc | 6 +- test/ffmpeg_decoder_seek_test.cc | 7 +- test/ffmpeg_decoder_sequential_test.cc | 9 +- test/recover_test.cc | 8 +- test/seek_zero_test.cc | 7 +- 11 files changed, 118 insertions(+), 78 deletions(-) diff --git a/src/lib/player.cc b/src/lib/player.cc index 817a390d6..5fe35e34d 100644 --- a/src/lib/player.cc +++ b/src/lib/player.cc @@ -218,7 +218,7 @@ Player::film_changed (Film::Property p) } list -Player::process_content_image_subtitles (shared_ptr content, list > subs) +Player::process_content_image_subtitles (shared_ptr content, list > subs) const { list all; @@ -269,7 +269,7 @@ Player::process_content_image_subtitles (shared_ptr content, li } list -Player::process_content_text_subtitles (list > sub) +Player::process_content_text_subtitles (list > sub) const { list all; for (list >::const_iterator i = sub.begin(); i != sub.end(); ++i) { @@ -305,45 +305,17 @@ Player::black_dcp_video (DCPTime time) const } shared_ptr -Player::get_video (DCPTime time, bool accurate) +Player::content_to_dcp ( + shared_ptr content, + ContentVideo content_video, + list > subs, + DCPTime time, + dcp::Size image_size) const { - if (!_have_valid_pieces) { - setup_pieces (); - } - - list > ov = overlaps ( - 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 = ov.back (); - shared_ptr decoder = dynamic_pointer_cast (piece->decoder); - assert (decoder); - shared_ptr content = dynamic_pointer_cast (piece->content); - assert (content); - - optional 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 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 ( - time, - time + DCPTime::from_frames (1, _film->video_frame_rate ()) - ); list sub_images; - for (list >::const_iterator i = ov.begin(); i != ov.end(); ++i) { + for (list >::const_iterator i = subs.begin(); i != subs.end(); ++i) { shared_ptr subtitle_decoder = dynamic_pointer_cast ((*i)->decoder); shared_ptr subtitle_content = dynamic_pointer_cast ((*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 > 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 > +Player::get_video (DCPTime time, bool accurate) +{ + if (!_have_valid_pieces) { + setup_pieces (); + } + + list > ov = overlaps ( + time, + time + DCPTime::from_frames (1, _film->video_frame_rate ()) + ); + + list > 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 = ov.back (); + shared_ptr decoder = dynamic_pointer_cast (piece->decoder); + assert (decoder); + shared_ptr content = dynamic_pointer_cast (piece->content); + assert (content); + + list 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::const_iterator i = content_video.begin(); i != content_video.end(); ++i) { + list > subs = overlaps ( + 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 Player::get_audio (DCPTime time, DCPTime length, bool accurate) { diff --git a/src/lib/player.h b/src/lib/player.h index b70bd3f64..9151d20c5 100644 --- a/src/lib/player.h +++ b/src/lib/player.h @@ -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, public boost::nonc public: Player (boost::shared_ptr, boost::shared_ptr); - boost::shared_ptr get_video (DCPTime time, bool accurate); + std::list > get_video (DCPTime time, bool accurate); boost::shared_ptr 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 process_content_image_subtitles ( boost::shared_ptr, std::list > - ); - std::list process_content_text_subtitles (std::list >); + ) const; + std::list process_content_text_subtitles (std::list >) const; void update_subtitle_from_text (); VideoFrame dcp_to_content_video (boost::shared_ptr piece, DCPTime t) const; AudioFrame dcp_to_content_audio (boost::shared_ptr piece, DCPTime t) const; ContentTime dcp_to_content_subtitle (boost::shared_ptr piece, DCPTime t) const; boost::shared_ptr black_dcp_video (DCPTime) const; + boost::shared_ptr content_to_dcp ( + boost::shared_ptr content, + ContentVideo content_video, + std::list > subs, + DCPTime time, + dcp::Size image_size + ) const; /** @return Pieces of content type C that overlap a specified time range in the DCP */ template diff --git a/src/lib/transcoder.cc b/src/lib/transcoder.cc index 810606391..cc41b4256 100644 --- a/src/lib/transcoder.cc +++ b/src/lib/transcoder.cc @@ -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 > v = _player->get_video (t, true); + for (list >::const_iterator i = v.begin(); i != v.end(); ++i) { + _encoder->process_video (*i); + } _encoder->process_audio (_player->get_audio (t, frame, true)); } diff --git a/src/lib/video_decoder.cc b/src/lib/video_decoder.cc index bd609d168..146120fe1 100644 --- a/src/lib/video_decoder.cc +++ b/src/lib/video_decoder.cc @@ -39,19 +39,21 @@ VideoDecoder::VideoDecoder (shared_ptr c) } -optional +list VideoDecoder::decoded_video (VideoFrame frame) { + list output; + for (list::const_iterator i = _decoded_video.begin(); i != _decoded_video.end(); ++i) { if (i->frame == frame) { - return *i; + output.push_back (*i); } } - return optional (); + return output; } -optional +list 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 dec; + list 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 ()); } } diff --git a/src/lib/video_decoder.h b/src/lib/video_decoder.h index 8715b9714..685b72bc8 100644 --- a/src/lib/video_decoder.h +++ b/src/lib/video_decoder.h @@ -35,7 +35,7 @@ class VideoDecoder : public virtual Decoder public: VideoDecoder (boost::shared_ptr c); - boost::optional get_video (VideoFrame frame, bool accurate); + std::list get_video (VideoFrame frame, bool accurate); boost::shared_ptr video_content () const { return _video_content; @@ -49,7 +49,7 @@ protected: void seek (ContentTime time, bool accurate); void video (boost::shared_ptr, VideoFrame frame); - boost::optional decoded_video (VideoFrame frame); + std::list decoded_video (VideoFrame frame); boost::shared_ptr _video_content; std::list _decoded_video; diff --git a/src/tools/server_test.cc b/src/tools/server_test.cc index ad3cf9481..ba1669756 100644 --- a/src/tools/server_test.cc +++ b/src/tools/server_test.cc @@ -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"; diff --git a/src/wx/film_viewer.cc b/src/wx/film_viewer.cc index 33af202bc..e517c9cca 100644 --- a/src/wx/film_viewer.cc +++ b/src/wx/film_viewer.cc @@ -150,9 +150,9 @@ FilmViewer::get (DCPTime p, bool accurate) return; } - shared_ptr dcp_video = _player->get_video (p, accurate); - if (dcp_video) { - _frame = dcp_video->image (PIX_FMT_BGRA, true); + list > 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 (); diff --git a/test/ffmpeg_decoder_seek_test.cc b/test/ffmpeg_decoder_seek_test.cc index dd80765f4..968c3bdf9 100644 --- a/test/ffmpeg_decoder_seek_test.cc +++ b/test/ffmpeg_decoder_seek_test.cc @@ -36,16 +36,17 @@ using std::cerr; using std::vector; +using std::list; using boost::shared_ptr; using boost::optional; static void check (FFmpegDecoder& decoder, int frame) { - optional v; + list 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 diff --git a/test/ffmpeg_decoder_sequential_test.cc b/test/ffmpeg_decoder_sequential_test.cc index 48b9b6b3b..b4ff36e6e 100644 --- a/test/ffmpeg_decoder_sequential_test.cc +++ b/test/ffmpeg_decoder_sequential_test.cc @@ -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 v; + list 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); diff --git a/test/recover_test.cc b/test/recover_test.cc index dfbc9f60d..31b882a2e 100644 --- a/test/recover_test.cc +++ b/test/recover_test.cc @@ -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, diff --git a/test/seek_zero_test.cc b/test/seek_zero_test.cc index 03968ae5c..77e95c28c 100644 --- a/test/seek_zero_test.cc +++ b/test/seek_zero_test.cc @@ -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 a = decoder.get_video (first_frame, true); - BOOST_CHECK (a); - BOOST_CHECK_EQUAL (a->frame, first_frame); + list a = decoder.get_video (first_frame, true); + BOOST_CHECK (a.size() == 1); + BOOST_CHECK_EQUAL (a.front().frame, first_frame); } -- 2.30.2