+2013-02-21 Carl Hetherington <cth@carlh.net>
+
+ * Version 0.73 released.
+
+2013-02-20 Carl Hetherington <cth@carlh.net>
+
+ * Version 0.73beta9 released.
+
+2013-02-18 Carl Hetherington <cth@carlh.net>
+
+ * Version 0.73beta8 released.
+
+2013-02-18 Carl Hetherington <cth@carlh.net>
+
+ * Version 0.73beta7 released.
+
+2013-02-17 Carl Hetherington <cth@carlh.net>
+
+ * Version 0.73beta6 released.
+
+2013-02-17 Carl Hetherington <cth@carlh.net>
+
+ * Version 0.73beta3 released.
+
+2013-02-16 Carl Hetherington <cth@carlh.net>
+
+ * Version 0.73beta2 released.
+
+2013-02-16 Carl Hetherington <cth@carlh.net>
+
+ * Version 0.73beta1 released.
+
2013-02-15 Carl Hetherington <cth@carlh.net>
* Fix non-recognition of BMP for still images (#55),
+dvdomatic (0.73-1) UNRELEASED; urgency=low
+
+ * New upstream release.
+
+ -- Carl Hetherington <carl@houllier.lan> Thu, 21 Feb 2013 00:43:40 +0000
+
+dvdomatic (0.73beta9-1) UNRELEASED; urgency=low
+
+ * New upstream release.
+
+ -- Carl Hetherington <carl@houllier.lan> Wed, 20 Feb 2013 23:40:24 +0000
+
+dvdomatic (0.73beta8-1) UNRELEASED; urgency=low
+
+ * New upstream release.
+
+ -- Carl Hetherington <carl@houllier.lan> Mon, 18 Feb 2013 22:35:51 +0000
+
+dvdomatic (0.73beta7-1) UNRELEASED; urgency=low
+
+ * New upstream release.
+
+ -- Carl Hetherington <carl@houllier.lan> Mon, 18 Feb 2013 20:38:51 +0000
+
+dvdomatic (0.73beta6-1) UNRELEASED; urgency=low
+
+ * New upstream release.
+
+ -- Carl Hetherington <carl@houllier.lan> Sun, 17 Feb 2013 23:05:56 +0000
+
+dvdomatic (0.73beta3-1) UNRELEASED; urgency=low
+
+ * New upstream release.
+
+ -- Carl Hetherington <carl@houllier.lan> Sun, 17 Feb 2013 23:05:05 +0000
+
+dvdomatic (0.73beta2-1) UNRELEASED; urgency=low
+
+ * New upstream release.
+
+ -- Carl Hetherington <carl@houllier.lan> Sat, 16 Feb 2013 22:42:32 +0000
+
+dvdomatic (0.73beta1-1) UNRELEASED; urgency=low
+
+ * New upstream release.
+
+ -- Carl Hetherington <carl@houllier.lan> Sat, 16 Feb 2013 21:19:24 +0000
+
dvdomatic (0.72-1) UNRELEASED; urgency=low
* New upstream release.
accurate (it may be slightly slower or faster than it should be, for
example). This player is really only intended for brief inspection of
content; if you need to check it more thoroughly, use another player
-such as Totem, mplayer or VLC.
+such as <ulink url="http://projects.gnome.org/totem/index.html">Totem</ulink>, <ulink url="http://www.mplayerhq.hu/design7/news.html">mplayer</ulink> or <ulink url="http://www.videolan.org/vlc/index.html">VLC</ulink>.
</para>
</section>
open by clicking on the <guilabel>Details</guilabel> button.
</para>
+<para>
+If the DCP name is long, it may not all be visible. You can see the
+full name by hovering the mouse pointer over the partial name.
+</para>
+
<para>
The <guilabel>Trust content's header</guilabel> button starts off
checked, and this means that DVD-o-matic will use the content's header
The remaining options can often be left alone, but may sometimes be
useful. The ‘crop’ settings can be used to crop your
content, which can be used to remove black borders from round the
-edges of DVD images, for example. The <guilabel>L</guilabel>,
-<guilabel>R</guilabel>, <guilabel>T</guilabel> and
-<guilabel>B</guilabel> settings correspond to the left, right, top and
-bottom of the image respectively. The specified number of pixels will
+edges of DVD images, for example. The specified number of pixels will
be trimmed from each edge, and the content image in the right of the
-window will be updated to show the cropping in action.
+window will be updated to show the effect of the crop.
</para>
<para>
<!-- XXX: link -->
</para>
+<para>
+The ‘colour look-up table’ specifies the colour space that
+your input content will be expected to be in. If in doubt, leave it
+set to ‘sRGB’.
+</para>
+
+<para>
+Finally, the ‘JPEG2000 bandwidth’ setting changes how big the final
+image files used within the DCP will be. Larger numbers will give
+better quality, but correspondingly larger DCPs. The bandwidth can be
+between 50 and 250 megabits per second (MBps).
+</para>
+
</section>
<section>
DCP</guilabel> from the <guilabel>Jobs</guilabel> menu. DVD-o-matic
will encode your DCP. This may take some time (many hours in some
cases). While the job is in progress, DVD-o-matic will update you on
-how it is getting on with the progress bar in the bottom right hand
-corner of its window, as shown in <xref linkend="fig-making-dcp"/>.
+how it is getting on with the progress bar in the bottom of its window, as shown in <xref linkend="fig-making-dcp"/>.
</para>
<figure id="fig-making-dcp">
</section>
-<section>
-<title>Colour look-up table</title>
-
-<para>
-This specifies the colour space that your input content will be
-expected to be in. If in doubt, leave it set to ‘sRGB’.
-</para>
-
-</section>
-
<section>
<title>A/B options</title>
</mediaobject>
</figure>
-<para>
-As it stands, these filters are somewhat disorganised! Work is
-ongoing to test them with various content and choose a selection which
-work well for cinema applications.
-</para>
-
-<para>
-If you want to examine them yourself, you may find the A/B option (see
-<xref linkend="sec-ab"/>) useful.
-</para>
-
<para>
After changing the filters setup, you will need to regenerate the DCP
to see the effect on the cinema screen. The preview in DVD-o-matic
shared_ptr<Socket> socket (new Socket);
- socket->connect (*endpoint_iterator, 30);
+ socket->connect (*endpoint_iterator);
stringstream s;
s << "encode please\n"
_input->lines(0), _input->lines(1), _input->lines(2),
_input->line_size()[0], _input->line_size()[1], _input->line_size()[2]
));
-
- socket->write ((uint8_t *) s.str().c_str(), s.str().length() + 1, 30);
+
+ socket->write (s.str().length() + 1);
+ socket->write ((uint8_t *) s.str().c_str(), s.str().length() + 1);
_input->write_to_socket (socket);
if (_subtitle) {
_subtitle->image()->write_to_socket (socket);
}
- char buffer[32];
- socket->read_indefinite ((uint8_t *) buffer, sizeof (buffer), 30);
- socket->consume (strlen (buffer) + 1);
- shared_ptr<EncodedData> e (new RemotelyEncodedData (atoi (buffer)));
-
- /* now read the rest */
- socket->read_definite_and_consume (e->data(), e->size(), 30);
+ shared_ptr<EncodedData> e (new RemotelyEncodedData (socket->read_uint32 ()));
+ socket->read (e->data(), e->size());
_log->log (String::compose ("Finished remotely-encoded frame %1", _frame));
void
EncodedData::send (shared_ptr<Socket> socket)
{
- stringstream s;
- s << _size;
- socket->write ((uint8_t *) s.str().c_str(), s.str().length() + 1, 30);
- socket->write (_data, _size, 30);
+ socket->write (_size);
+ socket->write (_data, _size);
}
LocallyEncodedData::LocallyEncodedData (uint8_t* d, int s)
}
out->set_frames (frames);
- _writer->write (out);
+ write_audio (out);
}
swr_free (&_swr_context);
}
#endif
- if (_film->audio_channels() == 1) {
- /* We need to switch things around so that the mono channel is on
- the centre channel of a 5.1 set (with other channels silent).
- */
-
- shared_ptr<AudioBuffers> b (new AudioBuffers (6, data->frames ()));
- b->make_silent (libdcp::LEFT);
- b->make_silent (libdcp::RIGHT);
- memcpy (b->data()[libdcp::CENTRE], data->data()[0], data->frames() * sizeof(float));
- b->make_silent (libdcp::LFE);
- b->make_silent (libdcp::LS);
- b->make_silent (libdcp::RS);
-
- data = b;
- }
-
- _writer->write (data);
+ write_audio (data);
}
void
_condition.notify_all ();
}
}
+
+void
+Encoder::write_audio (shared_ptr<const AudioBuffers> data)
+{
+ if (_film->audio_channels() == 1) {
+ /* We need to switch things around so that the mono channel is on
+ the centre channel of a 5.1 set (with other channels silent).
+ */
+
+ shared_ptr<AudioBuffers> b (new AudioBuffers (6, data->frames ()));
+ b->make_silent (libdcp::LEFT);
+ b->make_silent (libdcp::RIGHT);
+ memcpy (b->data()[libdcp::CENTRE], data->data()[0], data->frames() * sizeof(float));
+ b->make_silent (libdcp::LFE);
+ b->make_silent (libdcp::LS);
+ b->make_silent (libdcp::RS);
+
+ data = b;
+ }
+
+ _writer->write (data);
+}
void frame_done ();
- void write_audio (boost::shared_ptr<const AudioBuffers> audio);
+ void write_audio (boost::shared_ptr<const AudioBuffers> data);
void encoder_thread (ServerDescription *);
void terminate_threads ();
/* 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 (s->codec->channel_layout == 0) {
s->codec->channel_layout = av_get_default_channel_layout (s->codec->channels);
}
);
assert (_audio_codec_context->channels == _film->audio_channels());
- Audio (deinterleave_audio (_frame->data[0], data_size));
+ Audio (deinterleave_audio (_frame->data, data_size));
}
}
);
assert (_audio_codec_context->channels == _film->audio_channels());
- Audio (deinterleave_audio (_frame->data[0], data_size));
+ Audio (deinterleave_audio (_frame->data, data_size));
}
}
return false;
}
+/** @param data pointer to array of pointers to buffers.
+ * Only the first buffer will be used for non-planar data, otherwise there will be one per channel.
+ */
shared_ptr<AudioBuffers>
-FFmpegDecoder::deinterleave_audio (uint8_t* data, int size)
+FFmpegDecoder::deinterleave_audio (uint8_t** data, int size)
{
assert (_film->audio_channels());
assert (bytes_per_audio_sample());
switch (audio_sample_format()) {
case AV_SAMPLE_FMT_S16:
{
- int16_t* p = reinterpret_cast<int16_t *> (data);
+ int16_t* p = reinterpret_cast<int16_t *> (data[0]);
int sample = 0;
int channel = 0;
for (int i = 0; i < total_samples; ++i) {
case AV_SAMPLE_FMT_S16P:
{
- int16_t* p = reinterpret_cast<int16_t *> (data);
+ int16_t** p = reinterpret_cast<int16_t **> (data);
for (int i = 0; i < _film->audio_channels(); ++i) {
for (int j = 0; j < frames; ++j) {
- audio->data(i)[j] = static_cast<float>(*p++) / (1 << 15);
+ audio->data(i)[j] = static_cast<float>(p[i][j]) / (1 << 15);
}
}
}
case AV_SAMPLE_FMT_S32:
{
- int32_t* p = reinterpret_cast<int32_t *> (data);
+ int32_t* p = reinterpret_cast<int32_t *> (data[0]);
int sample = 0;
int channel = 0;
for (int i = 0; i < total_samples; ++i) {
case AV_SAMPLE_FMT_FLT:
{
- float* p = reinterpret_cast<float*> (data);
+ float* p = reinterpret_cast<float*> (data[0]);
int sample = 0;
int channel = 0;
for (int i = 0; i < total_samples; ++i) {
case AV_SAMPLE_FMT_FLTP:
{
- float* p = reinterpret_cast<float*> (data);
+ float** p = reinterpret_cast<float**> (data);
for (int i = 0; i < _film->audio_channels(); ++i) {
- memcpy (audio->data(i), p, frames * sizeof(float));
- p += frames;
+ memcpy (audio->data(i), p[i], frames * sizeof(float));
}
}
break;
void setup_subtitle ();
void maybe_add_subtitle ();
- boost::shared_ptr<AudioBuffers> deinterleave_audio (uint8_t* data, int size);
+ boost::shared_ptr<AudioBuffers> deinterleave_audio (uint8_t** data, int size);
void film_changed (Film::Property);
return video_state_identifier() + ".mxf";
}
-/** Add suitable Jobs to the JobManager to create a DCP for this Film.
- * @param true to transcode, false to use the WAV and J2K files that are already there.
- */
+/** Add suitable Jobs to the JobManager to create a DCP for this Film */
void
-Film::make_dcp (bool transcode)
+Film::make_dcp ()
{
set_dci_date_today ();
shared_ptr<Job> r;
- if (transcode) {
- if (dcp_ab()) {
- r = JobManager::instance()->add (shared_ptr<Job> (new ABTranscodeJob (shared_from_this(), od)));
- } else {
- r = JobManager::instance()->add (shared_ptr<Job> (new TranscodeJob (shared_from_this(), od)));
- }
+ if (dcp_ab()) {
+ r = JobManager::instance()->add (shared_ptr<Job> (new ABTranscodeJob (shared_from_this(), od)));
+ } else {
+ r = JobManager::instance()->add (shared_ptr<Job> (new TranscodeJob (shared_from_this(), od)));
}
}
void examine_content ();
void send_dcp_to_tms ();
- void make_dcp (bool);
+ void make_dcp ();
/** @return Logger.
* It is safe to call this from any thread.
for (int i = 0; i < components(); ++i) {
uint8_t* p = data()[i];
for (int y = 0; y < lines(i); ++y) {
- socket->read_definite_and_consume (p, line_size()[i], 30);
+ socket->read (p, line_size()[i]);
p += stride()[i];
}
}
for (int i = 0; i < components(); ++i) {
uint8_t* p = data()[i];
for (int y = 0; y < lines(i); ++y) {
- socket->write (p, line_size()[i], 30);
+ socket->write (p, line_size()[i]);
p += stride()[i];
}
}
: Image (p)
, _buffer (b)
{
-
+ _line_size = (int *) av_malloc (4 * sizeof (int));
+ _line_size[0] = _line_size[1] = _line_size[2] = _line_size[3] = 0;
+
+ for (int i = 0; i < components(); ++i) {
+ _line_size[i] = size().width * bytes_per_pixel(i);
+ }
}
FilterBufferImage::~FilterBufferImage ()
{
avfilter_unref_buffer (_buffer);
+ av_free (_line_size);
}
uint8_t **
int *
FilterBufferImage::line_size () const
{
- return _buffer->linesize;
+ return _line_size;
}
int *
FilterBufferImage::stride () const
{
- /* XXX? */
+ /* I've seen images where the _buffer->linesize is larger than the width
+ (by a small amount), suggesting that _buffer->linesize is what we call
+ stride. But I'm not sure.
+ */
return _buffer->linesize;
}
FilterBufferImage& operator= (FilterBufferImage const &);
AVFilterBufferRef* _buffer;
+ int* _line_size;
};
/** @class SimpleImage
#include <iostream>
#include <boost/algorithm/string.hpp>
#include <boost/lexical_cast.hpp>
+#include <boost/scoped_array.hpp>
#include "server.h"
#include "util.h"
#include "scaler.h"
using boost::algorithm::split;
using boost::thread;
using boost::bind;
+using boost::scoped_array;
using libdcp::Size;
/** Create a server description from a string of metadata returned from as_metadata().
int
Server::process (shared_ptr<Socket> socket)
{
- char buffer[512];
- socket->read_indefinite ((uint8_t *) buffer, sizeof (buffer), 30);
- socket->consume (strlen (buffer) + 1);
+ uint32_t length = socket->read_uint32 ();
+ scoped_array<char> buffer (new char[length]);
+ socket->read (reinterpret_cast<uint8_t*> (buffer.get()), length);
- stringstream s (buffer);
+ stringstream s (buffer.get());
multimap<string, string> kv = read_key_value (s);
if (get_required_string (kv, "encode") != "please") {
* Combining these two translations gives these expressions.
*/
- tx.x = target_x_scale * (sub_area.x + (sub_area.width * (1 - subtitle_scale) / 2));
- tx.y = target_y_scale * (sub_area.y + (sub_area.height * (1 - subtitle_scale) / 2));
+ tx.x = rint (target_x_scale * (sub_area.x + (sub_area.width * (1 - subtitle_scale) / 2)));
+ tx.y = rint (target_y_scale * (sub_area.y + (sub_area.height * (1 - subtitle_scale) / 2)));
return tx;
}
return "";
}
-Socket::Socket ()
+Socket::Socket (int timeout)
: _deadline (_io_service)
, _socket (_io_service)
- , _buffer_data (0)
+ , _timeout (timeout)
{
_deadline.expires_at (posix_time::pos_infin);
check ();
_deadline.async_wait (boost::bind (&Socket::check, this));
}
-/** Blocking connect with timeout.
+/** Blocking connect.
* @param endpoint End-point to connect to.
- * @param timeout Time-out in seconds.
*/
void
-Socket::connect (asio::ip::basic_resolver_entry<asio::ip::tcp> const & endpoint, int timeout)
+Socket::connect (asio::ip::basic_resolver_entry<asio::ip::tcp> const & endpoint)
{
- _deadline.expires_from_now (posix_time::seconds (timeout));
+ _deadline.expires_from_now (posix_time::seconds (_timeout));
system::error_code ec = asio::error::would_block;
_socket.async_connect (endpoint, lambda::var(ec) = lambda::_1);
do {
}
}
-/** Blocking write with timeout.
+/** Blocking write.
* @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)
+Socket::write (uint8_t const * data, int size)
{
- _deadline.expires_from_now (posix_time::seconds (timeout));
+ _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");
+ throw NetworkError (ec.message ());
}
}
-/** Blocking read with timeout.
+void
+Socket::write (uint32_t v)
+{
+ v = htonl (v);
+ write (reinterpret_cast<uint8_t*> (&v), 4);
+}
+
+/** Blocking read.
* @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)
+void
+Socket::read (uint8_t* data, int size)
{
- _deadline.expires_from_now (posix_time::seconds (timeout));
+ _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)
- );
+ asio::async_read (_socket, asio::buffer (data, size), lambda::var(ec) = lambda::_1);
do {
_io_service.run_one ();
} while (ec == asio::error::would_block);
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
-Socket::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);
+ throw NetworkError (ec.message ());
}
}
-/** 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
-Socket::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.
- *
- * XXX This method assumes that there is always lots of data to read();
- * if there isn't, it will hang waiting for data that will never arrive.
- */
-void
-Socket::read_indefinite (uint8_t* data, int size, int timeout)
+uint32_t
+Socket::read_uint32 ()
{
- 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);
+ uint32_t v;
+ read (reinterpret_cast<uint8_t *> (&v), 4);
+ return ntohl (v);
}
/** @param other A Rect.
* 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 peek into
- * data being read.
+ * most notably, sync read/write calls with timeouts.
*/
class Socket
{
public:
- Socket ();
+ Socket (int timeout = 30);
/** @return Our underlying socket */
boost::asio::ip::tcp::socket& socket () {
return _socket;
}
- void connect (boost::asio::ip::basic_resolver_entry<boost::asio::ip::tcp> const & endpoint, int timeout);
- void write (uint8_t const * data, int size, int timeout);
+ void connect (boost::asio::ip::basic_resolver_entry<boost::asio::ip::tcp> const & endpoint);
+
+ void write (uint32_t n);
+ void write (uint8_t const * data, int size);
- 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);
+ void read (uint8_t* data, int size);
+ uint32_t read_uint32 ();
private:
void check ();
- int read (uint8_t* data, int size, int timeout);
Socket (Socket const &);
boost::asio::io_service _io_service;
boost::asio::deadline_timer _deadline;
boost::asio::ip::tcp::socket _socket;
- /** a buffer for small reads */
- uint8_t _buffer[1024];
- /** amount of valid data in the buffer */
- int _buffer_data;
+ int _timeout;
};
/** @class AudioBuffers
_picture_asset_writer = _picture_asset->start_write (_first_nonexistant_frame > 0);
- if (_film->audio_channels() > 0) {
+ if (dcp_audio_channels (_film->audio_channels()) > 0) {
_sound_asset.reset (
new libdcp::SoundAsset (
_film->dir (_film->dcp_name()),
"audio.mxf",
DCPFrameRate (_film->frames_per_second()).frames_per_second,
- _film->audio_channels(),
+ dcp_audio_channels (_film->audio_channels()),
dcp_audio_sample_rate (_film->audio_stream()->sample_rate())
)
);
ID_jobs_send_dcp_to_tms,
ID_jobs_show_dcp,
ID_jobs_examine_content,
- ID_jobs_make_dcp_from_existing_transcode,
ID_help_about
};
add_item (jobs_menu, "S&how DCP", ID_jobs_show_dcp, NEEDS_FILM);
jobs_menu->AppendSeparator ();
add_item (jobs_menu, "&Examine content", ID_jobs_examine_content, NEEDS_FILM);
- add_item (jobs_menu, "Make DCP from existing &transcode", ID_jobs_make_dcp_from_existing_transcode, NEEDS_FILM);
wxMenu* help = new wxMenu;
add_item (help, "About", ID_help_about, ALWAYS);
Connect (ID_jobs_send_dcp_to_tms, wxEVT_COMMAND_MENU_SELECTED, wxCommandEventHandler (Frame::jobs_send_dcp_to_tms));
Connect (ID_jobs_show_dcp, wxEVT_COMMAND_MENU_SELECTED, wxCommandEventHandler (Frame::jobs_show_dcp));
Connect (ID_jobs_examine_content, wxEVT_COMMAND_MENU_SELECTED, wxCommandEventHandler (Frame::jobs_examine_content));
- Connect (ID_jobs_make_dcp_from_existing_transcode, wxEVT_COMMAND_MENU_SELECTED, wxCommandEventHandler (Frame::jobs_make_dcp_from_existing_transcode));
Connect (ID_help_about, wxEVT_COMMAND_MENU_SELECTED, wxCommandEventHandler (Frame::help_about));
Connect (wxID_ANY, wxEVT_MENU_OPEN, wxMenuEventHandler (Frame::menu_opened));
film_viewer = new FilmViewer (film, panel);
JobManagerView* job_manager_view = new JobManagerView (panel);
- wxSizer* top_sizer = new wxBoxSizer (wxHORIZONTAL);
- top_sizer->Add (film_editor, 0, wxALL, 6);
- top_sizer->Add (film_viewer, 1, wxEXPAND | wxALL, 6);
+ _top_sizer = new wxBoxSizer (wxHORIZONTAL);
+ _top_sizer->Add (film_editor, 0, wxALL, 6);
+ _top_sizer->Add (film_viewer, 1, wxEXPAND | wxALL, 6);
wxBoxSizer* main_sizer = new wxBoxSizer (wxVERTICAL);
- main_sizer->Add (top_sizer, 2, wxEXPAND | wxALL, 6);
+ main_sizer->Add (_top_sizer, 2, wxEXPAND | wxALL, 6);
main_sizer->Add (job_manager_view, 1, wxEXPAND | wxALL, 6);
panel->SetSizer (main_sizer);
} else {
file_changed ("");
}
-
+
set_film ();
+
+ film_editor->Connect (wxID_ANY, wxEVT_SIZE, wxSizeEventHandler (Frame::film_editor_sized), 0, this);
}
private:
+ void film_editor_sized (wxSizeEvent &)
+ {
+ static bool in_layout = false;
+ if (!in_layout) {
+ in_layout = true;
+ _top_sizer->Layout ();
+ in_layout = false;
+ }
+ }
+
void menu_opened (wxMenuEvent& ev)
{
if (ev.GetMenu() != jobs_menu) {
if (r == wxID_OK) {
if (boost::filesystem::exists (d->get_path())) {
- error_dialog (this, wxString::Format (_("The directory %s already exists"), d->get_path().c_str()));
+ error_dialog (this, wxString::Format (_("The directory %s already exists."), d->get_path().c_str()));
return;
}
void jobs_make_dcp (wxCommandEvent &)
{
- JobWrapper::make_dcp (this, film, true);
- }
-
- void jobs_make_dcp_from_existing_transcode (wxCommandEvent &)
- {
- JobWrapper::make_dcp (this, film, false);
+ JobWrapper::make_dcp (this, film);
}
void jobs_send_dcp_to_tms (wxCommandEvent &)
info.SetWebSite (wxT ("http://carlh.net/software/dvdomatic"));
wxAboutBox (info);
}
+
+ wxSizer* _top_sizer;
};
#if wxMINOR_VERSION == 9
pair<string, string> const f = Filter::ffmpeg_strings (film->filters ());
cout << "Filters: " << f.first << " " << f.second << "\n";
- film->make_dcp (true);
+ film->make_dcp ();
bool should_stop = false;
bool first = true;
#include "scaler.h"
#include "log.h"
#include "decoder_factory.h"
+#include "video_decoder.h"
-using namespace std;
-using namespace boost;
+using std::cout;
+using std::cerr;
+using std::string;
+using std::pair;
+using boost::shared_ptr;
-static Server* server;
-static Log log_ ("servomatictest.log");
+static ServerDescription* server;
+static FileLog log_ ("servomatictest.log");
+static int frame = 0;
void
-process_video (shared_ptr<Image> image, bool, int frame)
+process_video (shared_ptr<Image> image, bool, shared_ptr<Subtitle> sub)
{
- shared_ptr<DCPVideoFrame> local (new DCPVideoFrame (image, Size (1024, 1024), 0, Scaler::from_id ("bicubic"), frame, 24, "", 0, 250000000, &log_));
- shared_ptr<DCPVideoFrame> remote (new DCPVideoFrame (image, Size (1024, 1024), 0, Scaler::from_id ("bicubic"), frame, 24, "", 0, 250000000, &log_));
+ shared_ptr<DCPVideoFrame> local (
+ new DCPVideoFrame (
+ image, sub,
+ libdcp::Size (1024, 1024), 0, 0, 0,
+ Scaler::from_id ("bicubic"), frame, 24, "", 0, 250000000, &log_)
+ );
+
+ shared_ptr<DCPVideoFrame> remote (
+ new DCPVideoFrame (
+ image, sub,
+ libdcp::Size (1024, 1024), 0, 0, 0,
+ Scaler::from_id ("bicubic"), frame, 24, "", 0, 250000000, &log_)
+ );
cout << "Frame " << frame << ": ";
cout.flush ();
+ ++frame;
+
shared_ptr<EncodedData> local_encoded = local->encode_locally ();
shared_ptr<EncodedData> remote_encoded;
dvdomatic_setup ();
- server = new Server (server_host, 1);
- Film film (film_dir, true);
+ server = new ServerDescription (server_host, 1);
+ shared_ptr<Film> film (new Film (film_dir, true));
- shared_ptr<Options> opt (new Options ("fred", "jim", "sheila"));
- opt->out_size = Size (1024, 1024);
- opt->decode_audio = false;
+ DecodeOptions opt;
+ opt.decode_audio = false;
+ opt.decode_subtitles = true;
+ opt.video_sync = true;
- shared_ptr<Decoder> decoder = decoder_factory (film.state_copy(), opt, 0, &log_);
+ Decoders decoders = decoder_factory (film, opt);
try {
- decoder->Video.connect (sigc::ptr_fun (process_video));
- decoder->go ();
+ decoders.video->Video.connect (boost::bind (process_video, _1, _2, _3));
+ bool done = false;
+ while (!done) {
+ done = decoders.video->pass ();
+ }
} catch (std::exception& e) {
cerr << "Error: " << e.what() << "\n";
}
def build(bld):
- for t in ['makedcp', 'servomatic_cli']:
+ for t in ['makedcp', 'servomatic_cli', 'servomatictest']:
obj = bld(features = 'cxx cxxprogram')
obj.uselib = 'BOOST_THREAD OPENJPEG DCP AVFORMAT AVFILTER AVCODEC AVUTIL SWSCALE POSTPROC'
obj.includes = ['..']
_film->Changed.connect (boost::bind (&FilmViewer::film_changed, this, _1));
film_changed (Film::CONTENT);
- film_changed (Film::CROP);
film_changed (Film::FORMAT);
film_changed (Film::WITH_SUBTITLES);
film_changed (Film::SUBTITLE_OFFSET);
}
if (_raw_sub) {
+
+ /* Our output is already cropped by the decoder, so we need to account for that
+ when working out the scale that we are applying.
+ */
+
+ Size const cropped_size = _film->cropped_size (_film->size ());
+
Rect tx = subtitle_transformed_area (
- float (_film_size.width) / _film->size().width,
- float (_film_size.height) / _film->size().height,
+ float (_film_size.width) / cropped_size.width,
+ float (_film_size.height) / cropped_size.height,
_raw_sub->area(), _film->subtitle_offset(), _film->subtitle_scale()
);
if (!(*i)->finished ()) {
float const p = (*i)->overall_progress ();
if (p >= 0) {
- _job_records[*i].message->SetLabel (std_to_wx (st));
+ checked_set (_job_records[*i].message, st);
_job_records[*i].gauge->SetValue (p * 100);
} else {
- _job_records[*i].message->SetLabel (_("Running"));
+ checked_set (_job_records[*i].message, wx_to_std (_("Running")));
_job_records[*i].gauge->Pulse ();
}
}
if ((*i)->finished() && !_job_records[*i].finalised) {
_job_records[*i].gauge->SetValue (100);
- _job_records[*i].message->SetLabel (std_to_wx (st));
+ checked_set (_job_records[*i].message, st);
_job_records[*i].finalised = true;
if (!(*i)->error_details().empty ()) {
_job_records[*i].details->Enable (true);
using boost::shared_ptr;
void
-JobWrapper::make_dcp (wxWindow* parent, shared_ptr<Film> film, bool transcode)
+JobWrapper::make_dcp (wxWindow* parent, shared_ptr<Film> film)
{
if (!film) {
return;
}
try {
- film->make_dcp (transcode);
+ film->make_dcp ();
} catch (BadSettingError& e) {
error_dialog (parent, wxString::Format (_("Bad setting for %s (%s)"), e.setting().c_str(), e.what()));
} catch (std::exception& e) {
namespace JobWrapper
{
-void make_dcp (wxWindow *, boost::shared_ptr<Film>, bool);
+void make_dcp (wxWindow *, boost::shared_ptr<Film>);
}
}
}
+void
+checked_set (wxStaticText* widget, string value)
+{
+ if (widget->GetLabel() != std_to_wx (value)) {
+ widget->SetLabel (std_to_wx (value));
+ }
+}
+
void
checked_set (wxCheckBox* widget, bool value)
{
extern void checked_set (wxTextCtrl* widget, std::string value);
extern void checked_set (wxCheckBox* widget, bool value);
extern void checked_set (wxRadioButton* widget, bool value);
+extern void checked_set (wxStaticText* widget, std::string value);
film->set_content ("../../../test/test.mp4");
film->set_format (Format::from_nickname ("Flat"));
film->set_dcp_content_type (DCPContentType::from_pretty_name ("Test"));
- film->make_dcp (true);
+ film->make_dcp ();
film->write_metadata ();
while (JobManager::instance()->work_to_do ()) {
film->set_format (Format::from_nickname ("Flat"));
film->set_dcp_content_type (DCPContentType::from_pretty_name ("Test"));
film->set_trim_end (42);
- film->make_dcp (true);
+ film->make_dcp ();
while (JobManager::instance()->work_to_do() && !JobManager::instance()->errors()) {
dvdomatic_sleep (1);
File "%deps%/bin/libxml++-2.6-2.dll"
File "%deps%/bin/libxml2-2.dll"
File "%deps%/bin/libpixman-1-0.dll"
+File "%deps%/bin/libfontconfig-1.dll"
+File "%deps%/bin/libexpat-1.dll"
+File "%deps%/bin/libbz2.dll"
File "%binaries%/src/wx/dvdomatic-wx.dll"
File "%binaries%/src/lib/dvdomatic.dll"
File "%deps%/bin/libxml++-2.6-2.dll"
File "%deps%/bin/libxml2-2.dll"
File "%deps%/bin/libpixman-1-0.dll"
+File "%deps%/bin/libfontconfig-1.dll"
+File "%deps%/bin/libexpat-1.dll"
+File "%deps%/bin/libbz2.dll"
File "%binaries%/src/wx/dvdomatic-wx.dll"
File "%binaries%/src/lib/dvdomatic.dll"
import sys
APPNAME = 'dvdomatic'
-VERSION = '0.73pre'
+VERSION = '0.74pre'
def options(opt):
opt.load('compiler_cxx')