diff options
| author | Carl Hetherington <cth@carlh.net> | 2012-12-19 20:42:41 +0000 |
|---|---|---|
| committer | Carl Hetherington <cth@carlh.net> | 2012-12-19 20:42:41 +0000 |
| commit | 54a9c84e2b4d69b1e6ed669400f84b1604cc2369 (patch) | |
| tree | 18f914b82c073eef5f8f7b4c7ec86ede3072b075 /src/lib | |
| parent | dedac27070ac5ad65265a0db1fa316b3e436cea7 (diff) | |
Move audio into Encoder so that J2KStillEncoder can use it too. Rename J2KWAVEncoder -> J2KVideoEncoder.
Diffstat (limited to 'src/lib')
| -rw-r--r-- | src/lib/ab_transcode_job.cc | 1 | ||||
| -rw-r--r-- | src/lib/encoder.cc | 152 | ||||
| -rw-r--r-- | src/lib/encoder.h | 26 | ||||
| -rw-r--r-- | src/lib/encoder_factory.cc | 4 | ||||
| -rw-r--r-- | src/lib/j2k_still_encoder.h | 1 | ||||
| -rw-r--r-- | src/lib/j2k_video_encoder.cc (renamed from src/lib/j2k_wav_encoder.cc) | 167 | ||||
| -rw-r--r-- | src/lib/j2k_video_encoder.h (renamed from src/lib/j2k_wav_encoder.h) | 31 | ||||
| -rw-r--r-- | src/lib/transcode_job.cc | 2 | ||||
| -rw-r--r-- | src/lib/wscript | 2 |
9 files changed, 198 insertions, 188 deletions
diff --git a/src/lib/ab_transcode_job.cc b/src/lib/ab_transcode_job.cc index b9538ce2e..da9ce7933 100644 --- a/src/lib/ab_transcode_job.cc +++ b/src/lib/ab_transcode_job.cc @@ -19,7 +19,6 @@ #include <stdexcept> #include "ab_transcode_job.h" -#include "j2k_wav_encoder.h" #include "film.h" #include "format.h" #include "filter.h" diff --git a/src/lib/encoder.cc b/src/lib/encoder.cc index 1fc7d5997..f352f5a52 100644 --- a/src/lib/encoder.cc +++ b/src/lib/encoder.cc @@ -21,11 +21,17 @@ * @brief Parent class for classes which can encode video and audio frames. */ +#include <boost/filesystem.hpp> #include "encoder.h" #include "util.h" #include "options.h" +#include "film.h" +#include "log.h" +#include "exceptions.h" using std::pair; +using std::stringstream; +using std::vector; using namespace boost; int const Encoder::_history_size = 25; @@ -39,11 +45,109 @@ Encoder::Encoder (shared_ptr<const Film> f, shared_ptr<const EncodeOptions> o) , _just_skipped (false) , _video_frame (0) , _audio_frame (0) +#ifdef HAVE_SWRESAMPLE + , _swr_context (0) +#endif + , _audio_frames_written (0) { + if (_film->audio_stream()) { + /* 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) { + SF_INFO sf_info; + sf_info.samplerate = dcp_audio_sample_rate (_film->audio_stream()->sample_rate()); + /* We write mono files */ + sf_info.channels = 1; + sf_info.format = SF_FORMAT_WAV | SF_FORMAT_PCM_24; + SNDFILE* f = sf_open (_opt->multichannel_audio_out_path (i, true).c_str (), SFM_WRITE, &sf_info); + if (f == 0) { + throw CreateFileError (_opt->multichannel_audio_out_path (i, true)); + } + _sound_files.push_back (f); + } + } +} + +Encoder::~Encoder () +{ + close_sound_files (); +} +void +Encoder::process_begin () +{ + if (_film->audio_stream() && _film->audio_stream()->sample_rate() != _film->target_audio_sample_rate()) { +#ifdef HAVE_SWRESAMPLE + + stringstream s; + s << "Will resample audio from " << _film->audio_stream()->sample_rate() << " to " << _film->target_audio_sample_rate(); + _film->log()->log (s.str ()); + + /* We will be using planar float data when we call the resampler */ + _swr_context = swr_alloc_set_opts ( + 0, + _film->audio_stream()->channel_layout(), + AV_SAMPLE_FMT_FLTP, + _film->target_audio_sample_rate(), + _film->audio_stream()->channel_layout(), + AV_SAMPLE_FMT_FLTP, + _film->audio_stream()->sample_rate(), + 0, 0 + ); + + swr_init (_swr_context); +#else + throw EncodeError ("Cannot resample audio as libswresample is not present"); +#endif + } else { +#ifdef HAVE_SWRESAMPLE + _swr_context = 0; +#endif + } } +void +Encoder::process_end () +{ +#if HAVE_SWRESAMPLE + if (_film->audio_stream() && _swr_context) { + + shared_ptr<AudioBuffers> out (new AudioBuffers (_film->audio_stream()->channels(), 256)); + + while (1) { + int const frames = swr_convert (_swr_context, (uint8_t **) out->data(), 256, 0, 0); + + if (frames < 0) { + throw EncodeError ("could not run sample-rate converter"); + } + + if (frames == 0) { + break; + } + + out->set_frames (frames); + write_audio (out); + } + + swr_free (&_swr_context); + } +#endif + + if (_film->audio_stream()) { + close_sound_files (); + + /* Rename .wav.tmp files to .wav */ + for (int i = 0; i < _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)); + } + boost::filesystem::rename (_opt->multichannel_audio_out_path (i, true), _opt->multichannel_audio_out_path (i, false)); + } + } +} + /** @return an estimate of the current number of frames we are encoding per second, * or 0 if not known. */ @@ -152,7 +256,53 @@ Encoder::process_audio (shared_ptr<AudioBuffers> data) data = trimmed; } - do_process_audio (data); +#if HAVE_SWRESAMPLE + /* Maybe sample-rate convert */ + if (_swr_context) { + + /* Compute the resampled frames count and add 32 for luck */ + int const max_resampled_frames = ceil ((int64_t) data->frames() * _film->target_audio_sample_rate() / _film->audio_stream()->sample_rate()) + 32; + + shared_ptr<AudioBuffers> resampled (new AudioBuffers (_film->audio_stream()->channels(), max_resampled_frames)); + + /* Resample audio */ + int const resampled_frames = swr_convert ( + _swr_context, (uint8_t **) resampled->data(), max_resampled_frames, (uint8_t const **) data->data(), data->frames() + ); + + if (resampled_frames < 0) { + throw EncodeError ("could not run sample-rate converter"); + } + + resampled->set_frames (resampled_frames); + + /* And point our variables at the resampled audio */ + data = resampled; + } +#endif + 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) { + sf_write_float (_sound_files[i], audio->data(i), audio->frames()); + } + + _audio_frames_written += audio->frames (); +} + +void +Encoder::close_sound_files () +{ + for (vector<SNDFILE*>::iterator i = _sound_files.begin(); i != _sound_files.end(); ++i) { + sf_close (*i); + } + + _sound_files.clear (); +} + diff --git a/src/lib/encoder.h b/src/lib/encoder.h index 64f113d74..f355daff7 100644 --- a/src/lib/encoder.h +++ b/src/lib/encoder.h @@ -31,6 +31,12 @@ extern "C" { #include <libavutil/samplefmt.h> } +#ifdef HAVE_SWRESAMPLE +extern "C" { +#include <libswresample/swresample.h> +} +#endif +#include <sndfile.h> #include "util.h" #include "video_sink.h" #include "audio_sink.h" @@ -55,10 +61,10 @@ class Encoder : public VideoSink, public AudioSink { public: Encoder (boost::shared_ptr<const Film> f, boost::shared_ptr<const EncodeOptions> o); - virtual ~Encoder () {} + virtual ~Encoder (); /** Called to indicate that a processing run is about to begin */ - virtual void process_begin () {} + virtual void process_begin (); /** Call with a frame of video. * @param i Video frame image. @@ -70,7 +76,7 @@ public: void process_audio (boost::shared_ptr<AudioBuffers>); /** Called when a processing run has finished */ - virtual void process_end () {} + virtual void process_end (); float current_frames_per_second () const; bool skipping () const; @@ -84,9 +90,6 @@ protected: */ virtual void do_process_video (boost::shared_ptr<Image> i, boost::shared_ptr<Subtitle> s) = 0; - /** Called with some audio data */ - virtual void do_process_audio (boost::shared_ptr<AudioBuffers>) = 0; - void frame_done (); void frame_skipped (); @@ -110,6 +113,17 @@ protected: SourceFrame _video_frame; /** Number of audio frames received so far */ int64_t _audio_frame; + +private: + void close_sound_files (); + void write_audio (boost::shared_ptr<const AudioBuffers> audio); + +#if HAVE_SWRESAMPLE + SwrContext* _swr_context; +#endif + + std::vector<SNDFILE*> _sound_files; + int64_t _audio_frames_written; }; #endif diff --git a/src/lib/encoder_factory.cc b/src/lib/encoder_factory.cc index fe4d50ef3..8384ecee3 100644 --- a/src/lib/encoder_factory.cc +++ b/src/lib/encoder_factory.cc @@ -22,7 +22,7 @@ */ #include <boost/filesystem.hpp> -#include "j2k_wav_encoder.h" +#include "j2k_video_encoder.h" #include "j2k_still_encoder.h" #include "film.h" @@ -35,5 +35,5 @@ encoder_factory (shared_ptr<const Film> f, shared_ptr<const EncodeOptions> o) return shared_ptr<Encoder> (new J2KStillEncoder (f, o)); } - return shared_ptr<Encoder> (new J2KWAVEncoder (f, o)); + return shared_ptr<Encoder> (new J2KVideoEncoder (f, o)); } diff --git a/src/lib/j2k_still_encoder.h b/src/lib/j2k_still_encoder.h index 7c302474c..ad2a5d277 100644 --- a/src/lib/j2k_still_encoder.h +++ b/src/lib/j2k_still_encoder.h @@ -39,7 +39,6 @@ public: private: void do_process_video (boost::shared_ptr<Image>, boost::shared_ptr<Subtitle>); - void do_process_audio (boost::shared_ptr<AudioBuffers>) {} void link (std::string, std::string) const; }; diff --git a/src/lib/j2k_wav_encoder.cc b/src/lib/j2k_video_encoder.cc index e76591552..0f010b933 100644 --- a/src/lib/j2k_wav_encoder.cc +++ b/src/lib/j2k_video_encoder.cc @@ -17,8 +17,8 @@ */ -/** @file src/j2k_wav_encoder.cc - * @brief An encoder which writes JPEG2000 and WAV files. +/** @file src/j2k_video_encoder.cc + * @brief An encoder which writes JPEG2000 files, where they are video (ie not still). */ #include <sstream> @@ -30,7 +30,7 @@ #include <boost/lexical_cast.hpp> #include <sndfile.h> #include <openjpeg.h> -#include "j2k_wav_encoder.h" +#include "j2k_video_encoder.h" #include "config.h" #include "options.h" #include "exceptions.h" @@ -51,41 +51,20 @@ using boost::shared_ptr; using boost::thread; using boost::lexical_cast; -J2KWAVEncoder::J2KWAVEncoder (shared_ptr<const Film> f, shared_ptr<const EncodeOptions> o) +J2KVideoEncoder::J2KVideoEncoder (shared_ptr<const Film> f, shared_ptr<const EncodeOptions> o) : Encoder (f, o) -#ifdef HAVE_SWRESAMPLE - , _swr_context (0) -#endif - , _audio_frames_written (0) , _process_end (false) { - if (_film->audio_stream()) { - /* 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) { - SF_INFO sf_info; - sf_info.samplerate = dcp_audio_sample_rate (_film->audio_stream()->sample_rate()); - /* We write mono files */ - sf_info.channels = 1; - sf_info.format = SF_FORMAT_WAV | SF_FORMAT_PCM_24; - SNDFILE* f = sf_open (_opt->multichannel_audio_out_path (i, true).c_str (), SFM_WRITE, &sf_info); - if (f == 0) { - throw CreateFileError (_opt->multichannel_audio_out_path (i, true)); - } - _sound_files.push_back (f); - } - } + } -J2KWAVEncoder::~J2KWAVEncoder () +J2KVideoEncoder::~J2KVideoEncoder () { terminate_worker_threads (); - close_sound_files (); } void -J2KWAVEncoder::terminate_worker_threads () +J2KVideoEncoder::terminate_worker_threads () { boost::mutex::scoped_lock lock (_worker_mutex); _process_end = true; @@ -99,17 +78,7 @@ J2KWAVEncoder::terminate_worker_threads () } void -J2KWAVEncoder::close_sound_files () -{ - for (vector<SNDFILE*>::iterator i = _sound_files.begin(); i != _sound_files.end(); ++i) { - sf_close (*i); - } - - _sound_files.clear (); -} - -void -J2KWAVEncoder::do_process_video (shared_ptr<Image> yuv, shared_ptr<Subtitle> sub) +J2KVideoEncoder::do_process_video (shared_ptr<Image> yuv, shared_ptr<Subtitle> sub) { boost::mutex::scoped_lock lock (_worker_mutex); @@ -144,7 +113,7 @@ J2KWAVEncoder::do_process_video (shared_ptr<Image> yuv, shared_ptr<Subtitle> sub } void -J2KWAVEncoder::encoder_thread (ServerDescription* server) +J2KVideoEncoder::encoder_thread (ServerDescription* server) { /* Number of seconds that we currently wait between attempts to connect to the server; not relevant for localhost @@ -228,53 +197,28 @@ J2KWAVEncoder::encoder_thread (ServerDescription* server) } void -J2KWAVEncoder::process_begin () +J2KVideoEncoder::process_begin () { - if (_film->audio_stream() && _film->audio_stream()->sample_rate() != _film->target_audio_sample_rate()) { -#ifdef HAVE_SWRESAMPLE - - stringstream s; - s << "Will resample audio from " << _film->audio_stream()->sample_rate() << " to " << _film->target_audio_sample_rate(); - _film->log()->log (s.str ()); - - /* We will be using planar float data when we call the resampler */ - _swr_context = swr_alloc_set_opts ( - 0, - _film->audio_stream()->channel_layout(), - AV_SAMPLE_FMT_FLTP, - _film->target_audio_sample_rate(), - _film->audio_stream()->channel_layout(), - AV_SAMPLE_FMT_FLTP, - _film->audio_stream()->sample_rate(), - 0, 0 - ); - - swr_init (_swr_context); -#else - throw EncodeError ("Cannot resample audio as libswresample is not present"); -#endif - } else { -#ifdef HAVE_SWRESAMPLE - _swr_context = 0; -#endif - } + Encoder::process_begin (); for (int i = 0; i < Config::instance()->num_local_encoding_threads (); ++i) { - _worker_threads.push_back (new boost::thread (boost::bind (&J2KWAVEncoder::encoder_thread, this, (ServerDescription *) 0))); + _worker_threads.push_back (new boost::thread (boost::bind (&J2KVideoEncoder::encoder_thread, this, (ServerDescription *) 0))); } vector<ServerDescription*> servers = Config::instance()->servers (); for (vector<ServerDescription*>::iterator i = servers.begin(); i != servers.end(); ++i) { for (int j = 0; j < (*i)->threads (); ++j) { - _worker_threads.push_back (new boost::thread (boost::bind (&J2KWAVEncoder::encoder_thread, this, *i))); + _worker_threads.push_back (new boost::thread (boost::bind (&J2KVideoEncoder::encoder_thread, this, *i))); } } } void -J2KWAVEncoder::process_end () +J2KVideoEncoder::process_end () { + Encoder::process_end (); + boost::mutex::scoped_lock lock (_worker_mutex); _film->log()->log ("Clearing queue of " + lexical_cast<string> (_queue.size ())); @@ -311,84 +255,5 @@ J2KWAVEncoder::process_end () _film->log()->log (String::compose ("Local encode failed (%1)", e.what ())); } } - -#if HAVE_SWRESAMPLE - if (_film->audio_stream() && _swr_context) { - - shared_ptr<AudioBuffers> out (new AudioBuffers (_film->audio_stream()->channels(), 256)); - - while (1) { - int const frames = swr_convert (_swr_context, (uint8_t **) out->data(), 256, 0, 0); - - if (frames < 0) { - throw EncodeError ("could not run sample-rate converter"); - } - - if (frames == 0) { - break; - } - - out->set_frames (frames); - write_audio (out); - } - - swr_free (&_swr_context); - } -#endif - - if (_film->audio_stream()) { - close_sound_files (); - - /* Rename .wav.tmp files to .wav */ - for (int i = 0; i < _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)); - } - boost::filesystem::rename (_opt->multichannel_audio_out_path (i, true), _opt->multichannel_audio_out_path (i, false)); - } - } -} - -void -J2KWAVEncoder::do_process_audio (shared_ptr<AudioBuffers> audio) -{ - shared_ptr<AudioBuffers> resampled; - -#if HAVE_SWRESAMPLE - /* Maybe sample-rate convert */ - if (_swr_context) { - - /* Compute the resampled frames count and add 32 for luck */ - int const max_resampled_frames = ceil ((int64_t) audio->frames() * _film->target_audio_sample_rate() / _film->audio_stream()->sample_rate()) + 32; - - resampled.reset (new AudioBuffers (_film->audio_stream()->channels(), max_resampled_frames)); - - /* Resample audio */ - int const resampled_frames = swr_convert ( - _swr_context, (uint8_t **) resampled->data(), max_resampled_frames, (uint8_t const **) audio->data(), audio->frames() - ); - - if (resampled_frames < 0) { - throw EncodeError ("could not run sample-rate converter"); - } - - resampled->set_frames (resampled_frames); - - /* And point our variables at the resampled audio */ - audio = resampled; - } -#endif - - write_audio (audio); -} - -void -J2KWAVEncoder::write_audio (shared_ptr<const AudioBuffers> audio) -{ - for (int i = 0; i < _film->audio_channels(); ++i) { - sf_write_float (_sound_files[i], audio->data(i), audio->frames()); - } - - _audio_frames_written += audio->frames (); } diff --git a/src/lib/j2k_wav_encoder.h b/src/lib/j2k_video_encoder.h index 064f4221e..604110576 100644 --- a/src/lib/j2k_wav_encoder.h +++ b/src/lib/j2k_video_encoder.h @@ -17,8 +17,8 @@ */ -/** @file src/j2k_wav_encoder.h - * @brief An encoder which writes JPEG2000 and WAV files. +/** @file src/j2k_video_encoder.h + * @brief An encoder which writes JPEG2000 files, where they are video (ie not still). */ #include <list> @@ -26,12 +26,6 @@ #include <boost/thread/condition.hpp> #include <boost/thread/mutex.hpp> #include <boost/thread.hpp> -#ifdef HAVE_SWRESAMPLE -extern "C" { -#include <libswresample/swresample.h> -} -#endif -#include <sndfile.h> #include "encoder.h" class ServerDescription; @@ -39,16 +33,15 @@ class DCPVideoFrame; class Image; class Log; class Subtitle; -class AudioBuffers; -/** @class J2KWAVEncoder - * @brief An encoder which writes JPEG2000 and WAV files. +/** @class J2KVideoEncoder + * @brief An encoder which writes JPEG2000 files, where they are video (ie not still). */ -class J2KWAVEncoder : public Encoder +class J2KVideoEncoder : public Encoder { public: - J2KWAVEncoder (boost::shared_ptr<const Film>, boost::shared_ptr<const EncodeOptions>); - ~J2KWAVEncoder (); + J2KVideoEncoder (boost::shared_ptr<const Film>, boost::shared_ptr<const EncodeOptions>); + ~J2KVideoEncoder (); void process_begin (); void process_end (); @@ -56,20 +49,10 @@ public: private: void do_process_video (boost::shared_ptr<Image>, boost::shared_ptr<Subtitle>); - void do_process_audio (boost::shared_ptr<AudioBuffers>); - void write_audio (boost::shared_ptr<const AudioBuffers> audio); void encoder_thread (ServerDescription *); - void close_sound_files (); void terminate_worker_threads (); -#if HAVE_SWRESAMPLE - SwrContext* _swr_context; -#endif - - std::vector<SNDFILE*> _sound_files; - int64_t _audio_frames_written; - bool _process_end; std::list<boost::shared_ptr<DCPVideoFrame> > _queue; std::list<boost::thread *> _worker_threads; diff --git a/src/lib/transcode_job.cc b/src/lib/transcode_job.cc index 477c73c75..b429c4646 100644 --- a/src/lib/transcode_job.cc +++ b/src/lib/transcode_job.cc @@ -24,12 +24,12 @@ #include <iostream> #include <iomanip> #include "transcode_job.h" -#include "j2k_wav_encoder.h" #include "film.h" #include "format.h" #include "transcoder.h" #include "log.h" #include "encoder_factory.h" +#include "encoder.h" using std::string; using std::stringstream; diff --git a/src/lib/wscript b/src/lib/wscript index 5d3fbb906..d13de4f3b 100644 --- a/src/lib/wscript +++ b/src/lib/wscript @@ -38,7 +38,7 @@ def build(bld): image.cc imagemagick_decoder.cc j2k_still_encoder.cc - j2k_wav_encoder.cc + j2k_video_encoder.cc job.cc job_manager.cc log.cc |
