Merge master.
authorCarl Hetherington <cth@carlh.net>
Wed, 9 Jan 2013 18:48:19 +0000 (18:48 +0000)
committerCarl Hetherington <cth@carlh.net>
Wed, 9 Jan 2013 18:48:19 +0000 (18:48 +0000)
19 files changed:
ChangeLog
debian/changelog
doc/manual/dvdomatic.xml
src/lib/encoder.cc
src/lib/encoder.h
src/lib/ffmpeg_compatibility.cc
src/lib/ffmpeg_compatibility.h
src/lib/film.cc
src/lib/film.h
src/lib/filter_graph.h
src/lib/format.cc
src/lib/image.cc
src/lib/image.h
src/lib/make_dcp_job.cc
src/lib/matcher.h
src/lib/util.cc
src/lib/util.h
src/wx/film_editor.cc
wscript

index c1d62c2c31c98f286c694ed15a3dc634064fcd06..f2563ef109b6b45a780effcf6755c5f17b3be3fc 100644 (file)
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,44 @@
+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.
index aee2d0f4fa7c9c8c86c8f2ae0e5bee2f70e6caf7..ec1e3c77406a9e3883f604777e6fb9cff5d2e907 100644 (file)
@@ -1,3 +1,18 @@
+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.
index db19cfd9eb95923ddabcd0fd6f6e356752941be4..753358c22a84e86d52aa9678b69cb3a25b3008fc 100644 (file)
@@ -472,6 +472,11 @@ soundtracks from your content file; you can select the soundtrack that
 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
index 07ce8f3bc20c2aa35b43a7f9646da5db0b123ac6..693bd5bc8e5baecceb779189b4a1f7e339c1a3cb 100644 (file)
@@ -42,6 +42,7 @@ using std::stringstream;
 using std::vector;
 using std::list;
 using std::cout;
+using std::make_pair;
 using namespace boost;
 
 int const Encoder::_history_size = 25;
@@ -65,7 +66,7 @@ Encoder::Encoder (shared_ptr<const Film> f, shared_ptr<const EncodeOptions> o)
                /* 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 */
@@ -136,7 +137,7 @@ void
 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));
                        
@@ -163,7 +164,7 @@ Encoder::process_end ()
                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));
                        }
@@ -207,6 +208,12 @@ Encoder::process_end ()
                        _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,
@@ -305,9 +312,11 @@ Encoder::process_video (shared_ptr<Image> image, bool same, boost::shared_ptr<Su
        }
 
        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());
@@ -380,6 +389,22 @@ Encoder::process_audio (shared_ptr<AudioBuffers> data)
        }
 #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 ();
@@ -388,7 +413,7 @@ Encoder::process_audio (shared_ptr<AudioBuffers> data)
 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());
        }
 
index e5916ad3a022bc8f2f9c8c117e182f339d7f3def..52ccfc166833f60a2e0e9a6efe4583092f15ad54 100644 (file)
@@ -121,7 +121,13 @@ private:
 
 #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;
index c47cdf5ce71f03c4ee4edfc31b85e013af1085c4..09f9276ac0fbb8d80adec70b78554e28dffd27ed 100644 (file)
@@ -107,3 +107,11 @@ avfilter_inout_alloc ()
        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
index 80cc79ffb8b8995189c09d8bd976d9665c2c29fb..772d22c33f598433bc16c0275c8f0944d3857016 100644 (file)
@@ -22,3 +22,10 @@ struct AVFilterInOut;
 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
