X-Git-Url: https://git.carlh.net/gitweb/?a=blobdiff_plain;f=src%2Flib%2Fencoder.cc;h=2364b67a7ceccb5a1ced874efad51b83228fdcaa;hb=39bc73fe192f932ed6695eb87b19de446e8b4f55;hp=eb331551fffb6d6c10dee1e3b96280a72e8f89e4;hpb=7125d8ec2217ae874ce452602465f630f674e786;p=dcpomatic.git diff --git a/src/lib/encoder.cc b/src/lib/encoder.cc index eb331551f..2364b67a7 100644 --- a/src/lib/encoder.cc +++ b/src/lib/encoder.cc @@ -1,5 +1,5 @@ /* - Copyright (C) 2012 Carl Hetherington + Copyright (C) 2012-2014 Carl Hetherington 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 @@ -34,6 +34,8 @@ #include "cross.h" #include "writer.h" #include "server_finder.h" +#include "player.h" +#include "player_video_frame.h" #include "i18n.h" @@ -46,29 +48,25 @@ using std::cout; using std::min; using std::make_pair; using boost::shared_ptr; +using boost::weak_ptr; using boost::optional; using boost::scoped_array; int const Encoder::_history_size = 25; /** @param f Film that we are encoding */ -Encoder::Encoder (shared_ptr f, shared_ptr j) +Encoder::Encoder (shared_ptr f, weak_ptr j) : _film (f) , _job (j) , _video_frames_out (0) , _terminate (false) { - _have_a_real_frame[EYES_BOTH] = false; - _have_a_real_frame[EYES_LEFT] = false; - _have_a_real_frame[EYES_RIGHT] = false; + } Encoder::~Encoder () { terminate_threads (); - if (_writer) { - _writer->finish (); - } } /** Add a worker thread for a each thread on a remote server. Caller must hold @@ -78,6 +76,7 @@ Encoder::~Encoder () void Encoder::add_worker_threads (ServerDescription d) { + _film->log()->log (String::compose (N_("Adding %1 worker threads for remote %2"), d.host_name ())); for (int i = 0; i < d.threads(); ++i) { _threads.push_back (new boost::thread (boost::bind (&Encoder::encoder_thread, this, d))); } @@ -94,7 +93,6 @@ Encoder::process_begin () ServerFinder::instance()->connect (boost::bind (&Encoder::server_found, this, _1)); } - void Encoder::process_end () { @@ -125,9 +123,9 @@ Encoder::process_end () */ for (list >::iterator i = _queue.begin(); i != _queue.end(); ++i) { - _film->log()->log (String::compose (N_("Encode left-over frame %1"), (*i)->frame ())); + _film->log()->log (String::compose (N_("Encode left-over frame %1"), (*i)->index ())); try { - _writer->write ((*i)->encode_locally(), (*i)->frame (), (*i)->eyes ()); + _writer->write ((*i)->encode_locally(), (*i)->index (), (*i)->eyes ()); frame_done (); } catch (std::exception& e) { _film->log()->log (String::compose (N_("Local encode failed (%1)"), e.what ())); @@ -180,8 +178,10 @@ Encoder::frame_done () } void -Encoder::process_video (shared_ptr image, Eyes eyes, ColourConversion conversion, bool same) +Encoder::process_video (shared_ptr pvf) { + _waker.nudge (); + boost::mutex::scoped_lock lock (_mutex); /* XXX: discard 3D here if required */ @@ -197,33 +197,34 @@ Encoder::process_video (shared_ptr image, Eyes eyes, ColourConversi return; } - if (_writer->thrown ()) { - _writer->rethrow (); - } + _writer->rethrow (); + /* Re-throw any exception raised by one of our threads. If more + than one has thrown an exception, only one will be rethrown, I think; + but then, if that happens something has gone badly wrong. + */ + rethrow (); if (_writer->can_fake_write (_video_frames_out)) { - _writer->fake_write (_video_frames_out, eyes); - _have_a_real_frame[eyes] = false; - frame_done (); - } else if (same && _have_a_real_frame[eyes]) { - /* Use the last frame that we encoded. */ - _writer->repeat (_video_frames_out, eyes); + _writer->fake_write (_video_frames_out, pvf->eyes ()); frame_done (); } else { /* Queue this new frame for encoding */ TIMING ("adding to queue of %1", _queue.size ()); _queue.push_back (shared_ptr ( new DCPVideoFrame ( - image, _video_frames_out, eyes, conversion, _film->video_frame_rate(), - _film->j2k_bandwidth(), _film->log() + pvf, + _video_frames_out, + _film->video_frame_rate(), + _film->j2k_bandwidth(), + _film->resolution(), + _film->log() ) )); _condition.notify_all (); - _have_a_real_frame[eyes] = true; } - if (eyes != EYES_LEFT) { + if (pvf->eyes() != EYES_LEFT) { ++_video_frames_out; } } @@ -255,6 +256,7 @@ Encoder::terminate_threads () void Encoder::encoder_thread (optional server) +try { /* Number of seconds that we currently wait between attempts to connect to the server; not relevant for localhost @@ -276,7 +278,7 @@ Encoder::encoder_thread (optional server) TIMING ("encoder thread %1 wakes with queue of %2", boost::this_thread::get_id(), _queue.size()); shared_ptr vf = _queue.front (); - _film->log()->log (String::compose (N_("Encoder thread %1 pops frame %2 (%3) from queue"), boost::this_thread::get_id(), vf->frame(), vf->eyes ())); + TIMING ("encoder thread %1 pops frame %2 (%3) from queue", boost::this_thread::get_id(), vf->index(), vf->eyes ()); _queue.pop_front (); lock.unlock (); @@ -302,27 +304,27 @@ Encoder::encoder_thread (optional server) _film->log()->log ( String::compose ( N_("Remote encode of %1 on %2 failed (%3); thread sleeping for %4s"), - vf->frame(), server->host_name(), e.what(), remote_backoff) + vf->index(), server->host_name(), e.what(), remote_backoff) ); } } else { try { - TIMING ("encoder thread %1 begins local encode of %2", boost::this_thread::get_id(), vf->frame()); + TIMING ("encoder thread %1 begins local encode of %2", boost::this_thread::get_id(), vf->index()); encoded = vf->encode_locally (); - TIMING ("encoder thread %1 finishes local encode of %2", boost::this_thread::get_id(), vf->frame()); + TIMING ("encoder thread %1 finishes local encode of %2", boost::this_thread::get_id(), vf->index()); } catch (std::exception& e) { _film->log()->log (String::compose (N_("Local encode failed (%1)"), e.what ())); } } if (encoded) { - _writer->write (encoded, vf->frame (), vf->eyes ()); + _writer->write (encoded, vf->index (), vf->eyes ()); frame_done (); } else { lock.lock (); _film->log()->log ( - String::compose (N_("Encoder thread %1 pushes frame %2 back onto queue after failure"), boost::this_thread::get_id(), vf->frame()) + String::compose (N_("Encoder thread %1 pushes frame %2 back onto queue after failure"), boost::this_thread::get_id(), vf->index()) ); _queue.push_front (vf); lock.unlock (); @@ -336,6 +338,10 @@ Encoder::encoder_thread (optional server) _condition.notify_all (); } } +catch (...) +{ + store_current (); +} void Encoder::server_found (ServerDescription s)