}
shared_ptr<DCPVideo> frame(new DCPVideo(pvf, xml));
+ vector<shared_ptr<DCPVideo> > 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);
#include "util.h"
#include <boost/thread/mutex.hpp>
+
+using std::list;
+using std::make_pair;
+using std::pair;
using boost::optional;
+
EventHistory::EventHistory (int size)
: _size (size)
{
return optional<float>();
}
+ int total = 0;
+ for (list<pair<struct timeval, int> >::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 ();
}
}
explicit EventHistory (int size);
boost::optional<float> rate () const;
- void event ();
+ void event (int count = 1);
private:
/** Mutex for _history */
/** List of the times of the last _history_size events
first is the most recently completed.
*/
- std::list<struct timeval> _history;
- /** Number of events that we should keep history for */
+ std::list<std::pair<struct timeval, int> > _history;
+ /** Maximum size of _history */
int const _size;
};
#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"
using std::list;
using std::cout;
using std::exception;
+using std::vector;
using boost::shared_ptr;
using boost::weak_ptr;
using boost::optional;
BOOST_FOREACH (shared_ptr<DCPVideo> i, _queue) {
LOG_GENERAL (N_("Encode left-over frame %1"), i->index());
try {
+ /* XXX: ewww */
+ vector<shared_ptr<DCPVideo> > 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 ());
}
/** 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,
/* 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 */
LOG_TIMING ("encoder-sleep thread=%1", thread_id ());
boost::mutex::scoped_lock lock (_queue_mutex);
- while (_queue.empty ()) {
+ while (static_cast<int>(_queue.size()) < backend->quantity()) {
_empty_condition.wait (lock);
}
LOG_TIMING ("encoder-wake thread=%1 queue=%2", thread_id(), _queue.size());
- shared_ptr<DCPVideo> vf = _queue.front ();
+ vector<shared_ptr<DCPVideo> > 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<Data> encoded = backend->encode (vf);
+ vector<Data> encoded = backend->encode (video);
- if (encoded) {
- _writer->write (encoded.get(), vf->index (), vf->frame()->eyes());
- frame_done ();
+ if (!encoded.empty()) {
+ DCPOMATIC_ASSERT (static_cast<int>(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<shared_ptr<DCPVideo> >::const_reverse_iterator i = video.rbegin(); i != video.rend(); ++i) {
+ _queue.push_front (*i);
+ }
lock.unlock ();
}
}
}
}
+ shared_ptr<J2KEncoderFastvideoBackend> fastvideo(new J2KEncoderFastvideoBackend());
+ _threads->create_thread(boost::bind(&J2KEncoder::encoder_thread, this, fastvideo));
+
_writer->set_encoder_threads (_threads->size());
}
static void call_servers_list_changed (boost::weak_ptr<J2KEncoder> encoder);
- void frame_done ();
+ void frames_done (int number);
void encoder_thread (boost::shared_ptr<J2KEncoderBackend> backend);
void terminate_threads ();
#define DCPOMATIC_J2K_ENCODER_BACKEND_H
#include <dcp/data.h>
+#include <boost/foreach.hpp>
#include <boost/noncopyable.hpp>
#include <boost/optional.hpp>
#include <boost/shared_ptr.hpp>
class J2KEncoderBackend : public boost::noncopyable
{
public:
- virtual boost::optional<dcp::Data> encode (boost::shared_ptr<DCPVideo> video) = 0;
+ virtual std::vector<dcp::Data> encode (std::vector<boost::shared_ptr<DCPVideo> > video) = 0;
+
+ virtual int quantity () const {
+ return 1;
+ }
};
#endif
using std::string;
+using std::vector;
using boost::optional;
using boost::shared_ptr;
using dcp::Data;
-optional<Data>
-J2KEncoderCPUBackend::encode (shared_ptr<DCPVideo> video)
+vector<Data>
+J2KEncoderCPUBackend::encode (vector<shared_ptr<DCPVideo> > all_video)
{
+ DCPOMATIC_ASSERT (all_video.size() == 1);
+ shared_ptr<DCPVideo> 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();
}
LOG_TIMING ("finish-local-encode thread=%1 frame=%2", thread_id(), video->index());
- return enc;
+ vector<Data> 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());
class J2KEncoderCPUBackend : public J2KEncoderBackend
{
public:
- boost::optional<dcp::Data> encode (boost::shared_ptr<DCPVideo> video);
+ std::vector<dcp::Data> encode (std::vector<boost::shared_ptr<DCPVideo> > video);
};
#endif
using std::string;
+using std::vector;
using boost::optional;
using boost::shared_ptr;
using dcp::Data;
}
-optional<Data>
-J2KEncoderRemoteBackend::encode (shared_ptr<DCPVideo> video)
+vector<Data>
+J2KEncoderRemoteBackend::encode (vector<shared_ptr<DCPVideo> > all_video)
{
+ DCPOMATIC_ASSERT (all_video.size() == 1);
+ shared_ptr<DCPVideo> video = all_video.front();
+
int const timeout = 30;
try {
/* This job succeeded, so remove any backoff */
_backoff = 0;
- return e;
+ vector<Data> data;
+ data.push_back(e);
+ return data;
} catch (std::exception& e) {
if (_backoff < 60) {
);
boost::this_thread::sleep (boost::posix_time::seconds(_backoff));
- return optional<Data>();
+ return vector<Data>();
}
}
{
public:
J2KEncoderRemoteBackend (EncodeServerDescription server);
- boost::optional<dcp::Data> encode (boost::shared_ptr<DCPVideo> video);
+ std::vector<dcp::Data> encode (std::vector<boost::shared_ptr<DCPVideo> > video);
private:
EncodeServerDescription _server;
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;
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
using std::cerr;
using std::string;
using std::pair;
+using std::vector;
using boost::shared_ptr;
using boost::optional;
using boost::bind;
process_video (shared_ptr<PlayerVideo> pvf)
{
shared_ptr<DCPVideo> local (new DCPVideo (pvf, frame_count, film->video_frame_rate(), 250000000, RESOLUTION_2K));
+ vector<shared_ptr<DCPVideo> > locals;
+ locals.push_back (local);
shared_ptr<DCPVideo> remote (new DCPVideo (pvf, frame_count, film->video_frame_rate(), 250000000, RESOLUTION_2K));
+ vector<shared_ptr<DCPVideo> > remotes;
+ remotes.push_back (remote);
cout << "Frame " << frame_count << ": ";
cout.flush ();
++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 ();
}
#include <boost/thread.hpp>
using std::list;
+using std::vector;
using boost::shared_ptr;
using boost::thread;
using boost::optional;
do_remote_encode (shared_ptr<DCPVideo> frame, shared_ptr<J2KEncoderBackend> backend, Data locally_encoded)
{
Data remotely_encoded;
- BOOST_REQUIRE_NO_THROW (remotely_encoded = *backend->encode(frame));
+ vector<shared_ptr<DCPVideo> > 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);
)
);
+ vector<shared_ptr<DCPVideo> > 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);
)
);
+ vector<shared_ptr<DCPVideo> > 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);
)
);
+ vector<shared_ptr<DCPVideo> > 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<PlayerVideo> j2k_pvf (
new PlayerVideo (
)
);
- Data j2k_locally_encoded = *cpu.encode(j2k_frame);
+ vector<shared_ptr<DCPVideo> > j2k_frames;
+ j2k_frames.push_back (j2k_frame);
+
+ Data j2k_locally_encoded = cpu.encode(j2k_frames).front();
EncodeServer* server = new EncodeServer (true, 2);
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