+2013-01-09 Carl Hetherington <cth@carlh.net>
+
+ * Try to build with 0.10.4-ish ffmpeg.
+
+2013-01-07 Carl Hetherington <cth@carlh.net>
+
+ * Version 0.70 released.
+
+2013-01-07 Carl Hetherington <cth@carlh.net>
+
+ * Fix heinous thinko in mono soundtrack mapping code.
+
+2013-01-06 Carl Hetherington <cth@carlh.net>
+
+ * Version 0.70beta3 released.
+
+2013-01-06 Carl Hetherington <cth@carlh.net>
+
+ * Postpone linking of duplicate video frames so that copies
+ don't fail on Windows.
+
+2013-01-06 Carl Hetherington <cth@carlh.net>
+
+ * Version 0.70beta2 released.
+
+2013-01-06 Carl Hetherington <cth@carlh.net>
+
+ * Version 0.70beta1 released.
+
+2013-01-06 Carl Hetherington <cth@carlh.net>
+
+ * Put mono soundtracks on the centre speaker, rather
+ than on left (reported by Mike Blakesley).
+
+ * Add format for 16:9 without letterboxing (requested by Lilian
+ Lefranc).
+
+2012-12-23 Carl Hetherington <cth@carlh.net>
+
+ * Version 0.69 released.
+
2012-12-23 Carl Hetherington <cth@carlh.net>
* Version 0.68 released.
+dvdomatic (0.70-1) UNRELEASED; urgency=low
+
+ * New upstream release.
+
+ -- Carl Hetherington <carl@houllier.lan> Mon, 07 Jan 2013 23:57:26 +0000
+
+dvdomatic (0.70beta3-1) UNRELEASED; urgency=low
+
+ * New upstream release.
+ * New upstream release.
+ * New upstream release.
+ * New upstream release.
+
+ -- Carl Hetherington <cth@carlh.net> Sun, 06 Jan 2013 23:44:24 +0000
+
dvdomatic (0.68-1) UNRELEASED; urgency=low
* New upstream release.
you wish to use from the drop-down box.
</para>
+<para>
+Note that if your content's audio is mono, DVD-o-matic will place it
+in the centre channel in the DCP.
+</para>
+
<para>
Alternatively, you can supply different sound files by clicking the
<guilabel>Use external audio</guilabel> button and choosing a WAV file
using std::vector;
using std::list;
using std::cout;
+using std::make_pair;
using namespace boost;
int const Encoder::_history_size = 25;
/* Create sound output files with .tmp suffixes; we will rename
them if and when we complete.
*/
- for (int i = 0; i < _film->audio_channels(); ++i) {
+ for (int i = 0; i < dcp_audio_channels (_film->audio_channels()); ++i) {
SF_INFO sf_info;
sf_info.samplerate = dcp_audio_sample_rate (_film->audio_stream()->sample_rate());
/* We write mono files */
Encoder::process_end ()
{
#if HAVE_SWRESAMPLE
- if (_film->audio_stream() && _swr_context) {
+ if (_film->audio_stream() && _film->audio_stream()->channels() && _swr_context) {
shared_ptr<AudioBuffers> out (new AudioBuffers (_film->audio_stream()->channels(), 256));
close_sound_files ();
/* Rename .wav.tmp files to .wav */
- for (int i = 0; i < _film->audio_channels(); ++i) {
+ for (int i = 0; i < dcp_audio_channels (_film->audio_channels()); ++i) {
if (boost::filesystem::exists (_opt->multichannel_audio_out_path (i, false))) {
boost::filesystem::remove (_opt->multichannel_audio_out_path (i, false));
}
_film->log()->log (String::compose ("Local encode failed (%1)", e.what ()));
}
}
+
+ /* Now do links (or copies on windows) to duplicate frames */
+ for (list<pair<int, int> >::iterator i = _links_required.begin(); i != _links_required.end(); ++i) {
+ link (_opt->frame_out_path (i->first, false), _opt->frame_out_path (i->second, false));
+ link (_opt->hash_out_path (i->first, false), _opt->hash_out_path (i->second, false));
+ }
}
/** @return an estimate of the current number of frames we are encoding per second,
}
if (same && _last_real_frame) {
- /* Use the last frame that we encoded */
- link (_opt->frame_out_path (_last_real_frame.get(), false), _opt->frame_out_path (_video_frame, false));
- link (_opt->hash_out_path (_last_real_frame.get(), false), _opt->hash_out_path (_video_frame, false));
+ /* Use the last frame that we encoded. We need to postpone doing the actual link,
+ as on windows the link is really a copy and the reference frame might not have
+ finished encoding yet.
+ */
+ _links_required.push_back (make_pair (_last_real_frame.get(), _video_frame));
} else {
/* Queue this new frame for encoding */
pair<string, string> const s = Filter::ffmpeg_strings (_film->filters());
}
#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;
+ }
+
write_audio (data);
_audio_frame += data->frames ();
void
Encoder::write_audio (shared_ptr<const AudioBuffers> audio)
{
- for (int i = 0; i < _film->audio_channels(); ++i) {
+ for (int i = 0; i < audio->channels(); ++i) {
sf_write_float (_sound_files[i], audio->data(i), audio->frames());
}
#if HAVE_SWRESAMPLE
SwrContext* _swr_context;
-#endif
+#endif
+
+ /** List of links that we need to create when all frames have been processed;
+ * such that we need to call link (first, second) for each member of this list.
+ * In other words, `first' is a `real' frame and `second' should be a link to `first'.
+ */
+ std::list<std::pair<int, int> > _links_required;
std::vector<SNDFILE*> _sound_files;
int64_t _audio_frames_written;
return (AVFilterInOut *) av_malloc (sizeof (AVFilterInOut));
}
#endif
+
+#ifndef HAVE_AV_FRAME_GET_BEST_EFFORT_TIMESTAMP
+int64_t av_frame_get_best_effort_timestamp (AVFrame const * f)
+{
+ return f->best_effort_timestamp;
+}
+
+#endif
extern AVFilter* get_sink ();
extern AVFilterInOut* avfilter_inout_alloc ();
+#ifndef HAVE_AV_PIXEL_FORMAT
+#define AVPixelFormat PixelFormat
+#endif
+
+#ifndef HAVE_AV_FRAME_GET_BEST_EFFORT_TIMESTAMP
+extern int64_t av_frame_get_best_effort_timestamp (AVFrame const *);
+#endif
char buffer[128];
gethostname (buffer, sizeof (buffer));
log()->log (String::compose ("Starting to make DCP on %1", buffer));
+ log()->log (String::compose ("Content is %1; type %2", content_path(), (content_type() == STILL ? "still" : "video")));
+ log()->log (String::compose ("Content length %1", length()));
}
if (format() == 0) {
/** Size, in pixels, of the source (ignoring cropping) */
Size _size;
- /** Actual length of the source (in video frames) from examining it */
+ /** The length of the source, in video frames (as far as we know) */
boost::optional<SourceFrame> _length;
/** MD5 digest of our content file */
std::string _content_digest;
#define DVDOMATIC_FILTER_GRAPH_H
#include "util.h"
+#include "ffmpeg_compatibility.h"
class Image;
class VideoFilter;
_formats.push_back (new FixedFormat (166, Size (1793, 1080), "166", "1.66", "F"));
_formats.push_back (new FixedFormat (166, Size (1998, 1080), "166-in-flat", "1.66 within Flat", "F"));
_formats.push_back (new FixedFormat (178, Size (1998, 1080), "178-in-flat", "16:9 within Flat", "F"));
+ _formats.push_back (new FixedFormat (178, Size (1920, 1080), "178", "16:9", "F"));
_formats.push_back (new FixedFormat (185, Size (1998, 1080), "185", "Flat", "F"));
_formats.push_back (new FixedFormat (239, Size (2048, 858), "239", "Scope", "S"));
_formats.push_back (new VariableFormat (Size (1998, 1080), "var-185", "Flat", "F"));
av_free (_stride);
}
-SimpleImage::SimpleImage (shared_ptr<const Image> im, bool aligned)
- : Image (im->pixel_format())
-{
- assert (components() == im->components());
-
- for (int c = 0; c < components(); ++c) {
-
- assert (line_size()[c] == im->line_size()[c]);
-
- uint8_t* t = data()[c];
- uint8_t* o = im->data()[c];
-
- for (int y = 0; y < lines(c); ++y) {
- memcpy (t, o, line_size()[c]);
- t += stride()[c];
- o += im->stride()[c];
- }
- }
-}
-
uint8_t **
SimpleImage::data () const
{
#include <libavfilter/avfilter.h>
}
#include "util.h"
+#include "ffmpeg_compatibility.h"
class Scaler;
class RGBFrameImage;
SimpleImage (AVPixelFormat, Size, bool);
SimpleImage (SimpleImage const &);
SimpleImage& operator= (SimpleImage const &);
- SimpleImage (boost::shared_ptr<const Image>, bool aligned);
~SimpleImage ();
uint8_t ** data () const;
&dcp.Progress,
dfr.frames_per_second,
frames,
- _film->audio_channels(),
+ dcp_audio_channels (_film->audio_channels()),
_film->encrypted()
)
);
#include <boost/optional.hpp>
#include "processor.h"
+#include "ffmpeg_compatibility.h"
class Matcher : public AudioVideoProcessor
{
return 96000;
}
+int
+dcp_audio_channels (int f)
+{
+ if (f == 1) {
+ /* The source is mono, so to put the mono channel into
+ the centre we need to generate a 5.1 soundtrack.
+ */
+ return 6;
+ }
+
+ return f;
+}
+
+
bool operator== (Size const & a, Size const & b)
{
return (a.width == b.width && a.height == b.height);
extern std::string crop_string (Position, Size);
extern int dcp_audio_sample_rate (int);
extern DCPFrameRate dcp_frame_rate (float);
+extern int dcp_audio_channels (int);
extern std::string colour_lut_index_to_name (int index);
extern int stride_round_up (int, int const *, int);
extern int stride_lookup (int c, int const * stride);
_audio->SetLabel (wxT (""));
} else {
stringstream s;
- s << _film->audio_stream()->channels () << " channels, " << _film->audio_stream()->sample_rate() << "Hz";
+ if (_film->audio_stream()->channels() == 1) {
+ s << "1 channel";
+ } else {
+ s << _film->audio_stream()->channels () << " channels";
+ }
+ s << ", " << _film->audio_stream()->sample_rate() << "Hz";
_audio->SetLabel (std_to_wx (s.str ()));
}
}
import sys
APPNAME = 'dvdomatic'
-VERSION = '0.69pre'
+VERSION = '0.71pre'
def options(opt):
opt.load('compiler_cxx')
define_name = 'HAVE_G_FORMAT_SIZE',
mandatory = False)
+ conf.check_cc(fragment = """
+ extern "C" {
+ #include <libavutil/avutil.h>
+ }
+ int main() { AVPixelFormat f; }
+ """, msg = 'Checking for AVPixelFormat',
+ uselib = 'AVUTIL',
+ define_name = 'HAVE_AV_PIXEL_FORMAT',
+ mandatory = False)
+
+ conf.check_cc(fragment = """
+ extern "C" {
+ #include <libavcodec/avcodec.h>
+ }
+ int main() { AVFrame* f; av_frame_get_best_effort_timestamp(f); }
+ """, msg = 'Checking for av_frame_get_best_effort_timestamp',
+ uselib = 'AVCODEC',
+ define_name = 'HAVE_AV_FRAME_GET_BEST_EFFORT_TIMESTAMP',
+ mandatory = False)
+
conf.recurse('src')
conf.recurse('test')
bld.add_post_fun(post)
def dist(ctx):
- ctx.excl = 'TODO core *~ src/wx/*~ src/lib/*~ .waf* build .git deps alignment hacks sync *.tar.bz2 *.exe .lock* *build-windows doc/manual/pdf doc/manual/html'
+ ctx.excl = 'TODO core *~ src/wx/*~ src/lib/*~ builds/*~ doc/manual/*~ src/tools/*~ *.pyc .waf* build .git deps alignment hacks sync *.tar.bz2 *.exe .lock* *build-windows doc/manual/pdf doc/manual/html'
def create_version_cc(version):
if os.path.exists('.git'):