index cae4f5f9393f8d7364f157231298044afdf7387a..6e49dd4ea2df0b3e8f08fad1560861157f471af0 100644 (file)
@@ -247,6 +247,8 @@ Film::make_dcp (bool transcode)
                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) {
index eda2060b81ac89be0d1e20512f3bdce9ba54e1c4..b2f57eac81d0cee4940d395f58f5dc651e71682e 100644 (file)
@@ -466,7 +466,7 @@ private:
 
        /** 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;
index a4b9ef75fb68bd44ed9e9319d15359986c15c600..9e6ac62528859591acaf0af5152a5bb3e53e947f 100644 (file)
@@ -25,6 +25,7 @@
 #define DVDOMATIC_FILTER_GRAPH_H
 
 #include "util.h"
+#include "ffmpeg_compatibility.h"
 
 class Image;
 class VideoFilter;
index eb42593feada4da576d645842bbd44cb13d60b42..9758624118054ef20aedfb5430e3b6278f2521a3 100644 (file)
@@ -75,6 +75,7 @@ Format::setup_formats ()
        _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"));
index e136a84697c44eb8464ba94101467d5c83f48103..f774f476fd707c7b02ddf00b6ca099b6c3a6ca85 100644 (file)
@@ -448,26 +448,6 @@ SimpleImage::~SimpleImage ()
        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
 {
index 13b92d72f11d0b48f98440932274ca9848eb6079..e19c6f54b7055d916df185cdab98c102f9ea8496 100644 (file)
@@ -32,6 +32,7 @@ extern "C" {
 #include <libavfilter/avfilter.h>
 }
 #include "util.h"
+#include "ffmpeg_compatibility.h"
 
 class Scaler;
 class RGBFrameImage;
@@ -124,7 +125,6 @@ public:
        SimpleImage (AVPixelFormat, Size, bool);
        SimpleImage (SimpleImage const &);
        SimpleImage& operator= (SimpleImage const &);
-       SimpleImage (boost::shared_ptr<const Image>, bool aligned);
        ~SimpleImage ();
 
        uint8_t ** data () const;
index a8b80fd67ba7c059cc15be467566db02b968fd7e..e42018ad5875b962a1ad07fafcfbc8bbed6b55c7 100644 (file)
@@ -132,7 +132,7 @@ MakeDCPJob::run ()
                                &dcp.Progress,
                                dfr.frames_per_second,
                                frames,
-                               _film->audio_channels(),
+                               dcp_audio_channels (_film->audio_channels()),
                                _film->encrypted()
                                )
                        );
index 9bd30fe620bef802284a7ba06faf93cddc380589..b94c28446a4d7f3b69a8ebe8c70204ecf34e3b67 100644 (file)
@@ -19,6 +19,7 @@
 
 #include <boost/optional.hpp>
 #include "processor.h"
+#include "ffmpeg_compatibility.h"
 
 class Matcher : public AudioVideoProcessor
 {
index 9d42a52e50f06a980464b3f1e17debb5b2b38edb..987c2b9e53a5c37112a3f9b92de6fa2d9d3d420e 100644 (file)
@@ -367,6 +367,20 @@ dcp_audio_sample_rate (int fs)
        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);
index 3832cc57945900b9ca82f61b5caee0501a510425..0744d9c090080806fac6438a322cd9a715c2e7c7 100644 (file)
@@ -184,6 +184,7 @@ struct Rect
 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);
index 56bc60c7847bf6a7b30057d612725c0b7c0ea948..ea6055c94be1a95b611211bad91e0a03e3a213e5 100644 (file)
@@ -1095,7 +1095,12 @@ FilmEditor::setup_audio_details ()
                _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 ()));
        }
 }
diff --git a/wscript b/wscript
index b28082505e608e2d79490d1d6ffa2d1f1af7e29d..bc272b5d70dc65d8f873a4f3cea159f5fea50101 100644 (file)
--- a/wscript
+++ b/wscript
@@ -3,7 +3,7 @@ import os
 import sys
 
 APPNAME = 'dvdomatic'
-VERSION = '0.69pre'
+VERSION = '0.71pre'
 
 def options(opt):
     opt.load('compiler_cxx')
@@ -151,6 +151,26 @@ def configure(conf):
                              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')
 
@@ -176,7 +196,7 @@ def build(bld):
     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'):