diff options
| author | Carl Hetherington <cth@carlh.net> | 2012-10-20 15:40:46 +0100 |
|---|---|---|
| committer | Carl Hetherington <cth@carlh.net> | 2012-10-20 15:40:46 +0100 |
| commit | 476af651fc34d7c6394fea0e39d351392b4e46d3 (patch) | |
| tree | 0dc0cef257733a52cc347197cb0ed08ae53fe4f4 /src | |
| parent | a6976df179011056027a99ae210fb28117c36840 (diff) | |
Stuff.
Diffstat (limited to 'src')
| -rw-r--r-- | src/lib/decoder.cc | 103 | ||||
| -rw-r--r-- | src/lib/decoder.h | 7 | ||||
| -rw-r--r-- | src/lib/encoder.h | 6 | ||||
| -rw-r--r-- | src/lib/film_state.cc | 9 | ||||
| -rw-r--r-- | src/lib/image.cc | 8 | ||||
| -rw-r--r-- | src/lib/image.h | 14 | ||||
| -rw-r--r-- | src/lib/imagemagick_encoder.h | 2 | ||||
| -rw-r--r-- | src/lib/j2k_still_encoder.h | 2 | ||||
| -rw-r--r-- | src/lib/j2k_wav_encoder.cc | 125 | ||||
| -rw-r--r-- | src/lib/j2k_wav_encoder.h | 6 | ||||
| -rw-r--r-- | src/lib/util.cc | 6 |
11 files changed, 134 insertions, 154 deletions
diff --git a/src/lib/decoder.cc b/src/lib/decoder.cc index 03131dac2..ec046fcaf 100644 --- a/src/lib/decoder.cc +++ b/src/lib/decoder.cc @@ -105,7 +105,7 @@ Decoder::process_end () uint8_t remainder[-_delay_in_bytes]; _delay_line->get_remaining (remainder); _audio_frames_processed += _delay_in_bytes / (_fs->audio_channels() * _fs->bytes_per_sample()); - Audio (remainder, _delay_in_bytes); + emit_audio (remainder, _delay_in_bytes); } /* If we cut the decode off, the audio may be short; push some silence @@ -130,7 +130,7 @@ Decoder::process_end () while (bytes) { int64_t const t = min (bytes, silence_size); - Audio (silence, t); + emit_audio (silence, t); bytes -= t; } } @@ -175,53 +175,92 @@ Decoder::pass () } /** Called by subclasses to tell the world that some audio data is ready - * @param data Interleaved audio data, in FilmState::audio_sample_format. + * @param data Audio data, in FilmState::audio_sample_format. * @param size Number of bytes of data. */ void Decoder::process_audio (uint8_t* data, int size) { - /* Samples per channel */ - int const samples = size / _fs->bytes_per_sample(); + /* Push into the delay line */ + size = _delay_line->feed (data, size); - /* Maybe apply gain */ - if (_fs->audio_gain() != 0) { - float const linear_gain = pow (10, _fs->audio_gain() / 20); - uint8_t* p = data; - switch (_fs->audio_sample_format()) { - case AV_SAMPLE_FMT_S16: - for (int i = 0; i < samples; ++i) { - /* XXX: assumes little-endian; also we should probably be dithering here */ + emit_audio (data, size); +} - /* unsigned sample */ - int const ou = p[0] | (p[1] << 8); +void +Decoder::emit_audio (uint8_t* data, int size) +{ + /* Deinterleave and convert to float */ + + float* samples[_fs->audio_channels()]; + int const total_samples = size / _fs->bytes_per_sample(); + int const frames = total_samples / _fs->audio_channels(); + for (int i = 0; i < _fs->audio_channels(); ++i) { + samples[i] = new float[frames]; + } - /* signed sample */ - int const os = ou >= 0x8000 ? (- 0x10000 + ou) : ou; + switch (_fs->audio_sample_format()) { + case AV_SAMPLE_FMT_S16: + { + uint8_t* p = data; + int sample = 0; + int channel = 0; + for (int i = 0; i < total_samples; ++i) { + /* unsigned sample */ + int const ou = p[0] | (p[1] << 8); + /* signed sample */ + int const os = ou >= 0x8000 ? (- 0x10000 + ou) : ou; + /* float sample */ + samples[channel][sample] = float(os) / 0x8000; + + cout << samples[channel][sample] << " from s16\n"; + + ++channel; + if (channel == _fs->audio_channels()) { + channel = 0; + ++sample; + } - /* signed sample with altered gain */ - int const gs = int (os * linear_gain); + p += 2; + } + } + break; + + case AV_SAMPLE_FMT_FLTP: + { + float* p = reinterpret_cast<float*> (data); + for (int i = 0; i < _fs->audio_channels(); ++i) { + for (int j = 0; j < frames; ++j) { + samples[i][j] = *p++; + cout << samples[i][j] << " from float.\n"; + ++p; + } + } + } + break; - /* unsigned sample with altered gain */ - int const gu = gs > 0 ? gs : (0x10000 + gs); + default: + assert (false); + } - /* write it back */ - p[0] = gu & 0xff; - p[1] = (gu & 0xff00) >> 8; - p += 2; + /* Maybe apply gain */ + if (_fs->audio_gain() != 0) { + float const linear_gain = pow (10, _fs->audio_gain() / 20); + for (int i = 0; i < _fs->audio_channels(); ++i) { + for (int j = 0; j < frames; ++j) { + samples[i][j] *= linear_gain; } - break; - default: - assert (false); } } /* Update the number of audio frames we've pushed to the encoder */ - _audio_frames_processed += size / (_fs->audio_channels() * _fs->bytes_per_sample()); + _audio_frames_processed += frames; - /* Push into the delay line and then tell the world what we've got */ - int available = _delay_line->feed (data, size); - Audio (data, available); + Audio (samples, frames); + + for (int i = 0; i < _fs->audio_channels(); ++i) { + delete[] samples[i]; + } } /** Called by subclasses to tell the world that some video data is ready. diff --git a/src/lib/decoder.h b/src/lib/decoder.h index 312cbbe8e..88dd90f0c 100644 --- a/src/lib/decoder.h +++ b/src/lib/decoder.h @@ -100,10 +100,10 @@ public: sigc::signal<void, boost::shared_ptr<Image>, int, boost::shared_ptr<Subtitle> > Video; /** Emitted when some audio data is ready. - * First parameter is the interleaved sample data, format is given in the FilmState. - * Second parameter is the size of the data. + * First parameter is an array of pointers to deinterleaved, floating point sample data for each channel. + * Second parameter is the size of the data in frames (ie samples on each channel). */ - sigc::signal<void, uint8_t *, int> Audio; + sigc::signal<void, float**, int> Audio; protected: /** perform a single pass at our content */ @@ -137,6 +137,7 @@ protected: private: void setup_video_filters (); + void emit_audio (uint8_t* data, int size); /** last video frame to be processed */ int _video_frame; diff --git a/src/lib/encoder.h b/src/lib/encoder.h index 02a2d7723..5dc0804c6 100644 --- a/src/lib/encoder.h +++ b/src/lib/encoder.h @@ -64,10 +64,10 @@ public: virtual void process_video (boost::shared_ptr<Image> i, int f, boost::shared_ptr<Subtitle> s) = 0; /** Called with some audio data. - * @param d Data. - * @param s Size of data (in bytes) + * @param d Array of pointers to floating point sample data for each channel. + * @param s Number of frames (ie number of samples in each channel) */ - virtual void process_audio (uint8_t* d, int s) = 0; + virtual void process_audio (float** d, int s) = 0; /** Called when a processing run has finished */ virtual void process_end () = 0; diff --git a/src/lib/film_state.cc b/src/lib/film_state.cc index 82d492b9a..f2d83e4e2 100644 --- a/src/lib/film_state.cc +++ b/src/lib/film_state.cc @@ -358,14 +358,7 @@ FilmState::content_type () const int FilmState::bytes_per_sample () const { - switch (_audio_sample_format) { - case AV_SAMPLE_FMT_S16: - return 2; - default: - return 0; - } - - return 0; + return av_get_bytes_per_sample (_audio_sample_format); } int diff --git a/src/lib/image.cc b/src/lib/image.cc index b2024e0e9..c8303115b 100644 --- a/src/lib/image.cc +++ b/src/lib/image.cc @@ -293,7 +293,7 @@ Image::write_to_socket (shared_ptr<Socket> socket) const * @param p Pixel format. * @param s Size in pixels. */ -SimpleImage::SimpleImage (PixelFormat p, Size s, function<int (int)> rounder) +SimpleImage::SimpleImage (AVPixelFormat p, Size s, function<int (int)> rounder) : Image (p) , _size (s) { @@ -370,13 +370,13 @@ SimpleImage::size () const return _size; } -AlignedImage::AlignedImage (PixelFormat f, Size s) +AlignedImage::AlignedImage (AVPixelFormat f, Size s) : SimpleImage (f, s, boost::bind (round_up, _1, 32)) { } -CompactImage::CompactImage (PixelFormat f, Size s) +CompactImage::CompactImage (AVPixelFormat f, Size s) : SimpleImage (f, s, boost::bind (round_up, _1, 1)) { @@ -402,7 +402,7 @@ CompactImage::CompactImage (shared_ptr<Image> im) } } -FilterBufferImage::FilterBufferImage (PixelFormat p, AVFilterBufferRef* b) +FilterBufferImage::FilterBufferImage (AVPixelFormat p, AVFilterBufferRef* b) : Image (p) , _buffer (b) { diff --git a/src/lib/image.h b/src/lib/image.h index 6c3c9109e..b2b987279 100644 --- a/src/lib/image.h +++ b/src/lib/image.h @@ -49,7 +49,7 @@ class SimpleImage; class Image { public: - Image (PixelFormat p) + Image (AVPixelFormat p) : _pixel_format (p) {} @@ -79,12 +79,12 @@ public: void read_from_socket (boost::shared_ptr<Socket>); void write_to_socket (boost::shared_ptr<Socket>) const; - PixelFormat pixel_format () const { + AVPixelFormat pixel_format () const { return _pixel_format; } private: - PixelFormat _pixel_format; ///< FFmpeg's way of describing the pixel format of this Image + AVPixelFormat _pixel_format; ///< FFmpeg's way of describing the pixel format of this Image }; /** @class FilterBufferImage @@ -93,7 +93,7 @@ private: class FilterBufferImage : public Image { public: - FilterBufferImage (PixelFormat, AVFilterBufferRef *); + FilterBufferImage (AVPixelFormat, AVFilterBufferRef *); ~FilterBufferImage (); uint8_t ** data () const; @@ -111,7 +111,7 @@ private: class SimpleImage : public Image { public: - SimpleImage (PixelFormat, Size, boost::function<int (int)> rounder); + SimpleImage (AVPixelFormat, Size, boost::function<int (int)> rounder); ~SimpleImage (); uint8_t ** data () const; @@ -130,13 +130,13 @@ private: class AlignedImage : public SimpleImage { public: - AlignedImage (PixelFormat, Size); + AlignedImage (AVPixelFormat, Size); }; class CompactImage : public SimpleImage { public: - CompactImage (PixelFormat, Size); + CompactImage (AVPixelFormat, Size); CompactImage (boost::shared_ptr<Image>); }; diff --git a/src/lib/imagemagick_encoder.h b/src/lib/imagemagick_encoder.h index ce6ca3e8f..8e9c416ae 100644 --- a/src/lib/imagemagick_encoder.h +++ b/src/lib/imagemagick_encoder.h @@ -38,6 +38,6 @@ public: void process_begin (int64_t audio_channel_layout, AVSampleFormat audio_sample_format) {} void process_video (boost::shared_ptr<Image>, int, boost::shared_ptr<Subtitle>); - void process_audio (uint8_t *, int) {} + void process_audio (float**, int) {} void process_end () {} }; diff --git a/src/lib/j2k_still_encoder.h b/src/lib/j2k_still_encoder.h index c48b9e69c..3c8f236ee 100644 --- a/src/lib/j2k_still_encoder.h +++ b/src/lib/j2k_still_encoder.h @@ -38,6 +38,6 @@ public: void process_begin (int64_t audio_channel_layout, AVSampleFormat audio_sample_format) {} void process_video (boost::shared_ptr<Image>, int, boost::shared_ptr<Subtitle>); - void process_audio (uint8_t *, int) {} + void process_audio (float**, int) {} void process_end () {} }; diff --git a/src/lib/j2k_wav_encoder.cc b/src/lib/j2k_wav_encoder.cc index e5d120ad6..58f8a101f 100644 --- a/src/lib/j2k_wav_encoder.cc +++ b/src/lib/j2k_wav_encoder.cc @@ -49,8 +49,6 @@ J2KWAVEncoder::J2KWAVEncoder (shared_ptr<const FilmState> s, shared_ptr<const Op #ifdef HAVE_SWRESAMPLE , _swr_context (0) #endif - , _deinterleave_buffer_size (8192) - , _deinterleave_buffer (0) , _process_end (false) { /* Create sound output files with .tmp suffixes; we will rename @@ -68,15 +66,11 @@ J2KWAVEncoder::J2KWAVEncoder (shared_ptr<const FilmState> s, shared_ptr<const Op } _sound_files.push_back (f); } - - /* Create buffer for deinterleaving audio */ - _deinterleave_buffer = new uint8_t[_deinterleave_buffer_size]; } J2KWAVEncoder::~J2KWAVEncoder () { terminate_worker_threads (); - delete[] _deinterleave_buffer; close_sound_files (); } @@ -230,14 +224,15 @@ J2KWAVEncoder::process_begin (int64_t audio_channel_layout, AVSampleFormat audio stringstream s; s << "Will resample audio from " << _fs->audio_sample_rate() << " to " << _fs->target_sample_rate(); _log->log (s.str ()); - + + /* We will be using planar float data when we call the resampler */ _swr_context = swr_alloc_set_opts ( 0, audio_channel_layout, - audio_sample_format, + AV_SAMPLE_FMT_FLTP, _fs->target_sample_rate(), audio_channel_layout, - audio_sample_format, + AV_SAMPLE_FMT_FLTP, _fs->audio_sample_rate(), 0, 0 ); @@ -308,14 +303,13 @@ J2KWAVEncoder::process_end () #if HAVE_SWRESAMPLE if (_swr_context) { + float* out[_fs->audio_channels()]; + for (int i = 0; i < _fs->audio_channels(); ++i) { + out[i] = new float[256]; + } + while (1) { - uint8_t buffer[256 * _fs->bytes_per_sample() * _fs->audio_channels()]; - uint8_t* out[2] = { - buffer, - 0 - }; - - int const frames = swr_convert (_swr_context, out, 256, 0, 0); + int const frames = swr_convert (_swr_context, (uint8_t **) out, 256, 0, 0); if (frames < 0) { throw EncodeError ("could not run sample-rate converter"); @@ -325,7 +319,11 @@ J2KWAVEncoder::process_end () break; } - write_audio (buffer, frames * _fs->bytes_per_sample() * _fs->audio_channels()); + write_audio (out, frames); + } + + for (int i = 0; i < _fs->audio_channels(); ++i) { + delete[] out[i]; } swr_free (&_swr_context); @@ -344,97 +342,50 @@ J2KWAVEncoder::process_end () } void -J2KWAVEncoder::process_audio (uint8_t* data, int size) +J2KWAVEncoder::process_audio (float** data, int frames) { - /* This is a buffer we might use if we are sample-rate converting; - it will need freeing if so. - */ - uint8_t* out_buffer = 0; + float* resampled[_fs->audio_channels()]; - /* Maybe sample-rate convert */ #if HAVE_SWRESAMPLE + /* Maybe sample-rate convert */ if (_swr_context) { - uint8_t const * in[2] = { - data, - 0 - }; + /* Compute the resampled frames count and add 32 for luck */ + int const resampled_frames = ceil (frames * _fs->target_sample_rate() / _fs->audio_sample_rate()) + 32; - /* Here's samples per channel */ - int const samples = size / _fs->bytes_per_sample(); - - /* And here's frames (where 1 frame is a collection of samples, 1 for each channel, - so for 5.1 a frame would be 6 samples) - */ - 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 * _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]; - - uint8_t* out[2] = { - out_buffer, - 0 - }; + /* Make a buffer to put the result in */ + for (int i = 0; i < _fs->audio_channels(); ++i) { + resampled[i] = new float[resampled_frames]; + } /* Resample audio */ - int out_frames = swr_convert (_swr_context, out, out_buffer_size_frames, in, frames); + int out_frames = swr_convert (_swr_context, (uint8_t **) resampled, resampled_frames, (uint8_t const **) data, frames); if (out_frames < 0) { throw EncodeError ("could not run sample-rate converter"); } /* And point our variables at the resampled audio */ - data = out_buffer; - size = out_frames * _fs->audio_channels() * _fs->bytes_per_sample(); + data = resampled; + frames = resampled_frames; } #endif - write_audio (data, size); + write_audio (data, frames); - /* Delete the sample-rate conversion buffer, if it exists */ - delete[] out_buffer; +#if HAVE_SWRESAMPLE + if (_swr_context) { + for (int i = 0; i < _fs->audio_channels(); ++i) { + delete[] resampled[i]; + } + } +#endif } void -J2KWAVEncoder::write_audio (uint8_t* data, int size) +J2KWAVEncoder::write_audio (float** data, int frames) { - /* 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 ... */ - - /* Number of bytes left to read this time */ - int remaining = size; - /* Our position in the output buffers, in bytes */ - int position = 0; - while (remaining > 0) { - /* 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 += _fs->bytes_per_sample()) { - for (int k = 0; k < _fs->bytes_per_sample(); ++k) { - int const to = j + 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 / _fs->bytes_per_sample()); - break; - default: - throw EncodeError ("unknown audio sample format"); - } - } - - position += this_time; - remaining -= this_time * _fs->audio_channels(); + for (int i = 0; i < _fs->audio_channels(); ++i) { + sf_write_float (_sound_files[i], data[i], frames); } } diff --git a/src/lib/j2k_wav_encoder.h b/src/lib/j2k_wav_encoder.h index 87068ad3d..3fdefcb38 100644 --- a/src/lib/j2k_wav_encoder.h +++ b/src/lib/j2k_wav_encoder.h @@ -51,12 +51,12 @@ public: void process_begin (int64_t audio_channel_layout, AVSampleFormat audio_sample_format); void process_video (boost::shared_ptr<Image>, int, boost::shared_ptr<Subtitle>); - void process_audio (uint8_t *, int); + void process_audio (float**, int); void process_end (); private: - void write_audio (uint8_t* data, int size); + void write_audio (float** data, int frames); void encoder_thread (ServerDescription *); void close_sound_files (); void terminate_worker_threads (); @@ -66,8 +66,6 @@ private: #endif std::vector<SNDFILE*> _sound_files; - int _deinterleave_buffer_size; - uint8_t* _deinterleave_buffer; bool _process_end; std::list<boost::shared_ptr<DCPVideoFrame> > _queue; diff --git a/src/lib/util.cc b/src/lib/util.cc index dc0ee5642..47a86da9e 100644 --- a/src/lib/util.cc +++ b/src/lib/util.cc @@ -201,10 +201,8 @@ audio_sample_format_to_string (AVSampleFormat s) case AV_SAMPLE_FMT_S16: return "S16"; default: - break; + assert (false); } - - return "Unknown"; } /** @param s String representation of a sample format, as returned from audio_sample_format_to_string(). @@ -217,7 +215,7 @@ audio_sample_format_from_string (string s) return AV_SAMPLE_FMT_S16; } - return AV_SAMPLE_FMT_NONE; + assert (false); } /** @return Version of vobcopy that is on the path (and hence that we will use) */ |
