From 4fbd1901fdabc829cfa7e7d4d0c1272bba87033c Mon Sep 17 00:00:00 2001 From: Carl Hetherington Date: Thu, 15 Nov 2012 22:26:16 +0000 Subject: [PATCH] Untested external audio support; AB transcodes still broken. --- ChangeLog | 3 ++ src/lib/ab_transcoder.cc | 18 ++++--- src/lib/ab_transcoder.h | 7 +-- src/lib/audio_decoder.cc | 17 ++++++ src/lib/audio_decoder.h | 28 ++++++++++ src/lib/decoder.cc | 76 --------------------------- src/lib/decoder.h | 67 ++---------------------- src/lib/decoder_factory.cc | 17 ++++-- src/lib/decoder_factory.h | 8 +-- src/lib/examine_content_job.cc | 12 +++-- src/lib/examine_content_job.h | 5 -- src/lib/external_audio_decoder.cc | 87 +++++++++++++++++++++++++++++++ src/lib/external_audio_decoder.h | 10 ++++ src/lib/ffmpeg_decoder.cc | 6 ++- src/lib/ffmpeg_decoder.h | 5 +- src/lib/film.cc | 20 +++---- src/lib/imagemagick_decoder.cc | 1 + src/lib/imagemagick_decoder.h | 4 +- src/lib/transcoder.cc | 29 ++++++++--- src/lib/transcoder.h | 15 +++--- src/lib/util.cc | 12 +++-- src/lib/util.h | 1 + src/lib/video_decoder.cc | 79 ++++++++++++++++++++++++++++ src/lib/video_decoder.h | 60 +++++++++++++++++++++ src/lib/wscript | 3 ++ 25 files changed, 393 insertions(+), 197 deletions(-) create mode 100644 src/lib/audio_decoder.cc create mode 100644 src/lib/audio_decoder.h create mode 100644 src/lib/external_audio_decoder.cc create mode 100644 src/lib/external_audio_decoder.h create mode 100644 src/lib/video_decoder.cc create mode 100644 src/lib/video_decoder.h diff --git a/ChangeLog b/ChangeLog index 167536a88..7d73e186f 100644 --- a/ChangeLog +++ b/ChangeLog @@ -2,6 +2,9 @@ * Default to using a DCI name. + * Support for using external sound files instead + of the ones in the video source. + 2012-11-14 Carl Hetherington * Rearrange the GUI a bit to tidy things up. diff --git a/src/lib/ab_transcoder.cc b/src/lib/ab_transcoder.cc index 868ce9079..9999eda90 100644 --- a/src/lib/ab_transcoder.cc +++ b/src/lib/ab_transcoder.cc @@ -21,7 +21,8 @@ #include #include "ab_transcoder.h" #include "film.h" -#include "decoder.h" +#include "video_decoder.h" +#include "audio_decoder.h" #include "encoder.h" #include "job.h" #include "options.h" @@ -54,9 +55,11 @@ ABTranscoder::ABTranscoder ( _da = decoder_factory (_film_a, o, j); _db = decoder_factory (_film_b, o, j); - _da->Video.connect (bind (&ABTranscoder::process_video, this, _1, _2, 0)); - _db->Video.connect (bind (&ABTranscoder::process_video, this, _1, _2, 1)); - _da->Audio.connect (bind (&Encoder::process_audio, e, _1)); + /* XXX */ + +// _da->Video.connect (bind (&ABTranscoder::process_video, this, _1, _2, 0)); +// _db->Video.connect (bind (&ABTranscoder::process_video, this, _1, _2, 1)); +// _da->Audio.connect (bind (&Encoder::process_audio, e, _1)); } ABTranscoder::~ABTranscoder () @@ -100,10 +103,11 @@ ABTranscoder::go () _encoder->process_begin (); while (1) { - bool const a = _da->pass (); - bool const b = _db->pass (); + bool const va = _da.first->pass (); + bool const vb = _db.first->pass (); + bool const a = _da.first->pass (); - if (a && b) { + if (va && vb && a) { break; } } diff --git a/src/lib/ab_transcoder.h b/src/lib/ab_transcoder.h index c75398b5c..c951329f2 100644 --- a/src/lib/ab_transcoder.h +++ b/src/lib/ab_transcoder.h @@ -28,7 +28,8 @@ class Job; class Encoder; -class Decoder; +class VideoDecoder; +class AudioDecoder; class Options; class Image; class Log; @@ -62,7 +63,7 @@ private: boost::shared_ptr _opt; Job* _job; boost::shared_ptr _encoder; - boost::shared_ptr _da; - boost::shared_ptr _db; + std::pair, boost::shared_ptr > _da; + std::pair, boost::shared_ptr > _db; boost::shared_ptr _image; }; diff --git a/src/lib/audio_decoder.cc b/src/lib/audio_decoder.cc new file mode 100644 index 000000000..b34bf1ed4 --- /dev/null +++ b/src/lib/audio_decoder.cc @@ -0,0 +1,17 @@ +#include "audio_decoder.h" +#include "stream.h" + +using boost::optional; +using boost::shared_ptr; + +AudioDecoder::AudioDecoder (shared_ptr f, shared_ptr o, Job* j) + : Decoder (f, o, j) +{ + +} + +void +AudioDecoder::set_audio_stream (optional s) +{ + _audio_stream = s; +} diff --git a/src/lib/audio_decoder.h b/src/lib/audio_decoder.h new file mode 100644 index 000000000..f9948f597 --- /dev/null +++ b/src/lib/audio_decoder.h @@ -0,0 +1,28 @@ +#ifndef DVDOMATIC_AUDIO_DECODER_H +#define DVDOMATIC_AUDIO_DECODER_H + +#include "audio_source.h" +#include "stream.h" +#include "decoder.h" + +class AudioDecoder : public AudioSource, public virtual Decoder +{ +public: + AudioDecoder (boost::shared_ptr, boost::shared_ptr, Job *); + + virtual void set_audio_stream (boost::optional); + + boost::optional audio_stream () const { + return _audio_stream; + } + + std::vector audio_streams () const { + return _audio_streams; + } + +protected: + boost::optional _audio_stream; + std::vector _audio_streams; +}; + +#endif diff --git a/src/lib/decoder.cc b/src/lib/decoder.cc index 8d087b6ee..2bacf58e7 100644 --- a/src/lib/decoder.cc +++ b/src/lib/decoder.cc @@ -53,82 +53,6 @@ Decoder::Decoder (boost::shared_ptr f, boost::shared_ptr o, : _film (f) , _opt (o) , _job (j) - , _video_frame (0) { } - -/** Start decoding */ -void -Decoder::go () -{ - if (_job && !_film->dcp_length()) { - _job->set_progress_unknown (); - } - - while (pass () == false) { - if (_job && _film->dcp_length()) { - _job->set_progress (float (_video_frame) / _film->length().get()); - } - } -} - -/** Called by subclasses to tell the world that some video data is ready. - * We find a subtitle then emit it for listeners. - * @param frame to decode; caller manages memory. - */ -void -Decoder::emit_video (shared_ptr image) -{ - shared_ptr sub; - if (_timed_subtitle && _timed_subtitle->displayed_at (double (video_frame()) / _film->frames_per_second())) { - sub = _timed_subtitle->subtitle (); - } - - signal_video (image, sub); -} - -void -Decoder::repeat_last_video () -{ - if (!_last_image) { - _last_image.reset (new CompactImage (pixel_format(), native_size())); - _last_image->make_black (); - } - - signal_video (_last_image, _last_subtitle); -} - -void -Decoder::signal_video (shared_ptr image, shared_ptr sub) -{ - TIMING ("Decoder emits %1", _video_frame); - Video (image, sub); - ++_video_frame; - - _last_image = image; - _last_subtitle = sub; -} - -void -Decoder::emit_subtitle (shared_ptr s) -{ - _timed_subtitle = s; - - if (_timed_subtitle && _opt->apply_crop) { - Position const p = _timed_subtitle->subtitle()->position (); - _timed_subtitle->subtitle()->set_position (Position (p.x - _film->crop().left, p.y - _film->crop().top)); - } -} - -void -Decoder::set_audio_stream (optional s) -{ - _audio_stream = s; -} - -void -Decoder::set_subtitle_stream (optional s) -{ - _subtitle_stream = s; -} diff --git a/src/lib/decoder.h b/src/lib/decoder.h index 805f6e521..cd033b5f9 100644 --- a/src/lib/decoder.h +++ b/src/lib/decoder.h @@ -47,84 +47,27 @@ class FilterGraph; /** @class Decoder. * @brief Parent class for decoders of content. * - * These classes can be instructed run through their content - * (by calling ::go), and they emit signals when video or audio data is ready for something else - * to process. + * These classes can be instructed run through their content (by + * calling ::go), and they emit signals when video or audio data is + * ready for something else to process. */ -class Decoder : public VideoSource, public AudioSource +class Decoder { public: Decoder (boost::shared_ptr, boost::shared_ptr, Job *); virtual ~Decoder () {} - /* Methods to query our input video */ - - /** @return video frames per second, or 0 if unknown */ - virtual float frames_per_second () const = 0; - /** @return native size in pixels */ - virtual Size native_size () const = 0; - - virtual int time_base_numerator () const = 0; - virtual int time_base_denominator () const = 0; - virtual int sample_aspect_ratio_numerator () const = 0; - virtual int sample_aspect_ratio_denominator () const = 0; - virtual bool pass () = 0; - void go (); - - SourceFrame video_frame () const { - return _video_frame; - } - - virtual void set_audio_stream (boost::optional); - virtual void set_subtitle_stream (boost::optional); - - boost::optional audio_stream () const { - return _audio_stream; - } - - boost::optional subtitle_stream () const { - return _subtitle_stream; - } - - std::vector audio_streams () const { - return _audio_streams; - } - - std::vector subtitle_streams () const { - return _subtitle_streams; - } protected: + virtual void set_progress () const {} - virtual PixelFormat pixel_format () const = 0; - - void emit_video (boost::shared_ptr); - void emit_subtitle (boost::shared_ptr); - void repeat_last_video (); - /** our Film */ boost::shared_ptr _film; /** our options */ boost::shared_ptr _opt; /** associated Job, or 0 */ Job* _job; - - boost::optional _audio_stream; - boost::optional _subtitle_stream; - - std::vector _audio_streams; - std::vector _subtitle_streams; - -private: - void signal_video (boost::shared_ptr, boost::shared_ptr); - - SourceFrame _video_frame; - - boost::shared_ptr _timed_subtitle; - - boost::shared_ptr _last_image; - boost::shared_ptr _last_subtitle; }; #endif diff --git a/src/lib/decoder_factory.cc b/src/lib/decoder_factory.cc index bb6eff971..e9b5bfa9e 100644 --- a/src/lib/decoder_factory.cc +++ b/src/lib/decoder_factory.cc @@ -25,19 +25,30 @@ #include "ffmpeg_decoder.h" #include "imagemagick_decoder.h" #include "film.h" +#include "external_audio_decoder.h" using std::string; +using std::pair; +using std::make_pair; using boost::shared_ptr; -shared_ptr +pair, shared_ptr > decoder_factory ( shared_ptr f, shared_ptr o, Job* j ) { if (boost::filesystem::is_directory (f->content_path()) || f->content_type() == STILL) { /* A single image file, or a directory of them */ - return shared_ptr (new ImageMagickDecoder (f, o, j)); + return make_pair ( + shared_ptr (new ImageMagickDecoder (f, o, j)), + shared_ptr () + ); + } + + shared_ptr fd (new FFmpegDecoder (f, o, j)); + if (f->use_content_audio()) { + return make_pair (fd, fd); } - return shared_ptr (new FFmpegDecoder (f, o, j)); + return make_pair (fd, shared_ptr (new ExternalAudioDecoder (f, o, j))); } diff --git a/src/lib/decoder_factory.h b/src/lib/decoder_factory.h index 765b38816..1f3690611 100644 --- a/src/lib/decoder_factory.h +++ b/src/lib/decoder_factory.h @@ -18,15 +18,15 @@ */ /** @file src/decoder_factory.h - * @brief A method to create an appropriate decoder for some content. + * @brief A method to create appropriate decoders for some content. */ -class Decoder; class Film; class Options; class Job; -class Log; +class VideoDecoder; +class AudioDecoder; -extern boost::shared_ptr decoder_factory ( +extern std::pair, boost::shared_ptr > decoder_factory ( boost::shared_ptr, boost::shared_ptr, Job * ); diff --git a/src/lib/examine_content_job.cc b/src/lib/examine_content_job.cc index b13e9d9d5..8db74801f 100644 --- a/src/lib/examine_content_job.cc +++ b/src/lib/examine_content_job.cc @@ -30,9 +30,11 @@ #include "transcoder.h" #include "log.h" #include "film.h" +#include "video_decoder.h" using std::string; using std::vector; +using std::pair; using boost::shared_ptr; ExamineContentJob::ExamineContentJob (shared_ptr f, shared_ptr req) @@ -72,10 +74,14 @@ ExamineContentJob::run () descend (0.5); - _decoder = decoder_factory (_film, o, this); - _decoder->go (); + pair, shared_ptr > decoders = decoder_factory (_film, o, this); - _film->set_length (_decoder->video_frame()); + set_progress_unknown (); + while (!decoders.first->pass()) { + /* keep going */ + } + + _film->set_length (decoders.first->video_frame()); _film->log()->log (String::compose ("Video length is %1 frames", _film->length())); diff --git a/src/lib/examine_content_job.h b/src/lib/examine_content_job.h index d87bd0876..2004aca83 100644 --- a/src/lib/examine_content_job.h +++ b/src/lib/examine_content_job.h @@ -23,8 +23,6 @@ #include "job.h" -class Decoder; - /** @class ExamineContentJob * @brief A class to run through content at high speed to find its length. */ @@ -36,8 +34,5 @@ public: std::string name () const; void run (); - -private: - boost::shared_ptr _decoder; }; diff --git a/src/lib/external_audio_decoder.cc b/src/lib/external_audio_decoder.cc new file mode 100644 index 000000000..99dd1ded0 --- /dev/null +++ b/src/lib/external_audio_decoder.cc @@ -0,0 +1,87 @@ +#include +#include "external_audio_decoder.h" +#include "film.h" +#include "exceptions.h" + +using std::vector; +using std::string; +using std::min; +using boost::shared_ptr; + +ExternalAudioDecoder::ExternalAudioDecoder (shared_ptr f, shared_ptr o, Job* j) + : Decoder (f, o, j) + , AudioDecoder (f, o, j) +{ + +} + +bool +ExternalAudioDecoder::pass () +{ + vector const files = _film->external_audio (); + + int N = 0; + for (size_t i = 0; i < files.size(); ++i) { + if (!files[i].empty()) { + N = i + 1; + } + } + + if (N == 0) { + return true; + } + + bool first = true; + sf_count_t frames = 0; + + vector sndfiles; + for (vector::const_iterator i = files.begin(); i != files.end(); ++i) { + if (i->empty ()) { + sndfiles.push_back (0); + } else { + SF_INFO info; + SNDFILE* s = sf_open (i->c_str(), SFM_READ, &info); + if (!s) { + throw DecodeError ("could not open external audio file for reading"); + } + + if (info.channels != 1) { + throw DecodeError ("external audio files must be mono"); + } + + sndfiles.push_back (s); + + if (first) { + /* XXX: nasty magic value */ + AudioStream st ("DVDOMATIC-EXTERNAL", -1, info.samplerate, av_get_default_channel_layout (info.channels)); + _audio_streams.push_back (st); + _audio_stream = st; + frames = info.frames; + first = false; + } else { + if (info.frames != frames) { + throw DecodeError ("external audio files have differing lengths"); + } + } + } + } + + sf_count_t const block = 65536; + + shared_ptr audio (new AudioBuffers (_audio_stream.get().channels(), block)); + while (frames > 0) { + sf_count_t const this_time = min (block, frames); + for (size_t i = 0; i < sndfiles.size(); ++i) { + if (!sndfiles[i]) { + audio->make_silent (i); + } else { + sf_read_float (sndfiles[i], audio->data(i), block); + } + } + + Audio (audio); + frames -= this_time; + } + + return true; +} diff --git a/src/lib/external_audio_decoder.h b/src/lib/external_audio_decoder.h new file mode 100644 index 000000000..3cc431479 --- /dev/null +++ b/src/lib/external_audio_decoder.h @@ -0,0 +1,10 @@ +#include "decoder.h" +#include "audio_decoder.h" + +class ExternalAudioDecoder : public AudioDecoder +{ +public: + ExternalAudioDecoder (boost::shared_ptr, boost::shared_ptr, Job *); + + bool pass (); +}; diff --git a/src/lib/ffmpeg_decoder.cc b/src/lib/ffmpeg_decoder.cc index 3767d7c5f..60f192c85 100644 --- a/src/lib/ffmpeg_decoder.cc +++ b/src/lib/ffmpeg_decoder.cc @@ -60,6 +60,8 @@ using boost::optional; FFmpegDecoder::FFmpegDecoder (shared_ptr f, shared_ptr o, Job* j) : Decoder (f, o, j) + , VideoDecoder (f, o, j) + , AudioDecoder (f, o, j) , _format_context (0) , _video_stream (-1) , _frame (0) @@ -519,14 +521,14 @@ FFmpegDecoder::bytes_per_audio_sample () const void FFmpegDecoder::set_audio_stream (optional s) { - Decoder::set_audio_stream (s); + AudioDecoder::set_audio_stream (s); setup_audio (); } void FFmpegDecoder::set_subtitle_stream (optional s) { - Decoder::set_subtitle_stream (s); + VideoDecoder::set_subtitle_stream (s); setup_subtitle (); } diff --git a/src/lib/ffmpeg_decoder.h b/src/lib/ffmpeg_decoder.h index 5c6f8ab26..a4a9246f0 100644 --- a/src/lib/ffmpeg_decoder.h +++ b/src/lib/ffmpeg_decoder.h @@ -32,6 +32,8 @@ extern "C" { } #include "util.h" #include "decoder.h" +#include "video_decoder.h" +#include "audio_decoder.h" struct AVFilterGraph; struct AVCodecContext; @@ -49,13 +51,12 @@ class Log; /** @class FFmpegDecoder * @brief A decoder using FFmpeg to decode content. */ -class FFmpegDecoder : public Decoder +class FFmpegDecoder : public VideoDecoder, public AudioDecoder { public: FFmpegDecoder (boost::shared_ptr, boost::shared_ptr, Job *); ~FFmpegDecoder (); - /* Methods to query our input video */ float frames_per_second () const; Size native_size () const; int time_base_numerator () const; diff --git a/src/lib/film.cc b/src/lib/film.cc index 454ac9aa9..2330e3c73 100644 --- a/src/lib/film.cc +++ b/src/lib/film.cc @@ -52,6 +52,8 @@ #include "check_hashes_job.h" #include "version.h" #include "ui_signaller.h" +#include "video_decoder.h" +#include "audio_decoder.h" using std::string; using std::stringstream; @@ -939,20 +941,20 @@ Film::set_content (string c) shared_ptr o (new Options ("", "", "")); o->out_size = Size (1024, 1024); - shared_ptr d = decoder_factory (shared_from_this(), o, 0); + pair, shared_ptr > d = decoder_factory (shared_from_this(), o, 0); - set_size (d->native_size ()); - set_frames_per_second (d->frames_per_second ()); - set_audio_streams (d->audio_streams ()); - set_subtitle_streams (d->subtitle_streams ()); + set_size (d.first->native_size ()); + set_frames_per_second (d.first->frames_per_second ()); + set_subtitle_streams (d.first->subtitle_streams ()); + set_audio_streams (d.second->audio_streams ()); /* Start off with the first audio and subtitle streams */ - if (!d->audio_streams().empty()) { - set_audio_stream (d->audio_streams().front()); + if (!d.second->audio_streams().empty()) { + set_audio_stream (d.second->audio_streams().front()); } - if (!d->subtitle_streams().empty()) { - set_subtitle_stream (d->subtitle_streams().front()); + if (!d.first->subtitle_streams().empty()) { + set_subtitle_stream (d.first->subtitle_streams().front()); } { diff --git a/src/lib/imagemagick_decoder.cc b/src/lib/imagemagick_decoder.cc index 7faf74c61..d68c1648f 100644 --- a/src/lib/imagemagick_decoder.cc +++ b/src/lib/imagemagick_decoder.cc @@ -31,6 +31,7 @@ using boost::shared_ptr; ImageMagickDecoder::ImageMagickDecoder ( boost::shared_ptr f, boost::shared_ptr o, Job* j) : Decoder (f, o, j) + , VideoDecoder (f, o, j) { if (boost::filesystem::is_directory (_film->content_path())) { for ( diff --git a/src/lib/imagemagick_decoder.h b/src/lib/imagemagick_decoder.h index 6506d0177..f636191f2 100644 --- a/src/lib/imagemagick_decoder.h +++ b/src/lib/imagemagick_decoder.h @@ -17,13 +17,13 @@ */ -#include "decoder.h" +#include "video_decoder.h" namespace Magick { class Image; } -class ImageMagickDecoder : public Decoder +class ImageMagickDecoder : public VideoDecoder { public: ImageMagickDecoder (boost::shared_ptr, boost::shared_ptr, Job *); diff --git a/src/lib/transcoder.cc b/src/lib/transcoder.cc index 01f54be3f..32725f77c 100644 --- a/src/lib/transcoder.cc +++ b/src/lib/transcoder.cc @@ -34,9 +34,12 @@ #include "delay_line.h" #include "options.h" #include "gain.h" +#include "video_decoder.h" +#include "audio_decoder.h" using std::string; using boost::shared_ptr; +using boost::dynamic_pointer_cast; /** Construct a transcoder using a Decoder that we create and a supplied Encoder. * @param f Film that we are transcoding. @@ -47,7 +50,7 @@ using boost::shared_ptr; Transcoder::Transcoder (shared_ptr f, shared_ptr o, Job* j, shared_ptr e) : _job (j) , _encoder (e) - , _decoder (decoder_factory (f, o, j)) + , _decoders (decoder_factory (f, o, j)) { assert (_encoder); @@ -59,18 +62,18 @@ Transcoder::Transcoder (shared_ptr f, shared_ptr o, Job* j, } /* Set up the decoder to use the film's set streams */ - _decoder->set_audio_stream (f->audio_stream ()); - _decoder->set_subtitle_stream (f->subtitle_stream ()); + _decoders.first->set_subtitle_stream (f->subtitle_stream ()); + _decoders.second->set_audio_stream (f->audio_stream ()); if (_matcher) { - _decoder->connect_video (_matcher); + _decoders.first->connect_video (_matcher); _matcher->connect_video (_encoder); } else { - _decoder->connect_video (_encoder); + _decoders.first->connect_video (_encoder); } if (_matcher && _delay_line) { - _decoder->connect_audio (_delay_line); + _decoders.second->connect_audio (_delay_line); _delay_line->connect_audio (_matcher); _matcher->connect_audio (_gain); _gain->connect_audio (_encoder); @@ -85,7 +88,19 @@ Transcoder::go () { _encoder->process_begin (); try { - _decoder->go (); + while (1) { + bool const v = _decoders.first->pass (); + + bool a = false; + if (dynamic_pointer_cast (_decoders.second) != dynamic_pointer_cast (_decoders.first)) { + a = _decoders.second->pass (); + } + + if (v && a) { + break; + } + } + } catch (...) { /* process_end() is important as the decoder may have worker threads that need to be cleaned up. diff --git a/src/lib/transcoder.h b/src/lib/transcoder.h index 324a72037..e3ca2bb32 100644 --- a/src/lib/transcoder.h +++ b/src/lib/transcoder.h @@ -17,8 +17,6 @@ */ -#include "decoder.h" - /** @file src/transcoder.h * @brief A class which takes a FilmState and some Options, then uses those to transcode a Film. * @@ -33,6 +31,10 @@ class FilmState; class Matcher; class VideoFilter; class Gain; +class VideoDecoder; +class AudioDecoder; +class DelayLine; +class Options; /** @class Transcoder * @brief A class which takes a FilmState and some Options, then uses those to transcode a Film. @@ -47,18 +49,13 @@ public: void go (); - /** @return Our decoder */ - boost::shared_ptr decoder () { - return _decoder; - } - protected: /** A Job that is running this Transcoder, or 0 */ Job* _job; /** The encoder that we will use */ boost::shared_ptr _encoder; - /** The decoder that we will use */ - boost::shared_ptr _decoder; + /** The decoders that we will use */ + std::pair, boost::shared_ptr > _decoders; boost::shared_ptr _matcher; boost::shared_ptr _delay_line; boost::shared_ptr _gain; diff --git a/src/lib/util.cc b/src/lib/util.cc index 862ddc111..ed9594692 100644 --- a/src/lib/util.cc +++ b/src/lib/util.cc @@ -780,9 +780,15 @@ void AudioBuffers::make_silent () { for (int i = 0; i < _channels; ++i) { - for (int j = 0; j < _frames; ++j) { - _data[i][j] = 0; - } + make_silent (i); + } +} + +void +AudioBuffers::make_silent (int c) +{ + for (int i = 0; i < _frames; ++i) { + _data[c][i] = 0; } } diff --git a/src/lib/util.h b/src/lib/util.h index 301a8bc4e..53e78e57c 100644 --- a/src/lib/util.h +++ b/src/lib/util.h @@ -243,6 +243,7 @@ public: void set_frames (int f); void make_silent (); + void make_silent (int c); void copy_from (AudioBuffers* from, int frames_to_copy, int read_offset, int write_offset); void move (int from, int to, int frames); diff --git a/src/lib/video_decoder.cc b/src/lib/video_decoder.cc new file mode 100644 index 000000000..906f92ef1 --- /dev/null +++ b/src/lib/video_decoder.cc @@ -0,0 +1,79 @@ +#include "video_decoder.h" +#include "subtitle.h" +#include "film.h" +#include "image.h" +#include "log.h" +#include "options.h" +#include "job.h" + +using boost::shared_ptr; +using boost::optional; + +VideoDecoder::VideoDecoder (shared_ptr f, shared_ptr o, Job* j) + : Decoder (f, o, j) + , _video_frame (0) +{ + +} + +/** Called by subclasses to tell the world that some video data is ready. + * We find a subtitle then emit it for listeners. + * @param frame to decode; caller manages memory. + */ +void +VideoDecoder::emit_video (shared_ptr image) +{ + shared_ptr sub; + if (_timed_subtitle && _timed_subtitle->displayed_at (double (video_frame()) / _film->frames_per_second())) { + sub = _timed_subtitle->subtitle (); + } + + signal_video (image, sub); +} + +void +VideoDecoder::repeat_last_video () +{ + if (!_last_image) { + _last_image.reset (new CompactImage (pixel_format(), native_size())); + _last_image->make_black (); + } + + signal_video (_last_image, _last_subtitle); +} + +void +VideoDecoder::signal_video (shared_ptr image, shared_ptr sub) +{ + TIMING ("Decoder emits %1", _video_frame); + Video (image, sub); + ++_video_frame; + + _last_image = image; + _last_subtitle = sub; +} + +void +VideoDecoder::emit_subtitle (shared_ptr s) +{ + _timed_subtitle = s; + + if (_timed_subtitle && _opt->apply_crop) { + Position const p = _timed_subtitle->subtitle()->position (); + _timed_subtitle->subtitle()->set_position (Position (p.x - _film->crop().left, p.y - _film->crop().top)); + } +} + +void +VideoDecoder::set_subtitle_stream (optional s) +{ + _subtitle_stream = s; +} + +void +VideoDecoder::set_progress () const +{ + if (_job && _film->dcp_length()) { + _job->set_progress (float (_video_frame) / _film->length().get()); + } +} diff --git a/src/lib/video_decoder.h b/src/lib/video_decoder.h new file mode 100644 index 000000000..df06b7cd9 --- /dev/null +++ b/src/lib/video_decoder.h @@ -0,0 +1,60 @@ +#ifndef DVDOMATIC_VIDEO_DECODER_H +#define DVDOMATIC_VIDEO_DECODER_H + +#include "video_source.h" +#include "stream.h" +#include "decoder.h" + +class VideoDecoder : public VideoSource, public virtual Decoder +{ +public: + VideoDecoder (boost::shared_ptr, boost::shared_ptr, Job *); + + /** @return video frames per second, or 0 if unknown */ + virtual float frames_per_second () const = 0; + /** @return native size in pixels */ + virtual Size native_size () const = 0; + + virtual int time_base_numerator () const = 0; + virtual int time_base_denominator () const = 0; + virtual int sample_aspect_ratio_numerator () const = 0; + virtual int sample_aspect_ratio_denominator () const = 0; + + virtual void set_subtitle_stream (boost::optional); + + SourceFrame video_frame () const { + return _video_frame; + } + + boost::optional subtitle_stream () const { + return _subtitle_stream; + } + + std::vector subtitle_streams () const { + return _subtitle_streams; + } + +protected: + + virtual PixelFormat pixel_format () const = 0; + void set_progress () const; + + void emit_video (boost::shared_ptr); + void emit_subtitle (boost::shared_ptr); + void repeat_last_video (); + + boost::optional _subtitle_stream; + std::vector _subtitle_streams; + +private: + void signal_video (boost::shared_ptr, boost::shared_ptr); + + SourceFrame _video_frame; + + boost::shared_ptr _timed_subtitle; + + boost::shared_ptr _last_image; + boost::shared_ptr _last_subtitle; +}; + +#endif diff --git a/src/lib/wscript b/src/lib/wscript index 6d006f559..339c73e47 100644 --- a/src/lib/wscript +++ b/src/lib/wscript @@ -8,6 +8,7 @@ def build(bld): obj.source = """ ab_transcode_job.cc ab_transcoder.cc + audio_decoder.cc audio_source.cc check_hashes_job.cc config.cc @@ -23,6 +24,7 @@ def build(bld): encoder.cc encoder_factory.cc examine_content_job.cc + external_audio_decoder.cc filter_graph.cc ffmpeg_compatibility.cc ffmpeg_decoder.cc @@ -54,6 +56,7 @@ def build(bld): ui_signaller.cc util.cc version.cc + video_decoder.cc video_source.cc """ -- 2.30.2