From: Carl Hetherington Date: Fri, 21 Jun 2013 16:38:50 +0000 (+0100) Subject: Split examiner parts off decoder. X-Git-Tag: v2.0.48~1337^2~307 X-Git-Url: https://main.carlh.net/gitweb/?p=dcpomatic.git;a=commitdiff_plain;h=f1bf21a9c2581591ab80bfc997a22b93046f8c56 Split examiner parts off decoder. --- diff --git a/src/lib/ffmpeg.cc b/src/lib/ffmpeg.cc new file mode 100644 index 000000000..0d897abfa --- /dev/null +++ b/src/lib/ffmpeg.cc @@ -0,0 +1,138 @@ +/* + Copyright (C) 2013 Carl Hetherington + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + +*/ + +extern "C" { +#include +#include +#include +#include +} +#include "ffmpeg.h" +#include "ffmpeg_content.h" +#include "exceptions.h" + +#include "i18n.h" + +using std::string; +using std::stringstream; +using boost::shared_ptr; + +boost::mutex FFmpeg::_mutex; + +FFmpeg::FFmpeg (boost::shared_ptr c) + : _ffmpeg_content (c) + , _format_context (0) + , _frame (0) + , _video_stream (-1) + , _video_codec_context (0) + , _video_codec (0) + , _audio_codec_context (0) + , _audio_codec (0) +{ + setup_general (); + setup_video (); + setup_audio (); +} + +FFmpeg::~FFmpeg () +{ + boost::mutex::scoped_lock lm (_mutex); + + if (_audio_codec_context) { + avcodec_close (_audio_codec_context); + } + + if (_video_codec_context) { + avcodec_close (_video_codec_context); + } + + av_free (_frame); + + avformat_close_input (&_format_context); +} + +void +FFmpeg::setup_general () +{ + av_register_all (); + + if (avformat_open_input (&_format_context, _ffmpeg_content->file().string().c_str(), 0, 0) < 0) { + throw OpenFileError (_ffmpeg_content->file().string ()); + } + + if (avformat_find_stream_info (_format_context, 0) < 0) { + throw DecodeError (_("could not find stream information")); + } + + /* Find video stream */ + + for (uint32_t i = 0; i < _format_context->nb_streams; ++i) { + AVStream* s = _format_context->streams[i]; + if (s->codec->codec_type == AVMEDIA_TYPE_VIDEO) { + _video_stream = i; + } + } + + if (_video_stream < 0) { + throw DecodeError (N_("could not find video stream")); + } + + _frame = avcodec_alloc_frame (); + if (_frame == 0) { + throw DecodeError (N_("could not allocate frame")); + } +} + +void +FFmpeg::setup_video () +{ + boost::mutex::scoped_lock lm (_mutex); + + _video_codec_context = _format_context->streams[_video_stream]->codec; + _video_codec = avcodec_find_decoder (_video_codec_context->codec_id); + + if (_video_codec == 0) { + throw DecodeError (_("could not find video decoder")); + } + + if (avcodec_open2 (_video_codec_context, _video_codec, 0) < 0) { + throw DecodeError (N_("could not open video decoder")); + } +} + +void +FFmpeg::setup_audio () +{ + boost::mutex::scoped_lock lm (_mutex); + + if (!_ffmpeg_content->audio_stream ()) { + return; + } + + _audio_codec_context = _format_context->streams[_ffmpeg_content->audio_stream()->id]->codec; + _audio_codec = avcodec_find_decoder (_audio_codec_context->codec_id); + + if (_audio_codec == 0) { + throw DecodeError (_("could not find audio decoder")); + } + + if (avcodec_open2 (_audio_codec_context, _audio_codec, 0) < 0) { + throw DecodeError (N_("could not open audio decoder")); + } +} diff --git a/src/lib/ffmpeg.h b/src/lib/ffmpeg.h new file mode 100644 index 000000000..dcafe17f7 --- /dev/null +++ b/src/lib/ffmpeg.h @@ -0,0 +1,70 @@ +/* + Copyright (C) 2013 Carl Hetherington + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + +*/ + +#include +#include +#include +extern "C" { +#include +} + +struct AVFilterGraph; +struct AVCodecContext; +struct AVFilterContext; +struct AVFormatContext; +struct AVFrame; +struct AVBufferContext; +struct AVCodec; +struct AVStream; + +class FFmpegContent; + +class FFmpeg +{ +public: + FFmpeg (boost::shared_ptr); + virtual ~FFmpeg (); + + boost::shared_ptr ffmpeg_content () const { + return _ffmpeg_content; + } + +protected: + boost::shared_ptr _ffmpeg_content; + AVFormatContext* _format_context; + AVPacket _packet; + AVFrame* _frame; + int _video_stream; + + AVCodecContext* _video_codec_context; + AVCodec* _video_codec; + AVCodecContext* _audio_codec_context; ///< may be 0 if there is no audio + AVCodec* _audio_codec; ///< may be 0 if there is no audio + + /* It would appear (though not completely verified) that one must have + a mutex around calls to avcodec_open* and avcodec_close... and here + it is. + */ + static boost::mutex _mutex; + +private: + void setup_general (); + void setup_video (); + void setup_audio (); +}; diff --git a/src/lib/ffmpeg_content.cc b/src/lib/ffmpeg_content.cc index b030fe397..43e88c428 100644 --- a/src/lib/ffmpeg_content.cc +++ b/src/lib/ffmpeg_content.cc @@ -19,11 +19,12 @@ #include #include "ffmpeg_content.h" -#include "ffmpeg_decoder.h" +#include "ffmpeg_examiner.h" #include "compose.hpp" #include "job.h" #include "util.h" #include "filter.h" +#include "film.h" #include "log.h" #include "i18n.h" @@ -130,29 +131,29 @@ FFmpegContent::examine (shared_ptr job) shared_ptr film = _film.lock (); assert (film); - shared_ptr decoder (new FFmpegDecoder (film, shared_from_this (), true, false)); + shared_ptr examiner (new FFmpegExaminer (shared_from_this ())); ContentVideoFrame video_length = 0; - video_length = decoder->video_length (); - film->log()->log (String::compose ("Video length obtained from header as %1 frames", decoder->video_length ())); + video_length = examiner->video_length (); + film->log()->log (String::compose ("Video length obtained from header as %1 frames", examiner->video_length ())); { boost::mutex::scoped_lock lm (_mutex); _video_length = video_length; - _subtitle_streams = decoder->subtitle_streams (); + _subtitle_streams = examiner->subtitle_streams (); if (!_subtitle_streams.empty ()) { _subtitle_stream = _subtitle_streams.front (); } - _audio_streams = decoder->audio_streams (); + _audio_streams = examiner->audio_streams (); if (!_audio_streams.empty ()) { _audio_stream = _audio_streams.front (); } } - take_from_video_decoder (decoder); + take_from_video_examiner (examiner); signal_changed (ContentProperty::LENGTH); signal_changed (FFmpegContentProperty::SUBTITLE_STREAMS); diff --git a/src/lib/ffmpeg_decoder.cc b/src/lib/ffmpeg_decoder.cc index 2e586b8f7..b1f8aa3d0 100644 --- a/src/lib/ffmpeg_decoder.cc +++ b/src/lib/ffmpeg_decoder.cc @@ -28,13 +28,11 @@ #include #include #include +#include extern "C" { #include #include -#include -#include } -#include #include "film.h" #include "filter.h" #include "exceptions.h" @@ -59,162 +57,26 @@ using boost::optional; using boost::dynamic_pointer_cast; using libdcp::Size; -boost::mutex FFmpegDecoder::_mutex; - FFmpegDecoder::FFmpegDecoder (shared_ptr f, shared_ptr c, bool video, bool audio) : Decoder (f) , VideoDecoder (f, c) , AudioDecoder (f, c) - , _ffmpeg_content (c) - , _format_context (0) - , _video_stream (-1) - , _frame (0) - , _video_codec_context (0) - , _video_codec (0) - , _audio_codec_context (0) - , _audio_codec (0) + , FFmpeg (c) , _subtitle_codec_context (0) , _subtitle_codec (0) , _decode_video (video) , _decode_audio (audio) { - setup_general (); - setup_video (); - setup_audio (); setup_subtitle (); } FFmpegDecoder::~FFmpegDecoder () { - boost::mutex::scoped_lock lm (_mutex); - - if (_audio_codec_context) { - avcodec_close (_audio_codec_context); - } - - if (_video_codec_context) { - avcodec_close (_video_codec_context); - } - if (_subtitle_codec_context) { avcodec_close (_subtitle_codec_context); } - - av_free (_frame); - - avformat_close_input (&_format_context); } -void -FFmpegDecoder::setup_general () -{ - av_register_all (); - - if (avformat_open_input (&_format_context, _ffmpeg_content->file().string().c_str(), 0, 0) < 0) { - throw OpenFileError (_ffmpeg_content->file().string ()); - } - - if (avformat_find_stream_info (_format_context, 0) < 0) { - throw DecodeError (_("could not find stream information")); - } - - /* Find video, audio and subtitle streams */ - - for (uint32_t i = 0; i < _format_context->nb_streams; ++i) { - AVStream* s = _format_context->streams[i]; - if (s->codec->codec_type == AVMEDIA_TYPE_VIDEO) { - _video_stream = i; - } else if (s->codec->codec_type == AVMEDIA_TYPE_AUDIO) { - - /* This is a hack; sometimes it seems that _audio_codec_context->channel_layout isn't set up, - so bodge it here. No idea why we should have to do this. - */ - - if (s->codec->channel_layout == 0) { - s->codec->channel_layout = av_get_default_channel_layout (s->codec->channels); - } - - _audio_streams.push_back ( - shared_ptr ( - new FFmpegAudioStream (stream_name (s), i, s->codec->sample_rate, s->codec->channels) - ) - ); - - } else if (s->codec->codec_type == AVMEDIA_TYPE_SUBTITLE) { - _subtitle_streams.push_back (shared_ptr (new FFmpegSubtitleStream (stream_name (s), i))); - } - } - - if (_video_stream < 0) { - throw DecodeError (N_("could not find video stream")); - } - - _frame = avcodec_alloc_frame (); - if (_frame == 0) { - throw DecodeError (N_("could not allocate frame")); - } -} - -void -FFmpegDecoder::setup_video () -{ - boost::mutex::scoped_lock lm (_mutex); - - _video_codec_context = _format_context->streams[_video_stream]->codec; - _video_codec = avcodec_find_decoder (_video_codec_context->codec_id); - - if (_video_codec == 0) { - throw DecodeError (_("could not find video decoder")); - } - - if (avcodec_open2 (_video_codec_context, _video_codec, 0) < 0) { - throw DecodeError (N_("could not open video decoder")); - } -} - -void -FFmpegDecoder::setup_audio () -{ - boost::mutex::scoped_lock lm (_mutex); - - if (!_ffmpeg_content->audio_stream ()) { - return; - } - - _audio_codec_context = _format_context->streams[_ffmpeg_content->audio_stream()->id]->codec; - _audio_codec = avcodec_find_decoder (_audio_codec_context->codec_id); - - if (_audio_codec == 0) { - throw DecodeError (_("could not find audio decoder")); - } - - if (avcodec_open2 (_audio_codec_context, _audio_codec, 0) < 0) { - throw DecodeError (N_("could not open audio decoder")); - } -} - -void -FFmpegDecoder::setup_subtitle () -{ - boost::mutex::scoped_lock lm (_mutex); - - if (!_ffmpeg_content->subtitle_stream() || _ffmpeg_content->subtitle_stream()->id >= int (_format_context->nb_streams)) { - return; - } - - _subtitle_codec_context = _format_context->streams[_ffmpeg_content->subtitle_stream()->id]->codec; - _subtitle_codec = avcodec_find_decoder (_subtitle_codec_context->codec_id); - - if (_subtitle_codec == 0) { - throw DecodeError (_("could not find subtitle decoder")); - } - - if (avcodec_open2 (_subtitle_codec_context, _subtitle_codec, 0) < 0) { - throw DecodeError (N_("could not open subtitle decoder")); - } -} - - void FFmpegDecoder::pass () { @@ -377,18 +239,6 @@ FFmpegDecoder::deinterleave_audio (uint8_t** data, int size) return audio; } -float -FFmpegDecoder::video_frame_rate () const -{ - AVStream* s = _format_context->streams[_video_stream]; - - if (s->avg_frame_rate.num && s->avg_frame_rate.den) { - return av_q2d (s->avg_frame_rate); - } - - return av_q2d (s->r_frame_rate); -} - AVSampleFormat FFmpegDecoder::audio_sample_format () const { @@ -399,39 +249,6 @@ FFmpegDecoder::audio_sample_format () const return _audio_codec_context->sample_fmt; } -libdcp::Size -FFmpegDecoder::video_size () const -{ - return libdcp::Size (_video_codec_context->width, _video_codec_context->height); -} - -string -FFmpegDecoder::stream_name (AVStream* s) const -{ - stringstream n; - - if (s->metadata) { - AVDictionaryEntry const * lang = av_dict_get (s->metadata, N_("language"), 0, 0); - if (lang) { - n << lang->value; - } - - AVDictionaryEntry const * title = av_dict_get (s->metadata, N_("title"), 0, 0); - if (title) { - if (!n.str().empty()) { - n << N_(" "); - } - n << title->value; - } - } - - if (n.str().empty()) { - n << N_("unknown"); - } - - return n.str (); -} - int FFmpegDecoder::bytes_per_audio_sample () const { @@ -448,22 +265,22 @@ FFmpegDecoder::seek (Time t) void FFmpegDecoder::seek_back () { - if (position() < (2.5 * TIME_HZ / video_frame_rate())) { + if (position() < (2.5 * TIME_HZ / _ffmpeg_content->video_frame_rate())) { return; } - do_seek (position() - 2.5 * TIME_HZ / video_frame_rate(), true, true); + do_seek (position() - 2.5 * TIME_HZ / _ffmpeg_content->video_frame_rate(), true, true); VideoDecoder::seek_back (); } void FFmpegDecoder::seek_forward () { - if (position() >= (_ffmpeg_content->length() - 0.5 * TIME_HZ / video_frame_rate())) { + if (position() >= (_ffmpeg_content->length() - 0.5 * TIME_HZ / _ffmpeg_content->video_frame_rate())) { return; } - do_seek (position() - 0.5 * TIME_HZ / video_frame_rate(), true, true); + do_seek (position() - 0.5 * TIME_HZ / _ffmpeg_content->video_frame_rate(), true, true); VideoDecoder::seek_forward (); } @@ -505,13 +322,6 @@ FFmpegDecoder::do_seek (Time t, bool backwards, bool accurate) return; } -/** @return Length (in video frames) according to our content's header */ -ContentVideoFrame -FFmpegDecoder::video_length () const -{ - return (double(_format_context->duration) / AV_TIME_BASE) * video_frame_rate(); -} - void FFmpegDecoder::decode_audio_packet () { @@ -623,3 +433,23 @@ FFmpegDecoder::done () const return (!_decode_audio || !_audio_codec_context || audio_done()) && (!_decode_video || video_done()); } +void +FFmpegDecoder::setup_subtitle () +{ + boost::mutex::scoped_lock lm (_mutex); + + if (!_ffmpeg_content->subtitle_stream() || _ffmpeg_content->subtitle_stream()->id >= int (_format_context->nb_streams)) { + return; + } + + _subtitle_codec_context = _format_context->streams[_ffmpeg_content->subtitle_stream()->id]->codec; + _subtitle_codec = avcodec_find_decoder (_subtitle_codec_context->codec_id); + + if (_subtitle_codec == 0) { + throw DecodeError (_("could not find subtitle decoder")); + } + + if (avcodec_open2 (_subtitle_codec_context, _subtitle_codec, 0) < 0) { + throw DecodeError (N_("could not open subtitle decoder")); + } +} diff --git a/src/lib/ffmpeg_decoder.h b/src/lib/ffmpeg_decoder.h index be178dbfb..331d9be70 100644 --- a/src/lib/ffmpeg_decoder.h +++ b/src/lib/ffmpeg_decoder.h @@ -35,33 +35,19 @@ extern "C" { #include "decoder.h" #include "video_decoder.h" #include "audio_decoder.h" +#include "ffmpeg.h" -struct AVFilterGraph; -struct AVCodecContext; -struct AVFilterContext; -struct AVFormatContext; -struct AVFrame; -struct AVBufferContext; -struct AVCodec; -struct AVStream; -class Job; -class Options; -class Image; -class Log; -class FFmpegContent; class Film; /** @class FFmpegDecoder * @brief A decoder using FFmpeg to decode content. */ -class FFmpegDecoder : public VideoDecoder, public AudioDecoder +class FFmpegDecoder : public VideoDecoder, public AudioDecoder, public FFmpeg { public: FFmpegDecoder (boost::shared_ptr, boost::shared_ptr, bool video, bool audio); ~FFmpegDecoder (); - /* Decoder */ - void pass (); void seek (Time); void seek_back (); @@ -69,78 +55,30 @@ public: Time position () const; bool done () const; - /* VideoDecoder */ - - float video_frame_rate () const; - libdcp::Size video_size () const; - ContentVideoFrame video_length () const; - - /* FFmpegDecoder */ - - std::vector > subtitle_streams () const { - return _subtitle_streams; - } - - std::vector > audio_streams () const { - return _audio_streams; - } - - boost::shared_ptr ffmpeg_content () const { - return _ffmpeg_content; - } - private: /* No copy construction */ FFmpegDecoder (FFmpegDecoder const &); FFmpegDecoder& operator= (FFmpegDecoder const &); - PixelFormat pixel_format () const; + void setup_subtitle (); + AVSampleFormat audio_sample_format () const; int bytes_per_audio_sample () const; void do_seek (Time, bool, bool); - void setup_general (); - void setup_video (); - void setup_audio (); - void setup_subtitle (); - bool decode_video_packet (); void decode_audio_packet (); void maybe_add_subtitle (); boost::shared_ptr deinterleave_audio (uint8_t** data, int size); - std::string stream_name (AVStream* s) const; - - boost::shared_ptr _ffmpeg_content; - - AVFormatContext* _format_context; - int _video_stream; - - AVFrame* _frame; - - AVCodecContext* _video_codec_context; - AVCodec* _video_codec; - AVCodecContext* _audio_codec_context; ///< may be 0 if there is no audio - AVCodec* _audio_codec; ///< may be 0 if there is no audio AVCodecContext* _subtitle_codec_context; ///< may be 0 if there is no subtitle AVCodec* _subtitle_codec; ///< may be 0 if there is no subtitle - - AVPacket _packet; - + std::list > _filter_graphs; boost::mutex _filter_graphs_mutex; - std::vector > _subtitle_streams; - std::vector > _audio_streams; - bool _decode_video; bool _decode_audio; - - /* It would appear (though not completely verified) that one must have - a mutex around calls to avcodec_open* and avcodec_close... and here - it is. - */ - static boost::mutex _mutex; }; diff --git a/src/lib/ffmpeg_examiner.cc b/src/lib/ffmpeg_examiner.cc new file mode 100644 index 000000000..e5d356a27 --- /dev/null +++ b/src/lib/ffmpeg_examiner.cc @@ -0,0 +1,111 @@ +/* + Copyright (C) 2013 Carl Hetherington + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + +*/ + +extern "C" { +#include +#include +} +#include "ffmpeg_examiner.h" +#include "ffmpeg_content.h" + +using std::string; +using std::stringstream; +using boost::shared_ptr; + +FFmpegExaminer::FFmpegExaminer (shared_ptr c) + : FFmpeg (c) +{ + /* Find audio and subtitle streams */ + + for (uint32_t i = 0; i < _format_context->nb_streams; ++i) { + AVStream* s = _format_context->streams[i]; + if (s->codec->codec_type == AVMEDIA_TYPE_AUDIO) { + + /* This is a hack; sometimes it seems that _audio_codec_context->channel_layout isn't set up, + so bodge it here. No idea why we should have to do this. + */ + + if (s->codec->channel_layout == 0) { + s->codec->channel_layout = av_get_default_channel_layout (s->codec->channels); + } + + _audio_streams.push_back ( + shared_ptr ( + new FFmpegAudioStream (stream_name (s), i, s->codec->sample_rate, s->codec->channels) + ) + ); + + } else if (s->codec->codec_type == AVMEDIA_TYPE_SUBTITLE) { + _subtitle_streams.push_back (shared_ptr (new FFmpegSubtitleStream (stream_name (s), i))); + } + } + +} + +float +FFmpegExaminer::video_frame_rate () const +{ + AVStream* s = _format_context->streams[_video_stream]; + + if (s->avg_frame_rate.num && s->avg_frame_rate.den) { + return av_q2d (s->avg_frame_rate); + } + + return av_q2d (s->r_frame_rate); +} + +libdcp::Size +FFmpegExaminer::video_size () const +{ + return libdcp::Size (_video_codec_context->width, _video_codec_context->height); +} + +/** @return Length (in video frames) according to our content's header */ +ContentVideoFrame +FFmpegExaminer::video_length () const +{ + return (double (_format_context->duration) / AV_TIME_BASE) * video_frame_rate(); +} + +string +FFmpegExaminer::stream_name (AVStream* s) const +{ + stringstream n; + + if (s->metadata) { + AVDictionaryEntry const * lang = av_dict_get (s->metadata, "language", 0, 0); + if (lang) { + n << lang->value; + } + + AVDictionaryEntry const * title = av_dict_get (s->metadata, "title", 0, 0); + if (title) { + if (!n.str().empty()) { + n << " "; + } + n << title->value; + } + } + + if (n.str().empty()) { + n << "unknown"; + } + + return n.str (); +} diff --git a/src/lib/ffmpeg_examiner.h b/src/lib/ffmpeg_examiner.h new file mode 100644 index 000000000..875451507 --- /dev/null +++ b/src/lib/ffmpeg_examiner.h @@ -0,0 +1,48 @@ +/* + Copyright (C) 2013 Carl Hetherington + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + +*/ + +#include "ffmpeg.h" +#include "video_examiner.h" + +class FFmpegAudioStream; +class FFmpegSubtitleStream; + +class FFmpegExaminer : public FFmpeg, public VideoExaminer +{ +public: + FFmpegExaminer (boost::shared_ptr); + + float video_frame_rate () const; + libdcp::Size video_size () const; + ContentVideoFrame video_length () const; + + std::vector > subtitle_streams () const { + return _subtitle_streams; + } + + std::vector > audio_streams () const { + return _audio_streams; + } + +private: + std::string stream_name (AVStream* s) const; + + std::vector > _subtitle_streams; + std::vector > _audio_streams; +}; diff --git a/src/lib/filter_graph.cc b/src/lib/filter_graph.cc index b13b232a9..275c46909 100644 --- a/src/lib/filter_graph.cc +++ b/src/lib/filter_graph.cc @@ -33,7 +33,6 @@ extern "C" { #include "filter.h" #include "exceptions.h" #include "image.h" -#include "ffmpeg_decoder.h" #include "i18n.h" diff --git a/src/lib/imagemagick.h b/src/lib/imagemagick.h new file mode 100644 index 000000000..5a1712a3a --- /dev/null +++ b/src/lib/imagemagick.h @@ -0,0 +1,35 @@ +/* + Copyright (C) 2012 Carl Hetherington + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + +*/ + +class ImageMagickContent; + +class ImageMagick +{ +public: + ImageMagick (boost::shared_ptr c) + : _imagemagick_content (c) + {} + + boost::shared_ptr content () const { + return _imagemagick_content; + } + +protected: + boost::shared_ptr _imagemagick_content; +}; diff --git a/src/lib/imagemagick_content.cc b/src/lib/imagemagick_content.cc index 2b7449a6e..f9ee8cc84 100644 --- a/src/lib/imagemagick_content.cc +++ b/src/lib/imagemagick_content.cc @@ -19,9 +19,10 @@ #include #include "imagemagick_content.h" -#include "imagemagick_decoder.h" +#include "imagemagick_examiner.h" #include "config.h" #include "compose.hpp" +#include "film.h" #include "i18n.h" @@ -73,10 +74,10 @@ ImageMagickContent::examine (shared_ptr job) shared_ptr film = _film.lock (); assert (film); - shared_ptr decoder (new ImageMagickDecoder (film, shared_from_this())); + shared_ptr examiner (new ImageMagickExaminer (film, shared_from_this())); set_video_length (Config::instance()->default_still_length() * 24); - take_from_video_decoder (decoder); + take_from_video_examiner (examiner); } shared_ptr diff --git a/src/lib/imagemagick_decoder.cc b/src/lib/imagemagick_decoder.cc index 077d0174d..c9123c77c 100644 --- a/src/lib/imagemagick_decoder.cc +++ b/src/lib/imagemagick_decoder.cc @@ -1,5 +1,5 @@ /* - Copyright (C) 2012 Carl Hetherington + Copyright (C) 2012-2013 Carl Hetherington This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -35,41 +35,11 @@ using libdcp::Size; ImageMagickDecoder::ImageMagickDecoder (shared_ptr f, shared_ptr c) : Decoder (f) , VideoDecoder (f, c) - , _imagemagick_content (c) + , ImageMagick (c) { } -libdcp::Size -ImageMagickDecoder::video_size () const -{ - if (!_video_size) { - using namespace MagickCore; - Magick::Image* image = new Magick::Image (_imagemagick_content->file().string()); - _video_size = libdcp::Size (image->columns(), image->rows()); - delete image; - } - - return _video_size.get (); -} - -int -ImageMagickDecoder::video_length () const -{ - return _imagemagick_content->video_length (); -} - -float -ImageMagickDecoder::video_frame_rate () const -{ - boost::shared_ptr f = _film.lock (); - if (!f) { - return 24; - } - - return f->dcp_video_frame_rate (); -} - void ImageMagickDecoder::pass () { diff --git a/src/lib/imagemagick_decoder.h b/src/lib/imagemagick_decoder.h index 73858b58a..e169f9bc3 100644 --- a/src/lib/imagemagick_decoder.h +++ b/src/lib/imagemagick_decoder.h @@ -1,5 +1,5 @@ /* - Copyright (C) 2012 Carl Hetherington + Copyright (C) 2012-2013 Carl Hetherington This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -18,6 +18,7 @@ */ #include "video_decoder.h" +#include "imagemagick.h" namespace Magick { class Image; @@ -25,7 +26,7 @@ namespace Magick { class ImageMagickContent; -class ImageMagickDecoder : public VideoDecoder +class ImageMagickDecoder : public VideoDecoder, public ImageMagick { public: ImageMagickDecoder (boost::shared_ptr, boost::shared_ptr); @@ -39,20 +40,7 @@ public: Time position () const; bool done () const; - /* VideoDecoder */ - - float video_frame_rate () const; - libdcp::Size video_size () const; - ContentVideoFrame video_length () const; - - /* ImageMagickDecoder */ - - boost::shared_ptr content () const { - return _imagemagick_content; - } - private: - boost::shared_ptr _imagemagick_content; boost::shared_ptr _image; mutable boost::optional _video_size; }; diff --git a/src/lib/imagemagick_examiner.cc b/src/lib/imagemagick_examiner.cc new file mode 100644 index 000000000..0eee0d425 --- /dev/null +++ b/src/lib/imagemagick_examiner.cc @@ -0,0 +1,63 @@ +/* + Copyright (C) 2013 Carl Hetherington + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + +*/ + +#include +#include +#include "imagemagick_content.h" +#include "imagemagick_examiner.h" +#include "film.h" + +#include "i18n.h" + +using std::cout; +using boost::shared_ptr; + +ImageMagickExaminer::ImageMagickExaminer (shared_ptr f, shared_ptr c) + : ImageMagick (c) + , _film (f) +{ + using namespace MagickCore; + Magick::Image* image = new Magick::Image (_imagemagick_content->file().string()); + _video_size = libdcp::Size (image->columns(), image->rows()); + delete image; +} + +libdcp::Size +ImageMagickExaminer::video_size () const +{ + return _video_size; +} + +int +ImageMagickExaminer::video_length () const +{ + return _imagemagick_content->video_length (); +} + +float +ImageMagickExaminer::video_frame_rate () const +{ + boost::shared_ptr f = _film.lock (); + if (!f) { + return 24; + } + + return f->dcp_video_frame_rate (); +} + diff --git a/src/lib/imagemagick_examiner.h b/src/lib/imagemagick_examiner.h new file mode 100644 index 000000000..827dad67e --- /dev/null +++ b/src/lib/imagemagick_examiner.h @@ -0,0 +1,41 @@ +/* + Copyright (C) 2013 Carl Hetherington + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + +*/ + +#include "imagemagick.h" +#include "video_examiner.h" + +namespace Magick { + class Image; +} + +class ImageMagickContent; + +class ImageMagickExaminer : public ImageMagick, public VideoExaminer +{ +public: + ImageMagickExaminer (boost::shared_ptr, boost::shared_ptr); + + float video_frame_rate () const; + libdcp::Size video_size () const; + ContentVideoFrame video_length () const; + +private: + boost::weak_ptr _film; + libdcp::Size _video_size; +}; diff --git a/src/lib/video_content.cc b/src/lib/video_content.cc index 99471edc1..f9de6aa21 100644 --- a/src/lib/video_content.cc +++ b/src/lib/video_content.cc @@ -17,9 +17,10 @@ */ +#include #include #include "video_content.h" -#include "video_decoder.h" +#include "video_examiner.h" #include "ratio.h" #include "i18n.h" @@ -99,9 +100,9 @@ VideoContent::as_xml (xmlpp::Node* node) const } void -VideoContent::take_from_video_decoder (shared_ptr d) +VideoContent::take_from_video_examiner (shared_ptr d) { - /* These decoder calls could call other content methods which take a lock on the mutex */ + /* These examiner calls could call other content methods which take a lock on the mutex */ libdcp::Size const vs = d->video_size (); float const vfr = d->video_frame_rate (); diff --git a/src/lib/video_content.h b/src/lib/video_content.h index 44f1c2847..23bcaa89b 100644 --- a/src/lib/video_content.h +++ b/src/lib/video_content.h @@ -23,7 +23,7 @@ #include "content.h" #include "util.h" -class VideoDecoder; +class VideoExaminer; class Ratio; class VideoContentProperty @@ -80,7 +80,7 @@ public: } protected: - void take_from_video_decoder (boost::shared_ptr); + void take_from_video_examiner (boost::shared_ptr); ContentVideoFrame _video_length; diff --git a/src/lib/video_decoder.cc b/src/lib/video_decoder.cc index 54d14e2c6..fcc0ccf41 100644 --- a/src/lib/video_decoder.cc +++ b/src/lib/video_decoder.cc @@ -69,8 +69,8 @@ VideoDecoder::video (shared_ptr image, bool same, Time t) if (sub) { dcpomatic::Rect const tx = subtitle_transformed_area ( - float (image_size.width) / video_size().width, - float (image_size.height) / video_size().height, + float (image_size.width) / _video_content->video_size().width, + float (image_size.height) / _video_content->video_size().height, sub->area(), film->subtitle_offset(), film->subtitle_scale() ); diff --git a/src/lib/video_decoder.h b/src/lib/video_decoder.h index f0d140d80..8de76c10f 100644 --- a/src/lib/video_decoder.h +++ b/src/lib/video_decoder.h @@ -35,15 +35,6 @@ public: virtual void seek_back (); virtual void seek_forward (); - /* Calls for VideoContent to find out about itself */ - - /** @return video frame rate second, or 0 if unknown */ - virtual float video_frame_rate () const = 0; - /** @return video size in pixels */ - virtual libdcp::Size video_size () const = 0; - /** @return length according to our content's header */ - virtual ContentVideoFrame video_length () const = 0; - void set_video_container_size (libdcp::Size); protected: diff --git a/src/lib/video_examiner.h b/src/lib/video_examiner.h new file mode 100644 index 000000000..2f713291b --- /dev/null +++ b/src/lib/video_examiner.h @@ -0,0 +1,29 @@ +/* + Copyright (C) 2013 Carl Hetherington + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + +*/ + +#include +#include "types.h" + +class VideoExaminer +{ +public: + virtual float video_frame_rate () const = 0; + virtual libdcp::Size video_size () const = 0; + virtual ContentVideoFrame video_length () const = 0; +}; diff --git a/src/lib/wscript b/src/lib/wscript index 9945fc753..d0f102998 100644 --- a/src/lib/wscript +++ b/src/lib/wscript @@ -23,13 +23,16 @@ sources = """ examine_content_job.cc exceptions.cc filter_graph.cc + ffmpeg.cc ffmpeg_content.cc ffmpeg_decoder.cc + ffmpeg_examiner.cc film.cc filter.cc image.cc imagemagick_content.cc imagemagick_decoder.cc + imagemagick_examiner.cc job.cc job_manager.cc log.cc