From d89f53b1ad09cf0f739533483915b702a26594b4 Mon Sep 17 00:00:00 2001 From: Carl Hetherington Date: Fri, 14 Aug 2020 13:44:58 +0200 Subject: [PATCH] wip: encoding; crashes on startup. --- src/lib/encode_server.cc | 4 ++- src/lib/event_history.cc | 18 +++++++--- src/lib/event_history.h | 6 ++-- src/lib/j2k_encoder.cc | 50 ++++++++++++++++++--------- src/lib/j2k_encoder.h | 2 +- src/lib/j2k_encoder_backend.h | 7 +++- src/lib/j2k_encoder_cpu_backend.cc | 12 +++++-- src/lib/j2k_encoder_cpu_backend.h | 2 +- src/lib/j2k_encoder_remote_backend.cc | 14 +++++--- src/lib/j2k_encoder_remote_backend.h | 2 +- src/lib/player_video.cc | 2 +- src/lib/wscript | 1 + src/tools/server_test.cc | 9 +++-- test/client_server_test.cc | 25 +++++++++++--- wscript | 2 +- 15 files changed, 112 insertions(+), 44 deletions(-) diff --git a/src/lib/encode_server.cc b/src/lib/encode_server.cc index 85f3ca7b0..acb40c1b2 100644 --- a/src/lib/encode_server.cc +++ b/src/lib/encode_server.cc @@ -142,10 +142,12 @@ EncodeServer::process (shared_ptr socket, struct timeval& after_read, st } shared_ptr frame(new DCPVideo(pvf, xml)); + vector > frames; + frames.push_back (frame); gettimeofday (&after_read, 0); - Data encoded = *_cpu_encoder.encode (frame); + Data encoded = _cpu_encoder.encode (frames).front(); gettimeofday (&after_encode, 0); diff --git a/src/lib/event_history.cc b/src/lib/event_history.cc index efe80b243..75ef3319e 100644 --- a/src/lib/event_history.cc +++ b/src/lib/event_history.cc @@ -22,8 +22,13 @@ #include "util.h" #include + +using std::list; +using std::make_pair; +using std::pair; using boost::optional; + EventHistory::EventHistory (int size) : _size (size) { @@ -38,21 +43,26 @@ EventHistory::rate () const return optional(); } + int total = 0; + for (list >::const_iterator i = _history.begin(); i != _history.end(); ++i) { + total += i->second; + } + struct timeval now; gettimeofday (&now, 0); - return _size / (seconds (now) - seconds (_history.back ())); + return total / (seconds(now) - seconds(_history.back().first)); } void -EventHistory::event () +EventHistory::event (int count) { boost::mutex::scoped_lock lock (_mutex); struct timeval tv; gettimeofday (&tv, 0); - _history.push_front (tv); - if (int (_history.size()) > _size) { + _history.push_front (make_pair(tv, count)); + if (int(_history.size()) > _size) { _history.pop_back (); } } diff --git a/src/lib/event_history.h b/src/lib/event_history.h index 4670e7bfe..51684ea16 100644 --- a/src/lib/event_history.h +++ b/src/lib/event_history.h @@ -31,7 +31,7 @@ public: explicit EventHistory (int size); boost::optional rate () const; - void event (); + void event (int count = 1); private: /** Mutex for _history */ @@ -39,8 +39,8 @@ private: /** List of the times of the last _history_size events first is the most recently completed. */ - std::list _history; - /** Number of events that we should keep history for */ + std::list > _history; + /** Maximum size of _history */ int const _size; }; diff --git a/src/lib/j2k_encoder.cc b/src/lib/j2k_encoder.cc index ef38aaa55..8c915b567 100644 --- a/src/lib/j2k_encoder.cc +++ b/src/lib/j2k_encoder.cc @@ -26,6 +26,7 @@ #include "j2k_encoder_backend.h" #include "j2k_encoder_cpu_backend.h" #include "j2k_encoder_remote_backend.h" +#include "j2k_encoder_fastvideo_backend.h" #include "util.h" #include "film.h" #include "log.h" @@ -48,6 +49,7 @@ using std::list; using std::cout; using std::exception; +using std::vector; using boost::shared_ptr; using boost::weak_ptr; using boost::optional; @@ -130,12 +132,15 @@ J2KEncoder::end () BOOST_FOREACH (shared_ptr i, _queue) { LOG_GENERAL (N_("Encode left-over frame %1"), i->index()); try { + /* XXX: ewww */ + vector > frames; + frames.push_back (i); _writer->write ( - *_cpu_backend->encode(i), + _cpu_backend->encode(frames).front(), i->index(), i->frame()->eyes() ); - frame_done (); + frames_done (1); } catch (std::exception& e) { LOG_ERROR (N_("Local encode failed (%1)"), e.what ()); } @@ -164,9 +169,9 @@ J2KEncoder::video_frames_enqueued () const /** Should be called when a frame has been encoded successfully */ void -J2KEncoder::frame_done () +J2KEncoder::frames_done (int number) { - _history.event (); + _history.event (number); } /** Called to request encoding of the next video frame in the DCP. This is called in order, @@ -208,7 +213,7 @@ J2KEncoder::encode (shared_ptr pv, DCPTime time) /* We can fake-write this frame */ LOG_DEBUG_ENCODE("Frame @ %1 FAKE", to_string(time)); _writer->fake_write (position, pv->eyes ()); - frame_done (); + frames_done (1); } else if (pv->has_j2k() && !_film->reencode_j2k()) { LOG_DEBUG_ENCODE("Frame @ %1 J2K", to_string(time)); /* This frame already has J2K data, so just write it */ @@ -271,34 +276,44 @@ try LOG_TIMING ("encoder-sleep thread=%1", thread_id ()); boost::mutex::scoped_lock lock (_queue_mutex); - while (_queue.empty ()) { + while (static_cast(_queue.size()) < backend->quantity()) { _empty_condition.wait (lock); } LOG_TIMING ("encoder-wake thread=%1 queue=%2", thread_id(), _queue.size()); - shared_ptr vf = _queue.front (); + vector > video; + for (int i = 0; i < backend->quantity(); ++i) { + video.push_back (_queue.front()); + } - /* We're about to commit to either encoding this frame or putting it back onto the queue, + /* We're about to commit to either encoding these frame(s) or putting them back onto the queue, so we must not be interrupted until one or other of these things have happened. This block has thread interruption disabled. */ { boost::this_thread::disable_interruption dis; - LOG_TIMING ("encoder-pop thread=%1 frame=%2 eyes=%3", thread_id(), vf->index(), (int) vf->frame()->eyes()); - _queue.pop_front (); + LOG_TIMING ("encoder-pop thread=%1 frames=%2 eyes=%3", thread_id(), video.size()); + for (int i = 0; i < backend->quantity(); ++i) { + _queue.pop_front (); + } lock.unlock (); - optional encoded = backend->encode (vf); + vector encoded = backend->encode (video); - if (encoded) { - _writer->write (encoded.get(), vf->index (), vf->frame()->eyes()); - frame_done (); + if (!encoded.empty()) { + DCPOMATIC_ASSERT (static_cast(encoded.size()) == backend->quantity()); + for (int i = 0; i < backend->quantity(); ++i) { + _writer->write (encoded[i], video[i]->index(), video[i]->frame()->eyes()); + } + frames_done (backend->quantity()); } else { lock.lock (); - LOG_GENERAL (N_("[%1] J2KEncoder thread pushes frame %2 back onto queue after failure"), thread_id(), vf->index()); - _queue.push_front (vf); + LOG_GENERAL (N_("[%1] J2KEncoder thread pushes %2 frames back onto queue after failure"), thread_id(), video.size()); + for (vector >::const_reverse_iterator i = video.rbegin(); i != video.rend(); ++i) { + _queue.push_front (*i); + } lock.unlock (); } } @@ -350,5 +365,8 @@ J2KEncoder::servers_list_changed () } } + shared_ptr fastvideo(new J2KEncoderFastvideoBackend()); + _threads->create_thread(boost::bind(&J2KEncoder::encoder_thread, this, fastvideo)); + _writer->set_encoder_threads (_threads->size()); } diff --git a/src/lib/j2k_encoder.h b/src/lib/j2k_encoder.h index df23a5bae..cc782d96d 100644 --- a/src/lib/j2k_encoder.h +++ b/src/lib/j2k_encoder.h @@ -81,7 +81,7 @@ private: static void call_servers_list_changed (boost::weak_ptr encoder); - void frame_done (); + void frames_done (int number); void encoder_thread (boost::shared_ptr backend); void terminate_threads (); diff --git a/src/lib/j2k_encoder_backend.h b/src/lib/j2k_encoder_backend.h index 7688e5f15..a19beda53 100644 --- a/src/lib/j2k_encoder_backend.h +++ b/src/lib/j2k_encoder_backend.h @@ -2,6 +2,7 @@ #define DCPOMATIC_J2K_ENCODER_BACKEND_H #include +#include #include #include #include @@ -13,7 +14,11 @@ class DCPVideo; class J2KEncoderBackend : public boost::noncopyable { public: - virtual boost::optional encode (boost::shared_ptr video) = 0; + virtual std::vector encode (std::vector > video) = 0; + + virtual int quantity () const { + return 1; + } }; #endif diff --git a/src/lib/j2k_encoder_cpu_backend.cc b/src/lib/j2k_encoder_cpu_backend.cc index 732913c06..bdd393332 100644 --- a/src/lib/j2k_encoder_cpu_backend.cc +++ b/src/lib/j2k_encoder_cpu_backend.cc @@ -10,14 +10,18 @@ using std::string; +using std::vector; using boost::optional; using boost::shared_ptr; using dcp::Data; -optional -J2KEncoderCPUBackend::encode (shared_ptr video) +vector +J2KEncoderCPUBackend::encode (vector > all_video) { + DCPOMATIC_ASSERT (all_video.size() == 1); + shared_ptr video = all_video.front(); + try { LOG_TIMING ("start-local-encode thread=%1 frame=%2", thread_id(), video->index()); string const comment = Config::instance()->dcp_j2k_comment(); @@ -46,7 +50,9 @@ J2KEncoderCPUBackend::encode (shared_ptr video) } LOG_TIMING ("finish-local-encode thread=%1 frame=%2", thread_id(), video->index()); - return enc; + vector data; + data.push_back (enc); + return data; } catch (std::exception& e) { /* This is very bad, so don't cope with it, just pass it on */ LOG_ERROR (N_("Local encode failed (%1)"), e.what()); diff --git a/src/lib/j2k_encoder_cpu_backend.h b/src/lib/j2k_encoder_cpu_backend.h index 75d7c97a7..9518b5349 100644 --- a/src/lib/j2k_encoder_cpu_backend.h +++ b/src/lib/j2k_encoder_cpu_backend.h @@ -8,7 +8,7 @@ class J2KEncoderCPUBackend : public J2KEncoderBackend { public: - boost::optional encode (boost::shared_ptr video); + std::vector encode (std::vector > video); }; #endif diff --git a/src/lib/j2k_encoder_remote_backend.cc b/src/lib/j2k_encoder_remote_backend.cc index 831134718..40d9a1871 100644 --- a/src/lib/j2k_encoder_remote_backend.cc +++ b/src/lib/j2k_encoder_remote_backend.cc @@ -18,6 +18,7 @@ DCPOMATIC_ENABLE_WARNINGS using std::string; +using std::vector; using boost::optional; using boost::shared_ptr; using dcp::Data; @@ -32,9 +33,12 @@ J2KEncoderRemoteBackend::J2KEncoderRemoteBackend (EncodeServerDescription server } -optional -J2KEncoderRemoteBackend::encode (shared_ptr video) +vector +J2KEncoderRemoteBackend::encode (vector > all_video) { + DCPOMATIC_ASSERT (all_video.size() == 1); + shared_ptr video = all_video.front(); + int const timeout = 30; try { @@ -90,7 +94,9 @@ J2KEncoderRemoteBackend::encode (shared_ptr video) /* This job succeeded, so remove any backoff */ _backoff = 0; - return e; + vector data; + data.push_back(e); + return data; } catch (std::exception& e) { if (_backoff < 60) { @@ -102,7 +108,7 @@ J2KEncoderRemoteBackend::encode (shared_ptr video) ); boost::this_thread::sleep (boost::posix_time::seconds(_backoff)); - return optional(); + return vector(); } } diff --git a/src/lib/j2k_encoder_remote_backend.h b/src/lib/j2k_encoder_remote_backend.h index 5e62cd9a9..b17ac0407 100644 --- a/src/lib/j2k_encoder_remote_backend.h +++ b/src/lib/j2k_encoder_remote_backend.h @@ -6,7 +6,7 @@ class J2KEncoderRemoteBackend : public J2KEncoderBackend { public: J2KEncoderRemoteBackend (EncodeServerDescription server); - boost::optional encode (boost::shared_ptr video); + std::vector encode (std::vector > video); private: EncodeServerDescription _server; diff --git a/src/lib/player_video.cc b/src/lib/player_video.cc index 3c2f3f094..e88b65346 100644 --- a/src/lib/player_video.cc +++ b/src/lib/player_video.cc @@ -117,7 +117,7 @@ PlayerVideo::image (function pixel_format, bool a boost::mutex::scoped_lock lm (_mutex); if (!_image || _crop != _image_crop || _inter_size != _image_inter_size || _out_size != _image_out_size || _fade != _image_fade) { - timestamped_printf("_________________!!! make_image() for %d [%d]\n", time.frames_round(24), !_image); + //timestamped_printf("_________________!!! make_image() for %d [%d]\n", time.frames_round(24), !_image); make_image (pixel_format, aligned, fast); } return _image; diff --git a/src/lib/wscript b/src/lib/wscript index 59cc145a2..64ddc0762 100644 --- a/src/lib/wscript +++ b/src/lib/wscript @@ -127,6 +127,7 @@ sources = """ j2k_image_proxy.cc j2k_encoder.cc j2k_encoder_cpu_backend.cc + j2k_encoder_fastvideo_backend.cc j2k_encoder_remote_backend.cc job.cc job_manager.cc diff --git a/src/tools/server_test.cc b/src/tools/server_test.cc index 4f8d0b4d1..931b27082 100644 --- a/src/tools/server_test.cc +++ b/src/tools/server_test.cc @@ -42,6 +42,7 @@ using std::cout; using std::cerr; using std::string; using std::pair; +using std::vector; using boost::shared_ptr; using boost::optional; using boost::bind; @@ -58,7 +59,11 @@ void process_video (shared_ptr pvf) { shared_ptr local (new DCPVideo (pvf, frame_count, film->video_frame_rate(), 250000000, RESOLUTION_2K)); + vector > locals; + locals.push_back (local); shared_ptr remote (new DCPVideo (pvf, frame_count, film->video_frame_rate(), 250000000, RESOLUTION_2K)); + vector > remotes; + remotes.push_back (remote); cout << "Frame " << frame_count << ": "; cout.flush (); @@ -66,13 +71,13 @@ process_video (shared_ptr pvf) ++frame_count; J2KEncoderCPUBackend cpu_backend; - Data local_encoded = *cpu_backend.encode (local); + Data local_encoded = cpu_backend.encode(locals).front(); Data remote_encoded; string remote_error; try { J2KEncoderRemoteBackend remote_backend(*server); - remote_encoded = *remote_backend.encode (remote); + remote_encoded = remote_backend.encode(remotes).front(); } catch (NetworkError& e) { remote_error = e.what (); } diff --git a/test/client_server_test.cc b/test/client_server_test.cc index c0c853fc1..6f49f68b5 100644 --- a/test/client_server_test.cc +++ b/test/client_server_test.cc @@ -44,6 +44,7 @@ #include using std::list; +using std::vector; using boost::shared_ptr; using boost::thread; using boost::optional; @@ -56,7 +57,9 @@ void do_remote_encode (shared_ptr frame, shared_ptr backend, Data locally_encoded) { Data remotely_encoded; - BOOST_REQUIRE_NO_THROW (remotely_encoded = *backend->encode(frame)); + vector > frames; + frames.push_back (frame); + BOOST_REQUIRE_NO_THROW (remotely_encoded = backend->encode(frames).front()); BOOST_REQUIRE_EQUAL (locally_encoded.size(), remotely_encoded.size()); BOOST_CHECK_EQUAL (memcmp (locally_encoded.data().get(), remotely_encoded.data().get(), locally_encoded.size()), 0); @@ -122,8 +125,11 @@ BOOST_AUTO_TEST_CASE (client_server_test_rgb) ) ); + vector > frames; + frames.push_back (frame); + J2KEncoderCPUBackend cpu; - Data locally_encoded = *cpu.encode(frame); + Data locally_encoded = cpu.encode(frames).front(); EncodeServer* server = new EncodeServer (true, 2); @@ -210,8 +216,11 @@ BOOST_AUTO_TEST_CASE (client_server_test_yuv) ) ); + vector > frames; + frames.push_back (frame); + J2KEncoderCPUBackend cpu; - Data locally_encoded = *cpu.encode(frame); + Data locally_encoded = cpu.encode(frames).front(); EncodeServer* server = new EncodeServer (true, 2); @@ -283,8 +292,11 @@ BOOST_AUTO_TEST_CASE (client_server_test_j2k) ) ); + vector > raw_frames; + raw_frames.push_back (raw_frame); + J2KEncoderCPUBackend cpu; - Data raw_locally_encoded = *cpu.encode(raw_frame); + Data raw_locally_encoded = cpu.encode(raw_frames).front(); shared_ptr j2k_pvf ( new PlayerVideo ( @@ -313,7 +325,10 @@ BOOST_AUTO_TEST_CASE (client_server_test_j2k) ) ); - Data j2k_locally_encoded = *cpu.encode(j2k_frame); + vector > j2k_frames; + j2k_frames.push_back (j2k_frame); + + Data j2k_locally_encoded = cpu.encode(j2k_frames).front(); EncodeServer* server = new EncodeServer (true, 2); diff --git a/wscript b/wscript index 010fe8791..523052ee4 100644 --- a/wscript +++ b/wscript @@ -571,7 +571,7 @@ def configure(conf): if conf.options.fastvideo_sdk is not None: conf.env.INCLUDES_FASTVIDEO = [os.path.join(conf.options.fastvideo_sdk, "fastvideo_sdk", "inc") ] conf.env.LIBPATH_FASTVIDEO = [ os.path.join(conf.options.fastvideo_sdk, "fastvideo_sdk", "lib") ] - conf.env.LIB_FASTVIDEO = [ 'fastvideo_decoder_j2k', 'fastvideo_sdk', 'cuda', 'cudart' ] + conf.env.LIB_FASTVIDEO = [ 'fastvideo_decoder_j2k', 'fastvideo_encoder_j2k', 'fastvideo_sdk', 'cuda', 'cudart', 'omp5' ] # Other stuff -- 2.30.2