diff options
| author | Carl Hetherington <cth@carlh.net> | 2013-07-23 11:14:44 +0100 |
|---|---|---|
| committer | Carl Hetherington <cth@carlh.net> | 2013-07-23 11:14:44 +0100 |
| commit | 4eb77be6999a3758998bfe37b28d4bb1cd55d51e (patch) | |
| tree | 9e2882f27751ee6badb1ee9b333bf1d012bd083b | |
| parent | fa4bac5dd1b8d0e09bd4a4eb20c83c0564858649 (diff) | |
Various 3D fixes.
| -rw-r--r-- | src/lib/dcp_video_frame.cc | 14 | ||||
| -rw-r--r-- | src/lib/encoder.cc | 8 | ||||
| -rw-r--r-- | src/lib/player.cc | 3 | ||||
| -rw-r--r-- | src/lib/writer.cc | 81 | ||||
| -rw-r--r-- | test/threed_test.cc | 51 | ||||
| -rw-r--r-- | test/wscript | 1 |
6 files changed, 128 insertions, 30 deletions
diff --git a/src/lib/dcp_video_frame.cc b/src/lib/dcp_video_frame.cc index 10f1e4ad1..4f6ff9987 100644 --- a/src/lib/dcp_video_frame.cc +++ b/src/lib/dcp_video_frame.cc @@ -185,7 +185,19 @@ DCPVideoFrame::encode_locally () throw EncodeError (N_("JPEG2000 encoding failed")); } - _log->log (String::compose (N_("Finished locally-encoded frame %1"), _frame)); + switch (_eyes) { + case EYES_BOTH: + _log->log (String::compose (N_("Finished locally-encoded frame %1 for mono"), _frame)); + break; + case EYES_LEFT: + _log->log (String::compose (N_("Finished locally-encoded frame %1 for L"), _frame)); + break; + case EYES_RIGHT: + _log->log (String::compose (N_("Finished locally-encoded frame %1 for R"), _frame)); + break; + default: + break; + } shared_ptr<EncodedData> enc (new LocallyEncodedData (cio->buffer, cio_tell (cio))); diff --git a/src/lib/encoder.cc b/src/lib/encoder.cc index 8e61a0d60..7959fda6f 100644 --- a/src/lib/encoder.cc +++ b/src/lib/encoder.cc @@ -175,6 +175,8 @@ Encoder::process_video (shared_ptr<const Image> image, Eyes eyes, bool same) { boost::mutex::scoped_lock lock (_mutex); + /* XXX: discard 3D here if required */ + /* Wait until the queue has gone down a bit */ while (_queue.size() >= _threads.size() * 2 && !_terminate) { TIMING ("decoder sleeps with queue of %1", _queue.size()); @@ -212,7 +214,9 @@ Encoder::process_video (shared_ptr<const Image> image, Eyes eyes, bool same) _have_a_real_frame[eyes] = true; } - ++_video_frames_out; + if (eyes != EYES_LEFT) { + ++_video_frames_out; + } } void @@ -262,7 +266,7 @@ Encoder::encoder_thread (ServerDescription* server) TIMING ("encoder thread %1 wakes with queue of %2", boost::this_thread::get_id(), _queue.size()); shared_ptr<DCPVideoFrame> vf = _queue.front (); - _film->log()->log (String::compose (N_("Encoder thread %1 pops frame %2 from queue"), boost::this_thread::get_id(), vf->frame()), Log::VERBOSE); + _film->log()->log (String::compose (N_("Encoder thread %1 pops frame %2 (%3) from queue"), boost::this_thread::get_id(), vf->frame(), vf->eyes ())); _queue.pop_front (); lock.unlock (); diff --git a/src/lib/player.cc b/src/lib/player.cc index 20beda945..e1173a36b 100644 --- a/src/lib/player.cc +++ b/src/lib/player.cc @@ -32,6 +32,7 @@ #include "image.h" #include "ratio.h" #include "resampler.h" +#include "log.h" #include "scaler.h" using std::list; @@ -240,7 +241,7 @@ Player::process_video (weak_ptr<Piece> weak_piece, shared_ptr<const Image> image #ifdef DCPOMATIC_DEBUG _last_video = piece->content; -#endif +#endif Video (work_image, eyes, same, time); time += TIME_HZ / _film->dcp_video_frame_rate(); diff --git a/src/lib/writer.cc b/src/lib/writer.cc index 90e1bd554..b9c1ce2e1 100644 --- a/src/lib/writer.cc +++ b/src/lib/writer.cc @@ -57,6 +57,7 @@ Writer::Writer (shared_ptr<const Film> f, shared_ptr<Job> j) , _finish (false) , _queued_full_in_memory (0) , _last_written_frame (-1) + , _last_written_eyes (EYES_RIGHT) , _full_written (0) , _fake_written (0) , _repeat_written (0) @@ -127,10 +128,21 @@ Writer::write (shared_ptr<const EncodedData> encoded, int frame, Eyes eyes) qi.type = QueueItem::FULL; qi.encoded = encoded; qi.frame = frame; - qi.eyes = eyes; - _queue.push_back (qi); - ++_queued_full_in_memory; + if (_film->dcp_3d() && eyes == EYES_BOTH) { + /* 2D material in a 3D DCP; fake the 3D */ + qi.eyes = EYES_LEFT; + _queue.push_back (qi); + ++_queued_full_in_memory; + qi.eyes = EYES_RIGHT; + _queue.push_back (qi); + ++_queued_full_in_memory; + } else { + qi.eyes = eyes; + _queue.push_back (qi); + ++_queued_full_in_memory; + } + _condition.notify_all (); } @@ -159,7 +171,9 @@ Writer::write (shared_ptr<const AudioBuffers> audio) _sound_asset_writer->write (audio->data(), audio->frames()); } -/** This must be called from Writer::thread() with an appropriate lock held */ +/** This must be called from Writer::thread() with an appropriate lock held, + * and with _queue sorted. + */ bool Writer::have_sequenced_image_at_queue_head () const { @@ -167,13 +181,24 @@ Writer::have_sequenced_image_at_queue_head () const return false; } - /* We assume that we will get either all 2D frames or all 3D frames, not a mixture */ - - bool const eyes_ok = (_queue.front().eyes == EYES_BOTH) || - (_queue.front().eyes == EYES_LEFT && _last_written_eyes == EYES_RIGHT) || - (_queue.front().eyes == EYES_RIGHT && _last_written_eyes == EYES_LEFT); - - return _queue.front().frame == (_last_written_frame + 1) && eyes_ok; + /* The queue should contain only EYES_LEFT/EYES_RIGHT pairs or EYES_BOTH */ + + if (_queue.front().eyes == EYES_BOTH) { + /* 2D */ + return _queue.front().frame == (_last_written_frame + 1); + } + + /* 3D */ + + if (_last_written_eyes == EYES_LEFT && _queue.front().frame == _last_written_frame && _queue.front().eyes == EYES_RIGHT) { + return true; + } + + if (_last_written_eyes == EYES_RIGHT && _queue.front().frame == (_last_written_frame + 1) && _queue.front().eyes == EYES_LEFT) { + return true; + } + + return false; } void @@ -191,7 +216,7 @@ try if (_finish || _queued_full_in_memory > _maximum_frames_in_memory || have_sequenced_image_at_queue_head ()) { break; } - + TIMING (N_("writer sleeps with a queue of %1"), _queue.size()); _condition.wait (lock); TIMING (N_("writer wakes with a queue of %1"), _queue.size()); @@ -245,25 +270,21 @@ try if (_mono_picture_asset_writer) { libdcp::FrameInfo fin = _mono_picture_asset_writer->write ( - _last_written[EYES_BOTH]->data(), - _last_written[EYES_BOTH]->size() + _last_written[qi.eyes]->data(), + _last_written[qi.eyes]->size() ); - _last_written[EYES_BOTH]->write_info (_film, qi.frame, qi.eyes, fin); + _last_written[qi.eyes]->write_info (_film, qi.frame, qi.eyes, fin); } else { libdcp::FrameInfo fin = _stereo_picture_asset_writer->write ( - _last_written[EYES_LEFT]->data(), _last_written[EYES_LEFT]->size(), libdcp::EYE_LEFT + _last_written[qi.eyes]->data(), + _last_written[qi.eyes]->size(), + qi.eyes == EYES_LEFT ? libdcp::EYE_LEFT : libdcp::EYE_RIGHT ); - _last_written[EYES_LEFT]->write_info (_film, qi.frame, qi.eyes, fin); - - fin = _stereo_picture_asset_writer->write ( - _last_written[EYES_RIGHT]->data(), _last_written[EYES_RIGHT]->size(), libdcp::EYE_RIGHT - ); - - _last_written[EYES_RIGHT]->write_info (_film, qi.frame, qi.eyes, fin); + _last_written[qi.eyes]->write_info (_film, qi.frame, qi.eyes, fin); } ++_repeat_written; @@ -271,14 +292,15 @@ try } } lock.lock (); + + _last_written_frame = qi.frame; + _last_written_eyes = qi.eyes; if (_film->length()) { _job->set_progress ( float (_full_written + _fake_written + _repeat_written) / _film->time_to_video_frames (_film->length()) ); } - - ++_last_written_frame; } while (_queued_full_in_memory > _maximum_frames_in_memory) { @@ -298,7 +320,14 @@ try ++_pushed_to_disk; lock.unlock (); - _film->log()->log (String::compose (N_("Writer full (awaiting %1); pushes %2 to disk"), _last_written_frame + 1, qi.frame)); + + _film->log()->log ( + String::compose ( + "Writer full (awaiting %1 [last eye was %2]); pushes %3 to disk", + _last_written_frame + 1, + _last_written_eyes, qi.frame) + ); + qi.encoded->write (_film, qi.frame, qi.eyes); lock.lock (); qi.encoded.reset (); diff --git a/test/threed_test.cc b/test/threed_test.cc new file mode 100644 index 000000000..50fe87b4a --- /dev/null +++ b/test/threed_test.cc @@ -0,0 +1,51 @@ +/* + Copyright (C) 2013 Carl Hetherington <cth@carlh.net> + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + +*/ + +#include <boost/test/unit_test.hpp> +#include "test.h" +#include "lib/film.h" +#include "lib/ratio.h" +#include "lib/dcp_content_type.h" +#include "lib/ffmpeg_content.h" + +using std::cout; +using boost::shared_ptr; + +BOOST_AUTO_TEST_CASE (threed_test) +{ + cout << "here we go.\n"; + shared_ptr<Film> film = new_test_film ("threed_test"); + film->set_name ("test_film2"); + shared_ptr<FFmpegContent> c (new FFmpegContent (film, "test/data/test.mp4")); + c->set_ratio (Ratio::from_id ("185")); + c->set_video_frame_type (VIDEO_FRAME_TYPE_3D_LEFT_RIGHT); + film->examine_and_add_content (c); + + wait_for_jobs (); + + film->set_container (Ratio::from_id ("185")); + film->set_dcp_content_type (DCPContentType::from_pretty_name ("Test")); + film->set_dcp_3d (true); + film->make_dcp (); + film->write_metadata (); + + wait_for_jobs (); + + exit (EXIT_SUCCESS); +} diff --git a/test/wscript b/test/wscript index f0ee5f769..c59d9f7cf 100644 --- a/test/wscript +++ b/test/wscript @@ -16,6 +16,7 @@ def build(bld): obj.use = 'libdcpomatic' obj.source = """ test.cc + threed_test.cc play_test.cc frame_rate_test.cc silence_padding_test.cc |
