Implemented but faulty.
authorCarl Hetherington <cth@carlh.net>
Thu, 26 Jul 2012 21:17:58 +0000 (22:17 +0100)
committerCarl Hetherington <cth@carlh.net>
Thu, 26 Jul 2012 21:17:58 +0000 (22:17 +0100)
13 files changed:
src/lib/decoder.cc
src/lib/decoder.h
src/lib/ffmpeg_decoder.cc
src/lib/ffmpeg_decoder.h
src/lib/film_state.h
src/lib/imagemagick_decoder.h
src/lib/j2k_wav_encoder.cc
src/lib/tiff_decoder.cc
src/lib/tiff_decoder.h
src/lib/util.cc
src/lib/util.h
src/tools/wscript
wscript

index 9cbd93405e2317a709f649a5b1ef70e2bea310a1..efa37672ba203a3c07a8d36b3a14ccd2c42b717c 100644 (file)
@@ -32,6 +32,7 @@ extern "C" {
 #endif
 #include <libavformat/avio.h>
 }
+#include <samplerate.h>
 #include "film.h"
 #include "format.h"
 #include "job.h"
@@ -67,6 +68,7 @@ Decoder::Decoder (boost::shared_ptr<const FilmState> s, boost::shared_ptr<const
        , _video_frame (0)
        , _buffer_src_context (0)
        , _buffer_sink_context (0)
+       , _swr_context (0)
        , _have_setup_video_filters (false)
        , _delay_line (0)
        , _delay_in_bytes (0)
@@ -85,6 +87,23 @@ Decoder::~Decoder ()
 void
 Decoder::process_begin ()
 {
+       if (_fs->audio_sample_rate != dcp_audio_sample_rate (_fs->audio_sample_rate)) {
+               _swr_context = swr_alloc_set_opts (
+                       0,
+                       audio_channel_layout(),
+                       audio_sample_format(),
+                       dcp_audio_sample_rate (_fs->audio_sample_rate),
+                       audio_channel_layout(),
+                       audio_sample_format(),
+                       _fs->audio_sample_rate,
+                       0, 0
+                       );
+               
+               swr_init (_swr_context);
+       } else {
+               _swr_context = 0;
+       }
+
        /* This assumes 2 bytes per sample */
        _delay_in_bytes = _fs->audio_delay * _fs->audio_sample_rate * _fs->audio_channels * 2 / 1000;
        delete _delay_line;
@@ -96,6 +115,35 @@ Decoder::process_begin ()
 void
 Decoder::process_end ()
 {
+       if (_swr_context) {
+
+               int mop = 0;
+               while (1) {
+                       uint8_t buffer[256 * 2 * _fs->audio_channels];
+                       uint8_t* out[1] = {
+                               buffer
+                       };
+
+                       int const frames = swr_convert (_swr_context, out, 256, 0, 0);
+
+                       if (frames < 0) {
+                               throw DecodeError ("could not run sample-rate converter");
+                       }
+
+                       if (frames == 0) {
+                               break;
+                       }
+
+                       mop += frames;
+                       int available = _delay_line->feed (buffer, frames * _fs->audio_channels * 2);
+                       Audio (buffer, available);
+               }
+
+               cout << "mopped up " << mop << "\n";
+               
+               swr_free (&_swr_context);
+       }
+       
        if (_delay_in_bytes < 0) {
                uint8_t remainder[-_delay_in_bytes];
                _delay_line->get_remaining (remainder);
@@ -107,7 +155,7 @@ Decoder::process_end ()
           in to get it to the right length.
        */
 
-       int const audio_short_by_frames = (decoding_frames() * _fs->audio_sample_rate / _fs->frames_per_second) - _audio_frames_processed;
+       int const audio_short_by_frames = (decoding_frames() * dcp_audio_sample_rate (_fs->audio_sample_rate) / _fs->frames_per_second) - _audio_frames_processed;
 
        int bytes = audio_short_by_frames * audio_channels() * 2;
 
@@ -175,15 +223,12 @@ Decoder::pass ()
 void
 Decoder::process_audio (uint8_t* data, int channels, int size)
 {
-       /* Update the number of audio frames we've pushed to the encoder;
-          2 is the hard-coded (!) number of bytes per sample.
-       */
-       _audio_frames_processed += size / (channels * 2);
-               
+       int const samples = size / 2;
+       int const frames = samples / channels;
+       
        if (_fs->audio_gain != 0) {
                float const linear_gain = pow (10, _fs->audio_gain / 20);
                uint8_t* p = data;
-               int const samples = size / 2;
                switch (_fs->audio_sample_format) {
                case AV_SAMPLE_FMT_S16:
                        for (int i = 0; i < samples; ++i) {
@@ -202,6 +247,33 @@ Decoder::process_audio (uint8_t* data, int channels, int size)
                }
        }
 
+       if (_swr_context) {
+
+               uint8_t const * in[1] = {
+                       data
+               };
+
+               int const out_buffer_size_frames = ceil (frames * float (dcp_audio_sample_rate (_fs->audio_sample_rate)) / _fs->audio_sample_rate) + 32;
+               int const out_buffer_size_bytes = out_buffer_size_frames * channels * 2;
+               uint8_t out_buffer[out_buffer_size_bytes];
+
+               uint8_t* out[1] = {
+                       out_buffer
+               };
+               
+               int out_frames = swr_convert (_swr_context, out, out_buffer_size_frames, in, frames);
+               if (out_frames < 0) {
+                       throw DecodeError ("could not run sample-rate converter");
+               }
+
+               size = out_frames * channels * 2;
+       }
+               
+       /* Update the number of audio frames we've pushed to the encoder;
+          2 is the hard-coded (!) number of bytes per sample.
+       */
+       _audio_frames_processed += size / (channels * 2);
+       
        int available = _delay_line->feed (data, size);
        Audio (data, available);
 }
index d8551047043f08af5c84b01259a45035bad8d790..198dfb8dcb6d1ccd0cb2f52fc5119aa6d785e981 100644 (file)
@@ -29,6 +29,9 @@
 #include <stdint.h>
 #include <boost/shared_ptr.hpp>
 #include <sigc++/sigc++.h>
+extern "C" {
+#include <libswresample/swresample.h>
+}      
 #include "util.h"
 
 class Job;
@@ -65,6 +68,7 @@ public:
        virtual int audio_sample_rate () const = 0;
        /** @return format of audio samples */
        virtual AVSampleFormat audio_sample_format () const = 0;
+       virtual int64_t audio_channel_layout () const = 0;
 
        void process_begin ();
        bool pass ();
@@ -128,10 +132,15 @@ private:
        AVFilterContext* _buffer_src_context;
        AVFilterContext* _buffer_sink_context;
 
+       SwrContext* _swr_context;
+
        bool _have_setup_video_filters;
        DelayLine* _delay_line;
        int _delay_in_bytes;
 
+       /* Number of audio frames that we have pushed to the encoder
+          (at the DCP sample rate).
+       */
        int _audio_frames_processed;
 };
 
index af258f381cef9e9c3d32e592719e9211bbfc0fc8..df7434ff8c3072b9c8f2f867c140da23b2f0a265 100644 (file)
@@ -218,6 +218,12 @@ FFmpegDecoder::audio_sample_format () const
        return _audio_codec_context->sample_fmt;
 }
 
+int64_t
+FFmpegDecoder::audio_channel_layout () const
+{
+       return _audio_codec_context->channel_layout;
+}
+
 Size
 FFmpegDecoder::native_size () const
 {
index d66acad48fee72a243b56900a6c7bb812ec4d685..8e7d685805264213925102da1fd27968d9c0a5b8 100644 (file)
@@ -62,6 +62,7 @@ public:
        int audio_channels () const;
        int audio_sample_rate () const;
        AVSampleFormat audio_sample_format () const;
+       int64_t audio_channel_layout () const;
 
 private:
 
index 3a547ed1d141b0a5b6afaf546829acf1dbd75caf..f4ccf37fd753860d2b87ae70f394980aba53684c 100644 (file)
@@ -143,7 +143,7 @@ public:
        int length;
        /** Number of audio channels */
        int audio_channels;
-       /** Sample rate of the audio, in Hz */
+       /** Sample rate of the source audio, in Hz */
        int audio_sample_rate;
        /** Format of the audio samples */
        AVSampleFormat audio_sample_format;
index 707e6cacd1c5071ced4e2fd64a8760f863d89396..aca91ef5562d7392b1456942c6611df8b8c2aba1 100644 (file)
@@ -31,6 +31,10 @@ public:
                return AV_SAMPLE_FMT_NONE;
        }
 
+       int64_t audio_channel_layout () const {
+               return 0;
+       }
+
        static float static_frames_per_second () {
                return 24;
        }
index b0881daf25296848eaf37562b723d7e607cae6e5..3bcb1e5fd0f6d93b65cc03ea7bd89210d915073b 100644 (file)
@@ -54,7 +54,7 @@ J2KWAVEncoder::J2KWAVEncoder (shared_ptr<const FilmState> s, shared_ptr<const Op
        */
        for (int i = 0; i < _fs->audio_channels; ++i) {
                SF_INFO sf_info;
-               sf_info.samplerate = _fs->audio_sample_rate;
+               sf_info.samplerate = dcp_audio_sample_rate (_fs->audio_sample_rate);
                /* We write mono files */
                sf_info.channels = 1;
                sf_info.format = SF_FORMAT_WAV | SF_FORMAT_PCM_24;
index 6738de49b3e062765146b93ceb042d79d62d5505..101e0c047ee69cd575827fa8e856e71d33a86086 100644 (file)
@@ -130,6 +130,13 @@ TIFFDecoder::audio_sample_format () const
        return AV_SAMPLE_FMT_NONE;
 }
 
+
+int64_t
+TIFFDecoder::audio_channel_layout () const
+{
+       return 0;
+}
+
 bool
 TIFFDecoder::do_pass ()
 {
@@ -221,4 +228,3 @@ TIFFDecoder::sample_aspect_ratio_denominator () const
        /* XXX */
        return 1;
 }
-
index dbd76f36d05866c2b600f38fa3670fe8fb6d912a..d9b5b3969934b3000ef44368a9fa2e8a4f1eef1e 100644 (file)
@@ -52,6 +52,7 @@ public:
        int audio_channels () const;
        int audio_sample_rate () const;
        AVSampleFormat audio_sample_format () const;
+       int64_t audio_channel_layout () const;
 
 private:
        bool do_pass ();
index 450ba5b8ec5535eb6f3c831e1dc418bc31f3c928..9896bff602f073e89caf50d29606c5bbf1424793 100644 (file)
@@ -509,3 +509,13 @@ md5_digest (string file)
 
        return s.str ();
 }
+
+int
+dcp_audio_sample_rate (int fs)
+{
+       if (fs <= 48000) {
+               return 48000;
+       }
+
+       return 96000;
+}
index 1f635677aa81d3ba0d7cd14076bfaa4231197ddb..b3c1ebc0557693d65e4d352e545bb1bcf1a55fda 100644 (file)
@@ -119,4 +119,6 @@ struct Position
 
 extern std::string crop_string (Position, Size);
 
+extern int dcp_audio_sample_rate (int);
+
 #endif
index 4c4979190b25c4bca6b482149f6e65f5660feae4..3be2d0eba7a0ef413bfc6464f6141eb65fbe46ca 100644 (file)
@@ -14,7 +14,6 @@ def build(bld):
             p.append('playomatic')
         for t in p:
             obj = bld(features = 'cxx cxxprogram')
-            obj.uselib = 'BOOST_THREAD WXWIDGETS'
             obj.includes = ['..']
             obj.use    = ['libdvdomatic', 'libdvdomatic-wx']
             obj.source = '%s.cc' % t
diff --git a/wscript b/wscript
index 617875a7083ae821dd459b2b7a01c70a3a49aa22..8a7b2f5272552e8ad0c1bca7f18798be91fd66d2 100644 (file)
--- a/wscript
+++ b/wscript
@@ -58,6 +58,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 = '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', args = '--cflags --libs', uselib_store = 'DCP', mandatory = True)