From 330879b3555317a20ffe6cad2a489a8adac2c77a Mon Sep 17 00:00:00 2001 From: Carl Hetherington Date: Sat, 1 Sep 2012 10:41:22 +0100 Subject: Add 1.66-within-Flat format. --- src/lib/format.cc | 1 + 1 file changed, 1 insertion(+) (limited to 'src/lib') diff --git a/src/lib/format.cc b/src/lib/format.cc index ff3a5b202..e689aa05d 100644 --- a/src/lib/format.cc +++ b/src/lib/format.cc @@ -82,6 +82,7 @@ Format::setup_formats () _formats.push_back (new Format (133, Size (1998, 1080), "133-in-flat", "4:3 within Flat")); _formats.push_back (new Format (137, Size (1480, 1080), "137", "Academy")); _formats.push_back (new Format (166, Size (1793, 1080), "166", "1.66")); + _formats.push_back (new Format (166, Size (1998, 1080), "166-in-flat", "1.66 within Flat")); _formats.push_back (new Format (178, Size (1998, 1080), "178-in-flat", "16:9 within Flat")); _formats.push_back (new Format (185, Size (1998, 1080), "185", "Flat")); _formats.push_back (new Format (239, Size (2048, 858), "239", "Scope")); -- cgit v1.2.3 From 677c1df8fb6cad316a51d074d819be39a3b279ee Mon Sep 17 00:00:00 2001 From: Carl Hetherington Date: Mon, 10 Sep 2012 15:15:10 +0100 Subject: Update for newer libdcp. --- src/lib/make_dcp_job.cc | 7 +++++-- wscript | 2 +- 2 files changed, 6 insertions(+), 3 deletions(-) (limited to 'src/lib') diff --git a/src/lib/make_dcp_job.cc b/src/lib/make_dcp_job.cc index 525f76c0e..8d3547cae 100644 --- a/src/lib/make_dcp_job.cc +++ b/src/lib/make_dcp_job.cc @@ -87,9 +87,12 @@ MakeDCPJob::run () break; } - libdcp::DCP dcp (_fs->dir (_fs->name), _fs->name, _fs->dcp_content_type->libdcp_kind (), rint (_fs->frames_per_second), frames); + libdcp::DCP dcp (_fs->dir (_fs->name)); dcp.Progress.connect (sigc::mem_fun (*this, &MakeDCPJob::dcp_progress)); + shared_ptr cpl (new libdcp::CPL (_fs->dir (_fs->name), _fs->name, _fs->dcp_content_type->libdcp_kind (), frames, rint (_fs->frames_per_second))); + dcp.add_cpl (cpl); + descend (0.9); shared_ptr pa ( new libdcp::MonoPictureAsset ( @@ -124,7 +127,7 @@ MakeDCPJob::run () ascend (); } - dcp.add_reel (shared_ptr (new libdcp::Reel (pa, sa, shared_ptr ()))); + cpl->add_reel (shared_ptr (new libdcp::Reel (pa, sa, shared_ptr ()))); dcp.write_xml (); set_progress (1); diff --git a/wscript b/wscript index d3ec0d1f4..bf9e041e3 100644 --- a/wscript +++ b/wscript @@ -60,7 +60,7 @@ def configure(conf): conf.check_cfg(package = 'libswresample', args = '--cflags --libs', uselib_store = 'SWRESAMPLE', mandatory = True) conf.check_cfg(package = 'libpostproc', args = '--cflags --libs', uselib_store = 'POSTPROC', mandatory = True) conf.check_cfg(package = 'sndfile', args = '--cflags --libs', uselib_store = 'SNDFILE', mandatory = True) - conf.check_cfg(package = 'libdcp', atleast_version = '0.11', args = '--cflags --libs', uselib_store = 'DCP', mandatory = True) + conf.check_cfg(package = 'libdcp', atleast_version = '0.20', args = '--cflags --libs', uselib_store = 'DCP', mandatory = True) conf.check_cfg(package = 'glib-2.0', args = '--cflags --libs', uselib_store = 'GLIB', mandatory = True) conf.check_cfg(package = '', path = 'Magick++-config', args = '--cppflags --cxxflags --libs', uselib_store = 'MAGICK', mandatory = True) conf.check_cc(msg = 'Checking for library libtiff', function_name = 'TIFFOpen', header_name = 'tiffio.h', lib = 'tiff', uselib_store = 'TIFF') -- cgit v1.2.3 From 3e3fa3f58b9ce62768ca8a977334ae1b5fe7da69 Mon Sep 17 00:00:00 2001 From: Carl Hetherington Date: Wed, 12 Sep 2012 10:54:39 +0100 Subject: Allow build using Ubuntu 12.04 repos. --- src/lib/decoder.cc | 40 +++++++++++++++++++++++++++++----------- src/lib/decoder.h | 6 +++++- src/lib/wscript | 1 + wscript | 2 +- 4 files changed, 36 insertions(+), 13 deletions(-) (limited to 'src/lib') diff --git a/src/lib/decoder.cc b/src/lib/decoder.cc index faee5bece..fc808d819 100644 --- a/src/lib/decoder.cc +++ b/src/lib/decoder.cc @@ -29,6 +29,8 @@ extern "C" { #if (LIBAVFILTER_VERSION_MAJOR == 2 && LIBAVFILTER_VERSION_MINOR >= 53 && LIBAVFILTER_VERSION_MINOR <= 77) || LIBAVFILTER_VERSION_MAJOR == 3 #include #include +#elif LIBAVFILTER_VERSION_MAJOR == 2 && LIBAVFILTER_VERSION_MINOR == 15 +#include #endif #include } @@ -67,7 +69,9 @@ Decoder::Decoder (boost::shared_ptr s, boost::shared_ptraudio_sample_rate != dcp_audio_sample_rate (_fs->audio_sample_rate)) { +#if HAVE_SWRESAMPLE _swr_context = swr_alloc_set_opts ( 0, audio_channel_layout(), @@ -99,8 +104,13 @@ Decoder::process_begin () ); swr_init (_swr_context); +#else + throw DecodeError ("Cannot resample audio as libswresample is not present"); +#endif } else { +#if HAVE_SWRESAMPLE _swr_context = 0; +#endif } _delay_in_bytes = _fs->audio_delay * _fs->audio_sample_rate * _fs->audio_channels * _fs->bytes_per_sample() / 1000; @@ -113,6 +123,7 @@ Decoder::process_begin () void Decoder::process_end () { +#if HAVE_SWRESAMPLE if (_swr_context) { int mop = 0; @@ -139,6 +150,7 @@ Decoder::process_end () swr_free (&_swr_context); } +#endif if (_delay_in_bytes < 0) { uint8_t remainder[-_delay_in_bytes]; @@ -227,10 +239,12 @@ Decoder::process_audio (uint8_t* data, int size) /* Here's samples per channel */ int const samples = size / _fs->bytes_per_sample(); +#if HAVE_SWRESAMPLE /* And here's frames (where 1 frame is a collection of samples, 1 for each channel, so for 5.1 a frame would be 6 samples) */ int const frames = samples / _fs->audio_channels; +#endif /* Maybe apply gain */ if (_fs->audio_gain != 0) { @@ -270,6 +284,7 @@ Decoder::process_audio (uint8_t* data, int size) uint8_t* out_buffer = 0; /* Maybe sample-rate convert */ +#if HAVE_SWRESAMPLE if (_swr_context) { uint8_t const * in[2] = { @@ -297,6 +312,7 @@ Decoder::process_audio (uint8_t* data, int size) data = out_buffer; size = out_frames * _fs->audio_channels * _fs->bytes_per_sample(); } +#endif /* Update the number of audio frames we've pushed to the encoder */ _audio_frames_processed += size / (_fs->audio_channels * _fs->bytes_per_sample ()); @@ -339,10 +355,8 @@ Decoder::process_video (AVFrame* frame) throw DecodeError ("could not push buffer into filter chain."); } -#else +#elif LIBAVFILTER_VERSION_MAJOR == 2 && LIBAVFILTER_VERSION_MINOR == 15 -#if 0 - AVRational par; par.num = sample_aspect_ratio_numerator (); par.den = sample_aspect_ratio_denominator (); @@ -351,7 +365,7 @@ Decoder::process_video (AVFrame* frame) throw DecodeError ("could not push buffer into filter chain."); } -#endif +#else if (av_buffersrc_write_frame (_buffer_src_context, frame) < 0) { throw DecodeError ("could not push buffer into filter chain."); @@ -359,13 +373,13 @@ Decoder::process_video (AVFrame* frame) #endif -#if LIBAVFILTER_VERSION_MAJOR == 2 && LIBAVFILTER_VERSION_MINOR >= 23 && LIBAVFILTER_VERSION_MINOR <= 61 +#if LIBAVFILTER_VERSION_MAJOR == 2 && LIBAVFILTER_VERSION_MINOR >= 15 && LIBAVFILTER_VERSION_MINOR <= 61 while (avfilter_poll_frame (_buffer_sink_context->inputs[0])) { #else while (av_buffersink_read (_buffer_sink_context, 0)) { #endif -#if LIBAVFILTER_VERSION_MAJOR == 2 && LIBAVFILTER_VERSION_MINOR == 53 +#if LIBAVFILTER_VERSION_MAJOR == 2 && LIBAVFILTER_VERSION_MINOR >= 15 int r = avfilter_request_frame (_buffer_sink_context->inputs[0]); if (r < 0) { @@ -434,10 +448,7 @@ Decoder::setup_video_filters () throw DecodeError ("Could not find buffer src filter"); } - AVFilter* buffer_sink = avfilter_get_by_name("buffersink"); - if (buffer_sink == 0) { - throw DecodeError ("Could not create buffer sink filter"); - } + AVFilter* buffer_sink = get_sink (); stringstream a; a << native_size().width << ":" @@ -471,10 +482,17 @@ Decoder::setup_video_filters () inputs->next = 0; _log->log ("Using filter chain `" + filters + "'"); + +#if LIBAVFILTER_VERSION_MAJOR == 2 && LIBAVFILTER_VERSION_MINOR == 15 + if (avfilter_graph_parse (graph, filters.c_str(), inputs, outputs, 0) < 0) { + throw DecodeError ("could not set up filter graph."); + } +#else if (avfilter_graph_parse (graph, filters.c_str(), &inputs, &outputs, 0) < 0) { throw DecodeError ("could not set up filter graph."); } - +#endif + if (avfilter_graph_config (graph, 0) < 0) { throw DecodeError ("could not configure filter graph."); } diff --git a/src/lib/decoder.h b/src/lib/decoder.h index 5c69e12d0..792f7dde2 100644 --- a/src/lib/decoder.h +++ b/src/lib/decoder.h @@ -29,9 +29,11 @@ #include #include #include +#ifdef HAVE_SWRESAMPLE extern "C" { #include -} +} +#endif #include "util.h" class Job; @@ -132,7 +134,9 @@ private: AVFilterContext* _buffer_src_context; AVFilterContext* _buffer_sink_context; +#if HAVE_SWRESAMPLE SwrContext* _swr_context; +#endif bool _have_setup_video_filters; DelayLine* _delay_line; diff --git a/src/lib/wscript b/src/lib/wscript index b001fff2a..71a2b23f4 100644 --- a/src/lib/wscript +++ b/src/lib/wscript @@ -28,6 +28,7 @@ def build(bld): encoder.cc encoder_factory.cc examine_content_job.cc + ffmpeg_compatibility.cc ffmpeg_decoder.cc film.cc film_state.cc diff --git a/wscript b/wscript index bf9e041e3..405fdf5b1 100644 --- a/wscript +++ b/wscript @@ -57,7 +57,7 @@ def configure(conf): conf.check_cfg(package = 'libavcodec', args = '--cflags --libs', uselib_store = 'AVCODEC', mandatory = True) conf.check_cfg(package = 'libavutil', args = '--cflags --libs', uselib_store = 'AVUTIL', mandatory = True) conf.check_cfg(package = 'libswscale', args = '--cflags --libs', uselib_store = 'SWSCALE', mandatory = True) - conf.check_cfg(package = 'libswresample', args = '--cflags --libs', uselib_store = 'SWRESAMPLE', mandatory = True) + conf.check_cfg(package = 'libswresample', args = '--cflags --libs', uselib_store = 'SWRESAMPLE', mandatory = False) conf.check_cfg(package = 'libpostproc', args = '--cflags --libs', uselib_store = 'POSTPROC', mandatory = True) conf.check_cfg(package = 'sndfile', args = '--cflags --libs', uselib_store = 'SNDFILE', mandatory = True) conf.check_cfg(package = 'libdcp', atleast_version = '0.20', args = '--cflags --libs', uselib_store = 'DCP', mandatory = True) -- cgit v1.2.3 From edd4f83959b196bef442387f99ecece034171464 Mon Sep 17 00:00:00 2001 From: Carl Hetherington Date: Wed, 12 Sep 2012 12:06:43 +0100 Subject: Fix crash when FFMpeg doesn't set up the audio channel layout for some reason. --- ChangeLog | 5 +++++ src/lib/ffmpeg_decoder.cc | 12 ++++++++++-- 2 files changed, 15 insertions(+), 2 deletions(-) (limited to 'src/lib') diff --git a/ChangeLog b/ChangeLog index fcb18baa1..47f701c29 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,8 @@ +2012-09-12 Carl Hetherington + + * Fix crash when FFmpeg doesn't set up the audio channel + layout for some reason. + 2012-09-01 Carl Hetherington * Add 1.66-within-flat format. diff --git a/src/lib/ffmpeg_decoder.cc b/src/lib/ffmpeg_decoder.cc index c12e6728d..3471ffaab 100644 --- a/src/lib/ffmpeg_decoder.cc +++ b/src/lib/ffmpeg_decoder.cc @@ -142,10 +142,18 @@ FFmpegDecoder::setup_audio () if (_audio_codec == 0) { throw DecodeError ("could not find audio decoder"); } - + if (avcodec_open2 (_audio_codec_context, _audio_codec, 0) < 0) { throw DecodeError ("could not open audio decoder"); } + + /* This is a hack; sometimes it seems that _audio_codec_context->channel_layout isn't set up, + so bodge it here. No idea why we should have to do this. + */ + + if (_audio_codec_context->channel_layout == 0) { + _audio_codec_context->channel_layout = av_get_default_channel_layout (audio_channels ()); + } } bool @@ -200,7 +208,7 @@ FFmpegDecoder::audio_channels () const if (_audio_codec_context == 0) { return 0; } - + return _audio_codec_context->channels; } -- cgit v1.2.3 From bfecc8e56b657b57b5a496ef38cbf52d9120547e Mon Sep 17 00:00:00 2001 From: Carl Hetherington Date: Wed, 12 Sep 2012 14:10:44 +0100 Subject: Add missing file. --- src/lib/ffmpeg_compatibility.cc | 109 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 109 insertions(+) create mode 100644 src/lib/ffmpeg_compatibility.cc (limited to 'src/lib') diff --git a/src/lib/ffmpeg_compatibility.cc b/src/lib/ffmpeg_compatibility.cc new file mode 100644 index 000000000..c47cdf5ce --- /dev/null +++ b/src/lib/ffmpeg_compatibility.cc @@ -0,0 +1,109 @@ +/* + Copyright (C) 2012 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 + 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. + +*/ + +extern "C" { +#include +} +#include "exceptions.h" + +#if LIBAVFILTER_VERSION_MAJOR == 2 && LIBAVFILTER_VERSION_MINOR == 15 + +typedef struct { + enum PixelFormat pix_fmt; +} AVSinkContext; + +static int +avsink_init (AVFilterContext* ctx, const char* args, void* opaque) +{ + AVSinkContext* priv = (AVSinkContext *) ctx->priv; + if (!opaque) { + return AVERROR (EINVAL); + } + + *priv = *(AVSinkContext *) opaque; + return 0; +} + +static void +null_end_frame (AVFilterLink *) +{ + +} + +static int +avsink_query_formats (AVFilterContext* ctx) +{ + AVSinkContext* priv = (AVSinkContext *) ctx->priv; + enum PixelFormat pix_fmts[] = { + priv->pix_fmt, + PIX_FMT_NONE + }; + + avfilter_set_common_formats (ctx, avfilter_make_format_list ((int *) pix_fmts)); + return 0; +} + +#endif + +AVFilter* +get_sink () +{ +#if LIBAVFILTER_VERSION_MAJOR == 2 && LIBAVFILTER_VERSION_MINOR == 15 + /* XXX does this leak stuff? */ + AVFilter* buffer_sink = new AVFilter; + buffer_sink->name = av_strdup ("avsink"); + buffer_sink->priv_size = sizeof (AVSinkContext); + buffer_sink->init = avsink_init; + buffer_sink->query_formats = avsink_query_formats; + buffer_sink->inputs = new AVFilterPad[2]; + AVFilterPad* i0 = const_cast (&buffer_sink->inputs[0]); + i0->name = "default"; + i0->type = AVMEDIA_TYPE_VIDEO; + i0->min_perms = AV_PERM_READ; + i0->rej_perms = 0; + i0->start_frame = 0; + i0->get_video_buffer = 0; + i0->get_audio_buffer = 0; + i0->end_frame = null_end_frame; + i0->draw_slice = 0; + i0->filter_samples = 0; + i0->poll_frame = 0; + i0->request_frame = 0; + i0->config_props = 0; + const_cast (&buffer_sink->inputs[1])->name = 0; + buffer_sink->outputs = new AVFilterPad[1]; + const_cast (&buffer_sink->outputs[0])->name = 0; + return buffer_sink; +#else + AVFilter* buffer_sink = avfilter_get_by_name("buffersink"); + if (buffer_sink == 0) { + throw DecodeError ("Could not create buffer sink filter"); + } + + return buffer_sink; +#endif +} + +#if LIBAVFILTER_VERSION_MAJOR == 2 && LIBAVFILTER_VERSION_MINOR == 15 +AVFilterInOut * +avfilter_inout_alloc () +{ + return (AVFilterInOut *) av_malloc (sizeof (AVFilterInOut)); +} +#endif -- cgit v1.2.3 From 1e8f1be709e8a3fa58f1147db2e58a39396313d8 Mon Sep 17 00:00:00 2001 From: Carl Hetherington Date: Mon, 17 Sep 2012 22:50:47 +0100 Subject: Move server code into library; Server -> ServerDescription. --- src/lib/config.cc | 4 +- src/lib/config.h | 8 +- src/lib/dcp_video_frame.cc | 2 +- src/lib/dcp_video_frame.h | 4 +- src/lib/j2k_wav_encoder.cc | 8 +- src/lib/j2k_wav_encoder.h | 4 +- src/lib/log.h | 5 ++ src/lib/server.cc | 163 +++++++++++++++++++++++++++++++++++-- src/lib/server.h | 32 ++++++-- src/tools/servomatic.cc | 194 -------------------------------------------- src/tools/servomatic_cli.cc | 50 ++++++++++++ src/tools/wscript | 2 +- src/wx/config_dialog.cc | 14 ++-- src/wx/config_dialog.h | 4 +- src/wx/server_dialog.cc | 6 +- src/wx/server_dialog.h | 8 +- 16 files changed, 270 insertions(+), 238 deletions(-) delete mode 100644 src/tools/servomatic.cc create mode 100644 src/tools/servomatic_cli.cc (limited to 'src/lib') diff --git a/src/lib/config.cc b/src/lib/config.cc index 53674645d..44d110689 100644 --- a/src/lib/config.cc +++ b/src/lib/config.cc @@ -76,7 +76,7 @@ Config::Config () } else if (k == "reference_filter") { _reference_filters.push_back (Filter::from_id (v)); } else if (k == "server") { - _servers.push_back (Server::create_from_metadata (v)); + _servers.push_back (ServerDescription::create_from_metadata (v)); } else if (k == "screen") { _screens.push_back (Screen::create_from_metadata (v)); } else if (k == "tms_ip") { @@ -131,7 +131,7 @@ Config::write () const f << "reference_filter " << (*i)->id () << "\n"; } - for (vector::const_iterator i = _servers.begin(); i != _servers.end(); ++i) { + for (vector::const_iterator i = _servers.begin(); i != _servers.end(); ++i) { f << "server " << (*i)->as_metadata () << "\n"; } diff --git a/src/lib/config.h b/src/lib/config.h index 14b541ee6..b002da7df 100644 --- a/src/lib/config.h +++ b/src/lib/config.h @@ -28,7 +28,7 @@ #include #include -class Server; +class ServerDescription; class Screen; class Scaler; class Filter; @@ -65,7 +65,7 @@ public: } /** @return J2K encoding servers to use */ - std::vector servers () const { + std::vector servers () const { return _servers; } @@ -126,7 +126,7 @@ public: } /** @param s New list of servers */ - void set_servers (std::vector s) { + void set_servers (std::vector s) { _servers = s; Changed (); } @@ -188,7 +188,7 @@ private: int _j2k_bandwidth; /** J2K encoding servers to use */ - std::vector _servers; + std::vector _servers; /** Screen definitions */ std::vector > _screens; diff --git a/src/lib/dcp_video_frame.cc b/src/lib/dcp_video_frame.cc index 24cdda2e6..91c441543 100644 --- a/src/lib/dcp_video_frame.cc +++ b/src/lib/dcp_video_frame.cc @@ -289,7 +289,7 @@ DCPVideoFrame::encode_locally () * @return Encoded data. */ shared_ptr -DCPVideoFrame::encode_remotely (Server const * serv) +DCPVideoFrame::encode_remotely (ServerDescription const * serv) { asio::io_service io_service; asio::ip::tcp::resolver resolver (io_service); diff --git a/src/lib/dcp_video_frame.h b/src/lib/dcp_video_frame.h index 464d48515..ee54bc0f5 100644 --- a/src/lib/dcp_video_frame.h +++ b/src/lib/dcp_video_frame.h @@ -27,7 +27,7 @@ class FilmState; class Options; -class Server; +class ServerDescription; class Scaler; class Image; class Log; @@ -113,7 +113,7 @@ public: virtual ~DCPVideoFrame (); boost::shared_ptr encode_locally (); - boost::shared_ptr encode_remotely (Server const *); + boost::shared_ptr encode_remotely (ServerDescription const *); int frame () const { return _frame; diff --git a/src/lib/j2k_wav_encoder.cc b/src/lib/j2k_wav_encoder.cc index 2f29f9021..ff450d1ad 100644 --- a/src/lib/j2k_wav_encoder.cc +++ b/src/lib/j2k_wav_encoder.cc @@ -130,7 +130,7 @@ J2KWAVEncoder::process_video (shared_ptr yuv, int frame) } void -J2KWAVEncoder::encoder_thread (Server* server) +J2KWAVEncoder::encoder_thread (ServerDescription* server) { /* Number of seconds that we currently wait between attempts to connect to the server; not relevant for localhost @@ -210,12 +210,12 @@ void J2KWAVEncoder::process_begin () { for (int i = 0; i < Config::instance()->num_local_encoding_threads (); ++i) { - _worker_threads.push_back (new boost::thread (boost::bind (&J2KWAVEncoder::encoder_thread, this, (Server *) 0))); + _worker_threads.push_back (new boost::thread (boost::bind (&J2KWAVEncoder::encoder_thread, this, (ServerDescription *) 0))); } - vector servers = Config::instance()->servers (); + vector servers = Config::instance()->servers (); - for (vector::iterator i = servers.begin(); i != servers.end(); ++i) { + for (vector::iterator i = servers.begin(); i != servers.end(); ++i) { for (int j = 0; j < (*i)->threads (); ++j) { _worker_threads.push_back (new boost::thread (boost::bind (&J2KWAVEncoder::encoder_thread, this, *i))); } diff --git a/src/lib/j2k_wav_encoder.h b/src/lib/j2k_wav_encoder.h index 656af8321..1c2f50065 100644 --- a/src/lib/j2k_wav_encoder.h +++ b/src/lib/j2k_wav_encoder.h @@ -29,7 +29,7 @@ #include #include "encoder.h" -class Server; +class ServerDescription; class DCPVideoFrame; class Image; class Log; @@ -50,7 +50,7 @@ public: private: - void encoder_thread (Server *); + void encoder_thread (ServerDescription *); void close_sound_files (); void terminate_worker_threads (); diff --git a/src/lib/log.h b/src/lib/log.h index d4de8ebde..d32b368f5 100644 --- a/src/lib/log.h +++ b/src/lib/log.h @@ -17,6 +17,9 @@ */ +#ifndef DVDOMATIC_LOG_H +#define DVDOMATIC_LOG_H + /** @file src/log.h * @brief A very simple logging class. */ @@ -53,3 +56,5 @@ private: /** level above which to ignore log messages */ Level _level; }; + +#endif diff --git a/src/lib/server.cc b/src/lib/server.cc index 8a5b5cfca..f4aaa25e1 100644 --- a/src/lib/server.cc +++ b/src/lib/server.cc @@ -19,7 +19,7 @@ /** @file src/server.cc * @brief Class to describe a server to which we can send - * encoding work. + * encoding work, and a class to implement such a server. */ #include @@ -27,16 +27,21 @@ #include #include #include "server.h" +#include "util.h" +#include "scaler.h" +#include "image.h" +#include "dcp_video_frame.h" +#include "config.h" using namespace std; using namespace boost; -/** Create a server from a string of metadata returned from as_metadata(). +/** Create a server description from a string of metadata returned from as_metadata(). * @param v Metadata. - * @return Server, or 0. + * @return ServerDescription, or 0. */ -Server * -Server::create_from_metadata (string v) +ServerDescription * +ServerDescription::create_from_metadata (string v) { vector b; split (b, v, is_any_of (" ")); @@ -45,14 +50,158 @@ Server::create_from_metadata (string v) return 0; } - return new Server (b[0], atoi (b[1].c_str ())); + return new ServerDescription (b[0], atoi (b[1].c_str ())); } /** @return Description of this server as text */ string -Server::as_metadata () const +ServerDescription::as_metadata () const { stringstream s; s << _host_name << " " << _threads; return s.str (); } + +Server::Server () + : _log ("servomatic.log") +{ + +} + +int +Server::process (shared_ptr socket) +{ + SocketReader reader (socket); + + char buffer[128]; + reader.read_indefinite ((uint8_t *) buffer, sizeof (buffer)); + reader.consume (strlen (buffer) + 1); + + stringstream s (buffer); + + string command; + s >> command; + if (command != "encode") { + return -1; + } + + Size in_size; + int pixel_format_int; + Size out_size; + int padding; + string scaler_id; + int frame; + float frames_per_second; + string post_process; + int colour_lut_index; + int j2k_bandwidth; + + s >> in_size.width >> in_size.height + >> pixel_format_int + >> out_size.width >> out_size.height + >> padding + >> scaler_id + >> frame + >> frames_per_second + >> post_process + >> colour_lut_index + >> j2k_bandwidth; + + PixelFormat pixel_format = (PixelFormat) pixel_format_int; + Scaler const * scaler = Scaler::from_id (scaler_id); + if (post_process == "none") { + post_process = ""; + } + + shared_ptr image (new SimpleImage (pixel_format, in_size)); + + for (int i = 0; i < image->components(); ++i) { + int line_size; + s >> line_size; + image->set_line_size (i, line_size); + } + + for (int i = 0; i < image->components(); ++i) { + reader.read_definite_and_consume (image->data()[i], image->line_size()[i] * image->lines(i)); + } + +#ifdef DEBUG_HASH + image->hash ("Image for encoding (as received by server)"); +#endif + + DCPVideoFrame dcp_video_frame (image, out_size, padding, scaler, frame, frames_per_second, post_process, colour_lut_index, j2k_bandwidth, &_log); + shared_ptr encoded = dcp_video_frame.encode_locally (); + encoded->send (socket); + +#ifdef DEBUG_HASH + encoded->hash ("Encoded image (as made by server and as sent back)"); +#endif + + return frame; +} + +void +Server::worker_thread () +{ + while (1) { + mutex::scoped_lock lock (_worker_mutex); + while (_queue.empty ()) { + _worker_condition.wait (lock); + } + + shared_ptr socket = _queue.front (); + _queue.pop_front (); + + lock.unlock (); + + int frame = -1; + + struct timeval start; + gettimeofday (&start, 0); + + try { + frame = process (socket); + } catch (std::exception& e) { + cerr << "Error: " << e.what() << "\n"; + } + + socket.reset (); + + lock.lock (); + + if (frame >= 0) { + struct timeval end; + gettimeofday (&end, 0); + cout << "Encoded frame " << frame << " in " << (seconds (end) - seconds (start)) << "\n"; + } + + _worker_condition.notify_all (); + } +} + +void +Server::run () +{ + int const num_threads = Config::instance()->num_local_encoding_threads (); + + for (int i = 0; i < num_threads; ++i) { + _worker_threads.push_back (new thread (bind (&Server::worker_thread, this))); + } + + asio::io_service io_service; + asio::ip::tcp::acceptor acceptor (io_service, asio::ip::tcp::endpoint (asio::ip::tcp::v4(), Config::instance()->server_port ())); + while (1) { + shared_ptr socket (new asio::ip::tcp::socket (io_service)); + acceptor.accept (*socket); + + mutex::scoped_lock lock (_worker_mutex); + + /* Wait until the queue has gone down a bit */ + while (int (_queue.size()) >= num_threads * 2) { + _worker_condition.wait (lock); + } + + _queue.push_back (socket); + _worker_condition.notify_all (); + } +} diff --git a/src/lib/server.h b/src/lib/server.h index d06df34e9..8c0f86ebb 100644 --- a/src/lib/server.h +++ b/src/lib/server.h @@ -19,21 +19,25 @@ /** @file src/server.h * @brief Class to describe a server to which we can send - * encoding work. + * encoding work, and a class to implement such a server. */ #include +#include +#include +#include +#include "log.h" -/** @class Server +/** @class ServerDescription * @brief Class to describe a server to which we can send encoding work. */ -class Server +class ServerDescription { public: /** @param h Server host name or IP address in string form. * @param t Number of threads to use on the server. */ - Server (std::string h, int t) + ServerDescription (std::string h, int t) : _host_name (h) , _threads (t) {} @@ -58,7 +62,7 @@ public: std::string as_metadata () const; - static Server * create_from_metadata (std::string v); + static ServerDescription * create_from_metadata (std::string v); private: /** server's host name */ @@ -66,3 +70,21 @@ private: /** number of threads to use on the server */ int _threads; }; + +class Server +{ +public: + Server (); + + void run (); + +private: + void worker_thread (); + int process (boost::shared_ptr socket); + + std::vector _worker_threads; + std::list > _queue; + boost::mutex _worker_mutex; + boost::condition _worker_condition; + Log _log; +}; diff --git a/src/tools/servomatic.cc b/src/tools/servomatic.cc deleted file mode 100644 index a9c45b3df..000000000 --- a/src/tools/servomatic.cc +++ /dev/null @@ -1,194 +0,0 @@ -/* - Copyright (C) 2012 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 - 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 -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include "config.h" -#include "dcp_video_frame.h" -#include "exceptions.h" -#include "util.h" -#include "config.h" -#include "scaler.h" -#include "image.h" -#include "log.h" - -#define BACKLOG 8 - -using namespace std; -using namespace boost; - -static vector worker_threads; - -static std::list > queue; -static mutex worker_mutex; -static condition worker_condition; -static Log log_ ("servomatic.log"); - -int -process (shared_ptr socket) -{ - SocketReader reader (socket); - - char buffer[128]; - reader.read_indefinite ((uint8_t *) buffer, sizeof (buffer)); - reader.consume (strlen (buffer) + 1); - - stringstream s (buffer); - - string command; - s >> command; - if (command != "encode") { - return -1; - } - - Size in_size; - int pixel_format_int; - Size out_size; - int padding; - string scaler_id; - int frame; - float frames_per_second; - string post_process; - int colour_lut_index; - int j2k_bandwidth; - - s >> in_size.width >> in_size.height - >> pixel_format_int - >> out_size.width >> out_size.height - >> padding - >> scaler_id - >> frame - >> frames_per_second - >> post_process - >> colour_lut_index - >> j2k_bandwidth; - - PixelFormat pixel_format = (PixelFormat) pixel_format_int; - Scaler const * scaler = Scaler::from_id (scaler_id); - if (post_process == "none") { - post_process = ""; - } - - shared_ptr image (new SimpleImage (pixel_format, in_size)); - - for (int i = 0; i < image->components(); ++i) { - int line_size; - s >> line_size; - image->set_line_size (i, line_size); - } - - for (int i = 0; i < image->components(); ++i) { - reader.read_definite_and_consume (image->data()[i], image->line_size()[i] * image->lines(i)); - } - -#ifdef DEBUG_HASH - image->hash ("Image for encoding (as received by server)"); -#endif - - DCPVideoFrame dcp_video_frame (image, out_size, padding, scaler, frame, frames_per_second, post_process, colour_lut_index, j2k_bandwidth, &log_); - shared_ptr encoded = dcp_video_frame.encode_locally (); - encoded->send (socket); - -#ifdef DEBUG_HASH - encoded->hash ("Encoded image (as made by server and as sent back)"); -#endif - - return frame; -} - -void -worker_thread () -{ - while (1) { - mutex::scoped_lock lock (worker_mutex); - while (queue.empty ()) { - worker_condition.wait (lock); - } - - shared_ptr socket = queue.front (); - queue.pop_front (); - - lock.unlock (); - - int frame = -1; - - struct timeval start; - gettimeofday (&start, 0); - - try { - frame = process (socket); - } catch (std::exception& e) { - cerr << "Error: " << e.what() << "\n"; - } - - socket.reset (); - - lock.lock (); - - if (frame >= 0) { - struct timeval end; - gettimeofday (&end, 0); - cout << "Encoded frame " << frame << " in " << (seconds (end) - seconds (start)) << "\n"; - } - - worker_condition.notify_all (); - } -} - -int -main () -{ - Scaler::setup_scalers (); - - int const num_threads = Config::instance()->num_local_encoding_threads (); - - for (int i = 0; i < num_threads; ++i) { - worker_threads.push_back (new thread (worker_thread)); - } - - asio::io_service io_service; - asio::ip::tcp::acceptor acceptor (io_service, asio::ip::tcp::endpoint (asio::ip::tcp::v4(), Config::instance()->server_port ())); - while (1) { - shared_ptr socket (new asio::ip::tcp::socket (io_service)); - acceptor.accept (*socket); - - mutex::scoped_lock lock (worker_mutex); - - /* Wait until the queue has gone down a bit */ - while (int (queue.size()) >= num_threads * 2) { - worker_condition.wait (lock); - } - - queue.push_back (socket); - worker_condition.notify_all (); - } - - return 0; -} diff --git a/src/tools/servomatic_cli.cc b/src/tools/servomatic_cli.cc new file mode 100644 index 000000000..1fcd02117 --- /dev/null +++ b/src/tools/servomatic_cli.cc @@ -0,0 +1,50 @@ +/* + Copyright (C) 2012 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 + 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 "lib/server.h" +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "config.h" +#include "dcp_video_frame.h" +#include "exceptions.h" +#include "util.h" +#include "config.h" +#include "scaler.h" +#include "image.h" +#include "log.h" + +int +main () +{ + Scaler::setup_scalers (); + Server server; + server.run (); + return 0; +} diff --git a/src/tools/wscript b/src/tools/wscript index be3d44e6d..ff7134d15 100644 --- a/src/tools/wscript +++ b/src/tools/wscript @@ -1,5 +1,5 @@ def build(bld): - for t in ['makedcp', 'fixlengths', 'servomatic']: + for t in ['makedcp', 'fixlengths', 'servomatic_cli']: obj = bld(features = 'cxx cxxprogram') obj.uselib = 'BOOST_THREAD' obj.includes = ['..'] diff --git a/src/wx/config_dialog.cc b/src/wx/config_dialog.cc index b87f912b8..c53eeddf0 100644 --- a/src/wx/config_dialog.cc +++ b/src/wx/config_dialog.cc @@ -155,8 +155,8 @@ ConfigDialog::ConfigDialog (wxWindow* parent) _reference_filters->SetLabel (std_to_wx (p.first + " " + p.second)); _reference_filters_button->Connect (wxID_ANY, wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler (ConfigDialog::edit_reference_filters_clicked), 0, this); - vector servers = config->servers (); - for (vector::iterator i = servers.begin(); i != servers.end(); ++i) { + vector servers = config->servers (); + for (vector::iterator i = servers.begin(); i != servers.end(); ++i) { add_server_to_control (*i); } @@ -225,7 +225,7 @@ ConfigDialog::j2k_bandwidth_changed (wxCommandEvent &) } void -ConfigDialog::add_server_to_control (Server* s) +ConfigDialog::add_server_to_control (ServerDescription* s) { wxListItem item; int const n = _servers->GetItemCount (); @@ -240,11 +240,11 @@ ConfigDialog::add_server_clicked (wxCommandEvent &) { ServerDialog* d = new ServerDialog (this, 0); d->ShowModal (); - Server* s = d->server (); + ServerDescription* s = d->server (); d->Destroy (); add_server_to_control (s); - vector o = Config::instance()->servers (); + vector o = Config::instance()->servers (); o.push_back (s); Config::instance()->set_servers (o); } @@ -262,8 +262,8 @@ ConfigDialog::edit_server_clicked (wxCommandEvent &) item.SetColumn (0); _servers->GetItem (item); - vector servers = Config::instance()->servers (); - vector::iterator j = servers.begin(); + vector servers = Config::instance()->servers (); + vector::iterator j = servers.begin(); while (j != servers.end() && (*j)->host_name() != wx_to_std (item.GetText ())) { ++j; } diff --git a/src/wx/config_dialog.h b/src/wx/config_dialog.h index c9ca8034f..b1d3eb84d 100644 --- a/src/wx/config_dialog.h +++ b/src/wx/config_dialog.h @@ -26,7 +26,7 @@ #include class Screen; -class Server; +class ServerDescription; /** @class ConfigDialog * @brief A dialogue to edit DVD-o-matic configuration. @@ -52,7 +52,7 @@ private: void remove_server_clicked (wxCommandEvent &); void server_selection_changed (wxListEvent &); - void add_server_to_control (Server *); + void add_server_to_control (ServerDescription *); wxTextCtrl* _tms_ip; wxTextCtrl* _tms_path; diff --git a/src/wx/server_dialog.cc b/src/wx/server_dialog.cc index 0ae34b1fc..ad0f7a567 100644 --- a/src/wx/server_dialog.cc +++ b/src/wx/server_dialog.cc @@ -21,13 +21,13 @@ #include "server_dialog.h" #include "wx_util.h" -ServerDialog::ServerDialog (wxWindow* parent, Server* server) +ServerDialog::ServerDialog (wxWindow* parent, ServerDescription* server) : wxDialog (parent, wxID_ANY, wxString (_("Server"))) { if (server) { _server = server; } else { - _server = new Server ("localhost", 1); + _server = new ServerDescription ("localhost", 1); } wxFlexGridSizer* table = new wxFlexGridSizer (2, 4, 4); @@ -73,7 +73,7 @@ ServerDialog::threads_changed (wxCommandEvent &) _server->set_threads (_threads->GetValue ()); } -Server * +ServerDescription * ServerDialog::server () const { return _server; diff --git a/src/wx/server_dialog.h b/src/wx/server_dialog.h index 05630c377..0912fd60f 100644 --- a/src/wx/server_dialog.h +++ b/src/wx/server_dialog.h @@ -20,20 +20,20 @@ #include #include -class Server; +class ServerDescription; class ServerDialog : public wxDialog { public: - ServerDialog (wxWindow *, Server *); + ServerDialog (wxWindow *, ServerDescription *); - Server* server () const; + ServerDescription* server () const; private: void host_changed (wxCommandEvent &); void threads_changed (wxCommandEvent &); - Server* _server; + ServerDescription* _server; wxTextCtrl* _host; wxSpinCtrl* _threads; }; -- cgit v1.2.3 From 3c1b239453936128d1711ffa063ad4e1617b3e40 Mon Sep 17 00:00:00 2001 From: Carl Hetherington Date: Tue, 18 Sep 2012 02:07:59 +0100 Subject: Sort of working log window. --- src/lib/dcp_video_frame.cc | 4 ++-- src/lib/film.cc | 2 +- src/lib/log.cc | 29 +++++++++++++++++------- src/lib/log.h | 27 ++++++++++++++-------- src/lib/server.cc | 6 ++--- src/lib/server.h | 4 ++-- src/tools/servomatic_cli.cc | 3 ++- src/tools/servomatic_gui.cc | 55 +++++++++++++++++++++++++++++++++++++-------- src/wx/config_dialog.cc | 4 ++++ 9 files changed, 99 insertions(+), 35 deletions(-) (limited to 'src/lib') diff --git a/src/lib/dcp_video_frame.cc b/src/lib/dcp_video_frame.cc index 91c441543..b128f6fa0 100644 --- a/src/lib/dcp_video_frame.cc +++ b/src/lib/dcp_video_frame.cc @@ -277,7 +277,7 @@ DCPVideoFrame::encode_locally () { stringstream s; - s << "Finished locally-encoded frame " << _frame << " length " << cio_tell (_cio); + s << "Finished locally-encoded frame " << _frame; _log->log (s.str ()); } @@ -342,7 +342,7 @@ DCPVideoFrame::encode_remotely (ServerDescription const * serv) { stringstream s; - s << "Finished remotely-encoded frame " << _frame << " length " << e->size(); + s << "Finished remotely-encoded frame " << _frame; _log->log (s.str ()); } diff --git a/src/lib/film.cc b/src/lib/film.cc index f8a3b192d..3b74f1888 100644 --- a/src/lib/film.cc +++ b/src/lib/film.cc @@ -88,7 +88,7 @@ Film::Film (string d, bool must_exist) read_metadata (); - _log = new Log (_state.file ("log")); + _log = new FileLog (_state.file ("log")); } /** Copy constructor */ diff --git a/src/lib/log.cc b/src/lib/log.cc index accf3694d..7f1eea206 100644 --- a/src/lib/log.cc +++ b/src/lib/log.cc @@ -27,10 +27,8 @@ using namespace std; -/** @param f Filename to write log to */ -Log::Log (string f) - : _file (f) - , _level (VERBOSE) +Log::Log () + : _level (VERBOSE) { } @@ -45,13 +43,13 @@ Log::log (string m, Level l) return; } - ofstream f (_file.c_str(), fstream::app); - time_t t; time (&t); string a = ctime (&t); - - f << a.substr (0, a.length() - 1) << ": " << m << "\n"; + + stringstream s; + s << a.substr (0, a.length() - 1) << ": " << m; + do_log (s.str ()); } void @@ -61,3 +59,18 @@ Log::set_level (Level l) _level = l; } + +/** @param file Filename to write log to */ +FileLog::FileLog (string file) + : _file (file) +{ + +} + +void +FileLog::do_log (string m) +{ + ofstream f (_file.c_str(), fstream::app); + f << m << "\n"; +} + diff --git a/src/lib/log.h b/src/lib/log.h index d32b368f5..2a242e24c 100644 --- a/src/lib/log.h +++ b/src/lib/log.h @@ -29,15 +29,11 @@ /** @class Log * @brief A very simple logging class. - * - * This class simply accepts log messages and writes them to a file. - * Its single nod to complexity is that it has a mutex to prevent - * multi-thread logging from clashing. */ class Log { public: - Log (std::string f); + Log (); enum Level { STANDARD = 0, @@ -48,13 +44,26 @@ public: void set_level (Level l); -private: - /** mutex to prevent simultaneous writes to the file */ +protected: + /** mutex to protect the log */ boost::mutex _mutex; - /** filename to write to */ - std::string _file; + +private: + virtual void do_log (std::string m) = 0; + /** level above which to ignore log messages */ Level _level; }; +class FileLog : public Log +{ +public: + FileLog (std::string file); + +private: + void do_log (std::string m); + /** filename to write to */ + std::string _file; +}; + #endif diff --git a/src/lib/server.cc b/src/lib/server.cc index f4aaa25e1..9e43601c4 100644 --- a/src/lib/server.cc +++ b/src/lib/server.cc @@ -62,8 +62,8 @@ ServerDescription::as_metadata () const return s.str (); } -Server::Server () - : _log ("servomatic.log") +Server::Server (Log* log) + : _log (log) { } @@ -129,7 +129,7 @@ Server::process (shared_ptr socket) image->hash ("Image for encoding (as received by server)"); #endif - DCPVideoFrame dcp_video_frame (image, out_size, padding, scaler, frame, frames_per_second, post_process, colour_lut_index, j2k_bandwidth, &_log); + DCPVideoFrame dcp_video_frame (image, out_size, padding, scaler, frame, frames_per_second, post_process, colour_lut_index, j2k_bandwidth, _log); shared_ptr encoded = dcp_video_frame.encode_locally (); encoded->send (socket); diff --git a/src/lib/server.h b/src/lib/server.h index 8c0f86ebb..58cfe0b3f 100644 --- a/src/lib/server.h +++ b/src/lib/server.h @@ -74,7 +74,7 @@ private: class Server { public: - Server (); + Server (Log* log); void run (); @@ -86,5 +86,5 @@ private: std::list > _queue; boost::mutex _worker_mutex; boost::condition _worker_condition; - Log _log; + Log* _log; }; diff --git a/src/tools/servomatic_cli.cc b/src/tools/servomatic_cli.cc index 1fcd02117..3ad73faf9 100644 --- a/src/tools/servomatic_cli.cc +++ b/src/tools/servomatic_cli.cc @@ -44,7 +44,8 @@ int main () { Scaler::setup_scalers (); - Server server; + FileLog log ("servomatic.log"); + Server server (&log); server.run (); return 0; } diff --git a/src/tools/servomatic_gui.cc b/src/tools/servomatic_gui.cc index d89bd91ad..1d95f498a 100644 --- a/src/tools/servomatic_gui.cc +++ b/src/tools/servomatic_gui.cc @@ -24,28 +24,65 @@ #include "lib/util.h" #include "lib/server.h" +using namespace std; using namespace boost; enum { ID_status = 1, - ID_quit + ID_quit, + ID_timer }; +class MemoryLog : public Log +{ +public: + + string get () const { + boost::mutex::scoped_lock (_mutex); + return _log; + } + +private: + void do_log (string m) + { + _log = m; + } + + string _log; +}; + +static MemoryLog memory_log; + class StatusDialog : public wxDialog { public: StatusDialog () - : wxDialog (0, wxID_ANY, _("DVD-o-matic encode server"), wxDefaultPosition, wxDefaultSize, wxDEFAULT_DIALOG_STYLE) + : wxDialog (0, wxID_ANY, _("DVD-o-matic encode server"), wxDefaultPosition, wxSize (600, 40), wxDEFAULT_DIALOG_STYLE | wxRESIZE_BORDER) + , _timer (this, ID_timer) { - wxFlexGridSizer* table = new wxFlexGridSizer (2, 6, 6); - table->AddGrowableCol (1, 1); + _sizer = new wxFlexGridSizer (1, 6, 6); + _sizer->AddGrowableCol (0, 1); - add_label_to_sizer (table, this, "Hello"); + _text = new wxTextCtrl (this, wxID_ANY); + _sizer->Add (_text, 1, wxEXPAND); - SetSizer (table); - table->Layout (); - table->SetSizeHints (this); + SetSizer (_sizer); + _sizer->Layout (); + + Connect (ID_timer, wxEVT_TIMER, wxTimerEventHandler (StatusDialog::update)); + _timer.Start (1000); } + +private: + void update (wxTimerEvent &) + { + _text->ChangeValue (std_to_wx (memory_log.get ())); + _sizer->Layout (); + } + + wxFlexGridSizer* _sizer; + wxTextCtrl* _text; + wxTimer _timer; }; class TaskBarIcon : public wxTaskBarIcon @@ -103,7 +140,7 @@ private: void main_thread () { - Server server; + Server server (&memory_log); server.run (); } diff --git a/src/wx/config_dialog.cc b/src/wx/config_dialog.cc index c53eeddf0..c5d9be41f 100644 --- a/src/wx/config_dialog.cc +++ b/src/wx/config_dialog.cc @@ -287,6 +287,10 @@ ConfigDialog::remove_server_clicked (wxCommandEvent &) if (i >= 0) { _servers->DeleteItem (i); } + + vector o = Config::instance()->servers (); + o.erase (o.begin() + i); + Config::instance()->set_servers (o); } void -- cgit v1.2.3 From 8127ec3671ce9e294654c402c2414dfa8348a81f Mon Sep 17 00:00:00 2001 From: Carl Hetherington Date: Tue, 18 Sep 2012 02:28:50 +0100 Subject: Check return value of symlink(). --- ChangeLog | 6 ++++++ src/lib/j2k_still_encoder.cc | 5 ++++- 2 files changed, 10 insertions(+), 1 deletion(-) (limited to 'src/lib') diff --git a/ChangeLog b/ChangeLog index 09d671f29..25ba43490 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,9 @@ +2012-09-18 Carl Hetherington + + * Fix non-working removal of encode servers. + + * Add GUI front-end to encode server. + 2012-09-17 Carl Hetherington * Include servomatic in the Windows install. diff --git a/src/lib/j2k_still_encoder.cc b/src/lib/j2k_still_encoder.cc index 5243f0668..3109e244c 100644 --- a/src/lib/j2k_still_encoder.cc +++ b/src/lib/j2k_still_encoder.cc @@ -67,7 +67,10 @@ J2KStillEncoder::process_video (shared_ptr yuv, int frame) if (!boost::filesystem::exists (_opt->frame_out_path (i, false))) { string const link = _opt->frame_out_path (i, false); #ifdef DVDOMATIC_POSIX - symlink (real.c_str(), link.c_str()); + int const r = symlink (real.c_str(), link.c_str()); + if (r) { + throw EncodeError ("could not create symlink"); + } #endif #ifdef DVDOMATIC_WINDOWS filesystem::copy_file (real, link); -- cgit v1.2.3 From fb16d3932b49957672b5da3ced016186c926de9b Mon Sep 17 00:00:00 2001 From: Carl Hetherington Date: Sat, 22 Sep 2012 00:29:58 +0100 Subject: Tweak properties dialogue layout and add a note of how many J2K frames have already been encoded. --- ChangeLog | 4 ++++ src/lib/film.cc | 11 ++++++++++- src/lib/film.h | 2 ++ src/wx/properties_dialog.cc | 19 +++++++++++++++---- src/wx/properties_dialog.h | 1 + 5 files changed, 32 insertions(+), 5 deletions(-) (limited to 'src/lib') diff --git a/ChangeLog b/ChangeLog index 693b87b18..cc348b21e 100644 --- a/ChangeLog +++ b/ChangeLog @@ -3,6 +3,10 @@ * Rename servomatic to servomatic_cli and add a very basic system-tray-dwelling GUI server. + * Tweak formatting of properties dialogue + and add a note of how many J2K frames + have already been encoded. + 2012-09-18 Carl Hetherington * Fix non-working removal of encode servers. diff --git a/src/lib/film.cc b/src/lib/film.cc index 3b74f1888..92b91d0ac 100644 --- a/src/lib/film.cc +++ b/src/lib/film.cc @@ -19,6 +19,7 @@ #include #include +#include #include #include #include @@ -429,7 +430,6 @@ Film::j2k_dir () const filesystem::path p; - /* Start with j2c */ p /= "j2c"; @@ -641,3 +641,12 @@ Film::copy_from_dvd () JobManager::instance()->add (j); } +int +Film::encoded_frames () const +{ + if (format() == 0) { + return 0; + } + + return distance (filesystem::directory_iterator (j2k_dir()), filesystem::directory_iterator ()); +} diff --git a/src/lib/film.h b/src/lib/film.h index 3ff671fbe..40aa7b0f6 100644 --- a/src/lib/film.h +++ b/src/lib/film.h @@ -229,6 +229,8 @@ public: return _log; } + int encoded_frames () const; + /** Emitted when some metadata property has changed */ mutable sigc::signal1 Changed; diff --git a/src/wx/properties_dialog.cc b/src/wx/properties_dialog.cc index a447091c3..122d647ca 100644 --- a/src/wx/properties_dialog.cc +++ b/src/wx/properties_dialog.cc @@ -30,20 +30,24 @@ using namespace boost; PropertiesDialog::PropertiesDialog (wxWindow* parent, Film* film) : wxDialog (parent, wxID_ANY, _("Film Properties"), wxDefaultPosition, wxDefaultSize, wxDEFAULT_DIALOG_STYLE) { - wxFlexGridSizer* table = new wxFlexGridSizer (2, 6, 6); + wxFlexGridSizer* table = new wxFlexGridSizer (2, 3, 6); add_label_to_sizer (table, this, "Frames"); _frames = new wxStaticText (this, wxID_ANY, std_to_wx ("")); table->Add (_frames, 1, wxALIGN_CENTER_VERTICAL); - add_label_to_sizer (table, this, "Disk space for frames"); + add_label_to_sizer (table, this, "Disk space required for frames"); _disk_for_frames = new wxStaticText (this, wxID_ANY, std_to_wx ("")); table->Add (_disk_for_frames, 1, wxALIGN_CENTER_VERTICAL); - add_label_to_sizer (table, this, "Total disk space"); + add_label_to_sizer (table, this, "Total disk space required"); _total_disk = new wxStaticText (this, wxID_ANY, std_to_wx ("")); table->Add (_total_disk, 1, wxALIGN_CENTER_VERTICAL); + add_label_to_sizer (table, this, "Frames already encoded"); + _encoded = new wxStaticText (this, wxID_ANY, std_to_wx ("")); + table->Add (_encoded, 1, wxALIGN_CENTER_VERTICAL); + _frames->SetLabel (std_to_wx (lexical_cast (film->length ()))); double const disk = ((double) Config::instance()->j2k_bandwidth() / 8) * film->length() / (film->frames_per_second () * 1073741824); stringstream s; @@ -54,8 +58,15 @@ PropertiesDialog::PropertiesDialog (wxWindow* parent, Film* film) t << fixed << setprecision (1) << (disk * 2) << "Gb"; _total_disk->SetLabel (std_to_wx (t.str ())); + stringstream u; + u << film->encoded_frames(); + if (film->length()) { + u << " (" << (film->encoded_frames() * 100 / film->length()) << "%)"; + } + _encoded->SetLabel (std_to_wx (u.str ())); + wxBoxSizer* overall_sizer = new wxBoxSizer (wxVERTICAL); - overall_sizer->Add (table); + overall_sizer->Add (table, 0, wxALL, 8); wxSizer* buttons = CreateSeparatedButtonSizer (wxOK); if (buttons) { diff --git a/src/wx/properties_dialog.h b/src/wx/properties_dialog.h index e74344ff6..25c11e8d0 100644 --- a/src/wx/properties_dialog.h +++ b/src/wx/properties_dialog.h @@ -30,5 +30,6 @@ private: wxStaticText* _frames; wxStaticText* _disk_for_frames; wxStaticText* _total_disk; + wxStaticText* _encoded; }; -- cgit v1.2.3 From 266fe11af7f3bdc194cfedf92db7352b7b68be97 Mon Sep 17 00:00:00 2001 From: Carl Hetherington Date: Sat, 22 Sep 2012 11:35:36 +0100 Subject: Improve transcode job progress reporting. --- ChangeLog | 4 ++++ src/lib/encoder.cc | 31 ++++++++++++++++++++++++++++++- src/lib/encoder.h | 9 ++++++++- src/lib/j2k_still_encoder.cc | 2 +- src/lib/j2k_wav_encoder.cc | 6 ++++-- src/lib/job.cc | 13 ++++++++++--- src/lib/job.h | 2 ++ src/lib/tiff_encoder.cc | 2 +- src/lib/transcode_job.cc | 21 +++++++++++++++++++-- src/lib/transcode_job.h | 3 +++ 10 files changed, 82 insertions(+), 11 deletions(-) (limited to 'src/lib') diff --git a/ChangeLog b/ChangeLog index 231c19556..a4869ed82 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,7 @@ +2012-09-22 Carl Hetherington + + * Improve transcode job progress reporting. + 2012-09-22 Carl Hetherington * Version 0.50 released. diff --git a/src/lib/encoder.cc b/src/lib/encoder.cc index c8eb24c80..18ccd3f57 100644 --- a/src/lib/encoder.cc +++ b/src/lib/encoder.cc @@ -36,6 +36,8 @@ Encoder::Encoder (shared_ptr s, shared_ptr o, Lo : _fs (s) , _opt (o) , _log (l) + , _just_skipped (false) + , _last_frame (0) { } @@ -58,10 +60,27 @@ Encoder::current_frames_per_second () const return _history_size / (seconds (now) - seconds (_time_history.back ())); } +bool +Encoder::skipping () const +{ + boost::mutex::scoped_lock (_history_mutex); + return _just_skipped; +} + +int +Encoder::last_frame () const +{ + boost::mutex::scoped_lock (_history_mutex); + return _last_frame; +} + void -Encoder::frame_done () +Encoder::frame_done (int n) { boost::mutex::scoped_lock lock (_history_mutex); + _just_skipped = false; + _last_frame = n; + struct timeval tv; gettimeofday (&tv, 0); _time_history.push_front (tv); @@ -69,3 +88,13 @@ Encoder::frame_done () _time_history.pop_back (); } } + +/** Called by a subclass when it has just skipped the processing + of a frame because it has already been done. +*/ +void +Encoder::frame_skipped () +{ + boost::mutex::scoped_lock lock (_history_mutex); + _just_skipped = true; +} diff --git a/src/lib/encoder.h b/src/lib/encoder.h index bed2c0988..5c0c4c03f 100644 --- a/src/lib/encoder.h +++ b/src/lib/encoder.h @@ -68,9 +68,12 @@ public: virtual void process_end () = 0; float current_frames_per_second () const; + bool skipping () const; + int last_frame () const; protected: - void frame_done (); + void frame_done (int n); + void frame_skipped (); /** FilmState of the film that we are encoding */ boost::shared_ptr _fs; @@ -79,9 +82,13 @@ protected: /** Log */ Log* _log; + /** Mutex for _time_history, _just_skipped and _last_frame */ mutable boost::mutex _history_mutex; std::list _time_history; static int const _history_size; + /** true if the last frame we processed was skipped (because it was already done) */ + bool _just_skipped; + int _last_frame; }; #endif diff --git a/src/lib/j2k_still_encoder.cc b/src/lib/j2k_still_encoder.cc index 3109e244c..8f3339a0a 100644 --- a/src/lib/j2k_still_encoder.cc +++ b/src/lib/j2k_still_encoder.cc @@ -76,6 +76,6 @@ J2KStillEncoder::process_video (shared_ptr yuv, int frame) filesystem::copy_file (real, link); #endif } - frame_done (); + frame_done (0); } } diff --git a/src/lib/j2k_wav_encoder.cc b/src/lib/j2k_wav_encoder.cc index ff450d1ad..ef1e8edc1 100644 --- a/src/lib/j2k_wav_encoder.cc +++ b/src/lib/j2k_wav_encoder.cc @@ -126,6 +126,8 @@ J2KWAVEncoder::process_video (shared_ptr yuv, int frame) )); _worker_condition.notify_all (); + } else { + frame_skipped (); } } @@ -190,7 +192,7 @@ J2KWAVEncoder::encoder_thread (ServerDescription* server) if (encoded) { encoded->write (_opt, vf->frame ()); - frame_done (); + frame_done (vf->frame ()); } else { lock.lock (); _queue.push_front (vf); @@ -253,7 +255,7 @@ J2KWAVEncoder::process_end () try { shared_ptr e = (*i)->encode_locally (); e->write (_opt, (*i)->frame ()); - frame_done (); + frame_done ((*i)->frame ()); } catch (std::exception& e) { stringstream s; s << "Local encode failed " << e.what() << "."; diff --git a/src/lib/job.cc b/src/lib/job.cc index 0feb73d31..d446b3913 100644 --- a/src/lib/job.cc +++ b/src/lib/job.cc @@ -236,11 +236,12 @@ Job::status () const { float const p = overall_progress (); int const t = elapsed_time (); + int const r = remaining_time (); stringstream s; - if (!finished () && p >= 0 && t > 10) { - s << rint (p * 100) << "%; about " << seconds_to_approximate_hms (t / p - t) << " remaining"; - } else if (!finished () && t <= 10) { + if (!finished () && p >= 0 && t > 10 && r > 0) { + s << rint (p * 100) << "%; " << seconds_to_approximate_hms (r) << " remaining"; + } else if (!finished () && (t <= 10 || r == 0)) { s << rint (p * 100) << "%"; } else if (finished_ok ()) { s << "OK (ran for " << seconds_to_hms (t) << ")"; @@ -250,3 +251,9 @@ Job::status () const return s.str (); } + +int +Job::remaining_time () const +{ + return elapsed_time() / overall_progress() - elapsed_time(); +} diff --git a/src/lib/job.h b/src/lib/job.h index 2a77f78f7..95599bdbb 100644 --- a/src/lib/job.h +++ b/src/lib/job.h @@ -70,6 +70,8 @@ public: protected: + virtual int remaining_time () const; + enum State { NEW, ///< the job hasn't been started yet RUNNING, ///< the job is running diff --git a/src/lib/tiff_encoder.cc b/src/lib/tiff_encoder.cc index 2cf238006..19e34741d 100644 --- a/src/lib/tiff_encoder.cc +++ b/src/lib/tiff_encoder.cc @@ -73,5 +73,5 @@ TIFFEncoder::process_video (shared_ptr image, int frame) TIFFClose (output); boost::filesystem::rename (tmp_file, _opt->frame_out_path (frame, false)); - frame_done (); + frame_done (frame); } diff --git a/src/lib/transcode_job.cc b/src/lib/transcode_job.cc index 652a18441..f4e3d7af9 100644 --- a/src/lib/transcode_job.cc +++ b/src/lib/transcode_job.cc @@ -88,13 +88,30 @@ TranscodeJob::status () const if (!_encoder) { return "0%"; } + + if (_encoder->skipping ()) { + return "skipping frames already encoded"; + } + float const fps = _encoder->current_frames_per_second (); if (fps == 0) { return Job::status (); } - + stringstream s; - s << Job::status () << "; about " << fixed << setprecision (1) << fps << " frames per second."; + + s << Job::status () << "; " << fixed << setprecision (1) << fps << " frames per second"; return s.str (); } + +int +TranscodeJob::remaining_time () const +{ + float fps = _encoder->current_frames_per_second (); + if (fps == 0) { + return 0; + } + + return ((_fs->length - _encoder->last_frame()) / fps); +} diff --git a/src/lib/transcode_job.h b/src/lib/transcode_job.h index aa640f697..737f10de9 100644 --- a/src/lib/transcode_job.h +++ b/src/lib/transcode_job.h @@ -38,6 +38,9 @@ public: void run (); std::string status () const; +protected: + int remaining_time () const; + private: boost::shared_ptr _encoder; }; -- cgit v1.2.3 From 9e92b5193719e72072d903d10c1e71ee6447561d Mon Sep 17 00:00:00 2001 From: Carl Hetherington Date: Sat, 22 Sep 2012 13:38:38 +0100 Subject: Add missing include. --- src/lib/server.cc | 1 + 1 file changed, 1 insertion(+) (limited to 'src/lib') diff --git a/src/lib/server.cc b/src/lib/server.cc index 9e43601c4..ff784db5a 100644 --- a/src/lib/server.cc +++ b/src/lib/server.cc @@ -25,6 +25,7 @@ #include #include #include +#include #include #include "server.h" #include "util.h" -- cgit v1.2.3 From 292012d86ffda3c19530ad8e9d8788a51db2b6c5 Mon Sep 17 00:00:00 2001 From: Carl Hetherington Date: Sat, 22 Sep 2012 14:01:43 +0100 Subject: Do interruption of ThreadStaticText properly. --- src/lib/film.cc | 10 ++++++++-- src/lib/film.h | 1 + src/wx/properties_dialog.cc | 7 ++++++- src/wx/wx_util.cc | 2 +- 4 files changed, 16 insertions(+), 4 deletions(-) (limited to 'src/lib') diff --git a/src/lib/film.cc b/src/lib/film.cc index 92b91d0ac..d5327aa3a 100644 --- a/src/lib/film.cc +++ b/src/lib/film.cc @@ -647,6 +647,12 @@ Film::encoded_frames () const if (format() == 0) { return 0; } - - return distance (filesystem::directory_iterator (j2k_dir()), filesystem::directory_iterator ()); + + int N = 0; + for (filesystem::directory_iterator i = filesystem::directory_iterator (j2k_dir ()); i != filesystem::directory_iterator(); ++i) { + ++N; + this_thread::interruption_point (); + } + + return N; } diff --git a/src/lib/film.h b/src/lib/film.h index 40aa7b0f6..cd3b1b8a8 100644 --- a/src/lib/film.h +++ b/src/lib/film.h @@ -29,6 +29,7 @@ #include #include #include +#include #include extern "C" { #include diff --git a/src/wx/properties_dialog.cc b/src/wx/properties_dialog.cc index 0a997bc41..e6c6c9f81 100644 --- a/src/wx/properties_dialog.cc +++ b/src/wx/properties_dialog.cc @@ -76,7 +76,12 @@ string PropertiesDialog::frames_already_encoded () const { stringstream u; - u << _film->encoded_frames(); + try { + u << _film->encoded_frames (); + } catch (thread_interrupted &) { + return ""; + } + if (_film->length()) { u << " (" << (_film->encoded_frames() * 100 / _film->length()) << "%)"; } diff --git a/src/wx/wx_util.cc b/src/wx/wx_util.cc index 712e23570..44d9462e5 100644 --- a/src/wx/wx_util.cc +++ b/src/wx/wx_util.cc @@ -70,7 +70,7 @@ ThreadedStaticText::ThreadedStaticText (wxWindow* parent, string initial, functi ThreadedStaticText::~ThreadedStaticText () { - /* XXX: this is a bit unfortunate */ + _thread->interrupt (); _thread->join (); delete _thread; } -- cgit v1.2.3 From c2709fbe5438da124b2d493cb714a6c58720cf5b Mon Sep 17 00:00:00 2001 From: Carl Hetherington Date: Sun, 23 Sep 2012 12:39:27 +0100 Subject: Command-line option to specify servomatic_cli threads. --- src/lib/server.cc | 4 ++-- src/lib/server.h | 2 +- src/lib/util.cc | 8 ++++++-- src/tools/servomatic_cli.cc | 47 +++++++++++++++++++++++++++++++++++++++++++-- src/tools/servomatic_gui.cc | 3 ++- 5 files changed, 56 insertions(+), 8 deletions(-) (limited to 'src/lib') diff --git a/src/lib/server.cc b/src/lib/server.cc index ff784db5a..a62763447 100644 --- a/src/lib/server.cc +++ b/src/lib/server.cc @@ -181,9 +181,9 @@ Server::worker_thread () } void -Server::run () +Server::run (int num_threads) { - int const num_threads = Config::instance()->num_local_encoding_threads (); + cout << "Server starting with " << num_threads << " threads.\n"; for (int i = 0; i < num_threads; ++i) { _worker_threads.push_back (new thread (bind (&Server::worker_thread, this))); diff --git a/src/lib/server.h b/src/lib/server.h index 58cfe0b3f..fac440a76 100644 --- a/src/lib/server.h +++ b/src/lib/server.h @@ -76,7 +76,7 @@ class Server public: Server (Log* log); - void run (); + void run (int num_threads); private: void worker_thread (); diff --git a/src/lib/util.cc b/src/lib/util.cc index 1478bab2e..e79c7cd1c 100644 --- a/src/lib/util.cc +++ b/src/lib/util.cc @@ -518,5 +518,9 @@ colour_lut_index_to_name (int index) return ""; } - - +int +read_with_timeout (boost::asio::ip::tcp::socket* socket, uint8_t* data, int size) +{ + + return asio::read (socket, asio::buffer (data, size)); +} diff --git a/src/tools/servomatic_cli.cc b/src/tools/servomatic_cli.cc index 3ad73faf9..f8e713193 100644 --- a/src/tools/servomatic_cli.cc +++ b/src/tools/servomatic_cli.cc @@ -25,6 +25,7 @@ #include #include #include +#include #include #include #include @@ -39,13 +40,55 @@ #include "scaler.h" #include "image.h" #include "log.h" +#include "version.h" + +using namespace std; + +static void +help (string n) +{ + cerr << "Syntax: " << n << " [OPTION]\n" + << " -v, --version show DVD-o-matic version\n" + << " -h, --help show this help\n" + << " -t, --threads number of parallel encoding threads to use\n"; +} int -main () +main (int argc, char* argv[]) { + int num_threads = Config::instance()->num_local_encoding_threads (); + + int option_index = 0; + while (1) { + static struct option long_options[] = { + { "version", no_argument, 0, 'v'}, + { "help", no_argument, 0, 'h'}, + { "threads", required_argument, 0, 't'}, + { 0, 0, 0, 0 } + }; + + int c = getopt_long (argc, argv, "vht:", long_options, &option_index); + + if (c == -1) { + break; + } + + switch (c) { + case 'v': + cout << "dvdomatic version " << dvdomatic_version << " " << dvdomatic_git_commit << "\n"; + exit (EXIT_SUCCESS); + case 'h': + help (argv[0]); + exit (EXIT_SUCCESS); + case 't': + num_threads = atoi (optarg); + break; + } + } + Scaler::setup_scalers (); FileLog log ("servomatic.log"); Server server (&log); - server.run (); + server.run (num_threads); return 0; } diff --git a/src/tools/servomatic_gui.cc b/src/tools/servomatic_gui.cc index a151658f5..610ba8005 100644 --- a/src/tools/servomatic_gui.cc +++ b/src/tools/servomatic_gui.cc @@ -23,6 +23,7 @@ #include "wx_util.h" #include "lib/util.h" #include "lib/server.h" +#include "lib/config.h" using namespace std; using namespace boost; @@ -141,7 +142,7 @@ private: void main_thread () { Server server (&memory_log); - server.run (); + server.run (Config::instance()->num_local_encoding_threads ()); } boost::thread* _thread; -- cgit v1.2.3 From 93c3365a547fbb7467b6c47571c5a68e17b31e0c Mon Sep 17 00:00:00 2001 From: Carl Hetherington Date: Sun, 23 Sep 2012 14:02:01 +0100 Subject: Untested first cut. --- src/lib/dcp_video_frame.cc | 19 ++-- src/lib/server.cc | 14 +-- src/lib/server.h | 3 +- src/lib/util.cc | 242 +++++++++++++++++++++++++++++---------------- src/lib/util.h | 50 +++++----- 5 files changed, 205 insertions(+), 123 deletions(-) (limited to 'src/lib') diff --git a/src/lib/dcp_video_frame.cc b/src/lib/dcp_video_frame.cc index b128f6fa0..ade615bfb 100644 --- a/src/lib/dcp_video_frame.cc +++ b/src/lib/dcp_video_frame.cc @@ -293,11 +293,16 @@ DCPVideoFrame::encode_remotely (ServerDescription const * serv) { asio::io_service io_service; asio::ip::tcp::resolver resolver (io_service); + asio::ip::tcp::resolver::query query (serv->host_name(), boost::lexical_cast (Config::instance()->server_port ())); asio::ip::tcp::resolver::iterator endpoint_iterator = resolver.resolve (query); shared_ptr socket (new asio::ip::tcp::socket (io_service)); - socket->connect (*endpoint_iterator); + + DeadlineWrapper wrapper (io_service); + wrapper.set_socket (socket); + + wrapper.connect (*endpoint_iterator, 30); #ifdef DEBUG_HASH _input->hash ("Input for remote encoding (before sending)"); @@ -320,21 +325,19 @@ DCPVideoFrame::encode_remotely (ServerDescription const * serv) s << _input->line_size()[i] << " "; } - asio::write (*socket, asio::buffer (s.str().c_str(), s.str().length() + 1)); + wrapper.write ((uint8_t *) s.str().c_str(), s.str().length() + 1, 10); for (int i = 0; i < _input->components(); ++i) { - asio::write (*socket, asio::buffer (_input->data()[i], _input->line_size()[i] * _input->lines(i))); + wrapper.write (_input->data()[i], _input->line_size()[i] * _input->lines(i), 10); } - SocketReader reader (socket); - char buffer[32]; - reader.read_indefinite ((uint8_t *) buffer, sizeof (buffer)); - reader.consume (strlen (buffer) + 1); + wrapper.read_indefinite ((uint8_t *) buffer, sizeof (buffer), 30); + wrapper.consume (strlen (buffer) + 1); shared_ptr e (new RemotelyEncodedData (atoi (buffer))); /* now read the rest */ - reader.read_definite_and_consume (e->data(), e->size()); + wrapper.read_definite_and_consume (e->data(), e->size(), 30); #ifdef DEBUG_HASH e->hash ("Encoded image (after receiving)"); diff --git a/src/lib/server.cc b/src/lib/server.cc index a62763447..395786b67 100644 --- a/src/lib/server.cc +++ b/src/lib/server.cc @@ -72,11 +72,12 @@ Server::Server (Log* log) int Server::process (shared_ptr socket) { - SocketReader reader (socket); + DeadlineWrapper wrapper (_io_service); + wrapper.set_socket (socket); char buffer[128]; - reader.read_indefinite ((uint8_t *) buffer, sizeof (buffer)); - reader.consume (strlen (buffer) + 1); + wrapper.read_indefinite ((uint8_t *) buffer, sizeof (buffer), 30); + wrapper.consume (strlen (buffer) + 1); stringstream s (buffer); @@ -123,7 +124,7 @@ Server::process (shared_ptr socket) } for (int i = 0; i < image->components(); ++i) { - reader.read_definite_and_consume (image->data()[i], image->line_size()[i] * image->lines(i)); + wrapper.read_definite_and_consume (image->data()[i], image->line_size()[i] * image->lines(i), 30); } #ifdef DEBUG_HASH @@ -189,10 +190,9 @@ Server::run (int num_threads) _worker_threads.push_back (new thread (bind (&Server::worker_thread, this))); } - asio::io_service io_service; - asio::ip::tcp::acceptor acceptor (io_service, asio::ip::tcp::endpoint (asio::ip::tcp::v4(), Config::instance()->server_port ())); + asio::ip::tcp::acceptor acceptor (_io_service, asio::ip::tcp::endpoint (asio::ip::tcp::v4(), Config::instance()->server_port ())); while (1) { - shared_ptr socket (new asio::ip::tcp::socket (io_service)); + shared_ptr socket (new asio::ip::tcp::socket (_io_service)); acceptor.accept (*socket); mutex::scoped_lock lock (_worker_mutex); diff --git a/src/lib/server.h b/src/lib/server.h index fac440a76..747081443 100644 --- a/src/lib/server.h +++ b/src/lib/server.h @@ -81,7 +81,8 @@ public: private: void worker_thread (); int process (boost::shared_ptr socket); - + + boost::asio::io_service _io_service; std::vector _worker_threads; std::list > _queue; boost::mutex _worker_mutex; diff --git a/src/lib/util.cc b/src/lib/util.cc index e79c7cd1c..deab5d639 100644 --- a/src/lib/util.cc +++ b/src/lib/util.cc @@ -33,6 +33,8 @@ #include #include #include +#include +#include #include #include #include @@ -286,88 +288,6 @@ seconds (struct timeval t) return t.tv_sec + (double (t.tv_usec) / 1e6); } -/** @param socket Socket to read from */ -SocketReader::SocketReader (shared_ptr socket) - : _socket (socket) - , _buffer_data (0) -{ - -} - -/** Mark some data as being `consumed', so that it will not be returned - * as data again. - * @param size Amount of data to consume, in bytes. - */ -void -SocketReader::consume (int size) -{ - assert (_buffer_data >= size); - - _buffer_data -= size; - if (_buffer_data > 0) { - /* Shift still-valid data to the start of the buffer */ - memmove (_buffer, _buffer + size, _buffer_data); - } -} - -/** Read a definite amount of data from our socket, and mark - * it as consumed. - * @param data Where to put the data. - * @param size Number of bytes to read. - */ -void -SocketReader::read_definite_and_consume (uint8_t* data, int size) -{ - int const from_buffer = min (_buffer_data, size); - if (from_buffer > 0) { - /* Get data from our buffer */ - memcpy (data, _buffer, from_buffer); - consume (from_buffer); - /* Update our output state */ - data += from_buffer; - size -= from_buffer; - } - - /* read() the rest */ - while (size > 0) { - int const n = asio::read (*_socket, asio::buffer (data, size)); - if (n <= 0) { - throw NetworkError ("could not read"); - } - - data += n; - size -= n; - } -} - -/** Read as much data as is available, up to some limit. - * @param data Where to put the data. - * @param size Maximum amount of data to read. - */ -void -SocketReader::read_indefinite (uint8_t* data, int size) -{ - assert (size < int (sizeof (_buffer))); - - /* Amount of extra data we need to read () */ - int to_read = size - _buffer_data; - while (to_read > 0) { - /* read as much of it as we can (into our buffer) */ - int const n = asio::read (*_socket, asio::buffer (_buffer + _buffer_data, to_read)); - if (n <= 0) { - throw NetworkError ("could not read"); - } - - to_read -= n; - _buffer_data += n; - } - - assert (_buffer_data >= size); - - /* copy data into the output buffer */ - assert (size >= _buffer_data); - memcpy (data, _buffer, size); -} #ifdef DVDOMATIC_POSIX void @@ -518,9 +438,163 @@ colour_lut_index_to_name (int index) return ""; } +DeadlineWrapper::DeadlineWrapper (asio::io_service& io_service) + : _io_service (io_service) + , _deadline (io_service) + , _buffer_data (0) +{ + _deadline.expires_at (posix_time::pos_infin); + check (); +} + +void +DeadlineWrapper::set_socket (shared_ptr socket) +{ + _socket = socket; +} + +void +DeadlineWrapper::check () +{ + if (_deadline.expires_at() <= asio::deadline_timer::traits_type::now ()) { + if (_socket) { + _socket->close (); + } + _deadline.expires_at (posix_time::pos_infin); + } + + _deadline.async_wait (boost::bind (&DeadlineWrapper::check, this)); +} + +void +DeadlineWrapper::connect (asio::ip::basic_resolver_entry const & endpoint, int timeout) +{ + assert (_socket); + + system::error_code ec = asio::error::would_block; + _socket->async_connect (endpoint, lambda::var(ec) = lambda::_1); + do { + _io_service.run_one(); + } while (ec == asio::error::would_block); + + if (ec || !_socket->is_open ()) { + throw NetworkError ("connect timed out"); + } +} + +void +DeadlineWrapper::write (uint8_t const * data, int size, int timeout) +{ + assert (_socket); + + _deadline.expires_from_now (posix_time::seconds (timeout)); + system::error_code ec = asio::error::would_block; + + asio::async_write (*_socket, asio::buffer (data, size), lambda::var(ec) = lambda::_1); + do { + _io_service.run_one (); + } while (ec == asio::error::would_block); + + if (ec) { + throw NetworkError ("write timed out"); + } +} + int -read_with_timeout (boost::asio::ip::tcp::socket* socket, uint8_t* data, int size) +DeadlineWrapper::read (uint8_t* data, int size, int timeout) { + assert (_socket); + + _deadline.expires_from_now (posix_time::seconds (timeout)); + system::error_code ec = asio::error::would_block; + + int amount_read = 0; + + _socket->async_read_some ( + asio::buffer (data, size), + (lambda::var(ec) = lambda::_1, lambda::var(amount_read) = lambda::_2) + ); + + _io_service.run (); + + if (ec) { + amount_read = 0; + } + + return amount_read; +} + +/** Mark some data as being `consumed', so that it will not be returned + * as data again. + * @param size Amount of data to consume, in bytes. + */ +void +DeadlineWrapper::consume (int size) +{ + assert (_buffer_data >= size); - return asio::read (socket, asio::buffer (data, size)); + _buffer_data -= size; + if (_buffer_data > 0) { + /* Shift still-valid data to the start of the buffer */ + memmove (_buffer, _buffer + size, _buffer_data); + } +} + +/** Read a definite amount of data from our socket, and mark + * it as consumed. + * @param data Where to put the data. + * @param size Number of bytes to read. + */ +void +DeadlineWrapper::read_definite_and_consume (uint8_t* data, int size, int timeout) +{ + int const from_buffer = min (_buffer_data, size); + if (from_buffer > 0) { + /* Get data from our buffer */ + memcpy (data, _buffer, from_buffer); + consume (from_buffer); + /* Update our output state */ + data += from_buffer; + size -= from_buffer; + } + + /* read() the rest */ + while (size > 0) { + int const n = read (data, size, timeout); + if (n <= 0) { + throw NetworkError ("could not read"); + } + + data += n; + size -= n; + } +} + +/** Read as much data as is available, up to some limit. + * @param data Where to put the data. + * @param size Maximum amount of data to read. + */ +void +DeadlineWrapper::read_indefinite (uint8_t* data, int size, int timeout) +{ + assert (size < int (sizeof (_buffer))); + + /* Amount of extra data we need to read () */ + int to_read = size - _buffer_data; + while (to_read > 0) { + /* read as much of it as we can (into our buffer) */ + int const n = read (_buffer + _buffer_data, to_read, timeout); + if (n <= 0) { + throw NetworkError ("could not read"); + } + + to_read -= n; + _buffer_data += n; + } + + assert (_buffer_data >= size); + + /* copy data into the output buffer */ + assert (size >= _buffer_data); + memcpy (data, _buffer, size); } diff --git a/src/lib/util.h b/src/lib/util.h index 568fe05d0..c3a42e448 100644 --- a/src/lib/util.h +++ b/src/lib/util.h @@ -56,29 +56,6 @@ enum ContentType { extern void md5_data (std::string, void const *, int); #endif -/** @class SocketReader - * @brief A helper class from reading from sockets. - * - * You can probably do this stuff directly in boost, but I'm not sure how. - */ -class SocketReader -{ -public: - SocketReader (boost::shared_ptr); - - void read_definite_and_consume (uint8_t *, int); - void read_indefinite (uint8_t *, int); - void consume (int); - -private: - /** socket we are reading from */ - boost::shared_ptr _socket; - /** a buffer for small reads */ - uint8_t _buffer[256]; - /** amount of valid data in the buffer */ - int _buffer_data; -}; - /** @class Size * @brief Representation of the size of something */ struct Size @@ -136,4 +113,31 @@ extern std::string crop_string (Position, Size); extern int dcp_audio_sample_rate (int); extern std::string colour_lut_index_to_name (int index); +class DeadlineWrapper +{ +public: + DeadlineWrapper (boost::asio::io_service& io_service); + + void set_socket (boost::shared_ptr socket); + + void connect (boost::asio::ip::basic_resolver_entry const & endpoint, int timeout); + void write (uint8_t const * data, int size, int timeout); + int read (uint8_t* data, int size, int timeout); + + void read_definite_and_consume (uint8_t* data, int size, int timeout); + void read_indefinite (uint8_t* data, int size, int timeout); + void consume (int amount); + +private: + void check (); + + boost::asio::io_service& _io_service; + boost::asio::deadline_timer _deadline; + boost::shared_ptr _socket; + /** a buffer for small reads */ + uint8_t _buffer[256]; + /** amount of valid data in the buffer */ + int _buffer_data; +}; + #endif -- cgit v1.2.3 From 1fb3be8977e2300fd0ba30d6593bcb806e66cb9a Mon Sep 17 00:00:00 2001 From: Carl Hetherington Date: Sun, 23 Sep 2012 14:40:44 +0100 Subject: Fix up basic test to work. --- src/lib/util.cc | 8 +++++--- test/test.cc | 2 +- 2 files changed, 6 insertions(+), 4 deletions(-) (limited to 'src/lib') diff --git a/src/lib/util.cc b/src/lib/util.cc index deab5d639..3f48d696b 100644 --- a/src/lib/util.cc +++ b/src/lib/util.cc @@ -486,7 +486,7 @@ void DeadlineWrapper::write (uint8_t const * data, int size, int timeout) { assert (_socket); - + _deadline.expires_from_now (posix_time::seconds (timeout)); system::error_code ec = asio::error::would_block; @@ -515,8 +515,10 @@ DeadlineWrapper::read (uint8_t* data, int size, int timeout) (lambda::var(ec) = lambda::_1, lambda::var(amount_read) = lambda::_2) ); - _io_service.run (); - + do { + _io_service.run_one (); + } while (ec == asio::error::would_block); + if (ec) { amount_read = 0; } diff --git a/test/test.cc b/test/test.cc index 06954822d..6d5efa455 100644 --- a/test/test.cc +++ b/test/test.cc @@ -289,7 +289,7 @@ BOOST_AUTO_TEST_CASE (client_server_test) Config::instance()->set_server_port (61920); Server server (&log); - thread t (boost::bind (&Server::run, &server, 1)); + new thread (boost::bind (&Server::run, &server, 1)); ServerDescription description ("localhost", 1); shared_ptr remotely_encoded = frame.encode_remotely (&description); -- cgit v1.2.3 From 794e306a0f5b16cbb49ef9e75e1b9fb88c489b31 Mon Sep 17 00:00:00 2001 From: Carl Hetherington Date: Sun, 23 Sep 2012 14:47:45 +0100 Subject: Bump timeouts a bit. --- src/lib/dcp_video_frame.cc | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'src/lib') diff --git a/src/lib/dcp_video_frame.cc b/src/lib/dcp_video_frame.cc index ade615bfb..d202109d0 100644 --- a/src/lib/dcp_video_frame.cc +++ b/src/lib/dcp_video_frame.cc @@ -325,10 +325,10 @@ DCPVideoFrame::encode_remotely (ServerDescription const * serv) s << _input->line_size()[i] << " "; } - wrapper.write ((uint8_t *) s.str().c_str(), s.str().length() + 1, 10); + wrapper.write ((uint8_t *) s.str().c_str(), s.str().length() + 1, 30); for (int i = 0; i < _input->components(); ++i) { - wrapper.write (_input->data()[i], _input->line_size()[i] * _input->lines(i), 10); + wrapper.write (_input->data()[i], _input->line_size()[i] * _input->lines(i), 30); } char buffer[32]; -- cgit v1.2.3 From f62909cfe63e6a2e238e655ea0536a5f627e0ddf Mon Sep 17 00:00:00 2001 From: Carl Hetherington Date: Sun, 23 Sep 2012 14:48:58 +0100 Subject: Use log rather the cout in server. --- src/lib/server.cc | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) (limited to 'src/lib') diff --git a/src/lib/server.cc b/src/lib/server.cc index 395786b67..d92fdf2b6 100644 --- a/src/lib/server.cc +++ b/src/lib/server.cc @@ -174,7 +174,9 @@ Server::worker_thread () if (frame >= 0) { struct timeval end; gettimeofday (&end, 0); - cout << "Encoded frame " << frame << " in " << (seconds (end) - seconds (start)) << "\n"; + stringstream s; + s << "Encoded frame " << frame << " in " << (seconds (end) - seconds (start)); + _log->log (s.str ()); } _worker_condition.notify_all (); @@ -184,7 +186,9 @@ Server::worker_thread () void Server::run (int num_threads) { - cout << "Server starting with " << num_threads << " threads.\n"; + stringstream s; + s << "Server starting with " << num_threads << " threads."; + _log->log (s.str ()); for (int i = 0; i < num_threads; ++i) { _worker_threads.push_back (new thread (bind (&Server::worker_thread, this))); -- cgit v1.2.3 From 46f1b3106ab959e21946fe1f035efc6dc1743b49 Mon Sep 17 00:00:00 2001 From: Carl Hetherington Date: Sun, 23 Sep 2012 15:07:30 +0100 Subject: Missing use of wrapper. --- src/lib/dcp_video_frame.cc | 6 +++--- src/lib/dcp_video_frame.h | 2 +- src/lib/server.cc | 2 +- 3 files changed, 5 insertions(+), 5 deletions(-) (limited to 'src/lib') diff --git a/src/lib/dcp_video_frame.cc b/src/lib/dcp_video_frame.cc index d202109d0..ee29d8601 100644 --- a/src/lib/dcp_video_frame.cc +++ b/src/lib/dcp_video_frame.cc @@ -378,12 +378,12 @@ EncodedData::write (shared_ptr opt, int frame) * @param socket Socket */ void -EncodedData::send (shared_ptr socket) +EncodedData::send (DeadlineWrapper& wrapper) { stringstream s; s << _size; - asio::write (*socket, asio::buffer (s.str().c_str(), s.str().length() + 1)); - asio::write (*socket, asio::buffer (_data, _size)); + wrapper.write ((uint8_t *) s.str().c_str(), s.str().length() + 1, 30); + wrapper.write (_data, _size, 30); } #ifdef DEBUG_HASH diff --git a/src/lib/dcp_video_frame.h b/src/lib/dcp_video_frame.h index ee54bc0f5..d82aee367 100644 --- a/src/lib/dcp_video_frame.h +++ b/src/lib/dcp_video_frame.h @@ -48,7 +48,7 @@ public: virtual ~EncodedData () {} - void send (boost::shared_ptr); + void send (DeadlineWrapper& wrapper); void write (boost::shared_ptr, int); #ifdef DEBUG_HASH diff --git a/src/lib/server.cc b/src/lib/server.cc index d92fdf2b6..9e61c2282 100644 --- a/src/lib/server.cc +++ b/src/lib/server.cc @@ -133,7 +133,7 @@ Server::process (shared_ptr socket) DCPVideoFrame dcp_video_frame (image, out_size, padding, scaler, frame, frames_per_second, post_process, colour_lut_index, j2k_bandwidth, _log); shared_ptr encoded = dcp_video_frame.encode_locally (); - encoded->send (socket); + encoded->send (wrapper); #ifdef DEBUG_HASH encoded->hash ("Encoded image (as made by server and as sent back)"); -- cgit v1.2.3 From 6726393a4b186333b8e1080f3f1c5c4b77d4c2e6 Mon Sep 17 00:00:00 2001 From: Carl Hetherington Date: Sun, 23 Sep 2012 16:51:10 +0100 Subject: Multi-thread test. --- src/lib/util.h | 2 ++ test/test.cc | 53 ++++++++++++++++++++++++++++++++++++----------------- 2 files changed, 38 insertions(+), 17 deletions(-) (limited to 'src/lib') diff --git a/src/lib/util.h b/src/lib/util.h index c3a42e448..2785a5dc1 100644 --- a/src/lib/util.h +++ b/src/lib/util.h @@ -131,6 +131,8 @@ public: private: void check (); + DeadlineWrapper (DeadlineWrapper const &); + boost::asio::io_service& _io_service; boost::asio::deadline_timer _deadline; boost::shared_ptr _socket; diff --git a/test/test.cc b/test/test.cc index 2a99c862f..b77eb2b51 100644 --- a/test/test.cc +++ b/test/test.cc @@ -254,6 +254,17 @@ BOOST_AUTO_TEST_CASE (paths_test) BOOST_CHECK_EQUAL (s.content_path(), "build/test/a/b/c/d/e/foo/bar/baz"); } +void +do_remote_encode (shared_ptr frame, ServerDescription* description, shared_ptr locally_encoded) +{ + shared_ptr remotely_encoded; + BOOST_CHECK_NO_THROW (remotely_encoded = frame->encode_remotely (description)); + BOOST_CHECK (remotely_encoded); + + BOOST_CHECK_EQUAL (locally_encoded->size(), remotely_encoded->size()); + BOOST_CHECK (memcmp (locally_encoded->data(), remotely_encoded->data(), locally_encoded->size()) == 0); +} + BOOST_AUTO_TEST_CASE (client_server_test) { shared_ptr image (new SimpleImage (PIX_FMT_RGB24, Size (1998, 1080))); @@ -271,29 +282,37 @@ BOOST_AUTO_TEST_CASE (client_server_test) FileLog log ("build/test/client_server_test.log"); - DCPVideoFrame frame ( - image, - Size (1998, 1080), - 0, - Scaler::from_id ("bicubic"), - 0, - 24, - "", - 0, - 200000000, - &log + shared_ptr frame ( + new DCPVideoFrame ( + image, + Size (1998, 1080), + 0, + Scaler::from_id ("bicubic"), + 0, + 24, + "", + 0, + 200000000, + &log + ) ); - shared_ptr locally_encoded = frame.encode_locally (); + shared_ptr locally_encoded = frame->encode_locally (); Config::instance()->set_server_port (61920); Server* server = new Server (&log); - new thread (boost::bind (&Server::run, server, 1)); + new thread (boost::bind (&Server::run, server, 2)); - ServerDescription description ("localhost", 1); - shared_ptr remotely_encoded = frame.encode_remotely (&description); + ServerDescription description ("localhost", 2); - BOOST_CHECK_EQUAL (locally_encoded->size(), remotely_encoded->size()); - BOOST_CHECK (memcmp (locally_encoded->data(), remotely_encoded->data(), locally_encoded->size()) == 0); + thread* a = new thread (boost::bind (do_remote_encode, frame, &description, locally_encoded)); + thread* b = new thread (boost::bind (do_remote_encode, frame, &description, locally_encoded)); + thread* c = new thread (boost::bind (do_remote_encode, frame, &description, locally_encoded)); + thread* d = new thread (boost::bind (do_remote_encode, frame, &description, locally_encoded)); + + a->join (); + b->join (); + c->join (); + d->join (); } -- cgit v1.2.3 From e89fb9d81358b51ed0e231725f7fb6eb63f96c5b Mon Sep 17 00:00:00 2001 From: Carl Hetherington Date: Sun, 23 Sep 2012 17:50:31 +0100 Subject: Use io_service per thread. --- src/lib/dcp_video_frame.cc | 11 ++++------- src/lib/dcp_video_frame.h | 2 +- src/lib/server.cc | 28 +++++++++++++--------------- src/lib/server.h | 7 ++++--- src/lib/util.cc | 30 ++++++++---------------------- src/lib/util.h | 10 ++++++---- test/test.cc | 17 ++++++++--------- 7 files changed, 44 insertions(+), 61 deletions(-) (limited to 'src/lib') diff --git a/src/lib/dcp_video_frame.cc b/src/lib/dcp_video_frame.cc index ee29d8601..5c0ec6a6a 100644 --- a/src/lib/dcp_video_frame.cc +++ b/src/lib/dcp_video_frame.cc @@ -297,10 +297,7 @@ DCPVideoFrame::encode_remotely (ServerDescription const * serv) asio::ip::tcp::resolver::query query (serv->host_name(), boost::lexical_cast (Config::instance()->server_port ())); asio::ip::tcp::resolver::iterator endpoint_iterator = resolver.resolve (query); - shared_ptr socket (new asio::ip::tcp::socket (io_service)); - - DeadlineWrapper wrapper (io_service); - wrapper.set_socket (socket); + DeadlineWrapper wrapper; wrapper.connect (*endpoint_iterator, 30); @@ -378,12 +375,12 @@ EncodedData::write (shared_ptr opt, int frame) * @param socket Socket */ void -EncodedData::send (DeadlineWrapper& wrapper) +EncodedData::send (shared_ptr wrapper) { stringstream s; s << _size; - wrapper.write ((uint8_t *) s.str().c_str(), s.str().length() + 1, 30); - wrapper.write (_data, _size, 30); + wrapper->write ((uint8_t *) s.str().c_str(), s.str().length() + 1, 30); + wrapper->write (_data, _size, 30); } #ifdef DEBUG_HASH diff --git a/src/lib/dcp_video_frame.h b/src/lib/dcp_video_frame.h index d82aee367..752f0dda7 100644 --- a/src/lib/dcp_video_frame.h +++ b/src/lib/dcp_video_frame.h @@ -48,7 +48,7 @@ public: virtual ~EncodedData () {} - void send (DeadlineWrapper& wrapper); + void send (boost::shared_ptr wrapper); void write (boost::shared_ptr, int); #ifdef DEBUG_HASH diff --git a/src/lib/server.cc b/src/lib/server.cc index 9e61c2282..1f860d254 100644 --- a/src/lib/server.cc +++ b/src/lib/server.cc @@ -70,14 +70,11 @@ Server::Server (Log* log) } int -Server::process (shared_ptr socket) +Server::process (shared_ptr wrapper) { - DeadlineWrapper wrapper (_io_service); - wrapper.set_socket (socket); - char buffer[128]; - wrapper.read_indefinite ((uint8_t *) buffer, sizeof (buffer), 30); - wrapper.consume (strlen (buffer) + 1); + wrapper->read_indefinite ((uint8_t *) buffer, sizeof (buffer), 30); + wrapper->consume (strlen (buffer) + 1); stringstream s (buffer); @@ -124,7 +121,7 @@ Server::process (shared_ptr socket) } for (int i = 0; i < image->components(); ++i) { - wrapper.read_definite_and_consume (image->data()[i], image->line_size()[i] * image->lines(i), 30); + wrapper->read_definite_and_consume (image->data()[i], image->line_size()[i] * image->lines(i), 30); } #ifdef DEBUG_HASH @@ -151,7 +148,7 @@ Server::worker_thread () _worker_condition.wait (lock); } - shared_ptr socket = _queue.front (); + shared_ptr wrapper = _queue.front (); _queue.pop_front (); lock.unlock (); @@ -162,12 +159,12 @@ Server::worker_thread () gettimeofday (&start, 0); try { - frame = process (socket); + frame = process (wrapper); } catch (std::exception& e) { cerr << "Error: " << e.what() << "\n"; } - socket.reset (); + wrapper.reset (); lock.lock (); @@ -193,11 +190,12 @@ Server::run (int num_threads) for (int i = 0; i < num_threads; ++i) { _worker_threads.push_back (new thread (bind (&Server::worker_thread, this))); } - - asio::ip::tcp::acceptor acceptor (_io_service, asio::ip::tcp::endpoint (asio::ip::tcp::v4(), Config::instance()->server_port ())); + + asio::io_service io_service; + asio::ip::tcp::acceptor acceptor (io_service, asio::ip::tcp::endpoint (asio::ip::tcp::v4(), Config::instance()->server_port ())); while (1) { - shared_ptr socket (new asio::ip::tcp::socket (_io_service)); - acceptor.accept (*socket); + shared_ptr wrapper (new DeadlineWrapper); + acceptor.accept (wrapper->socket ()); mutex::scoped_lock lock (_worker_mutex); @@ -206,7 +204,7 @@ Server::run (int num_threads) _worker_condition.wait (lock); } - _queue.push_back (socket); + _queue.push_back (wrapper); _worker_condition.notify_all (); } } diff --git a/src/lib/server.h b/src/lib/server.h index 747081443..4cb6f2563 100644 --- a/src/lib/server.h +++ b/src/lib/server.h @@ -28,6 +28,8 @@ #include #include "log.h" +class DeadlineWrapper; + /** @class ServerDescription * @brief Class to describe a server to which we can send encoding work. */ @@ -80,11 +82,10 @@ public: private: void worker_thread (); - int process (boost::shared_ptr socket); + int process (boost::shared_ptr wrapper); - boost::asio::io_service _io_service; std::vector _worker_threads; - std::list > _queue; + std::list > _queue; boost::mutex _worker_mutex; boost::condition _worker_condition; Log* _log; diff --git a/src/lib/util.cc b/src/lib/util.cc index 3f48d696b..8713c5922 100644 --- a/src/lib/util.cc +++ b/src/lib/util.cc @@ -438,28 +438,20 @@ colour_lut_index_to_name (int index) return ""; } -DeadlineWrapper::DeadlineWrapper (asio::io_service& io_service) - : _io_service (io_service) - , _deadline (io_service) +DeadlineWrapper::DeadlineWrapper () + : _deadline (_io_service) + , _socket (_io_service) , _buffer_data (0) { _deadline.expires_at (posix_time::pos_infin); check (); } -void -DeadlineWrapper::set_socket (shared_ptr socket) -{ - _socket = socket; -} - void DeadlineWrapper::check () { if (_deadline.expires_at() <= asio::deadline_timer::traits_type::now ()) { - if (_socket) { - _socket->close (); - } + _socket.close (); _deadline.expires_at (posix_time::pos_infin); } @@ -469,15 +461,13 @@ DeadlineWrapper::check () void DeadlineWrapper::connect (asio::ip::basic_resolver_entry const & endpoint, int timeout) { - assert (_socket); - system::error_code ec = asio::error::would_block; - _socket->async_connect (endpoint, lambda::var(ec) = lambda::_1); + _socket.async_connect (endpoint, lambda::var(ec) = lambda::_1); do { _io_service.run_one(); } while (ec == asio::error::would_block); - if (ec || !_socket->is_open ()) { + if (ec || !_socket.is_open ()) { throw NetworkError ("connect timed out"); } } @@ -485,12 +475,10 @@ DeadlineWrapper::connect (asio::ip::basic_resolver_entry const & void DeadlineWrapper::write (uint8_t const * data, int size, int timeout) { - assert (_socket); - _deadline.expires_from_now (posix_time::seconds (timeout)); system::error_code ec = asio::error::would_block; - asio::async_write (*_socket, asio::buffer (data, size), lambda::var(ec) = lambda::_1); + asio::async_write (_socket, asio::buffer (data, size), lambda::var(ec) = lambda::_1); do { _io_service.run_one (); } while (ec == asio::error::would_block); @@ -503,14 +491,12 @@ DeadlineWrapper::write (uint8_t const * data, int size, int timeout) int DeadlineWrapper::read (uint8_t* data, int size, int timeout) { - assert (_socket); - _deadline.expires_from_now (posix_time::seconds (timeout)); system::error_code ec = asio::error::would_block; int amount_read = 0; - _socket->async_read_some ( + _socket.async_read_some ( asio::buffer (data, size), (lambda::var(ec) = lambda::_1, lambda::var(amount_read) = lambda::_2) ); diff --git a/src/lib/util.h b/src/lib/util.h index 2785a5dc1..8d6e2f541 100644 --- a/src/lib/util.h +++ b/src/lib/util.h @@ -116,9 +116,11 @@ extern std::string colour_lut_index_to_name (int index); class DeadlineWrapper { public: - DeadlineWrapper (boost::asio::io_service& io_service); + DeadlineWrapper (); - void set_socket (boost::shared_ptr socket); + boost::asio::ip::tcp::socket& socket () { + return _socket; + } void connect (boost::asio::ip::basic_resolver_entry const & endpoint, int timeout); void write (uint8_t const * data, int size, int timeout); @@ -133,9 +135,9 @@ private: DeadlineWrapper (DeadlineWrapper const &); - boost::asio::io_service& _io_service; + boost::asio::io_service _io_service; boost::asio::deadline_timer _deadline; - boost::shared_ptr _socket; + boost::asio::ip::tcp::socket _socket; /** a buffer for small reads */ uint8_t _buffer[256]; /** amount of valid data in the buffer */ diff --git a/test/test.cc b/test/test.cc index b77eb2b51..638d526e0 100644 --- a/test/test.cc +++ b/test/test.cc @@ -306,13 +306,12 @@ BOOST_AUTO_TEST_CASE (client_server_test) ServerDescription description ("localhost", 2); - thread* a = new thread (boost::bind (do_remote_encode, frame, &description, locally_encoded)); - thread* b = new thread (boost::bind (do_remote_encode, frame, &description, locally_encoded)); - thread* c = new thread (boost::bind (do_remote_encode, frame, &description, locally_encoded)); - thread* d = new thread (boost::bind (do_remote_encode, frame, &description, locally_encoded)); - - a->join (); - b->join (); - c->join (); - d->join (); + list threads; + for (int i = 0; i < 8; ++i) { + threads.push_back (new thread (boost::bind (do_remote_encode, frame, &description, locally_encoded))); + } + + for (list::iterator i = threads.begin(); i != threads.end(); ++i) { + (*i)->join (); + } } -- cgit v1.2.3 From 737c3392039740f7a22a9ff922f8492905173b9c Mon Sep 17 00:00:00 2001 From: Carl Hetherington Date: Sun, 23 Sep 2012 17:56:08 +0100 Subject: Tidy up naming. --- src/lib/dcp_video_frame.cc | 21 ++++++++++----------- src/lib/dcp_video_frame.h | 2 +- src/lib/server.cc | 22 +++++++++++----------- src/lib/server.h | 6 +++--- src/lib/util.cc | 18 +++++++++--------- src/lib/util.h | 8 ++++---- 6 files changed, 38 insertions(+), 39 deletions(-) (limited to 'src/lib') diff --git a/src/lib/dcp_video_frame.cc b/src/lib/dcp_video_frame.cc index 5c0ec6a6a..d8af3462d 100644 --- a/src/lib/dcp_video_frame.cc +++ b/src/lib/dcp_video_frame.cc @@ -293,13 +293,12 @@ DCPVideoFrame::encode_remotely (ServerDescription const * serv) { asio::io_service io_service; asio::ip::tcp::resolver resolver (io_service); - asio::ip::tcp::resolver::query query (serv->host_name(), boost::lexical_cast (Config::instance()->server_port ())); asio::ip::tcp::resolver::iterator endpoint_iterator = resolver.resolve (query); - DeadlineWrapper wrapper; + Socket socket; - wrapper.connect (*endpoint_iterator, 30); + socket.connect (*endpoint_iterator, 30); #ifdef DEBUG_HASH _input->hash ("Input for remote encoding (before sending)"); @@ -322,19 +321,19 @@ DCPVideoFrame::encode_remotely (ServerDescription const * serv) s << _input->line_size()[i] << " "; } - wrapper.write ((uint8_t *) s.str().c_str(), s.str().length() + 1, 30); + socket.write ((uint8_t *) s.str().c_str(), s.str().length() + 1, 30); for (int i = 0; i < _input->components(); ++i) { - wrapper.write (_input->data()[i], _input->line_size()[i] * _input->lines(i), 30); + socket.write (_input->data()[i], _input->line_size()[i] * _input->lines(i), 30); } char buffer[32]; - wrapper.read_indefinite ((uint8_t *) buffer, sizeof (buffer), 30); - wrapper.consume (strlen (buffer) + 1); + socket.read_indefinite ((uint8_t *) buffer, sizeof (buffer), 30); + socket.consume (strlen (buffer) + 1); shared_ptr e (new RemotelyEncodedData (atoi (buffer))); /* now read the rest */ - wrapper.read_definite_and_consume (e->data(), e->size(), 30); + socket.read_definite_and_consume (e->data(), e->size(), 30); #ifdef DEBUG_HASH e->hash ("Encoded image (after receiving)"); @@ -375,12 +374,12 @@ EncodedData::write (shared_ptr opt, int frame) * @param socket Socket */ void -EncodedData::send (shared_ptr wrapper) +EncodedData::send (shared_ptr socket) { stringstream s; s << _size; - wrapper->write ((uint8_t *) s.str().c_str(), s.str().length() + 1, 30); - wrapper->write (_data, _size, 30); + socket->write ((uint8_t *) s.str().c_str(), s.str().length() + 1, 30); + socket->write (_data, _size, 30); } #ifdef DEBUG_HASH diff --git a/src/lib/dcp_video_frame.h b/src/lib/dcp_video_frame.h index 752f0dda7..da4e0c301 100644 --- a/src/lib/dcp_video_frame.h +++ b/src/lib/dcp_video_frame.h @@ -48,7 +48,7 @@ public: virtual ~EncodedData () {} - void send (boost::shared_ptr wrapper); + void send (boost::shared_ptr socket); void write (boost::shared_ptr, int); #ifdef DEBUG_HASH diff --git a/src/lib/server.cc b/src/lib/server.cc index 1f860d254..8ca426049 100644 --- a/src/lib/server.cc +++ b/src/lib/server.cc @@ -70,11 +70,11 @@ Server::Server (Log* log) } int -Server::process (shared_ptr wrapper) +Server::process (shared_ptr socket) { char buffer[128]; - wrapper->read_indefinite ((uint8_t *) buffer, sizeof (buffer), 30); - wrapper->consume (strlen (buffer) + 1); + socket->read_indefinite ((uint8_t *) buffer, sizeof (buffer), 30); + socket->consume (strlen (buffer) + 1); stringstream s (buffer); @@ -121,7 +121,7 @@ Server::process (shared_ptr wrapper) } for (int i = 0; i < image->components(); ++i) { - wrapper->read_definite_and_consume (image->data()[i], image->line_size()[i] * image->lines(i), 30); + socket->read_definite_and_consume (image->data()[i], image->line_size()[i] * image->lines(i), 30); } #ifdef DEBUG_HASH @@ -130,7 +130,7 @@ Server::process (shared_ptr wrapper) DCPVideoFrame dcp_video_frame (image, out_size, padding, scaler, frame, frames_per_second, post_process, colour_lut_index, j2k_bandwidth, _log); shared_ptr encoded = dcp_video_frame.encode_locally (); - encoded->send (wrapper); + encoded->send (socket); #ifdef DEBUG_HASH encoded->hash ("Encoded image (as made by server and as sent back)"); @@ -148,7 +148,7 @@ Server::worker_thread () _worker_condition.wait (lock); } - shared_ptr wrapper = _queue.front (); + shared_ptr socket = _queue.front (); _queue.pop_front (); lock.unlock (); @@ -159,12 +159,12 @@ Server::worker_thread () gettimeofday (&start, 0); try { - frame = process (wrapper); + frame = process (socket); } catch (std::exception& e) { cerr << "Error: " << e.what() << "\n"; } - wrapper.reset (); + socket.reset (); lock.lock (); @@ -194,8 +194,8 @@ Server::run (int num_threads) asio::io_service io_service; asio::ip::tcp::acceptor acceptor (io_service, asio::ip::tcp::endpoint (asio::ip::tcp::v4(), Config::instance()->server_port ())); while (1) { - shared_ptr wrapper (new DeadlineWrapper); - acceptor.accept (wrapper->socket ()); + shared_ptr socket (new Socket); + acceptor.accept (socket->socket ()); mutex::scoped_lock lock (_worker_mutex); @@ -204,7 +204,7 @@ Server::run (int num_threads) _worker_condition.wait (lock); } - _queue.push_back (wrapper); + _queue.push_back (socket); _worker_condition.notify_all (); } } diff --git a/src/lib/server.h b/src/lib/server.h index 4cb6f2563..32ba8dc4b 100644 --- a/src/lib/server.h +++ b/src/lib/server.h @@ -28,7 +28,7 @@ #include #include "log.h" -class DeadlineWrapper; +class Socket; /** @class ServerDescription * @brief Class to describe a server to which we can send encoding work. @@ -82,10 +82,10 @@ public: private: void worker_thread (); - int process (boost::shared_ptr wrapper); + int process (boost::shared_ptr socket); std::vector _worker_threads; - std::list > _queue; + std::list > _queue; boost::mutex _worker_mutex; boost::condition _worker_condition; Log* _log; diff --git a/src/lib/util.cc b/src/lib/util.cc index 8713c5922..d12bd3e77 100644 --- a/src/lib/util.cc +++ b/src/lib/util.cc @@ -438,7 +438,7 @@ colour_lut_index_to_name (int index) return ""; } -DeadlineWrapper::DeadlineWrapper () +Socket::Socket () : _deadline (_io_service) , _socket (_io_service) , _buffer_data (0) @@ -448,18 +448,18 @@ DeadlineWrapper::DeadlineWrapper () } void -DeadlineWrapper::check () +Socket::check () { if (_deadline.expires_at() <= asio::deadline_timer::traits_type::now ()) { _socket.close (); _deadline.expires_at (posix_time::pos_infin); } - _deadline.async_wait (boost::bind (&DeadlineWrapper::check, this)); + _deadline.async_wait (boost::bind (&Socket::check, this)); } void -DeadlineWrapper::connect (asio::ip::basic_resolver_entry const & endpoint, int timeout) +Socket::connect (asio::ip::basic_resolver_entry const & endpoint, int timeout) { system::error_code ec = asio::error::would_block; _socket.async_connect (endpoint, lambda::var(ec) = lambda::_1); @@ -473,7 +473,7 @@ DeadlineWrapper::connect (asio::ip::basic_resolver_entry const & } void -DeadlineWrapper::write (uint8_t const * data, int size, int timeout) +Socket::write (uint8_t const * data, int size, int timeout) { _deadline.expires_from_now (posix_time::seconds (timeout)); system::error_code ec = asio::error::would_block; @@ -489,7 +489,7 @@ DeadlineWrapper::write (uint8_t const * data, int size, int timeout) } int -DeadlineWrapper::read (uint8_t* data, int size, int timeout) +Socket::read (uint8_t* data, int size, int timeout) { _deadline.expires_from_now (posix_time::seconds (timeout)); system::error_code ec = asio::error::would_block; @@ -517,7 +517,7 @@ DeadlineWrapper::read (uint8_t* data, int size, int timeout) * @param size Amount of data to consume, in bytes. */ void -DeadlineWrapper::consume (int size) +Socket::consume (int size) { assert (_buffer_data >= size); @@ -534,7 +534,7 @@ DeadlineWrapper::consume (int size) * @param size Number of bytes to read. */ void -DeadlineWrapper::read_definite_and_consume (uint8_t* data, int size, int timeout) +Socket::read_definite_and_consume (uint8_t* data, int size, int timeout) { int const from_buffer = min (_buffer_data, size); if (from_buffer > 0) { @@ -563,7 +563,7 @@ DeadlineWrapper::read_definite_and_consume (uint8_t* data, int size, int timeout * @param size Maximum amount of data to read. */ void -DeadlineWrapper::read_indefinite (uint8_t* data, int size, int timeout) +Socket::read_indefinite (uint8_t* data, int size, int timeout) { assert (size < int (sizeof (_buffer))); diff --git a/src/lib/util.h b/src/lib/util.h index 8d6e2f541..d7f233003 100644 --- a/src/lib/util.h +++ b/src/lib/util.h @@ -113,10 +113,10 @@ extern std::string crop_string (Position, Size); extern int dcp_audio_sample_rate (int); extern std::string colour_lut_index_to_name (int index); -class DeadlineWrapper +class Socket { public: - DeadlineWrapper (); + Socket (); boost::asio::ip::tcp::socket& socket () { return _socket; @@ -124,7 +124,6 @@ public: void connect (boost::asio::ip::basic_resolver_entry const & endpoint, int timeout); void write (uint8_t const * data, int size, int timeout); - int read (uint8_t* data, int size, int timeout); void read_definite_and_consume (uint8_t* data, int size, int timeout); void read_indefinite (uint8_t* data, int size, int timeout); @@ -132,8 +131,9 @@ public: private: void check (); + int read (uint8_t* data, int size, int timeout); - DeadlineWrapper (DeadlineWrapper const &); + Socket (Socket const &); boost::asio::io_service _io_service; boost::asio::deadline_timer _deadline; -- cgit v1.2.3 From 5395f0b529b4127feffff310dbe648ffc0eb5aa3 Mon Sep 17 00:00:00 2001 From: Carl Hetherington Date: Sun, 23 Sep 2012 20:13:04 +0100 Subject: Add some more logging when finishing up an encode. --- src/lib/j2k_wav_encoder.cc | 6 ++++++ 1 file changed, 6 insertions(+) (limited to 'src/lib') diff --git a/src/lib/j2k_wav_encoder.cc b/src/lib/j2k_wav_encoder.cc index ef1e8edc1..9ae01c774 100644 --- a/src/lib/j2k_wav_encoder.cc +++ b/src/lib/j2k_wav_encoder.cc @@ -27,6 +27,7 @@ #include #include #include +#include #include #include #include "j2k_wav_encoder.h" @@ -229,8 +230,11 @@ J2KWAVEncoder::process_end () { boost::mutex::scoped_lock lock (_worker_mutex); + _log->log ("Clearing queue of " + lexical_cast (_queue.size ())); + /* Keep waking workers until the queue is empty */ while (!_queue.empty ()) { + _log->log ("Waking with " + lexical_cast (_queue.size ())); _worker_condition.notify_all (); _worker_condition.wait (lock); } @@ -239,6 +243,8 @@ J2KWAVEncoder::process_end () terminate_worker_threads (); + _log->log ("Mopping up " + lexical_cast (_queue.size())); + /* The following sequence of events can occur in the above code: 1. a remote worker takes the last image off the queue 2. the loop above terminates -- cgit v1.2.3 From 226fc87130cd013d9e964650dfc9655fcac4521b Mon Sep 17 00:00:00 2001 From: Carl Hetherington Date: Sun, 23 Sep 2012 22:28:19 +0100 Subject: Formatting. --- src/lib/film.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src/lib') diff --git a/src/lib/film.cc b/src/lib/film.cc index d5327aa3a..022cc4f5b 100644 --- a/src/lib/film.cc +++ b/src/lib/film.cc @@ -69,7 +69,7 @@ Film::Film (string d, bool must_exist) filesystem::path p (filesystem::system_complete (d)); filesystem::path result; - for(filesystem::path::iterator i = p.begin(); i != p.end(); ++i) { + for (filesystem::path::iterator i = p.begin(); i != p.end(); ++i) { if (*i == "..") { if (filesystem::is_symlink (result) || result.filename() == "..") { result /= *i; -- cgit v1.2.3 From d4168894a231253d2625a7c1f7b4df68c9c8557c Mon Sep 17 00:00:00 2001 From: Carl Hetherington Date: Sun, 23 Sep 2012 22:28:42 +0100 Subject: Remove probably unnecessary and certainly erroneous hack for content digest back compat. --- src/lib/film_state.cc | 5 ----- 1 file changed, 5 deletions(-) (limited to 'src/lib') diff --git a/src/lib/film_state.cc b/src/lib/film_state.cc index e0ad20417..739eeac3c 100644 --- a/src/lib/film_state.cc +++ b/src/lib/film_state.cc @@ -165,11 +165,6 @@ FilmState::read_metadata (string k, string v) } else if (k == "content_digest") { content_digest = v; } - - /* Itsy bitsy hack: compute digest here if don't have one (for backwards compatibility) */ - if (content_digest.empty() && !content.empty()) { - content_digest = md5_digest (content_path ()); - } } -- cgit v1.2.3 From e72351201130c4523dc1420dd64bc2bc3be213d8 Mon Sep 17 00:00:00 2001 From: Carl Hetherington Date: Sun, 23 Sep 2012 22:32:26 +0100 Subject: Ignore windows line endings when reading metadata on Linux. --- src/lib/film.cc | 4 ++++ 1 file changed, 4 insertions(+) (limited to 'src/lib') diff --git a/src/lib/film.cc b/src/lib/film.cc index 022cc4f5b..d1334130e 100644 --- a/src/lib/film.cc +++ b/src/lib/film.cc @@ -123,6 +123,10 @@ Film::read_metadata () continue; } + if (line[line.size() - 1] == '\r') { + line = line.substr (0, line.size() - 1); + } + size_t const s = line.find (' '); if (s == string::npos) { continue; -- cgit v1.2.3 From 3fc9a435a720d8b2abd78c1bdc7b34bc635ad797 Mon Sep 17 00:00:00 2001 From: Carl Hetherington Date: Mon, 24 Sep 2012 01:58:56 +0100 Subject: Some doxygen documentation improvements. --- Doxyfile | 2 +- doc/mainpage.txt | 2 +- src/lib/config.h | 18 +++++++++++++----- src/lib/decoder.cc | 2 ++ src/lib/encoder.cc | 5 +++++ src/lib/encoder.h | 5 +++++ src/lib/exceptions.h | 5 +++++ src/lib/job.cc | 4 +++- src/lib/job.h | 12 +++++++++--- src/lib/util.cc | 23 +++++++++++++++++++++++ src/lib/util.h | 19 ++++++++++++++++++- src/wx/film_viewer.cc | 3 +++ src/wx/wx_util.cc | 19 ++++++++++++++++++- src/wx/wx_util.h | 5 ++++- 14 files changed, 110 insertions(+), 14 deletions(-) (limited to 'src/lib') diff --git a/Doxyfile b/Doxyfile index 80a4b9c25..56f7e1d3c 100644 --- a/Doxyfile +++ b/Doxyfile @@ -661,7 +661,7 @@ WARN_LOGFILE = # directories like "/usr/src/myproject". Separate the files or directories # with spaces. -INPUT = src \ +INPUT = src/lib src/wx src/tools \ doc/mainpage.txt # This tag can be used to specify the character encoding of the source files diff --git a/doc/mainpage.txt b/doc/mainpage.txt index 81c3b4558..e89ca8d26 100644 --- a/doc/mainpage.txt +++ b/doc/mainpage.txt @@ -23,7 +23,7 @@ * and libsndfile (http://www.mega-nerd.com/libsndfile/) for WAV file manipulation. It * also makes heavy use of the boost libraries (http://www.boost.org/). libtiff * (http://www.libtiff.org/) is used for TIFF encoding and decoding, and the GUI is - * built using GTK (http://www.gtk.org/) and GTKMM (http://www.gtkmm.org). It also uses libmhash (http://mhash.sourceforge.net/) + * built using wxWidgets (http://wxwidgets.org/). It also uses libmhash (http://mhash.sourceforge.net/) * for debugging purposes. * * Thanks are due to the authors and communities of all DVD-o-matic's dependencies. diff --git a/src/lib/config.h b/src/lib/config.h index b002da7df..840dcdaef 100644 --- a/src/lib/config.h +++ b/src/lib/config.h @@ -81,18 +81,22 @@ public: return _reference_filters; } + /** @return The IP address of a TMS that we can copy DCPs to */ std::string tms_ip () const { return _tms_ip; } + /** @return The path on a TMS that we should write DCPs to */ std::string tms_path () const { return _tms_path; } + /** @return User name to log into the TMS with */ std::string tms_user () const { return _tms_user; } + /** @return Password to log into the TMS with */ std::string tms_password () const { return _tms_password; } @@ -146,21 +150,25 @@ public: Changed (); } + /** @param i IP address of a TMS that we can copy DCPs to */ void set_tms_ip (std::string i) { _tms_ip = i; Changed (); } + /** @param p Path on a TMS that we should write DCPs to */ void set_tms_path (std::string p) { _tms_path = p; Changed (); } + /** @param u User name to log into the TMS with */ void set_tms_user (std::string u) { _tms_user = u; Changed (); } + /** @param p Password to log into the TMS with */ void set_tms_password (std::string p) { _tms_password = p; Changed (); @@ -189,21 +197,21 @@ private: /** J2K encoding servers to use */ std::vector _servers; - /** Screen definitions */ std::vector > _screens; - /** Scaler to use for the "A" part of A/B comparisons */ Scaler const * _reference_scaler; - /** Filters to use for the "A" part of A/B comparisons */ std::vector _reference_filters; - + /** The IP address of a TMS that we can copy DCPs to */ std::string _tms_ip; + /** The path on a TMS that we should write DCPs to */ std::string _tms_path; + /** User name to log into the TMS with */ std::string _tms_user; + /** Password to log into the TMS with */ std::string _tms_password; - + /** Our sound processor */ SoundProcessor const * _sound_processor; /** Singleton instance, or 0 */ diff --git a/src/lib/decoder.cc b/src/lib/decoder.cc index fc808d819..9332511bc 100644 --- a/src/lib/decoder.cc +++ b/src/lib/decoder.cc @@ -87,6 +87,7 @@ Decoder::~Decoder () delete _delay_line; } +/** Start off a decode processing run */ void Decoder::process_begin () { @@ -120,6 +121,7 @@ Decoder::process_begin () _audio_frames_processed = 0; } +/** Finish off a decode processing run */ void Decoder::process_end () { diff --git a/src/lib/encoder.cc b/src/lib/encoder.cc index 18ccd3f57..62ba922da 100644 --- a/src/lib/encoder.cc +++ b/src/lib/encoder.cc @@ -60,6 +60,7 @@ Encoder::current_frames_per_second () const return _history_size / (seconds (now) - seconds (_time_history.back ())); } +/** @return true if the last frame to be processed was skipped as it already existed */ bool Encoder::skipping () const { @@ -67,6 +68,7 @@ Encoder::skipping () const return _just_skipped; } +/** @return Index of last frame to be successfully encoded */ int Encoder::last_frame () const { @@ -74,6 +76,9 @@ Encoder::last_frame () const return _last_frame; } +/** Should be called when a frame has been encoded successfully. + * @param n Frame index. + */ void Encoder::frame_done (int n) { diff --git a/src/lib/encoder.h b/src/lib/encoder.h index 5c0c4c03f..539b2912c 100644 --- a/src/lib/encoder.h +++ b/src/lib/encoder.h @@ -84,10 +84,15 @@ protected: /** Mutex for _time_history, _just_skipped and _last_frame */ mutable boost::mutex _history_mutex; + /** List of the times of completion of the last _history_size frames; + first is the most recently completed. + */ std::list _time_history; + /** Number of frames that we should keep history for */ static int const _history_size; /** true if the last frame we processed was skipped (because it was already done) */ bool _just_skipped; + /** Index of the last frame to be processed */ int _last_frame; }; diff --git a/src/lib/exceptions.h b/src/lib/exceptions.h index 6b567805b..8ef09875b 100644 --- a/src/lib/exceptions.h +++ b/src/lib/exceptions.h @@ -77,6 +77,9 @@ public: class FileError : public StringError { public: + /** @param m Error message. + * @param f Name of the file that this exception concerns. + */ FileError (std::string m, std::string f) : StringError (m) , _file (f) @@ -84,11 +87,13 @@ public: virtual ~FileError () throw () {} + /** @return name of the file that this exception concerns */ std::string file () const { return _file; } private: + /** name of the file that this exception concerns */ std::string _file; }; diff --git a/src/lib/job.cc b/src/lib/job.cc index d446b3913..22754eb90 100644 --- a/src/lib/job.cc +++ b/src/lib/job.cc @@ -223,7 +223,7 @@ Job::set_error (string e) _error = e; } -/** Set that this job's progress will always be unknown */ +/** Say that this job's progress will always be unknown */ void Job::set_progress_unknown () { @@ -231,6 +231,7 @@ Job::set_progress_unknown () _progress_unknown = true; } +/** @return Human-readable status of this job */ string Job::status () const { @@ -252,6 +253,7 @@ Job::status () const return s.str (); } +/** @return An estimate of the remaining time for this job, in seconds */ int Job::remaining_time () const { diff --git a/src/lib/job.h b/src/lib/job.h index 95599bdbb..fee887b42 100644 --- a/src/lib/job.h +++ b/src/lib/job.h @@ -72,6 +72,7 @@ protected: virtual int remaining_time () const; + /** Description of a job's state */ enum State { NEW, ///< the job hasn't been started yet RUNNING, ///< the job is running @@ -82,10 +83,11 @@ protected: void set_state (State); void set_error (std::string e); + /** FilmState for this job */ boost::shared_ptr _fs; + /** options in use for this job */ boost::shared_ptr _opt; - - /** A log that this job can write to */ + /** a log that this job can write to */ Log* _log; private: @@ -94,11 +96,15 @@ private: /** mutex for _state and _error */ mutable boost::mutex _state_mutex; + /** current state of the job */ State _state; + /** message for an error that has occurred (when state == FINISHED_ERROR) */ std::string _error; + /** time that this job was started */ time_t _start_time; - + + /** mutex for _stack and _progress_unknown */ mutable boost::mutex _progress_mutex; struct Level { diff --git a/src/lib/util.cc b/src/lib/util.cc index d12bd3e77..73222083a 100644 --- a/src/lib/util.cc +++ b/src/lib/util.cc @@ -369,6 +369,9 @@ md5_data (string title, void const * data, int size) } #endif +/** @param file File name. + * @return MD5 digest of file's contents. + */ string md5_digest (string file) { @@ -404,6 +407,9 @@ md5_digest (string file) return s.str (); } +/** @param An arbitrary sampling rate. + * @return The appropriate DCP-approved sampling rate (48kHz or 96kHz). + */ int dcp_audio_sample_rate (int fs) { @@ -424,6 +430,9 @@ bool operator!= (Crop const & a, Crop const & b) return !(a == b); } +/** @param index Colour LUT index. + * @return Human-readable name. + */ string colour_lut_index_to_name (int index) { @@ -458,6 +467,10 @@ Socket::check () _deadline.async_wait (boost::bind (&Socket::check, this)); } +/** Blocking connect with timeout. + * @param endpoint End-point to connect to. + * @param timeout Time-out in seconds. + */ void Socket::connect (asio::ip::basic_resolver_entry const & endpoint, int timeout) { @@ -472,6 +485,11 @@ Socket::connect (asio::ip::basic_resolver_entry const & endpoint, } } +/** Blocking write with timeout. + * @param data Buffer to write. + * @param size Number of bytes to write. + * @param timeout Time-out, in seconds. + */ void Socket::write (uint8_t const * data, int size, int timeout) { @@ -488,6 +506,11 @@ Socket::write (uint8_t const * data, int size, int timeout) } } +/** Blocking read with timeout. + * @param data Buffer to read to. + * @param size Number of bytes to read. + * @param timeout Time-out, in seconds. + */ int Socket::read (uint8_t* data, int size, int timeout) { diff --git a/src/lib/util.h b/src/lib/util.h index d7f233003..63d492e60 100644 --- a/src/lib/util.h +++ b/src/lib/util.h @@ -80,19 +80,25 @@ struct Size int height; }; +/** A description of the crop of an image or video. */ struct Crop { Crop () : left (0), right (0), top (0), bottom (0) {} - + + /** Number of pixels to remove from the left-hand side */ int left; + /** Number of pixels to remove from the right-hand side */ int right; + /** Number of pixels to remove from the top */ int top; + /** Number of pixels to remove from the bottom */ int bottom; }; extern bool operator== (Crop const & a, Crop const & b); extern bool operator!= (Crop const & a, Crop const & b); +/** A position */ struct Position { Position () @@ -105,7 +111,9 @@ struct Position , y (y_) {} + /** x coordinate */ int x; + /** y coordinate */ int y; }; @@ -113,11 +121,20 @@ extern std::string crop_string (Position, Size); extern int dcp_audio_sample_rate (int); extern std::string colour_lut_index_to_name (int index); +/** @class Socket + * @brief A class to wrap a boost::asio::ip::tcp::socket with some things + * that are useful for DVD-o-matic. + * + * This class wraps some things that I could not work out how to do with boost; + * most notably, sync read/write calls with timeouts, and the ability to peak into + * data being read. + */ class Socket { public: Socket (); + /** @return Our underlying socket */ boost::asio::ip::tcp::socket& socket () { return _socket; } diff --git a/src/wx/film_viewer.cc b/src/wx/film_viewer.cc index 56f20449b..0d17baf83 100644 --- a/src/wx/film_viewer.cc +++ b/src/wx/film_viewer.cc @@ -47,6 +47,7 @@ public: { } + /** Handle a paint event */ void paint_event (wxPaintEvent& ev) { if (_current_image != _pending_image) { @@ -67,6 +68,7 @@ public: } } + /** Handle a size event */ void size_event (wxSizeEvent &) { if (!_image) { @@ -101,6 +103,7 @@ public: } } + /** Clear our thumbnail image */ void clear () { delete _bitmap; diff --git a/src/wx/wx_util.cc b/src/wx/wx_util.cc index 44d9462e5..4277ed12d 100644 --- a/src/wx/wx_util.cc +++ b/src/wx/wx_util.cc @@ -27,6 +27,12 @@ using namespace std; using namespace boost; +/** Add a wxStaticText to a wxSizer, aligning it at vertical centre. + * @param s Sizer to add to. + * @param p Parent window for the wxStaticText. + * @param t Text for the wxStaticText. + * @param prop Properties to pass when calling Add() on the wxSizer. + */ wxStaticText * add_label_to_sizer (wxSizer* s, wxWindow* p, string t, int prop) { @@ -35,6 +41,10 @@ add_label_to_sizer (wxSizer* s, wxWindow* p, string t, int prop) return m; } +/** Pop up an error dialogue box. + * @param parent Parent. + * @param m Message. + */ void error_dialog (wxWindow* parent, string m) { @@ -43,12 +53,18 @@ error_dialog (wxWindow* parent, string m) d->Destroy (); } +/** @param s wxWidgets string. + * @return Corresponding STL string. + */ string wx_to_std (wxString s) { return string (s.mb_str ()); } +/** @param s STL string. + * @return Corresponding wxWidgets string. + */ wxString std_to_wx (string s) { @@ -75,15 +91,16 @@ ThreadedStaticText::~ThreadedStaticText () delete _thread; } +/** Run our thread and post the result to the GUI thread via AddPendingEvent */ void ThreadedStaticText::run (function fn) { - /* Run the thread and post the result to the GUI thread via AddPendingEvent */ wxCommandEvent ev (wxEVT_COMMAND_TEXT_UPDATED, _update_event_id); ev.SetString (std_to_wx (fn ())); GetEventHandler()->AddPendingEvent (ev); } +/** Called in the GUI thread when our worker thread has finished */ void ThreadedStaticText::thread_finished (wxCommandEvent& ev) { diff --git a/src/wx/wx_util.h b/src/wx/wx_util.h index 3a454c7c4..12a6e8837 100644 --- a/src/wx/wx_util.h +++ b/src/wx/wx_util.h @@ -30,7 +30,9 @@ extern wxStaticText* add_label_to_sizer (wxSizer *, wxWindow *, std::string, int extern std::string wx_to_std (wxString); extern wxString std_to_wx (std::string); -/** A wxStaticText whose content is computed in a separate thread, to avoid holding +/** @class ThreadedStaticText + * + * @brief A wxStaticText whose content is computed in a separate thread, to avoid holding * up the GUI while work is done. */ class ThreadedStaticText : public wxStaticText @@ -43,6 +45,7 @@ private: void run (boost::function fn); void thread_finished (wxCommandEvent& ev); + /** Thread to do our work in */ boost::thread* _thread; static const int _update_event_id; -- cgit v1.2.3 From b8b9800d1022fe0912b180e8b3b41fd4b616478a Mon Sep 17 00:00:00 2001 From: Carl Hetherington Date: Mon, 24 Sep 2012 13:12:34 +0100 Subject: Fix problems with overflow on long films. --- .../666e8ba3-f1a3-4245-9d00-9a3a5e048ed9/values | 17 ++++++++++++++ ChangeLog | 4 ++++ src/lib/decoder.cc | 26 ++++++++++++---------- src/lib/decoder.h | 2 +- 4 files changed, 36 insertions(+), 13 deletions(-) create mode 100644 .be/aff5ca2c-44ee-4ed6-800b-4abe9c3e794c/bugs/666e8ba3-f1a3-4245-9d00-9a3a5e048ed9/values (limited to 'src/lib') diff --git a/.be/aff5ca2c-44ee-4ed6-800b-4abe9c3e794c/bugs/666e8ba3-f1a3-4245-9d00-9a3a5e048ed9/values b/.be/aff5ca2c-44ee-4ed6-800b-4abe9c3e794c/bugs/666e8ba3-f1a3-4245-9d00-9a3a5e048ed9/values new file mode 100644 index 000000000..8861f1d19 --- /dev/null +++ b/.be/aff5ca2c-44ee-4ed6-800b-4abe9c3e794c/bugs/666e8ba3-f1a3-4245-9d00-9a3a5e048ed9/values @@ -0,0 +1,17 @@ +creator: Carl Hetherington + + +reporter: Carl Hetherington + + +severity: minor + + +status: open + + +summary: Re-setting content file runs thumb scan twice? + + +time: Mon, 24 Sep 2012 09:42:18 +0000 + diff --git a/ChangeLog b/ChangeLog index 70c097f16..1aaed3818 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,7 @@ +2012-09-24 Carl Hetherington + + * Fix problems with overflow on long films. + 2012-09-24 Carl Hetherington * Version 0.52 released. diff --git a/src/lib/decoder.cc b/src/lib/decoder.cc index 9332511bc..2f02147e3 100644 --- a/src/lib/decoder.cc +++ b/src/lib/decoder.cc @@ -165,20 +165,22 @@ Decoder::process_end () in to get it to the right length. */ - int const audio_short_by_frames = - (decoding_frames() * dcp_audio_sample_rate (_fs->audio_sample_rate) / _fs->frames_per_second) + int64_t const audio_short_by_frames = + ((int64_t) decoding_frames() * dcp_audio_sample_rate (_fs->audio_sample_rate) / _fs->frames_per_second) - _audio_frames_processed; - int bytes = audio_short_by_frames * _fs->audio_channels * _fs->bytes_per_sample(); - - int const silence_size = 64 * 1024; - uint8_t silence[silence_size]; - memset (silence, 0, silence_size); - - while (bytes) { - int const t = min (bytes, silence_size); - Audio (silence, t); - bytes -= t; + if (audio_short_by_frames >= 0) { + int bytes = audio_short_by_frames * _fs->audio_channels * _fs->bytes_per_sample(); + + int const silence_size = 64 * 1024; + uint8_t silence[silence_size]; + memset (silence, 0, silence_size); + + while (bytes) { + int const t = min (bytes, silence_size); + Audio (silence, t); + bytes -= t; + } } } diff --git a/src/lib/decoder.h b/src/lib/decoder.h index 792f7dde2..14b25c7b0 100644 --- a/src/lib/decoder.h +++ b/src/lib/decoder.h @@ -145,7 +145,7 @@ private: /* Number of audio frames that we have pushed to the encoder (at the DCP sample rate). */ - int _audio_frames_processed; + int64_t _audio_frames_processed; }; #endif -- cgit v1.2.3 From 45698c6bc5cd3a596e7f0c963733d502c11dd854 Mon Sep 17 00:00:00 2001 From: Carl Hetherington Date: Mon, 24 Sep 2012 13:40:21 +0100 Subject: Report finished even when the transcode skipped everything. --- src/lib/transcode_job.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src/lib') diff --git a/src/lib/transcode_job.cc b/src/lib/transcode_job.cc index f4e3d7af9..c91058973 100644 --- a/src/lib/transcode_job.cc +++ b/src/lib/transcode_job.cc @@ -89,7 +89,7 @@ TranscodeJob::status () const return "0%"; } - if (_encoder->skipping ()) { + if (_encoder->skipping () && !finished ()) { return "skipping frames already encoded"; } -- cgit v1.2.3 From 4fd257106009b2db170dafddece06ee3c190fceb Mon Sep 17 00:00:00 2001 From: Carl Hetherington Date: Mon, 24 Sep 2012 23:49:53 +0100 Subject: Remove long-since disused hash debugging. --- src/lib/dcp_video_frame.cc | 30 ------------------------------ src/lib/dcp_video_frame.h | 4 ---- src/lib/image.cc | 32 +------------------------------- src/lib/image.h | 4 ---- src/lib/server.cc | 8 -------- src/lib/util.cc | 24 +++++++++++------------- src/lib/util.h | 4 +--- src/lib/wscript | 8 ++------ src/tools/servomatictest.cc | 9 --------- wscript | 2 -- 10 files changed, 15 insertions(+), 110 deletions(-) (limited to 'src/lib') diff --git a/src/lib/dcp_video_frame.cc b/src/lib/dcp_video_frame.cc index d8af3462d..96c40358a 100644 --- a/src/lib/dcp_video_frame.cc +++ b/src/lib/dcp_video_frame.cc @@ -55,10 +55,6 @@ #include "image.h" #include "log.h" -#ifdef DEBUG_HASH -#include -#endif - using namespace std; using namespace boost; @@ -255,12 +251,6 @@ DCPVideoFrame::encode_locally () /* Set event manager to null (openjpeg 1.3 bug) */ _cinfo->event_mgr = 0; -#ifdef DEBUG_HASH - md5_data ("J2K in X frame " + lexical_cast (_frame), _image->comps[0].data, size * sizeof (int)); - md5_data ("J2K in Y frame " + lexical_cast (_frame), _image->comps[1].data, size * sizeof (int)); - md5_data ("J2K in Z frame " + lexical_cast (_frame), _image->comps[2].data, size * sizeof (int)); -#endif - /* Setup the encoder parameters using the current image and user parameters */ opj_setup_encoder (_cinfo, _parameters, _image); @@ -271,10 +261,6 @@ DCPVideoFrame::encode_locally () throw EncodeError ("jpeg2000 encoding failed"); } -#ifdef DEBUG_HASH - md5_data ("J2K out frame " + lexical_cast (_frame), _cio->buffer, cio_tell (_cio)); -#endif - { stringstream s; s << "Finished locally-encoded frame " << _frame; @@ -300,10 +286,6 @@ DCPVideoFrame::encode_remotely (ServerDescription const * serv) socket.connect (*endpoint_iterator, 30); -#ifdef DEBUG_HASH - _input->hash ("Input for remote encoding (before sending)"); -#endif - stringstream s; s << "encode " << _input->size().width << " " << _input->size().height << " " @@ -335,10 +317,6 @@ DCPVideoFrame::encode_remotely (ServerDescription const * serv) /* now read the rest */ socket.read_definite_and_consume (e->data(), e->size(), 30); -#ifdef DEBUG_HASH - e->hash ("Encoded image (after receiving)"); -#endif - { stringstream s; s << "Finished remotely-encoded frame " << _frame; @@ -382,14 +360,6 @@ EncodedData::send (shared_ptr socket) socket->write (_data, _size, 30); } -#ifdef DEBUG_HASH -void -EncodedData::hash (string n) const -{ - md5_data (n, _data, _size); -} -#endif - /** @param s Size of data in bytes */ RemotelyEncodedData::RemotelyEncodedData (int s) : EncodedData (new uint8_t[s], s) diff --git a/src/lib/dcp_video_frame.h b/src/lib/dcp_video_frame.h index da4e0c301..72f885e45 100644 --- a/src/lib/dcp_video_frame.h +++ b/src/lib/dcp_video_frame.h @@ -51,10 +51,6 @@ public: void send (boost::shared_ptr socket); void write (boost::shared_ptr, int); -#ifdef DEBUG_HASH - void hash (std::string) const; -#endif - /** @return data */ uint8_t* data () const { return _data; diff --git a/src/lib/image.cc b/src/lib/image.cc index f16bb9f77..89536da33 100644 --- a/src/lib/image.cc +++ b/src/lib/image.cc @@ -27,6 +27,7 @@ #include #include #include +#include extern "C" { #include #include @@ -39,10 +40,6 @@ extern "C" { #include "exceptions.h" #include "scaler.h" -#ifdef DEBUG_HASH -#include -#endif - using namespace std; using namespace boost; @@ -85,33 +82,6 @@ Image::components () const return 0; } -#ifdef DEBUG_HASH -/** Write a MD5 hash of the image's data to stdout. - * @param n Title to give the output. - */ -void -Image::hash (string n) const -{ - MHASH ht = mhash_init (MHASH_MD5); - if (ht == MHASH_FAILED) { - throw EncodeError ("could not create hash thread"); - } - - for (int i = 0; i < components(); ++i) { - mhash (ht, data()[i], line_size()[i] * lines(i)); - } - - uint8_t hash[16]; - mhash_deinit (ht, hash); - - printf ("%s: ", n.c_str ()); - for (int i = 0; i < int (mhash_get_block_size (MHASH_MD5)); ++i) { - printf ("%.2x", hash[i]); - } - printf ("\n"); -} -#endif - /** Scale this image to a given size and convert it to RGB. * @param out_size Output image size in pixels. * @param scaler Scaler to use. diff --git a/src/lib/image.h b/src/lib/image.h index 97ab1d5ff..0161d2b01 100644 --- a/src/lib/image.h +++ b/src/lib/image.h @@ -68,10 +68,6 @@ public: boost::shared_ptr scale_and_convert_to_rgb (Size, int, Scaler const *) const; boost::shared_ptr post_process (std::string) const; -#ifdef DEBUG_HASH - void hash (std::string) const; -#endif - void make_black (); PixelFormat pixel_format () const { diff --git a/src/lib/server.cc b/src/lib/server.cc index 8ca426049..f8c4425d9 100644 --- a/src/lib/server.cc +++ b/src/lib/server.cc @@ -124,17 +124,9 @@ Server::process (shared_ptr socket) socket->read_definite_and_consume (image->data()[i], image->line_size()[i] * image->lines(i), 30); } -#ifdef DEBUG_HASH - image->hash ("Image for encoding (as received by server)"); -#endif - DCPVideoFrame dcp_video_frame (image, out_size, padding, scaler, frame, frames_per_second, post_process, colour_lut_index, j2k_bandwidth, _log); shared_ptr encoded = dcp_video_frame.encode_locally (); encoded->send (socket); - -#ifdef DEBUG_HASH - encoded->hash ("Encoded image (as made by server and as sent back)"); -#endif return frame; } diff --git a/src/lib/util.cc b/src/lib/util.cc index 73222083a..c779268e2 100644 --- a/src/lib/util.cc +++ b/src/lib/util.cc @@ -40,6 +40,7 @@ #include #include #include +#include extern "C" { #include #include @@ -61,10 +62,6 @@ extern "C" { #include "player_manager.h" #endif -#ifdef DEBUG_HASH -#include -#endif - using namespace std; using namespace boost; @@ -347,9 +344,8 @@ split_at_spaces_considering_quotes (string s) return out; } -#ifdef DEBUG_HASH -void -md5_data (string title, void const * data, int size) +string +md5_hash (void const * data, int size) { MHASH ht = mhash_init (MHASH_MD5); if (ht == MHASH_FAILED) { @@ -360,14 +356,16 @@ md5_data (string title, void const * data, int size) uint8_t hash[16]; mhash_deinit (ht, hash); - - printf ("%s [%d]: ", title.c_str (), size); - for (int i = 0; i < int (mhash_get_block_size (MHASH_MD5)); ++i) { - printf ("%.2x", hash[i]); + + int const N = mhash_get_block_size (MHASH_MD5); + stringstream s; + s << hex << setfill('0') << setw(2); + for (int i = 0; i < N; ++i) { + s << ((int) hash[i]); } - printf ("\n"); + + return s.str (); } -#endif /** @param file File name. * @return MD5 digest of file's contents. diff --git a/src/lib/util.h b/src/lib/util.h index 63d492e60..03d04b852 100644 --- a/src/lib/util.h +++ b/src/lib/util.h @@ -52,9 +52,7 @@ enum ContentType { VIDEO }; -#ifdef DEBUG_HASH -extern void md5_data (std::string, void const *, int); -#endif +extern std::string md5_hash (void const *, int); /** @class Size * @brief Representation of the size of something */ diff --git a/src/lib/wscript b/src/lib/wscript index 71a2b23f4..26740a7e9 100644 --- a/src/lib/wscript +++ b/src/lib/wscript @@ -1,17 +1,13 @@ def configure(conf): - if conf.options.debug_hash: - conf.env.append_value('CXXFLAGS', '-DDEBUG_HASH') - conf.check_cc(msg = 'Checking for library libmhash', function_name = 'mhash_init', header_name = 'mhash.h', lib = 'mhash', uselib_store = 'MHASH') + conf.check_cc(msg = 'Checking for library libmhash', function_name = 'mhash_init', header_name = 'mhash.h', lib = 'mhash', uselib_store = 'MHASH') def build(bld): obj = bld(features = 'cxx cxxshlib') obj.name = 'libdvdomatic' obj.export_includes = ['.'] - obj.uselib = 'AVCODEC AVUTIL AVFORMAT AVFILTER SWSCALE SWRESAMPLE SNDFILE BOOST_FILESYSTEM BOOST_THREAD OPENJPEG POSTPROC TIFF SIGC++ MAGICK SSH DCP GLIB' + obj.uselib = 'AVCODEC AVUTIL AVFORMAT AVFILTER SWSCALE SWRESAMPLE SNDFILE BOOST_FILESYSTEM BOOST_THREAD OPENJPEG POSTPROC TIFF SIGC++ MAGICK SSH DCP GLIB MHASH' if bld.env.TARGET_WINDOWS: obj.uselib += ' WINSOCK2' - if bld.env.DEBUG_HASH: - obj.uselib += ' MHASH' obj.source = """ ab_transcode_job.cc ab_transcoder.cc diff --git a/src/tools/servomatictest.cc b/src/tools/servomatictest.cc index 0f37e73a5..d6804c981 100644 --- a/src/tools/servomatictest.cc +++ b/src/tools/servomatictest.cc @@ -47,12 +47,8 @@ process_video (shared_ptr image, int frame) shared_ptr local (new DCPVideoFrame (image, Size (1024, 1024), 0, Scaler::from_id ("bicubic"), frame, 24, "", 0, 250000000, &log_)); shared_ptr remote (new DCPVideoFrame (image, Size (1024, 1024), 0, Scaler::from_id ("bicubic"), frame, 24, "", 0, 250000000, &log_)); -#if defined(DEBUG_HASH) - cout << "Frame " << frame << ":\n"; -#else cout << "Frame " << frame << ": "; cout.flush (); -#endif shared_ptr local_encoded = local->encode_locally (); shared_ptr remote_encoded; @@ -64,11 +60,6 @@ process_video (shared_ptr image, int frame) remote_error = e.what (); } -#if defined(DEBUG_HASH) - cout << "Frame " << frame << ": "; - cout.flush (); -#endif - if (!remote_error.empty ()) { cout << "\033[0;31mnetwork problem: " << remote_error << "\033[0m\n"; return; diff --git a/wscript b/wscript index 71a89dfd3..69d68a35c 100644 --- a/wscript +++ b/wscript @@ -9,7 +9,6 @@ def options(opt): opt.load('compiler_cxx') opt.load('winres') - opt.add_option('--debug-hash', action='store_true', default = False, help = 'print hashes of data at various points') opt.add_option('--enable-debug', action='store_true', default = False, help = 'build with debugging information and without optimisation') opt.add_option('--disable-gui', action='store_true', default = False, help = 'disable building of GUI tools') opt.add_option('--disable-player', action='store_true', default = False, help = 'disable building of the player components') @@ -37,7 +36,6 @@ def configure(conf): boost_lib_suffix = '' boost_thread = 'boost_thread' - conf.env.DEBUG_HASH = conf.options.debug_hash conf.env.TARGET_WINDOWS = conf.options.target_windows conf.env.DISABLE_GUI = conf.options.disable_gui conf.env.DISABLE_PLAYER = conf.options.disable_player -- cgit v1.2.3 From 8b3f7c38278952dc97feba7d51ef39775608689b Mon Sep 17 00:00:00 2001 From: Carl Hetherington Date: Tue, 25 Sep 2012 00:27:14 +0100 Subject: Use openssl for all MD5-ing. --- src/lib/util.cc | 23 ++++++++--------------- src/lib/wscript | 5 +---- src/wscript | 1 - 3 files changed, 9 insertions(+), 20 deletions(-) (limited to 'src/lib') diff --git a/src/lib/util.cc b/src/lib/util.cc index c779268e2..935566440 100644 --- a/src/lib/util.cc +++ b/src/lib/util.cc @@ -40,7 +40,6 @@ #include #include #include -#include extern "C" { #include #include @@ -345,23 +344,17 @@ split_at_spaces_considering_quotes (string s) } string -md5_hash (void const * data, int size) +md5_digest (void const * data, int size) { - MHASH ht = mhash_init (MHASH_MD5); - if (ht == MHASH_FAILED) { - throw EncodeError ("could not create hash thread"); - } - - mhash (ht, data, size); + MD5_CTX md5_context; + MD5_Init (&md5_context); + MD5_Update (&md5_context, data, size); + unsigned char digest[MD5_DIGEST_LENGTH]; + MD5_Final (digest, &md5_context); - uint8_t hash[16]; - mhash_deinit (ht, hash); - - int const N = mhash_get_block_size (MHASH_MD5); stringstream s; - s << hex << setfill('0') << setw(2); - for (int i = 0; i < N; ++i) { - s << ((int) hash[i]); + for (int i = 0; i < MD5_DIGEST_LENGTH; ++i) { + s << hex << setfill('0') << setw(2) << ((int) digest[i]); } return s.str (); diff --git a/src/lib/wscript b/src/lib/wscript index 26740a7e9..803ffd9ee 100644 --- a/src/lib/wscript +++ b/src/lib/wscript @@ -1,11 +1,8 @@ -def configure(conf): - conf.check_cc(msg = 'Checking for library libmhash', function_name = 'mhash_init', header_name = 'mhash.h', lib = 'mhash', uselib_store = 'MHASH') - def build(bld): obj = bld(features = 'cxx cxxshlib') obj.name = 'libdvdomatic' obj.export_includes = ['.'] - obj.uselib = 'AVCODEC AVUTIL AVFORMAT AVFILTER SWSCALE SWRESAMPLE SNDFILE BOOST_FILESYSTEM BOOST_THREAD OPENJPEG POSTPROC TIFF SIGC++ MAGICK SSH DCP GLIB MHASH' + obj.uselib = 'AVCODEC AVUTIL AVFORMAT AVFILTER SWSCALE SWRESAMPLE SNDFILE BOOST_FILESYSTEM BOOST_THREAD OPENJPEG POSTPROC TIFF SIGC++ MAGICK SSH DCP GLIB' if bld.env.TARGET_WINDOWS: obj.uselib += ' WINSOCK2' obj.source = """ diff --git a/src/wscript b/src/wscript index 2ebeba210..3f17b3e6c 100644 --- a/src/wscript +++ b/src/wscript @@ -1,5 +1,4 @@ def configure(conf): - conf.recurse('lib') if not conf.env.DISABLE_GUI: conf.recurse('wx') -- cgit v1.2.3 From 82af50304f55a961cba6afefbfa7edd5440bfcc4 Mon Sep 17 00:00:00 2001 From: Carl Hetherington Date: Tue, 25 Sep 2012 01:20:58 +0100 Subject: Basic J2K hash checking. --- src/lib/check_hashes_job.cc | 79 +++++++++++++++++++++++++++++++++++++++++++++ src/lib/check_hashes_job.h | 33 +++++++++++++++++++ src/lib/dcp_video_frame.cc | 11 ++++++- src/lib/film.cc | 4 ++- src/lib/transcode_job.cc | 1 - src/lib/util.h | 3 +- src/lib/wscript | 1 + 7 files changed, 127 insertions(+), 5 deletions(-) create mode 100644 src/lib/check_hashes_job.cc create mode 100644 src/lib/check_hashes_job.h (limited to 'src/lib') diff --git a/src/lib/check_hashes_job.cc b/src/lib/check_hashes_job.cc new file mode 100644 index 000000000..87eb40d14 --- /dev/null +++ b/src/lib/check_hashes_job.cc @@ -0,0 +1,79 @@ +/* + Copyright (C) 2012 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 + 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 +#include +#include +#include "check_hashes_job.h" +#include "film_state.h" +#include "options.h" +#include "log.h" + +using namespace std; +using namespace boost; + +CheckHashesJob::CheckHashesJob (shared_ptr s, shared_ptr o, Log* l) + : Job (s, o, l) + , _bad (0) +{ + +} + +string +CheckHashesJob::name () const +{ + stringstream s; + s << "Check hashes of " << _fs->name; + return s.str (); +} + +void +CheckHashesJob::run () +{ + _bad = 0; + + for (int i = 0; i < _fs->length; ++i) { + string const j2k_file = _opt->frame_out_path (i, false); + string const hash_file = j2k_file + ".md5"; + + ifstream ref (hash_file.c_str ()); + string hash; + ref >> hash; + + if (hash != md5_digest (j2k_file)) { + _log->log ("Frame " + lexical_cast (i) + " has wrong hash; deleting."); + filesystem::remove (j2k_file); + filesystem::remove (hash_file); + ++_bad; + } + + set_progress (float (i) / _fs->length); + } + + set_progress (1); + set_state (FINISHED_OK); +} + +string +CheckHashesJob::status () const +{ + stringstream s; + s << Job::status () << "; " << _bad << " bad frames found"; + return s.str (); +} diff --git a/src/lib/check_hashes_job.h b/src/lib/check_hashes_job.h new file mode 100644 index 000000000..b59cf031b --- /dev/null +++ b/src/lib/check_hashes_job.h @@ -0,0 +1,33 @@ +/* + Copyright (C) 2012 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 + 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 "job.h" + +class CheckHashesJob : public Job +{ +public: + CheckHashesJob (boost::shared_ptr s, boost::shared_ptr o, Log* l); + + std::string name () const; + void run (); + std::string status () const; + +private: + int _bad; +}; diff --git a/src/lib/dcp_video_frame.cc b/src/lib/dcp_video_frame.cc index 96c40358a..da7133c4b 100644 --- a/src/lib/dcp_video_frame.cc +++ b/src/lib/dcp_video_frame.cc @@ -36,6 +36,7 @@ #include #include #include +#include #include #include #include @@ -344,8 +345,16 @@ EncodedData::write (shared_ptr opt, int frame) fwrite (_data, 1, _size, f); fclose (f); + string const real_j2k = opt->frame_out_path (frame, false); + /* Rename the file from foo.j2c.tmp to foo.j2c now that it is complete */ - filesystem::rename (tmp_j2k, opt->frame_out_path (frame, false)); + filesystem::rename (tmp_j2k, real_j2k); + + /* Write a file containing the hash */ + string const hash = real_j2k + ".md5"; + ofstream h (hash.c_str()); + h << md5_digest (_data, _size) << "\n"; + h.close (); } /** Send this data to a socket. diff --git a/src/lib/film.cc b/src/lib/film.cc index d1334130e..583a15e19 100644 --- a/src/lib/film.cc +++ b/src/lib/film.cc @@ -48,6 +48,7 @@ #include "scaler.h" #include "decoder_factory.h" #include "config.h" +#include "check_hashes_job.h" using namespace std; using namespace boost; @@ -544,7 +545,8 @@ Film::make_dcp (bool transcode, int freq) JobManager::instance()->add (shared_ptr (new TranscodeJob (fs, o, log ()))); } } - + + JobManager::instance()->add (shared_ptr (new CheckHashesJob (fs, o, log ()))); JobManager::instance()->add (shared_ptr (new MakeDCPJob (fs, o, log ()))); } diff --git a/src/lib/transcode_job.cc b/src/lib/transcode_job.cc index c91058973..2de6e90ca 100644 --- a/src/lib/transcode_job.cc +++ b/src/lib/transcode_job.cc @@ -78,7 +78,6 @@ TranscodeJob::run () _log->log (s.str ()); throw; - } } diff --git a/src/lib/util.h b/src/lib/util.h index 03d04b852..bc5a00fc4 100644 --- a/src/lib/util.h +++ b/src/lib/util.h @@ -46,14 +46,13 @@ extern double seconds (struct timeval); extern void dvdomatic_setup (); extern std::vector split_at_spaces_considering_quotes (std::string); extern std::string md5_digest (std::string); +extern std::string md5_digest (void const *, int); enum ContentType { STILL, VIDEO }; -extern std::string md5_hash (void const *, int); - /** @class Size * @brief Representation of the size of something */ struct Size diff --git a/src/lib/wscript b/src/lib/wscript index 803ffd9ee..c809226ce 100644 --- a/src/lib/wscript +++ b/src/lib/wscript @@ -8,6 +8,7 @@ def build(bld): obj.source = """ ab_transcode_job.cc ab_transcoder.cc + check_hashes_job.cc config.cc copy_from_dvd_job.cc cross.cc -- cgit v1.2.3 From 922361469072474da4294a90f1436cd0117cb90f Mon Sep 17 00:00:00 2001 From: Carl Hetherington Date: Tue, 25 Sep 2012 01:36:53 +0100 Subject: Re-transcode and re-check J2Ks after a bad one is found. --- src/lib/check_hashes_job.cc | 27 ++++++++++++++++++++++++++- src/lib/job.h | 3 ++- src/lib/job_manager.cc | 12 ++++++++++-- src/lib/job_manager.h | 1 + src/lib/transcode_job.cc | 2 +- 5 files changed, 40 insertions(+), 5 deletions(-) (limited to 'src/lib') diff --git a/src/lib/check_hashes_job.cc b/src/lib/check_hashes_job.cc index 87eb40d14..5a927f752 100644 --- a/src/lib/check_hashes_job.cc +++ b/src/lib/check_hashes_job.cc @@ -24,6 +24,9 @@ #include "film_state.h" #include "options.h" #include "log.h" +#include "job_manager.h" +#include "ab_transcode_job.h" +#include "transcode_job.h" using namespace std; using namespace boost; @@ -66,6 +69,19 @@ CheckHashesJob::run () set_progress (float (i) / _fs->length); } + if (_bad) { + shared_ptr tc; + + if (_fs->dcp_ab) { + tc.reset (new ABTranscodeJob (_fs, _opt, _log)); + } else { + tc.reset (new TranscodeJob (_fs, _opt, _log)); + } + + JobManager::instance()->add_after (shared_from_this(), tc); + JobManager::instance()->add_after (tc, shared_ptr (new CheckHashesJob (_fs, _opt, _log))); + } + set_progress (1); set_state (FINISHED_OK); } @@ -74,6 +90,15 @@ string CheckHashesJob::status () const { stringstream s; - s << Job::status () << "; " << _bad << " bad frames found"; + s << Job::status (); + if (overall_progress() > 0) { + if (_bad == 0) { + s << "; no bad frames found"; + } else if (_bad == 1) { + s << "; 1 bad frame found"; + } else { + s << "; " << _bad << " bad frames found"; + } + } return s.str (); } diff --git a/src/lib/job.h b/src/lib/job.h index fee887b42..b39130479 100644 --- a/src/lib/job.h +++ b/src/lib/job.h @@ -26,6 +26,7 @@ #include #include +#include #include class Log; @@ -35,7 +36,7 @@ class Options; /** @class Job * @brief A parent class to represent long-running tasks which are run in their own thread. */ -class Job +class Job : public boost::enable_shared_from_this { public: Job (boost::shared_ptr s, boost::shared_ptr o, Log* l); diff --git a/src/lib/job_manager.cc b/src/lib/job_manager.cc index 93fdbd27a..a166b5924 100644 --- a/src/lib/job_manager.cc +++ b/src/lib/job_manager.cc @@ -41,15 +41,23 @@ void JobManager::add (shared_ptr j) { boost::mutex::scoped_lock lm (_mutex); - _jobs.push_back (j); } +void +JobManager::add_after (shared_ptr after, shared_ptr j) +{ + boost::mutex::scoped_lock lm (_mutex); + list >::iterator i = find (_jobs.begin(), _jobs.end(), after); + assert (i != _jobs.end ()); + ++i; + _jobs.insert (i, j); +} + list > JobManager::get () const { boost::mutex::scoped_lock lm (_mutex); - return _jobs; } diff --git a/src/lib/job_manager.h b/src/lib/job_manager.h index f2f5e0057..d1d33cfc2 100644 --- a/src/lib/job_manager.h +++ b/src/lib/job_manager.h @@ -38,6 +38,7 @@ class JobManager public: void add (boost::shared_ptr); + void add_after (boost::shared_ptr after, boost::shared_ptr j); std::list > get () const; bool work_to_do () const; diff --git a/src/lib/transcode_job.cc b/src/lib/transcode_job.cc index 2de6e90ca..9113593f0 100644 --- a/src/lib/transcode_job.cc +++ b/src/lib/transcode_job.cc @@ -89,7 +89,7 @@ TranscodeJob::status () const } if (_encoder->skipping () && !finished ()) { - return "skipping frames already encoded"; + return "skipping already-encoded frames"; } -- cgit v1.2.3 From 493fa08920fbed2d8cda546d86a2b5e68083ed58 Mon Sep 17 00:00:00 2001 From: Carl Hetherington Date: Tue, 25 Sep 2012 01:39:16 +0100 Subject: Remove unnecessary include. --- src/lib/image.cc | 1 - 1 file changed, 1 deletion(-) (limited to 'src/lib') diff --git a/src/lib/image.cc b/src/lib/image.cc index 89536da33..620e71aa7 100644 --- a/src/lib/image.cc +++ b/src/lib/image.cc @@ -27,7 +27,6 @@ #include #include #include -#include extern "C" { #include #include -- cgit v1.2.3 From 034e63ec04e416f4944069adfb0c01ca163e0cc0 Mon Sep 17 00:00:00 2001 From: Carl Hetherington Date: Thu, 27 Sep 2012 10:29:38 +0100 Subject: Try to fix problems with upper-case still-image extensions. --- src/lib/film_state.cc | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) (limited to 'src/lib') diff --git a/src/lib/film_state.cc b/src/lib/film_state.cc index 739eeac3c..e472434ce 100644 --- a/src/lib/film_state.cc +++ b/src/lib/film_state.cc @@ -251,10 +251,13 @@ ContentType FilmState::content_type () const { #if BOOST_FILESYSTEM_VERSION == 3 - string const ext = filesystem::path(content).extension().string(); + string ext = filesystem::path(content).extension().string(); #else - string const ext = filesystem::path(content).extension(); + string ext = filesystem::path(content).extension(); #endif + + transform (ext.begin(), ext.end(), ext.begin(), ::tolower); + if (ext == ".tif" || ext == ".tiff" || ext == ".jpg" || ext == ".jpeg" || ext == ".png") { return STILL; } -- cgit v1.2.3 From ead1fe52045b83a1a37479bc08f51a4c626e0f8d Mon Sep 17 00:00:00 2001 From: Carl Hetherington Date: Fri, 28 Sep 2012 11:35:00 +0100 Subject: Fix probably-incorrect parameter passing, not spotted by compiler due to use of void. --- src/lib/decoder.cc | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) (limited to 'src/lib') diff --git a/src/lib/decoder.cc b/src/lib/decoder.cc index 2f02147e3..973582ca4 100644 --- a/src/lib/decoder.cc +++ b/src/lib/decoder.cc @@ -464,12 +464,18 @@ Decoder::setup_video_filters () << sample_aspect_ratio_denominator(); int r; + if ((r = avfilter_graph_create_filter (&_buffer_src_context, buffer_src, "in", a.str().c_str(), 0, graph)) < 0) { throw DecodeError ("could not create buffer source"); } - enum PixelFormat pixel_formats[] = { pixel_format(), PIX_FMT_NONE }; - if (avfilter_graph_create_filter (&_buffer_sink_context, buffer_sink, "out", 0, pixel_formats, graph) < 0) { + AVBufferSinkParams* sink_params = av_buffersink_params_alloc (); + PixelFormat* pixel_fmts = new PixelFormat[2]; + pixel_fmts[0] = pixel_format (); + pixel_fmts[1] = PIX_FMT_NONE; + sink_params->pixel_fmts = pixel_fmts; + + if (avfilter_graph_create_filter (&_buffer_sink_context, buffer_sink, "out", 0, sink_params, graph) < 0) { throw DecodeError ("could not create buffer sink."); } -- cgit v1.2.3