Various fixes to resampling.
authorCarl Hetherington <cth@carlh.net>
Mon, 1 Oct 2012 18:51:36 +0000 (19:51 +0100)
committerCarl Hetherington <cth@carlh.net>
Mon, 1 Oct 2012 18:51:36 +0000 (19:51 +0100)
src/lib/decoder.cc
src/lib/film_state.cc
src/lib/film_state.h
src/lib/j2k_wav_encoder.cc
src/lib/j2k_wav_encoder.h

index b7aca764d7605790ea96138f188c3c082884c717..213ff9dd49888b693e93ddc6784d79d462e0f5d0 100644 (file)
@@ -111,18 +111,23 @@ Decoder::process_end ()
        */
 
        int64_t const audio_short_by_frames =
-               ((int64_t) decoding_frames() * _fs->audio_sample_rate / _fs->frames_per_second)
+               ((int64_t) decoding_frames() * _fs->target_sample_rate() / _fs->frames_per_second)
                - _audio_frames_processed;
 
        if (audio_short_by_frames >= 0) {
-               int bytes = audio_short_by_frames * _fs->audio_channels * _fs->bytes_per_sample();
+
+               stringstream s;
+               s << "Adding " << audio_short_by_frames << " frames of silence to the end.";
+               _log->log (s.str ());
+
+               int64_t bytes = audio_short_by_frames * _fs->audio_channels * _fs->bytes_per_sample();
                
-               int const silence_size = 64 * 1024;
+               int64_t const silence_size = 64 * 1024;
                uint8_t silence[silence_size];
                memset (silence, 0, silence_size);
                
                while (bytes) {
-                       int const t = min (bytes, silence_size);
+                       int64_t const t = min (bytes, silence_size);
                        Audio (silence, t);
                        bytes -= t;
                }
index e472434ce97442373117b38da39f8119924242dc..0c1ac87dc76d28f6470fd624300d15d6c8db8a60 100644 (file)
@@ -35,6 +35,7 @@
 #include "format.h"
 #include "dcp_content_type.h"
 #include "util.h"
+#include "exceptions.h"
 
 using namespace std;
 using namespace boost;
@@ -278,3 +279,23 @@ FilmState::bytes_per_sample () const
 
        return 0;
 }
+
+int
+FilmState::target_sample_rate () const
+{
+       double t = dcp_audio_sample_rate (audio_sample_rate);
+       if (rint (frames_per_second) != frames_per_second) {
+               if (fabs (frames_per_second - 23.976) < 1e-6) {
+                       /* 24fps drop-frame ie 24 * 1000 / 1001 frames per second;
+                          hence we need to resample the audio to dcp_audio_sample_rate * 1000 / 1001
+                          so that when we play it back at dcp_audio_sample_rate it is sped up
+                          by the same amount that the video is
+                       */
+                       t *= double(1000) / 1001;
+               } else {
+                       throw EncodeError ("unknown fractional frame rate");
+               }
+       }
+
+       return rint (t);
+}
index 12d44cdce23797557aac7c23a8229b5835094298..8dc0ce11bf320cde84f09e79ec17cd7be6dc47ca 100644 (file)
@@ -80,6 +80,7 @@ public:
        int thumb_frame (int) const;
 
        int bytes_per_sample () const;
+       int target_sample_rate () const;
        
        void write_metadata (std::ofstream &) const;
        void read_metadata (std::string, std::string);
