Various 3D fixes.
authorCarl Hetherington <cth@carlh.net>
Tue, 23 Jul 2013 10:14:44 +0000 (11:14 +0100)
committerCarl Hetherington <cth@carlh.net>
Tue, 23 Jul 2013 10:14:44 +0000 (11:14 +0100)
src/lib/dcp_video_frame.cc
src/lib/encoder.cc
src/lib/player.cc
src/lib/writer.cc
test/threed_test.cc [new file with mode: 0644]
test/wscript

index 10f1e4ad170816ff1e44b15f982051f0f8a5ba92..4f6ff99872e6557733cbad77ad2123f7423155cf 100644 (file)
@@ -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)));
 
index 8e61a0d60d7a303231d0e3f4ef85221e84d2c4f3..7959fda6f49989ab5f42a5e0e8e48fd6a06bcefa 100644 (file)
@@ -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 ();
index 20beda9453d11c3a0c253bc71b0fa9033fe049a9..e1173a36bf654b6a8591c9d1c77de8ff7adab84e 100644 (file)
@@ -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();
index 90e1bd5549f5244fcfae1134fd34c9ef0d17bbd5..b9c1ce2e1c7762b10ddccf20904c530237b31e3c 100644 (file)
@@ -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 (file)
index 0000000..50fe87b
--- /dev/null
@@ -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);
+}
index f0ee5f7693a5a3742cf76b4a5e4a18cb6b5f7f25..c59d9f7cfbd9673cc3df3aeff0a1c516454fabe3 100644 (file)
@@ -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