From 12251f1f5084175a456ef0ea437de8f2cd856f4d Mon Sep 17 00:00:00 2001 From: Carl Hetherington Date: Wed, 10 Jul 2013 14:39:04 +0100 Subject: Remove old combiner.cc --- src/lib/combiner.cc | 74 ----------------------------------------------------- 1 file changed, 74 deletions(-) delete mode 100644 src/lib/combiner.cc (limited to 'src/lib') diff --git a/src/lib/combiner.cc b/src/lib/combiner.cc deleted file mode 100644 index f7d634832..000000000 --- a/src/lib/combiner.cc +++ /dev/null @@ -1,74 +0,0 @@ -/* - 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. - -*/ - -#include "combiner.h" -#include "image.h" - -using boost::shared_ptr; - -Combiner::Combiner (shared_ptr log) - : TimedVideoProcessor (log) -{ - -} - -/** Process video for the left half of the frame. - * Subtitle parameter will be ignored. - * @param image Frame image. - */ -void -Combiner::process_video (shared_ptr image, bool, shared_ptr, double) -{ - _image.reset (new SimpleImage (image)); -} - -/** Process video for the right half of the frame. - * @param image Frame image. - * @param sub Subtitle (which will be put onto the whole frame) - */ -void -Combiner::process_video_b (shared_ptr image, bool, shared_ptr sub, double t) -{ - if (!_image) { - /* It's possible for filters in the A-side to mean that we get a B frame - before any A; just skip the B frame in that case. This at least prevents - a crash, but may not be right. - */ - return; - } - - /* Copy the right half of this image into our _image */ - /* XXX: this should probably be in the Image class */ - for (int i = 0; i < image->components(); ++i) { - int const line_size = image->line_size()[i]; - int const half_line_size = line_size / 2; - - uint8_t* p = _image->data()[i]; - uint8_t* q = image->data()[i]; - - for (int j = 0; j < image->lines (i); ++j) { - memcpy (p + half_line_size, q + half_line_size, half_line_size); - p += _image->stride()[i]; - q += image->stride()[i]; - } - } - - Video (_image, false, sub, t); - _image.reset (); -} -- cgit v1.2.3 From 2f0a5a26708d904bdad3e6e54928e734aad8550e Mon Sep 17 00:00:00 2001 From: Carl Hetherington Date: Wed, 10 Jul 2013 14:51:28 +0100 Subject: Add missing virtual content. --- src/lib/content.h | 1 + 1 file changed, 1 insertion(+) (limited to 'src/lib') diff --git a/src/lib/content.h b/src/lib/content.h index e33f517ab..5dcf27597 100644 --- a/src/lib/content.h +++ b/src/lib/content.h @@ -48,6 +48,7 @@ public: Content (boost::shared_ptr, boost::filesystem::path); Content (boost::shared_ptr, boost::shared_ptr); Content (Content const &); + virtual ~Content () {} virtual void examine (boost::shared_ptr); virtual std::string summary () const = 0; -- cgit v1.2.3 From 611f2241c6732c2c38d87e129e51cf9d8d7a08b8 Mon Sep 17 00:00:00 2001 From: Carl Hetherington Date: Wed, 10 Jul 2013 15:04:57 +0100 Subject: Basic return of subtitles. --- src/lib/ffmpeg_decoder.cc | 48 +++++++++++++++++++++++++-------------------- src/lib/ffmpeg_decoder.h | 4 +++- src/lib/player.cc | 44 ++++++++++++++++++++++++++--------------- src/lib/player.h | 5 +++++ src/lib/subtitle.h | 1 + src/lib/subtitle_decoder.cc | 41 ++++++++++++++++++++++++++++++++++++++ src/lib/subtitle_decoder.h | 35 +++++++++++++++++++++++++++++++++ src/lib/video_decoder.cc | 18 ----------------- src/lib/wscript | 1 + 9 files changed, 141 insertions(+), 56 deletions(-) create mode 100644 src/lib/subtitle_decoder.cc create mode 100644 src/lib/subtitle_decoder.h (limited to 'src/lib') diff --git a/src/lib/ffmpeg_decoder.cc b/src/lib/ffmpeg_decoder.cc index d8ee278b3..3714c1542 100644 --- a/src/lib/ffmpeg_decoder.cc +++ b/src/lib/ffmpeg_decoder.cc @@ -61,6 +61,7 @@ FFmpegDecoder::FFmpegDecoder (shared_ptr f, shared_ptraudio_stream() && _packet.stream_index == _ffmpeg_content->audio_stream()->id && _decode_audio) { decode_audio_packet (); } else if (_ffmpeg_content->subtitle_stream() && _packet.stream_index == _ffmpeg_content->subtitle_stream()->id) { -#if 0 - - int got_subtitle; - AVSubtitle sub; - if (avcodec_decode_subtitle2 (_subtitle_codec_context, &sub, &got_subtitle, &_packet) && got_subtitle) { - /* Sometimes we get an empty AVSubtitle, which is used by some codecs to - indicate that the previous subtitle should stop. - */ - if (sub.num_rects > 0) { - shared_ptr ts; - try { - subtitle (shared_ptr (new TimedSubtitle (sub))); - } catch (...) { - /* some problem with the subtitle; we probably didn't understand it */ - } - } else { - subtitle (shared_ptr ()); - } - avsubtitle_free (&sub); - } -#endif + decode_subtitle_packet (); } av_free_packet (&_packet); @@ -489,3 +470,28 @@ FFmpegDecoder::done () const return vd && ad; } +void +FFmpegDecoder::decode_subtitle_packet () +{ + int got_subtitle; + AVSubtitle sub; + if (avcodec_decode_subtitle2 (_subtitle_codec_context, &sub, &got_subtitle, &_packet) < 0 || !got_subtitle) { + return; + } + + /* Sometimes we get an empty AVSubtitle, which is used by some codecs to + indicate that the previous subtitle should stop. + */ + if (sub.num_rects > 0) { + shared_ptr ts; + try { + subtitle (shared_ptr (new TimedSubtitle (sub))); + } catch (...) { + /* some problem with the subtitle; we probably didn't understand it */ + } + } else { + subtitle (shared_ptr ()); + } + + avsubtitle_free (&sub); +} diff --git a/src/lib/ffmpeg_decoder.h b/src/lib/ffmpeg_decoder.h index eebf75445..8819954db 100644 --- a/src/lib/ffmpeg_decoder.h +++ b/src/lib/ffmpeg_decoder.h @@ -35,6 +35,7 @@ extern "C" { #include "decoder.h" #include "video_decoder.h" #include "audio_decoder.h" +#include "subtitle_decoder.h" #include "ffmpeg.h" class Film; @@ -43,7 +44,7 @@ class ffmpeg_pts_offset_test; /** @class FFmpegDecoder * @brief A decoder using FFmpeg to decode content. */ -class FFmpegDecoder : public VideoDecoder, public AudioDecoder, public FFmpeg +class FFmpegDecoder : public VideoDecoder, public AudioDecoder, public SubtitleDecoder, public FFmpeg { public: FFmpegDecoder (boost::shared_ptr, boost::shared_ptr, bool video, bool audio); @@ -69,6 +70,7 @@ private: bool decode_video_packet (); void decode_audio_packet (); + void decode_subtitle_packet (); void maybe_add_subtitle (); boost::shared_ptr deinterleave_audio (uint8_t** data, int size); diff --git a/src/lib/player.cc b/src/lib/player.cc index 6b7dc2722..2bafbdcd5 100644 --- a/src/lib/player.cc +++ b/src/lib/player.cc @@ -31,6 +31,7 @@ #include "image.h" #include "ratio.h" #include "resampler.h" +#include "subtitle.h" using std::list; using std::cout; @@ -215,48 +216,46 @@ Player::process_video (weak_ptr weak_piece, shared_ptr image return; } - image = image->crop (content->crop(), true); + shared_ptr work_image = image->crop (content->crop(), true); libdcp::Size const image_size = content->ratio()->size (_video_container_size); - image = image->scale_and_convert_to_rgb (image_size, _film->scaler(), true); + work_image = work_image->scale_and_convert_to_rgb (image_size, _film->scaler(), true); -#if 0 - if (film->with_subtitles ()) { + Time time = content->start() + (frame * frc.factor() * TIME_HZ / _film->dcp_video_frame_rate()); + + if (_film->with_subtitles ()) { shared_ptr sub; - if (_timed_subtitle && _timed_subtitle->displayed_at (t)) { - sub = _timed_subtitle->subtitle (); + if (_subtitle && _subtitle->displayed_at (time - _subtitle_offset)) { + sub = _subtitle->subtitle (); } if (sub) { dcpomatic::Rect const tx = subtitle_transformed_area ( float (image_size.width) / content->video_size().width, float (image_size.height) / content->video_size().height, - sub->area(), film->subtitle_offset(), film->subtitle_scale() + sub->area(), _film->subtitle_offset(), _film->subtitle_scale() ); - shared_ptr im = sub->image()->scale (tx.size(), film->scaler(), true); - image->alpha_blend (im, tx.position()); + shared_ptr im = sub->image()->scale (tx.size(), _film->scaler(), true); + work_image->alpha_blend (im, tx.position()); } } -#endif if (image_size != _video_container_size) { assert (image_size.width <= _video_container_size.width); assert (image_size.height <= _video_container_size.height); shared_ptr im (new SimpleImage (PIX_FMT_RGB24, _video_container_size, true)); im->make_black (); - im->copy (image, Position ((_video_container_size.width - image_size.width) / 2, (_video_container_size.height - image_size.height) / 2)); - image = im; + im->copy (work_image, Position ((_video_container_size.width - image_size.width) / 2, (_video_container_size.height - image_size.height) / 2)); + work_image = im; } - Time time = content->start() + (frame * frc.factor() * TIME_HZ / _film->dcp_video_frame_rate()); - - Video (image, same, time); + Video (work_image, same, time); time += TIME_HZ / _film->dcp_video_frame_rate(); if (frc.repeat) { - Video (image, true, time); + Video (work_image, true, time); time += TIME_HZ / _film->dcp_video_frame_rate(); } @@ -390,6 +389,7 @@ Player::setup_pieces () fd->Video.connect (bind (&Player::process_video, this, piece, _1, _2, _3)); fd->Audio.connect (bind (&Player::process_audio, this, piece, _1, _2)); + fd->Subtitle.connect (bind (&Player::process_subtitle, this, piece, _1)); piece->decoder = fd; } @@ -514,3 +514,15 @@ Player::film_changed (Film::Property p) Changed (); } } + +void +Player::process_subtitle (weak_ptr weak_piece, shared_ptr sub) +{ + shared_ptr piece = weak_piece.lock (); + if (!piece) { + return; + } + + _subtitle = sub; + _subtitle_offset = piece->content->start (); +} diff --git a/src/lib/player.h b/src/lib/player.h index 15fa4dbd6..f96d5ac69 100644 --- a/src/lib/player.h +++ b/src/lib/player.h @@ -35,6 +35,7 @@ class AudioContent; class Piece; class Image; class Resampler; +class TimedSubtitle; /** @class Player * @brief A class which can `play' a Playlist; emitting its audio and video. @@ -77,6 +78,7 @@ private: void process_video (boost::weak_ptr, boost::shared_ptr, bool, VideoContent::Frame); void process_audio (boost::weak_ptr, boost::shared_ptr, AudioContent::Frame); + void process_subtitle (boost::weak_ptr, boost::shared_ptr); void setup_pieces (); void playlist_changed (); void content_changed (boost::weak_ptr, int); @@ -107,6 +109,9 @@ private: libdcp::Size _video_container_size; boost::shared_ptr _black_frame; std::map, boost::shared_ptr > _resamplers; + + boost::shared_ptr _subtitle; + Time _subtitle_offset; }; #endif diff --git a/src/lib/subtitle.h b/src/lib/subtitle.h index 1020397cc..47735c453 100644 --- a/src/lib/subtitle.h +++ b/src/lib/subtitle.h @@ -60,6 +60,7 @@ subtitle_transformed_area ( ); /** A Subtitle class with details of the time over which it should be shown */ +/** XXX: merge with Subtitle? */ class TimedSubtitle { public: diff --git a/src/lib/subtitle_decoder.cc b/src/lib/subtitle_decoder.cc new file mode 100644 index 000000000..0ffe5e501 --- /dev/null +++ b/src/lib/subtitle_decoder.cc @@ -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 +#include "subtitle_decoder.h" +#include "subtitle.h" + +using boost::shared_ptr; + +SubtitleDecoder::SubtitleDecoder (shared_ptr f) + : Decoder (f) +{ + +} + + +/** Called by subclasses when a subtitle is ready. + * s may be 0 to say that there is no current subtitle. + * @param s New current subtitle, or 0. + */ +void +SubtitleDecoder::subtitle (shared_ptr s) +{ + Subtitle (s); +} diff --git a/src/lib/subtitle_decoder.h b/src/lib/subtitle_decoder.h new file mode 100644 index 000000000..0c299f61f --- /dev/null +++ b/src/lib/subtitle_decoder.h @@ -0,0 +1,35 @@ +/* + 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 "decoder.h" + +class Film; +class TimedSubtitle; + +class SubtitleDecoder : public virtual Decoder +{ +public: + SubtitleDecoder (boost::shared_ptr); + + boost::signals2::signal)> Subtitle; + +protected: + void subtitle (boost::shared_ptr); +}; diff --git a/src/lib/video_decoder.cc b/src/lib/video_decoder.cc index f61e63d4d..0616cd437 100644 --- a/src/lib/video_decoder.cc +++ b/src/lib/video_decoder.cc @@ -42,21 +42,3 @@ VideoDecoder::video (shared_ptr image, bool same, VideoContent::Fra _video_position = frame + 1; } -#if 0 - -/** Called by subclasses when a subtitle is ready. - * s may be 0 to say that there is no current subtitle. - * @param s New current subtitle, or 0. - */ -void -VideoDecoder::subtitle (shared_ptr s) -{ - _timed_subtitle = s; - - if (_timed_subtitle) { - Position const p = _timed_subtitle->subtitle()->position (); - _timed_subtitle->subtitle()->set_position (Position (p.x - _video_content->crop().left, p.y - _video_content->crop().top)); - } -} -#endif - diff --git a/src/lib/wscript b/src/lib/wscript index 2f8653984..34d44ec5b 100644 --- a/src/lib/wscript +++ b/src/lib/wscript @@ -44,6 +44,7 @@ sources = """ sndfile_content.cc sndfile_decoder.cc sound_processor.cc + subtitle_decoder.cc subtitle.cc timer.cc transcode_job.cc -- cgit v1.2.3 From f0d79f2ee79becbcb7bc9065155eaa0963a6aa99 Mon Sep 17 00:00:00 2001 From: Carl Hetherington Date: Wed, 10 Jul 2013 16:46:08 +0100 Subject: Add SubtitleContent. --- src/lib/ffmpeg_content.cc | 4 +++ src/lib/ffmpeg_content.h | 3 +- src/lib/film.cc | 28 ------------------ src/lib/film.h | 20 ------------- src/lib/player.cc | 19 ++++++------ src/lib/player.h | 4 ++- src/lib/subtitle_content.cc | 72 +++++++++++++++++++++++++++++++++++++++++++++ src/lib/subtitle_content.h | 62 ++++++++++++++++++++++++++++++++++++++ src/lib/util.cc | 4 +-- src/lib/wscript | 3 +- src/wx/film_editor.cc | 35 ++++++++++++++-------- src/wx/film_editor.h | 1 + src/wx/film_viewer.cc | 2 +- 13 files changed, 182 insertions(+), 75 deletions(-) create mode 100644 src/lib/subtitle_content.cc create mode 100644 src/lib/subtitle_content.h (limited to 'src/lib') diff --git a/src/lib/ffmpeg_content.cc b/src/lib/ffmpeg_content.cc index 1135cc9a3..35f9f71f2 100644 --- a/src/lib/ffmpeg_content.cc +++ b/src/lib/ffmpeg_content.cc @@ -47,6 +47,7 @@ FFmpegContent::FFmpegContent (shared_ptr f, boost::filesystem::path : Content (f, p) , VideoContent (f, p) , AudioContent (f, p) + , SubtitleContent (f, p) { } @@ -55,6 +56,7 @@ FFmpegContent::FFmpegContent (shared_ptr f, shared_ptr > c = node->node_children ("SubtitleStream"); for (list >::const_iterator i = c.begin(); i != c.end(); ++i) { @@ -84,6 +86,7 @@ FFmpegContent::FFmpegContent (FFmpegContent const & o) : Content (o) , VideoContent (o) , AudioContent (o) + , SubtitleContent (o) , _subtitle_streams (o._subtitle_streams) , _subtitle_stream (o._subtitle_stream) , _audio_streams (o._audio_streams) @@ -99,6 +102,7 @@ FFmpegContent::as_xml (xmlpp::Node* node) const Content::as_xml (node); VideoContent::as_xml (node); AudioContent::as_xml (node); + SubtitleContent::as_xml (node); boost::mutex::scoped_lock lm (_mutex); diff --git a/src/lib/ffmpeg_content.h b/src/lib/ffmpeg_content.h index c5ccee77a..5b9f1f579 100644 --- a/src/lib/ffmpeg_content.h +++ b/src/lib/ffmpeg_content.h @@ -23,6 +23,7 @@ #include #include "video_content.h" #include "audio_content.h" +#include "subtitle_content.h" class Filter; @@ -79,7 +80,7 @@ public: static int const FILTERS; }; -class FFmpegContent : public VideoContent, public AudioContent +class FFmpegContent : public VideoContent, public AudioContent, public SubtitleContent { public: FFmpegContent (boost::shared_ptr, boost::filesystem::path); diff --git a/src/lib/film.cc b/src/lib/film.cc index 11fa87912..dad9d6808 100644 --- a/src/lib/film.cc +++ b/src/lib/film.cc @@ -94,8 +94,6 @@ Film::Film (string d) , _container (Config::instance()->default_container ()) , _scaler (Scaler::from_id ("bicubic")) , _with_subtitles (false) - , _subtitle_offset (0) - , _subtitle_scale (1) , _colour_lut (0) , _j2k_bandwidth (200000000) , _dci_metadata (Config::instance()->default_dci_metadata ()) @@ -142,8 +140,6 @@ Film::Film (Film const & o) , _container (o._container) , _scaler (o._scaler) , _with_subtitles (o._with_subtitles) - , _subtitle_offset (o._subtitle_offset) - , _subtitle_scale (o._subtitle_scale) , _colour_lut (o._colour_lut) , _j2k_bandwidth (o._j2k_bandwidth) , _dci_metadata (o._dci_metadata) @@ -348,8 +344,6 @@ Film::write_metadata () const root->add_child("Scaler")->add_child_text (_scaler->id ()); root->add_child("WithSubtitles")->add_child_text (_with_subtitles ? "1" : "0"); - root->add_child("SubtitleOffset")->add_child_text (lexical_cast (_subtitle_offset)); - root->add_child("SubtitleScale")->add_child_text (lexical_cast (_subtitle_scale)); root->add_child("ColourLUT")->add_child_text (lexical_cast (_colour_lut)); root->add_child("J2KBandwidth")->add_child_text (lexical_cast (_j2k_bandwidth)); _dci_metadata.as_xml (root->add_child ("DCIMetadata")); @@ -395,8 +389,6 @@ Film::read_metadata () _scaler = Scaler::from_id (f.string_child ("Scaler")); _with_subtitles = f.bool_child ("WithSubtitles"); - _subtitle_offset = f.number_child ("SubtitleOffset"); - _subtitle_scale = f.number_child ("SubtitleScale"); _colour_lut = f.number_child ("ColourLUT"); _j2k_bandwidth = f.number_child ("J2KBandwidth"); _dci_metadata = DCIMetadata (f.node_child ("DCIMetadata")); @@ -593,26 +585,6 @@ Film::set_with_subtitles (bool w) signal_changed (WITH_SUBTITLES); } -void -Film::set_subtitle_offset (int o) -{ - { - boost::mutex::scoped_lock lm (_state_mutex); - _subtitle_offset = o; - } - signal_changed (SUBTITLE_OFFSET); -} - -void -Film::set_subtitle_scale (float s) -{ - { - boost::mutex::scoped_lock lm (_state_mutex); - _subtitle_scale = s; - } - signal_changed (SUBTITLE_SCALE); -} - void Film::set_colour_lut (int i) { diff --git a/src/lib/film.h b/src/lib/film.h index 5bb9acf29..08fdc587b 100644 --- a/src/lib/film.h +++ b/src/lib/film.h @@ -135,8 +135,6 @@ public: CONTAINER, SCALER, WITH_SUBTITLES, - SUBTITLE_OFFSET, - SUBTITLE_SCALE, COLOUR_LUT, J2K_BANDWIDTH, DCI_METADATA, @@ -181,16 +179,6 @@ public: return _with_subtitles; } - int subtitle_offset () const { - boost::mutex::scoped_lock lm (_state_mutex); - return _subtitle_offset; - } - - float subtitle_scale () const { - boost::mutex::scoped_lock lm (_state_mutex); - return _subtitle_scale; - } - int colour_lut () const { boost::mutex::scoped_lock lm (_state_mutex); return _colour_lut; @@ -229,8 +217,6 @@ public: void set_container (Ratio const *); void set_scaler (Scaler const *); void set_with_subtitles (bool); - void set_subtitle_offset (int); - void set_subtitle_scale (float); void set_colour_lut (int); void set_j2k_bandwidth (int); void set_dci_metadata (DCIMetadata); @@ -278,12 +264,6 @@ private: Scaler const * _scaler; /** True if subtitles should be shown for this film */ bool _with_subtitles; - /** y offset for placing subtitles, in source pixels; +ve is further down - the frame, -ve is further up. - */ - int _subtitle_offset; - /** scale factor to apply to subtitles */ - float _subtitle_scale; /** index of colour LUT to use when converting RGB to XYZ. * 0: sRGB * 1: Rec 709 diff --git a/src/lib/player.cc b/src/lib/player.cc index 2bafbdcd5..c615f0a89 100644 --- a/src/lib/player.cc +++ b/src/lib/player.cc @@ -26,6 +26,7 @@ #include "imagemagick_content.h" #include "sndfile_decoder.h" #include "sndfile_content.h" +#include "subtitle_content.h" #include "playlist.h" #include "job.h" #include "image.h" @@ -226,7 +227,7 @@ Player::process_video (weak_ptr weak_piece, shared_ptr image if (_film->with_subtitles ()) { shared_ptr sub; - if (_subtitle && _subtitle->displayed_at (time - _subtitle_offset)) { + if (_subtitle && _subtitle->displayed_at (time - _subtitle_content_time)) { sub = _subtitle->subtitle (); } @@ -234,7 +235,7 @@ Player::process_video (weak_ptr weak_piece, shared_ptr image dcpomatic::Rect const tx = subtitle_transformed_area ( float (image_size.width) / content->video_size().width, float (image_size.height) / content->video_size().height, - sub->area(), _film->subtitle_offset(), _film->subtitle_scale() + sub->area(), _subtitle_offset, _subtitle_scale ); shared_ptr im = sub->image()->scale (tx.size(), _film->scaler(), true); @@ -505,12 +506,7 @@ Player::film_changed (Film::Property p) last time we were run. */ - if ( - p == Film::SCALER || p == Film::WITH_SUBTITLES || - p == Film::SUBTITLE_SCALE || p == Film::SUBTITLE_OFFSET || - p == Film::CONTAINER - ) { - + if (p == Film::SCALER || p == Film::WITH_SUBTITLES || p == Film::CONTAINER) { Changed (); } } @@ -523,6 +519,11 @@ Player::process_subtitle (weak_ptr weak_piece, shared_ptr return; } + shared_ptr sc = dynamic_pointer_cast (piece->content); + assert (sc); + _subtitle = sub; - _subtitle_offset = piece->content->start (); + _subtitle_content_time = piece->content->start (); + _subtitle_offset = sc->subtitle_offset (); + _subtitle_scale = sc->subtitle_scale (); } diff --git a/src/lib/player.h b/src/lib/player.h index f96d5ac69..32ef25d47 100644 --- a/src/lib/player.h +++ b/src/lib/player.h @@ -111,7 +111,9 @@ private: std::map, boost::shared_ptr > _resamplers; boost::shared_ptr _subtitle; - Time _subtitle_offset; + Time _subtitle_content_time; + int _subtitle_offset; + float _subtitle_scale; }; #endif diff --git a/src/lib/subtitle_content.cc b/src/lib/subtitle_content.cc new file mode 100644 index 000000000..c8de9887e --- /dev/null +++ b/src/lib/subtitle_content.cc @@ -0,0 +1,72 @@ +/* + 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 "subtitle_content.h" + +using std::string; +using boost::shared_ptr; +using boost::lexical_cast; + +int const SubtitleContentProperty::SUBTITLE_OFFSET = 500; +int const SubtitleContentProperty::SUBTITLE_SCALE = 501; + +SubtitleContent::SubtitleContent (shared_ptr f, boost::filesystem::path p) + : Content (f, p) + , _subtitle_offset (0) + , _subtitle_scale (1) +{ + +} + +SubtitleContent::SubtitleContent (shared_ptr f, shared_ptr node) + : Content (f, node) + , _subtitle_offset (0) + , _subtitle_scale (1) +{ + _subtitle_offset = node->number_child ("SubtitleOffset"); + _subtitle_scale = node->number_child ("SubtitleScale"); +} + +void +SubtitleContent::as_xml (xmlpp::Node* root) const +{ + root->add_child("SubtitleOffset")->add_child_text (lexical_cast (_subtitle_offset)); + root->add_child("SubtitleScale")->add_child_text (lexical_cast (_subtitle_scale)); +} + +void +SubtitleContent::set_subtitle_offset (int o) +{ + { + boost::mutex::scoped_lock lm (_mutex); + _subtitle_offset = o; + } + signal_changed (SubtitleContentProperty::SUBTITLE_OFFSET); +} + +void +SubtitleContent::set_subtitle_scale (float s) +{ + { + boost::mutex::scoped_lock lm (_mutex); + _subtitle_scale = s; + } + signal_changed (SubtitleContentProperty::SUBTITLE_SCALE); +} diff --git a/src/lib/subtitle_content.h b/src/lib/subtitle_content.h new file mode 100644 index 000000000..5eb4e500d --- /dev/null +++ b/src/lib/subtitle_content.h @@ -0,0 +1,62 @@ +/* + 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. + +*/ + +#ifndef DCPOMATIC_SUBTITLE_CONTENT_H +#define DCPOMATIC_SUBTITLE_CONTENT_H + +#include "content.h" + +class SubtitleContentProperty +{ +public: + static int const SUBTITLE_OFFSET; + static int const SUBTITLE_SCALE; +}; + +class SubtitleContent : public virtual Content +{ +public: + SubtitleContent (boost::shared_ptr, boost::filesystem::path); + SubtitleContent (boost::shared_ptr, boost::shared_ptr); + + void as_xml (xmlpp::Node *) const; + + void set_subtitle_offset (int); + void set_subtitle_scale (float); + + int subtitle_offset () const { + boost::mutex::scoped_lock lm (_mutex); + return _subtitle_offset; + } + + float subtitle_scale () const { + boost::mutex::scoped_lock lm (_mutex); + return _subtitle_scale; + } + +private: + /** y offset for placing subtitles, in source pixels; +ve is further down + the frame, -ve is further up. + */ + int _subtitle_offset; + /** scale factor to apply to subtitles */ + float _subtitle_scale; +}; + +#endif diff --git a/src/lib/util.cc b/src/lib/util.cc index 2e4abe64d..53c457898 100644 --- a/src/lib/util.cc +++ b/src/lib/util.cc @@ -91,8 +91,8 @@ using boost::lexical_cast; using boost::optional; using libdcp::Size; -boost::thread::id ui_thread; -boost::filesystem::path backtrace_file; +static boost::thread::id ui_thread; +static boost::filesystem::path backtrace_file; /** Convert some number of seconds to a string representation * in hours, minutes and seconds. diff --git a/src/lib/wscript b/src/lib/wscript index 34d44ec5b..789db1551 100644 --- a/src/lib/wscript +++ b/src/lib/wscript @@ -44,8 +44,9 @@ sources = """ sndfile_content.cc sndfile_decoder.cc sound_processor.cc - subtitle_decoder.cc subtitle.cc + subtitle_content.cc + subtitle_decoder.cc timer.cc transcode_job.cc transcoder.cc diff --git a/src/wx/film_editor.cc b/src/wx/film_editor.cc index 315951168..f63121201 100644 --- a/src/wx/film_editor.cc +++ b/src/wx/film_editor.cc @@ -527,21 +527,23 @@ FilmEditor::name_changed (wxCommandEvent &) void FilmEditor::subtitle_offset_changed (wxCommandEvent &) { - if (!_film) { + shared_ptr c = selected_subtitle_content (); + if (!c) { return; } - _film->set_subtitle_offset (_subtitle_offset->GetValue ()); + c->set_subtitle_offset (_subtitle_offset->GetValue ()); } void FilmEditor::subtitle_scale_changed (wxCommandEvent &) { - if (!_film) { + shared_ptr c = selected_subtitle_content (); + if (!c) { return; } - _film->set_subtitle_scale (_subtitle_scale->GetValue() / 100.0); + c->set_subtitle_scale (_subtitle_scale->GetValue() / 100.0); } void @@ -626,12 +628,6 @@ FilmEditor::film_changed (Film::Property p) setup_subtitle_control_sensitivity (); setup_dcp_name (); break; - case Film::SUBTITLE_OFFSET: - checked_set (_subtitle_offset, _film->subtitle_offset ()); - break; - case Film::SUBTITLE_SCALE: - checked_set (_subtitle_scale, _film->subtitle_scale() * 100); - break; case Film::COLOUR_LUT: checked_set (_colour_lut, _film->colour_lut ()); break; @@ -679,10 +675,12 @@ FilmEditor::film_content_changed (weak_ptr weak_content, int property) shared_ptr content = weak_content.lock (); shared_ptr video_content; shared_ptr audio_content; + shared_ptr subtitle_content; shared_ptr ffmpeg_content; if (content) { video_content = dynamic_pointer_cast (content); audio_content = dynamic_pointer_cast (content); + subtitle_content = dynamic_pointer_cast (content); ffmpeg_content = dynamic_pointer_cast (content); } @@ -776,6 +774,10 @@ FilmEditor::film_content_changed (weak_ptr weak_content, int property) } _dcp_sizer->Layout (); } + } else if (property == SubtitleContentProperty::SUBTITLE_OFFSET) { + checked_set (_subtitle_offset, subtitle_content ? subtitle_content->subtitle_offset() : 0); + } else if (property == SubtitleContentProperty::SUBTITLE_SCALE) { + checked_set (_subtitle_scale, subtitle_content ? (subtitle_content->subtitle_scale() * 100) : 100); } } @@ -861,8 +863,6 @@ FilmEditor::set_film (shared_ptr f) film_changed (Film::CONTAINER); film_changed (Film::SCALER); film_changed (Film::WITH_SUBTITLES); - film_changed (Film::SUBTITLE_OFFSET); - film_changed (Film::SUBTITLE_SCALE); film_changed (Film::COLOUR_LUT); film_changed (Film::J2K_BANDWIDTH); film_changed (Film::DCI_METADATA); @@ -1270,6 +1270,17 @@ FilmEditor::selected_audio_content () return dynamic_pointer_cast (c); } +shared_ptr +FilmEditor::selected_subtitle_content () +{ + shared_ptr c = selected_content (); + if (!c) { + return shared_ptr (); + } + + return dynamic_pointer_cast (c); +} + void FilmEditor::setup_scaling_description () { diff --git a/src/wx/film_editor.h b/src/wx/film_editor.h index 4b096a2e1..fdc6e077d 100644 --- a/src/wx/film_editor.h +++ b/src/wx/film_editor.h @@ -118,6 +118,7 @@ private: boost::shared_ptr selected_content (); boost::shared_ptr selected_video_content (); boost::shared_ptr selected_audio_content (); + boost::shared_ptr selected_subtitle_content (); wxNotebook* _main_notebook; wxNotebook* _content_notebook; diff --git a/src/wx/film_viewer.cc b/src/wx/film_viewer.cc index 185c3c53f..f64020ba7 100644 --- a/src/wx/film_viewer.cc +++ b/src/wx/film_viewer.cc @@ -301,7 +301,7 @@ FilmViewer::fetch_next_frame () try { _got_frame = false; - while (!_got_frame && !_player->pass ()); + while (!_got_frame && !_player->pass ()) {} } catch (DecodeError& e) { _play_button->SetValue (false); check_play_state (); -- cgit v1.2.3 From 320a74efb8d9c8aacded2799459a92d5b7235d90 Mon Sep 17 00:00:00 2001 From: Carl Hetherington Date: Wed, 10 Jul 2013 20:29:00 +0100 Subject: Make subtitles work at least a bit. --- src/lib/decoder.h | 2 - src/lib/ffmpeg_decoder.cc | 64 ++++++++++++++++--- src/lib/image.cc | 4 +- src/lib/image.h | 5 +- src/lib/player.cc | 77 +++++++++++++++-------- src/lib/player.h | 23 +++++-- src/lib/position.h | 46 ++++++++++++++ src/lib/rect.h | 79 +++++++++++++++++++++++ src/lib/server.cc | 1 - src/lib/subtitle.cc | 149 -------------------------------------------- src/lib/subtitle.h | 82 ------------------------ src/lib/subtitle_content.cc | 4 +- src/lib/subtitle_content.h | 16 ++--- src/lib/subtitle_decoder.cc | 8 +-- src/lib/subtitle_decoder.h | 6 +- src/lib/types.cc | 22 ------- src/lib/types.h | 62 ------------------ src/lib/video_decoder.cc | 3 - src/lib/wscript | 1 - src/wx/film_editor.cc | 8 +-- src/wx/timeline.cc | 18 +++--- src/wx/timeline.h | 7 ++- test/client_server_test.cc | 2 +- test/test.cc | 1 - 24 files changed, 287 insertions(+), 403 deletions(-) create mode 100644 src/lib/position.h create mode 100644 src/lib/rect.h delete mode 100644 src/lib/subtitle.cc delete mode 100644 src/lib/subtitle.h (limited to 'src/lib') diff --git a/src/lib/decoder.h b/src/lib/decoder.h index cfca6867f..dea4def3a 100644 --- a/src/lib/decoder.h +++ b/src/lib/decoder.h @@ -34,8 +34,6 @@ class Image; class Log; class DelayLine; -class TimedSubtitle; -class Subtitle; class FilterGraph; /** @class Decoder. diff --git a/src/lib/ffmpeg_decoder.cc b/src/lib/ffmpeg_decoder.cc index 3714c1542..fddb70294 100644 --- a/src/lib/ffmpeg_decoder.cc +++ b/src/lib/ffmpeg_decoder.cc @@ -41,7 +41,6 @@ extern "C" { #include "log.h" #include "ffmpeg_decoder.h" #include "filter_graph.h" -#include "subtitle.h" #include "audio_buffers.h" #include "i18n.h" @@ -478,20 +477,65 @@ FFmpegDecoder::decode_subtitle_packet () if (avcodec_decode_subtitle2 (_subtitle_codec_context, &sub, &got_subtitle, &_packet) < 0 || !got_subtitle) { return; } - + /* Sometimes we get an empty AVSubtitle, which is used by some codecs to indicate that the previous subtitle should stop. */ - if (sub.num_rects > 0) { - shared_ptr ts; - try { - subtitle (shared_ptr (new TimedSubtitle (sub))); - } catch (...) { - /* some problem with the subtitle; we probably didn't understand it */ + if (sub.num_rects <= 0) { + subtitle (shared_ptr (), dcpomatic::Rect (), 0, 0); + return; + } else if (sub.num_rects > 1) { + throw DecodeError (_("multi-part subtitles not yet supported")); + } + + /* Subtitle PTS in seconds (within the source, not taking into account any of the + source that we may have chopped off for the DCP) + */ + double const packet_time = static_cast (sub.pts) / AV_TIME_BASE; + + /* hence start time for this sub */ + Time const from = (packet_time + (double (sub.start_display_time) / 1e3)) * TIME_HZ; + Time const to = (packet_time + (double (sub.end_display_time) / 1e3)) * TIME_HZ; + + AVSubtitleRect const * rect = sub.rects[0]; + + if (rect->type != SUBTITLE_BITMAP) { + throw DecodeError (_("non-bitmap subtitles not yet supported")); + } + + shared_ptr image (new SimpleImage (PIX_FMT_RGBA, libdcp::Size (rect->w, rect->h), true)); + + /* Start of the first line in the subtitle */ + uint8_t* sub_p = rect->pict.data[0]; + /* sub_p looks up into a RGB palette which is here */ + uint32_t const * palette = (uint32_t *) rect->pict.data[1]; + /* Start of the output data */ + uint32_t* out_p = (uint32_t *) image->data()[0]; + + for (int y = 0; y < rect->h; ++y) { + uint8_t* sub_line_p = sub_p; + uint32_t* out_line_p = out_p; + for (int x = 0; x < rect->w; ++x) { + *out_line_p++ = palette[*sub_line_p++]; } - } else { - subtitle (shared_ptr ()); + sub_p += rect->pict.linesize[0]; + out_p += image->stride()[0] / sizeof (uint32_t); } + + libdcp::Size const vs = _ffmpeg_content->video_size (); + + subtitle ( + image, + dcpomatic::Rect ( + static_cast (rect->x) / vs.width, + static_cast (rect->y) / vs.height, + static_cast (rect->w) / vs.width, + static_cast (rect->h) / vs.height + ), + from, + to + ); + avsubtitle_free (&sub); } diff --git a/src/lib/image.cc b/src/lib/image.cc index ac30f4ff0..c11bcbb8d 100644 --- a/src/lib/image.cc +++ b/src/lib/image.cc @@ -336,7 +336,7 @@ Image::make_black () } void -Image::alpha_blend (shared_ptr other, Position position) +Image::alpha_blend (shared_ptr other, Position position) { /* Only implemented for RGBA onto RGB24 so far */ assert (_pixel_format == PIX_FMT_RGB24 && other->pixel_format() == PIX_FMT_RGBA); @@ -372,7 +372,7 @@ Image::alpha_blend (shared_ptr other, Position position) } void -Image::copy (shared_ptr other, Position position) +Image::copy (shared_ptr other, Position position) { /* Only implemented for RGB24 onto RGB24 so far */ assert (_pixel_format == PIX_FMT_RGB24 && other->pixel_format() == PIX_FMT_RGB24); diff --git a/src/lib/image.h b/src/lib/image.h index 5407ce66e..d40ba77b4 100644 --- a/src/lib/image.h +++ b/src/lib/image.h @@ -32,6 +32,7 @@ extern "C" { #include } #include "util.h" +#include "position.h" class Scaler; class SimpleImage; @@ -75,8 +76,8 @@ public: boost::shared_ptr scale_and_convert_to_rgb (libdcp::Size, Scaler const *, bool) const; boost::shared_ptr scale (libdcp::Size, Scaler const *, bool aligned) const; boost::shared_ptr post_process (std::string, bool aligned) const; - void alpha_blend (boost::shared_ptr image, Position pos); - void copy (boost::shared_ptr image, Position pos); + void alpha_blend (boost::shared_ptr image, Position pos); + void copy (boost::shared_ptr image, Position pos); boost::shared_ptr crop (Crop c, bool aligned) const; void make_black (); diff --git a/src/lib/player.cc b/src/lib/player.cc index c615f0a89..58ba57bdc 100644 --- a/src/lib/player.cc +++ b/src/lib/player.cc @@ -32,7 +32,7 @@ #include "image.h" #include "ratio.h" #include "resampler.h" -#include "subtitle.h" +#include "scaler.h" using std::list; using std::cout; @@ -45,7 +45,7 @@ using boost::shared_ptr; using boost::weak_ptr; using boost::dynamic_pointer_cast; -#define DEBUG_PLAYER 1 +//#define DEBUG_PLAYER 1 class Piece { @@ -225,22 +225,8 @@ Player::process_video (weak_ptr weak_piece, shared_ptr image Time time = content->start() + (frame * frc.factor() * TIME_HZ / _film->dcp_video_frame_rate()); - if (_film->with_subtitles ()) { - shared_ptr sub; - if (_subtitle && _subtitle->displayed_at (time - _subtitle_content_time)) { - sub = _subtitle->subtitle (); - } - - if (sub) { - dcpomatic::Rect const tx = subtitle_transformed_area ( - float (image_size.width) / content->video_size().width, - float (image_size.height) / content->video_size().height, - sub->area(), _subtitle_offset, _subtitle_scale - ); - - shared_ptr im = sub->image()->scale (tx.size(), _film->scaler(), true); - work_image->alpha_blend (im, tx.position()); - } + if (_film->with_subtitles () && _out_subtitle.image && time >= _out_subtitle.from && time <= _out_subtitle.to) { + work_image->alpha_blend (_out_subtitle.image, _out_subtitle.position); } if (image_size != _video_container_size) { @@ -248,7 +234,7 @@ Player::process_video (weak_ptr weak_piece, shared_ptr image assert (image_size.height <= _video_container_size.height); shared_ptr im (new SimpleImage (PIX_FMT_RGB24, _video_container_size, true)); im->make_black (); - im->copy (work_image, Position ((_video_container_size.width - image_size.width) / 2, (_video_container_size.height - image_size.height) / 2)); + im->copy (work_image, Position ((_video_container_size.width - image_size.width) / 2, (_video_container_size.height - image_size.height) / 2)); work_image = im; } @@ -390,7 +376,7 @@ Player::setup_pieces () fd->Video.connect (bind (&Player::process_video, this, piece, _1, _2, _3)); fd->Audio.connect (bind (&Player::process_audio, this, piece, _1, _2)); - fd->Subtitle.connect (bind (&Player::process_subtitle, this, piece, _1)); + fd->Subtitle.connect (bind (&Player::process_subtitle, this, piece, _1, _2, _3, _4)); piece->decoder = fd; } @@ -449,6 +435,10 @@ Player::content_changed (weak_ptr w, int p) _have_valid_pieces = false; Changed (); + + } else if (p == SubtitleContentProperty::SUBTITLE_OFFSET || p == SubtitleContentProperty::SUBTITLE_SCALE) { + update_subtitle (); + Changed (); } } @@ -512,9 +502,21 @@ Player::film_changed (Film::Property p) } void -Player::process_subtitle (weak_ptr weak_piece, shared_ptr sub) +Player::process_subtitle (weak_ptr weak_piece, shared_ptr image, dcpomatic::Rect rect, Time from, Time to) { - shared_ptr piece = weak_piece.lock (); + _in_subtitle.piece = weak_piece; + _in_subtitle.image = image; + _in_subtitle.rect = rect; + _in_subtitle.from = from; + _in_subtitle.to = to; + + update_subtitle (); +} + +void +Player::update_subtitle () +{ + shared_ptr piece = _in_subtitle.piece.lock (); if (!piece) { return; } @@ -522,8 +524,31 @@ Player::process_subtitle (weak_ptr weak_piece, shared_ptr shared_ptr sc = dynamic_pointer_cast (piece->content); assert (sc); - _subtitle = sub; - _subtitle_content_time = piece->content->start (); - _subtitle_offset = sc->subtitle_offset (); - _subtitle_scale = sc->subtitle_scale (); + dcpomatic::Rect in_rect = _in_subtitle.rect; + libdcp::Size scaled_size; + + in_rect.y += sc->subtitle_offset (); + + /* We will scale the subtitle up to fit _video_container_size, and also by the additional subtitle_scale */ + scaled_size.width = in_rect.width * _video_container_size.width * sc->subtitle_scale (); + scaled_size.height = in_rect.height * _video_container_size.height * sc->subtitle_scale (); + + /* Then we need a corrective translation, consisting of two parts: + * + * 1. that which is the result of the scaling of the subtitle by _video_container_size; this will be + * rect.x * _video_container_size.width and rect.y * _video_container_size.height. + * + * 2. that to shift the origin of the scale by subtitle_scale to the centre of the subtitle; this will be + * (width_before_subtitle_scale * (1 - subtitle_scale) / 2) and + * (height_before_subtitle_scale * (1 - subtitle_scale) / 2). + * + * Combining these two translations gives these expressions. + */ + + _out_subtitle.position.x = rint (_video_container_size.width * (in_rect.x + (in_rect.width * (1 - sc->subtitle_scale ()) / 2))); + _out_subtitle.position.y = rint (_video_container_size.height * (in_rect.y + (in_rect.height * (1 - sc->subtitle_scale ()) / 2))); + + _out_subtitle.image = _in_subtitle.image->scale (libdcp::Size (scaled_size.width, scaled_size.height), Scaler::from_id ("bicubic"), true); + _out_subtitle.from = _in_subtitle.from + piece->content->start (); + _out_subtitle.to = _in_subtitle.to + piece->content->start (); } diff --git a/src/lib/player.h b/src/lib/player.h index 32ef25d47..5a4ee97be 100644 --- a/src/lib/player.h +++ b/src/lib/player.h @@ -27,6 +27,7 @@ #include "audio_buffers.h" #include "content.h" #include "film.h" +#include "rect.h" class Job; class Film; @@ -35,7 +36,6 @@ class AudioContent; class Piece; class Image; class Resampler; -class TimedSubtitle; /** @class Player * @brief A class which can `play' a Playlist; emitting its audio and video. @@ -78,7 +78,7 @@ private: void process_video (boost::weak_ptr, boost::shared_ptr, bool, VideoContent::Frame); void process_audio (boost::weak_ptr, boost::shared_ptr, AudioContent::Frame); - void process_subtitle (boost::weak_ptr, boost::shared_ptr); + void process_subtitle (boost::weak_ptr, boost::shared_ptr, dcpomatic::Rect, Time, Time); void setup_pieces (); void playlist_changed (); void content_changed (boost::weak_ptr, int); @@ -88,6 +88,7 @@ private: void emit_silence (OutputAudioFrame); boost::shared_ptr resampler (boost::shared_ptr); void film_changed (Film::Property); + void update_subtitle (); boost::shared_ptr _film; boost::shared_ptr _playlist; @@ -110,10 +111,20 @@ private: boost::shared_ptr _black_frame; std::map, boost::shared_ptr > _resamplers; - boost::shared_ptr _subtitle; - Time _subtitle_content_time; - int _subtitle_offset; - float _subtitle_scale; + struct { + boost::weak_ptr piece; + boost::shared_ptr image; + dcpomatic::Rect rect; + Time from; + Time to; + } _in_subtitle; + + struct { + boost::shared_ptr image; + Position position; + Time from; + Time to; + } _out_subtitle; }; #endif diff --git a/src/lib/position.h b/src/lib/position.h new file mode 100644 index 000000000..f904fe661 --- /dev/null +++ b/src/lib/position.h @@ -0,0 +1,46 @@ +/* + 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. + +*/ + +#ifndef DVDOMATIC_POSITION_H +#define DVDOMATIC_POSITION_H + +/** @struct Position + * @brief A position. + */ +template +class Position +{ +public: + Position () + : x (0) + , y (0) + {} + + Position (T x_, T y_) + : x (x_) + , y (y_) + {} + + /** x coordinate */ + T x; + /** y coordinate */ + T y; +}; + +#endif diff --git a/src/lib/rect.h b/src/lib/rect.h new file mode 100644 index 000000000..df1869841 --- /dev/null +++ b/src/lib/rect.h @@ -0,0 +1,79 @@ +/* + 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. + +*/ + +#ifndef DVDOMATIC_RECT_H +#define DVDOMATIC_RECT_H + +#include "position.h" + +/* Put this inside a namespace as Apple put a Rect in the global namespace */ + +namespace dcpomatic +{ + +/** @struct Rect + * @brief A rectangle. + */ +template +class Rect +{ +public: + + Rect () + : x (0) + , y (0) + , width (0) + , height (0) + {} + + Rect (T x_, T y_, T w_, T h_) + : x (x_) + , y (y_) + , width (w_) + , height (h_) + {} + + T x; + T y; + T width; + T height; + + Position position () const { + return Position (x, y); + } + + Rect intersection (Rect const & other) const { + T const tx = max (x, other.x); + T const ty = max (y, other.y); + + return Rect ( + tx, ty, + min (x + width, other.x + other.width) - tx, + min (y + height, other.y + other.height) - ty + ); + } + + bool contains (Position p) const { + return (p.x >= x && p.x <= (x + width) && p.y >= y && p.y <= (y + height)); + } +}; + +} + +#endif diff --git a/src/lib/server.cc b/src/lib/server.cc index 5ca04c692..40d1c4c0c 100644 --- a/src/lib/server.cc +++ b/src/lib/server.cc @@ -36,7 +36,6 @@ #include "image.h" #include "dcp_video_frame.h" #include "config.h" -#include "subtitle.h" #include "i18n.h" diff --git a/src/lib/subtitle.cc b/src/lib/subtitle.cc deleted file mode 100644 index 7013f1d7d..000000000 --- a/src/lib/subtitle.cc +++ /dev/null @@ -1,149 +0,0 @@ -/* - 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. - -*/ - -/** @file src/subtitle.cc - * @brief Representations of subtitles. - */ - -#include "subtitle.h" -#include "image.h" -#include "exceptions.h" - -#include "i18n.h" - -using boost::shared_ptr; -using libdcp::Size; - -/** Construct a TimedSubtitle. This is a subtitle image, position, - * and a range of time over which it should be shown. - * @param sub AVSubtitle to read. - */ -TimedSubtitle::TimedSubtitle (AVSubtitle const & sub) -{ - assert (sub.num_rects > 0); - - /* Subtitle PTS in seconds (within the source, not taking into account any of the - source that we may have chopped off for the DCP) - */ - double const packet_time = static_cast (sub.pts) / AV_TIME_BASE; - - /* hence start time for this sub */ - _from = (packet_time + (double (sub.start_display_time) / 1e3)) * TIME_HZ; - _to = (packet_time + (double (sub.end_display_time) / 1e3)) * TIME_HZ; - - if (sub.num_rects > 1) { - throw DecodeError (_("multi-part subtitles not yet supported")); - } - - AVSubtitleRect const * rect = sub.rects[0]; - - if (rect->type != SUBTITLE_BITMAP) { - throw DecodeError (_("non-bitmap subtitles not yet supported")); - } - - shared_ptr image (new SimpleImage (PIX_FMT_RGBA, libdcp::Size (rect->w, rect->h), true)); - - /* Start of the first line in the subtitle */ - uint8_t* sub_p = rect->pict.data[0]; - /* sub_p looks up into a RGB palette which is here */ - uint32_t const * palette = (uint32_t *) rect->pict.data[1]; - /* Start of the output data */ - uint32_t* out_p = (uint32_t *) image->data()[0]; - - for (int y = 0; y < rect->h; ++y) { - uint8_t* sub_line_p = sub_p; - uint32_t* out_line_p = out_p; - for (int x = 0; x < rect->w; ++x) { - *out_line_p++ = palette[*sub_line_p++]; - } - sub_p += rect->pict.linesize[0]; - out_p += image->stride()[0] / sizeof (uint32_t); - } - - _subtitle.reset (new Subtitle (Position (rect->x, rect->y), image)); -} - -/** @param t Time from the start of the source */ -bool -TimedSubtitle::displayed_at (Time t) const -{ - return t >= _from && t <= _to; -} - -/** Construct a subtitle, which is an image and a position. - * @param p Position within the (uncropped) source frame. - * @param i Image of the subtitle (should be RGBA). - */ -Subtitle::Subtitle (Position p, shared_ptr i) - : _position (p) - , _image (i) -{ - -} - -/** Given the area of a subtitle, work out the area it should - * take up when its video frame is scaled up, and it is optionally - * itself scaled and offset. - * @param target_x_scale the x scaling of the video frame that the subtitle is in. - * @param target_y_scale the y scaling of the video frame that the subtitle is in. - * @param sub_area The area of the subtitle within the original source. - * @param subtitle_offset y offset to apply to the subtitle position (+ve is down) - * in the coordinate space of the source. - * @param subtitle_scale scaling factor to apply to the subtitle image. - */ -dcpomatic::Rect -subtitle_transformed_area ( - float target_x_scale, float target_y_scale, - dcpomatic::Rect sub_area, int subtitle_offset, float subtitle_scale - ) -{ - dcpomatic::Rect tx; - - sub_area.y += subtitle_offset; - - /* We will scale the subtitle by the same amount as the video frame, and also by the additional - subtitle_scale - */ - tx.width = sub_area.width * target_x_scale * subtitle_scale; - tx.height = sub_area.height * target_y_scale * subtitle_scale; - - /* Then we need a corrective translation, consisting of two parts: - * - * 1. that which is the result of the scaling of the subtitle by target_x_scale and target_y_scale; this will be - * sub_area.x * target_x_scale and sub_area.y * target_y_scale. - * - * 2. that to shift the origin of the scale by subtitle_scale to the centre of the subtitle; this will be - * (width_before_subtitle_scale * (1 - subtitle_scale) / 2) and - * (height_before_subtitle_scale * (1 - subtitle_scale) / 2). - * - * Combining these two translations gives these expressions. - */ - - tx.x = rint (target_x_scale * (sub_area.x + (sub_area.width * (1 - subtitle_scale) / 2))); - tx.y = rint (target_y_scale * (sub_area.y + (sub_area.height * (1 - subtitle_scale) / 2))); - - return tx; -} - -/** @return area that this subtitle takes up, in the original uncropped source's coordinate space */ -dcpomatic::Rect -Subtitle::area () const -{ - return dcpomatic::Rect (_position.x, _position.y, _image->size().width, _image->size().height); -} diff --git a/src/lib/subtitle.h b/src/lib/subtitle.h deleted file mode 100644 index 47735c453..000000000 --- a/src/lib/subtitle.h +++ /dev/null @@ -1,82 +0,0 @@ -/* - 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. - -*/ - -/** @file src/subtitle.h - * @brief Representations of subtitles. - */ - -#include -#include -#include "types.h" - -struct AVSubtitle; -class Image; - -/** A subtitle, consisting of an image and a position */ -class Subtitle -{ -public: - Subtitle (Position p, boost::shared_ptr i); - - void set_position (Position p) { - _position = p; - } - - Position position () const { - return _position; - } - - boost::shared_ptr image () const { - return _image; - } - - dcpomatic::Rect area () const; - -private: - Position _position; - boost::shared_ptr _image; -}; - -dcpomatic::Rect -subtitle_transformed_area ( - float target_x_scale, float target_y_scale, - dcpomatic::Rect sub_area, int subtitle_offset, float subtitle_scale - ); - -/** A Subtitle class with details of the time over which it should be shown */ -/** XXX: merge with Subtitle? */ -class TimedSubtitle -{ -public: - TimedSubtitle (AVSubtitle const &); - - bool displayed_at (Time) const; - - boost::shared_ptr subtitle () const { - return _subtitle; - } - -private: - /** the subtitle */ - boost::shared_ptr _subtitle; - /** display from time from the start of the content */ - Time _from; - /** display to time from the start of the content */ - Time _to; -}; diff --git a/src/lib/subtitle_content.cc b/src/lib/subtitle_content.cc index c8de9887e..9fefbbfcd 100644 --- a/src/lib/subtitle_content.cc +++ b/src/lib/subtitle_content.cc @@ -52,7 +52,7 @@ SubtitleContent::as_xml (xmlpp::Node* root) const } void -SubtitleContent::set_subtitle_offset (int o) +SubtitleContent::set_subtitle_offset (double o) { { boost::mutex::scoped_lock lm (_mutex); @@ -62,7 +62,7 @@ SubtitleContent::set_subtitle_offset (int o) } void -SubtitleContent::set_subtitle_scale (float s) +SubtitleContent::set_subtitle_scale (double s) { { boost::mutex::scoped_lock lm (_mutex); diff --git a/src/lib/subtitle_content.h b/src/lib/subtitle_content.h index 5eb4e500d..1092b7b1c 100644 --- a/src/lib/subtitle_content.h +++ b/src/lib/subtitle_content.h @@ -37,26 +37,26 @@ public: void as_xml (xmlpp::Node *) const; - void set_subtitle_offset (int); - void set_subtitle_scale (float); + void set_subtitle_offset (double); + void set_subtitle_scale (double); - int subtitle_offset () const { + double subtitle_offset () const { boost::mutex::scoped_lock lm (_mutex); return _subtitle_offset; } - float subtitle_scale () const { + double subtitle_scale () const { boost::mutex::scoped_lock lm (_mutex); return _subtitle_scale; } private: - /** y offset for placing subtitles, in source pixels; +ve is further down - the frame, -ve is further up. + /** y offset for placing subtitles, as a proportion of the container height; + +ve is further down the frame, -ve is further up. */ - int _subtitle_offset; + double _subtitle_offset; /** scale factor to apply to subtitles */ - float _subtitle_scale; + double _subtitle_scale; }; #endif diff --git a/src/lib/subtitle_decoder.cc b/src/lib/subtitle_decoder.cc index 0ffe5e501..c06f3d718 100644 --- a/src/lib/subtitle_decoder.cc +++ b/src/lib/subtitle_decoder.cc @@ -19,7 +19,6 @@ #include #include "subtitle_decoder.h" -#include "subtitle.h" using boost::shared_ptr; @@ -31,11 +30,10 @@ SubtitleDecoder::SubtitleDecoder (shared_ptr f) /** Called by subclasses when a subtitle is ready. - * s may be 0 to say that there is no current subtitle. - * @param s New current subtitle, or 0. + * Image may be 0 to say that there is no current subtitle. */ void -SubtitleDecoder::subtitle (shared_ptr s) +SubtitleDecoder::subtitle (shared_ptr image, dcpomatic::Rect rect, Time from, Time to) { - Subtitle (s); + Subtitle (image, rect, from, to); } diff --git a/src/lib/subtitle_decoder.h b/src/lib/subtitle_decoder.h index 0c299f61f..628f4d60d 100644 --- a/src/lib/subtitle_decoder.h +++ b/src/lib/subtitle_decoder.h @@ -19,6 +19,8 @@ #include #include "decoder.h" +#include "rect.h" +#include "types.h" class Film; class TimedSubtitle; @@ -28,8 +30,8 @@ class SubtitleDecoder : public virtual Decoder public: SubtitleDecoder (boost::shared_ptr); - boost::signals2::signal)> Subtitle; + boost::signals2::signal, dcpomatic::Rect, Time, Time)> Subtitle; protected: - void subtitle (boost::shared_ptr); + void subtitle (boost::shared_ptr, dcpomatic::Rect, Time, Time); }; diff --git a/src/lib/types.cc b/src/lib/types.cc index 78cb4cd64..035c8363d 100644 --- a/src/lib/types.cc +++ b/src/lib/types.cc @@ -32,25 +32,3 @@ bool operator!= (Crop const & a, Crop const & b) return !(a == b); } - -/** @param other A Rect. - * @return The intersection of this with `other'. - */ -dcpomatic::Rect -dcpomatic::Rect::intersection (Rect const & other) const -{ - int const tx = max (x, other.x); - int const ty = max (y, other.y); - - return Rect ( - tx, ty, - min (x + width, other.x + other.width) - tx, - min (y + height, other.y + other.height) - ty - ); -} - -bool -dcpomatic::Rect::contains (Position p) const -{ - return (p.x >= x && p.x <= (x + width) && p.y >= y && p.y <= (y + height)); -} diff --git a/src/lib/types.h b/src/lib/types.h index 33f8239d8..67384103d 100644 --- a/src/lib/types.h +++ b/src/lib/types.h @@ -53,66 +53,4 @@ struct Crop extern bool operator== (Crop const & a, Crop const & b); extern bool operator!= (Crop const & a, Crop const & b); -/** @struct Position - * @brief A position. - */ -struct Position -{ - Position () - : x (0) - , y (0) - {} - - Position (int x_, int y_) - : x (x_) - , y (y_) - {} - - /** x coordinate */ - int x; - /** y coordinate */ - int y; -}; - -namespace dcpomatic { - -/** @struct Rect - * @brief A rectangle. - */ -struct Rect -{ - Rect () - : x (0) - , y (0) - , width (0) - , height (0) - {} - - Rect (int x_, int y_, int w_, int h_) - : x (x_) - , y (y_) - , width (w_) - , height (h_) - {} - - int x; - int y; - int width; - int height; - - Position position () const { - return Position (x, y); - } - - libdcp::Size size () const { - return libdcp::Size (width, height); - } - - Rect intersection (Rect const & other) const; - - bool contains (Position) const; -}; - -} - #endif diff --git a/src/lib/video_decoder.cc b/src/lib/video_decoder.cc index 0616cd437..457cfe47b 100644 --- a/src/lib/video_decoder.cc +++ b/src/lib/video_decoder.cc @@ -18,10 +18,7 @@ */ #include "video_decoder.h" -#include "subtitle.h" -#include "film.h" #include "image.h" -#include "ratio.h" #include "i18n.h" diff --git a/src/lib/wscript b/src/lib/wscript index f646d9781..5c381b69c 100644 --- a/src/lib/wscript +++ b/src/lib/wscript @@ -44,7 +44,6 @@ sources = """ sndfile_content.cc sndfile_decoder.cc sound_processor.cc - subtitle.cc subtitle_content.cc subtitle_decoder.cc timer.cc diff --git a/src/wx/film_editor.cc b/src/wx/film_editor.cc index f63121201..e3c4af12c 100644 --- a/src/wx/film_editor.cc +++ b/src/wx/film_editor.cc @@ -426,7 +426,7 @@ FilmEditor::make_subtitle_panel () wxBoxSizer* s = new wxBoxSizer (wxHORIZONTAL); _subtitle_offset = new wxSpinCtrl (_subtitle_panel); s->Add (_subtitle_offset); - add_label_to_sizer (s, _subtitle_panel, _("pixels"), false); + add_label_to_sizer (s, _subtitle_panel, _("%"), false); grid->Add (s); } @@ -443,7 +443,7 @@ FilmEditor::make_subtitle_panel () _subtitle_stream = new wxChoice (_subtitle_panel, wxID_ANY); grid->Add (_subtitle_stream, 1, wxEXPAND); - _subtitle_offset->SetRange (-1024, 1024); + _subtitle_offset->SetRange (-100, 100); _subtitle_scale->SetRange (1, 1000); } @@ -532,7 +532,7 @@ FilmEditor::subtitle_offset_changed (wxCommandEvent &) return; } - c->set_subtitle_offset (_subtitle_offset->GetValue ()); + c->set_subtitle_offset (_subtitle_offset->GetValue() / 100.0); } void @@ -775,7 +775,7 @@ FilmEditor::film_content_changed (weak_ptr weak_content, int property) _dcp_sizer->Layout (); } } else if (property == SubtitleContentProperty::SUBTITLE_OFFSET) { - checked_set (_subtitle_offset, subtitle_content ? subtitle_content->subtitle_offset() : 0); + checked_set (_subtitle_offset, subtitle_content ? (subtitle_content->subtitle_offset() * 100) : 0); } else if (property == SubtitleContentProperty::SUBTITLE_SCALE) { checked_set (_subtitle_scale, subtitle_content ? (subtitle_content->subtitle_scale() * 100) : 100); } diff --git a/src/wx/timeline.cc b/src/wx/timeline.cc index bd2d314a4..f9223f19d 100644 --- a/src/wx/timeline.cc +++ b/src/wx/timeline.cc @@ -55,7 +55,7 @@ public: _timeline.force_redraw (bbox ()); } - virtual dcpomatic::Rect bbox () const = 0; + virtual dcpomatic::Rect bbox () const = 0; protected: virtual void do_paint (wxGraphicsContext *) = 0; @@ -68,7 +68,7 @@ protected: Timeline& _timeline; private: - dcpomatic::Rect _last_paint_bbox; + dcpomatic::Rect _last_paint_bbox; }; class ContentView : public View @@ -83,15 +83,15 @@ public: _content_connection = c->Changed.connect (bind (&ContentView::content_changed, this, _2)); } - dcpomatic::Rect bbox () const + dcpomatic::Rect bbox () const { shared_ptr film = _timeline.film (); shared_ptr content = _content.lock (); if (!film || !content) { - return dcpomatic::Rect (); + return dcpomatic::Rect (); } - return dcpomatic::Rect ( + return dcpomatic::Rect ( time_x (content->start ()) - 8, y_pos (_track) - 8, content->length () * _timeline.pixels_per_time_unit() + 16, @@ -243,9 +243,9 @@ public: , _y (y) {} - dcpomatic::Rect bbox () const + dcpomatic::Rect bbox () const { - return dcpomatic::Rect (0, _y - 4, _timeline.width(), 24); + return dcpomatic::Rect (0, _y - 4, _timeline.width(), 24); } void set_y (int y) @@ -476,7 +476,7 @@ void Timeline::left_down (wxMouseEvent& ev) { list >::iterator i = _views.begin(); - Position const p (ev.GetX(), ev.GetY()); + Position const p (ev.GetX(), ev.GetY()); while (i != _views.end() && !(*i)->bbox().contains (p)) { ++i; } @@ -545,7 +545,7 @@ Timeline::mouse_moved (wxMouseEvent& ev) } void -Timeline::force_redraw (dcpomatic::Rect const & r) +Timeline::force_redraw (dcpomatic::Rect const & r) { RefreshRect (wxRect (r.x, r.y, r.width, r.height), false); } diff --git a/src/wx/timeline.h b/src/wx/timeline.h index 5c25a6426..3e984bfe1 100644 --- a/src/wx/timeline.h +++ b/src/wx/timeline.h @@ -22,6 +22,7 @@ #include #include #include "util.h" +#include "rect.h" class Film; class View; @@ -36,7 +37,7 @@ public: boost::shared_ptr film () const; - void force_redraw (dcpomatic::Rect const &); + void force_redraw (dcpomatic::Rect const &); int x_offset () const { return 8; @@ -54,8 +55,8 @@ public: return _pixels_per_time_unit; } - Position tracks_position () const { - return Position (8, 8); + Position tracks_position () const { + return Position (8, 8); } int tracks () const; diff --git a/test/client_server_test.cc b/test/client_server_test.cc index 51b52331a..232190286 100644 --- a/test/client_server_test.cc +++ b/test/client_server_test.cc @@ -56,7 +56,7 @@ BOOST_AUTO_TEST_CASE (client_server_test) p += sub_image->stride()[0]; } - shared_ptr subtitle (new Subtitle (Position (50, 60), sub_image)); +// shared_ptr subtitle (new Subtitle (Position (50, 60), sub_image)); shared_ptr log (new FileLog ("build/test/client_server_test.log")); diff --git a/test/test.cc b/test/test.cc index d6c7842d7..0a682383a 100644 --- a/test/test.cc +++ b/test/test.cc @@ -36,7 +36,6 @@ #include "server.h" #include "cross.h" #include "job.h" -#include "subtitle.h" #include "scaler.h" #include "ffmpeg_decoder.h" #include "sndfile_decoder.h" -- cgit v1.2.3