index 24163940078f0d36bd78302c271ddf4a9349690b..9b25717ef3d1cb84b2633fd342ee1081218fc6ce 100644 (file)
@@ -219,14 +219,14 @@ J2KWAVEncoder::process_begin (int64_t audio_channel_layout, AVSampleFormat audio
 #ifdef HAVE_SWRESAMPLE
 
                stringstream s;
-               s << "Will resample audio from " << _fs->audio_sample_rate << " to " << target_sample_rate();
+               s << "Will resample audio from " << _fs->audio_sample_rate << " to " << _fs->target_sample_rate();
                _log->log (s.str ());
                
                _swr_context = swr_alloc_set_opts (
                        0,
                        audio_channel_layout,
                        audio_sample_format,
-                       target_sample_rate(),
+                       _fs->target_sample_rate(),
                        audio_channel_layout,
                        audio_sample_format,
                        _fs->audio_sample_rate,
@@ -303,11 +303,11 @@ J2KWAVEncoder::process_end ()
 #if HAVE_SWRESAMPLE    
        if (_swr_context) {
 
-               int mop = 0;
                while (1) {
                        uint8_t buffer[256 * _fs->bytes_per_sample() * _fs->audio_channels];
-                       uint8_t* out[1] = {
-                               buffer
+                       uint8_t* out[2] = {
+                               buffer,
+                               0
                        };
 
                        int const frames = swr_convert (_swr_context, out, 256, 0, 0);
@@ -320,8 +320,7 @@ J2KWAVEncoder::process_end ()
                                break;
                        }
 
-                       mop += frames;
-                       write_audio (buffer, frames);
+                       write_audio (buffer, frames * _fs->bytes_per_sample() * _fs->audio_channels);
                }
 
                swr_free (&_swr_context);
@@ -365,7 +364,7 @@ J2KWAVEncoder::process_audio (uint8_t* data, int size)
                int const frames = samples / _fs->audio_channels;
 
                /* Compute the resampled frame count and add 32 for luck */
-               int const out_buffer_size_frames = ceil (frames * target_sample_rate() / _fs->audio_sample_rate) + 32;
+               int const out_buffer_size_frames = ceil (frames * _fs->target_sample_rate() / _fs->audio_sample_rate) + 32;
                int const out_buffer_size_bytes = out_buffer_size_frames * _fs->audio_channels * _fs->bytes_per_sample();
                out_buffer = new uint8_t[out_buffer_size_bytes];
 
@@ -375,7 +374,7 @@ J2KWAVEncoder::process_audio (uint8_t* data, int size)
                };
 
                /* Resample audio */
-               int out_frames = swr_convert (_swr_context, out, out_buffer_size_frames, in, size);
+               int out_frames = swr_convert (_swr_context, out, out_buffer_size_frames, in, frames);
                if (out_frames < 0) {
                        throw EncodeError ("could not run sample-rate converter");
                }
@@ -395,12 +394,12 @@ J2KWAVEncoder::process_audio (uint8_t* data, int size)
 void
 J2KWAVEncoder::write_audio (uint8_t* data, int size)
 {
-       /* Size of a sample in bytes */
-       int const sample_size = 2;
-
-       /* XXX: we are assuming that sample_size is right, the _deinterleave_buffer_size is a multiple
-          of the sample size and that data_size is a multiple of _fs->audio_channels * sample_size.
+       /* XXX: we are assuming that the _deinterleave_buffer_size is a multiple
+          of the sample size and that size is a multiple of _fs->audio_channels * sample_size.
        */
+
+       assert ((size % (_fs->audio_channels * _fs->bytes_per_sample())) == 0);
+       assert ((_deinterleave_buffer_size % _fs->bytes_per_sample()) == 0);
        
        /* XXX: this code is very tricksy and it must be possible to make it simpler ... */
        
@@ -412,17 +411,17 @@ J2KWAVEncoder::write_audio (uint8_t* data, int size)
                /* How many bytes of the deinterleaved data to do this time */
                int this_time = min (remaining / _fs->audio_channels, _deinterleave_buffer_size);
                for (int i = 0; i < _fs->audio_channels; ++i) {
-                       for (int j = 0; j < this_time; j += sample_size) {
-                               for (int k = 0; k < sample_size; ++k) {
+                       for (int j = 0; j < this_time; j += _fs->bytes_per_sample()) {
+                               for (int k = 0; k < _fs->bytes_per_sample(); ++k) {
                                        int const to = j + k;
-                                       int const from = position + (i * sample_size) + (j * _fs->audio_channels) + k;
+                                       int const from = position + (i * _fs->bytes_per_sample()) + (j * _fs->audio_channels) + k;
                                        _deinterleave_buffer[to] = data[from];
                                }
                        }
                        
                        switch (_fs->audio_sample_format) {
                        case AV_SAMPLE_FMT_S16:
-                               sf_write_short (_sound_files[i], (const short *) _deinterleave_buffer, this_time / sample_size);
+                               sf_write_short (_sound_files[i], (const short *) _deinterleave_buffer, this_time / _fs->bytes_per_sample());
                                break;
                        default:
                                throw EncodeError ("unknown audio sample format");
@@ -434,22 +433,3 @@ J2KWAVEncoder::write_audio (uint8_t* data, int size)
        }
 }
 
-int
-J2KWAVEncoder::target_sample_rate () const
-{
-       double t = dcp_audio_sample_rate (_fs->audio_sample_rate);
-       if (rint (_fs->frames_per_second) != _fs->frames_per_second) {
-               if (_fs->frames_per_second == 23.976) {
-                       /* 24fps drop-frame ie 24 * 1000 / 1001 frames per second;
-                          hence we need to resample the audio to dcp_audio_sample_rate * 1000 / 1001
-                          so that when we play it back at dcp_audio_sample_rate it is sped up
-                          by the same amount that the video is
-                       */
-                       t *= double(1000) / 1001;
-               } else {
-                       throw EncodeError ("unknown fractional frame rate");
-               }
-       }
-
-       return rint (t);
-}
index 3f01ac48099a0bfceac5f58d4d88074c16f5835e..e11358c2c6328dd3f1ea584f2654d7268a1f9118 100644 (file)
@@ -55,8 +55,6 @@ public:
 
 private:
 
-       int target_sample_rate () const;
-
        void write_audio (uint8_t* data, int size);
        void encoder_thread (ServerDescription *);
        void close_sound_files ();