Remove all use of stringstream in an attempt to fix
[dcpomatic.git] / src / lib / encoder.cc
index 8f2aa58f70ebbe53db9fb1ef3bd3418d23af1a68..364d29fbed589228c60b9d304984914e944c1646 100644 (file)
@@ -53,7 +53,7 @@ using boost::weak_ptr;
 using boost::optional;
 using dcp::Data;
 
-int const Encoder::_history_size = 25;
+int const Encoder::_history_size = 200;
 
 /** @param f Film that we are encoding */
 Encoder::Encoder (shared_ptr<const Film> film, shared_ptr<Writer> writer)
@@ -65,14 +65,35 @@ Encoder::Encoder (shared_ptr<const Film> film, shared_ptr<Writer> writer)
 
 Encoder::~Encoder ()
 {
-       terminate_threads ();
+       try {
+               terminate_threads ();
+       } catch (...) {
+               /* Destructors must not throw exceptions; anything bad
+                  happening now is too late to worry about anyway,
+                  I think.
+               */
+       }
 }
 
 void
 Encoder::begin ()
 {
-       if (!EncodeServerFinder::instance()->disabled ()) {
-               _server_found_connection = EncodeServerFinder::instance()->ServersListChanged.connect (boost::bind (&Encoder::servers_list_changed, this));
+       weak_ptr<Encoder> wp = shared_from_this ();
+       _server_found_connection = EncodeServerFinder::instance()->ServersListChanged.connect (
+               boost::bind (&Encoder::call_servers_list_changed, wp)
+               );
+}
+
+/* We don't want the servers-list-changed callback trying to do things
+   during destruction of Encoder, and I think this is the neatest way
+   to achieve that.
+*/
+void
+Encoder::call_servers_list_changed (weak_ptr<Encoder> encoder)
+{
+       shared_ptr<Encoder> e = encoder.lock ();
+       if (e) {
+               e->servers_list_changed ();
        }
 }
 
@@ -143,6 +164,10 @@ Encoder::current_encoding_rate () const
 int
 Encoder::video_frames_enqueued () const
 {
+       if (!_last_player_video) {
+               return 0;
+       }
+
        return _last_player_video->time().frames_floor (_film->video_frame_rate ());
 }
 
@@ -180,11 +205,13 @@ Encoder::encode (shared_ptr<PlayerVideo> pv)
 
        boost::mutex::scoped_lock queue_lock (_queue_mutex);
 
-       /* Wait until the queue has gone down a bit */
-       while (_queue.size() >= threads * 2) {
-               LOG_TIMING ("decoder-sleep queue=%1", _queue.size());
+       /* Wait until the queue has gone down a bit.  Allow one thing in the queue even
+          when there are no threads.
+       */
+       while (_queue.size() >= (threads * 2) + 1) {
+               LOG_TIMING ("decoder-sleep queue=%1 threads=%2", _queue.size(), threads);
                _full_condition.wait (queue_lock);
-               LOG_TIMING ("decoder-wake queue=%1", _queue.size());
+               LOG_TIMING ("decoder-wake queue=%1 threads=%2", _queue.size(), threads);
        }
 
        _writer->rethrow ();
@@ -238,7 +265,11 @@ Encoder::terminate_threads ()
                LOG_GENERAL ("Terminating thread %1 of %2", n + 1, _threads.size ());
                (*i)->interrupt ();
                DCPOMATIC_ASSERT ((*i)->joinable ());
-               (*i)->join ();
+               try {
+                       (*i)->join ();
+               } catch (boost::thread_interrupted& e) {
+                       /* This is to be expected */
+               }
                delete *i;
                LOG_GENERAL_NC ("Thread terminated");
                ++n;
@@ -273,7 +304,7 @@ try
 
                LOG_TIMING ("encoder-wake thread=%1 queue=%2", boost::this_thread::get_id(), _queue.size());
                shared_ptr<DCPVideo> vf = _queue.front ();
-               LOG_TIMING ("encoder-pop thread=%1 frame=%2 eyes=%3", boost::this_thread::get_id(), vf->index(), vf->eyes ());
+               LOG_TIMING ("encoder-pop thread=%1 frame=%2 eyes=%3", boost::this_thread::get_id(), vf->index(), (int) vf->eyes ());
                _queue.pop_front ();
 
                lock.unlock ();
@@ -333,6 +364,10 @@ try
                _full_condition.notify_all ();
        }
 }
+catch (boost::thread_interrupted& e) {
+       /* Ignore these and just stop the thread */
+       _full_condition.notify_all ();
+}
 catch (...)
 {
        store_current ();