Make subtitles work at least a bit.
authorCarl Hetherington <cth@carlh.net>
Wed, 10 Jul 2013 19:29:00 +0000 (20:29 +0100)
committerCarl Hetherington <cth@carlh.net>
Wed, 10 Jul 2013 19:29:00 +0000 (20:29 +0100)
24 files changed:
src/lib/decoder.h
src/lib/ffmpeg_decoder.cc
src/lib/image.cc
src/lib/image.h
src/lib/player.cc
src/lib/player.h
src/lib/position.h [new file with mode: 0644]
src/lib/rect.h [new file with mode: 0644]
src/lib/server.cc
src/lib/subtitle.cc [deleted file]
src/lib/subtitle.h [deleted file]
src/lib/subtitle_content.cc
src/lib/subtitle_content.h
src/lib/subtitle_decoder.cc
src/lib/subtitle_decoder.h
src/lib/types.cc
src/lib/types.h
src/lib/video_decoder.cc
src/lib/wscript
src/wx/film_editor.cc
src/wx/timeline.cc
src/wx/timeline.h
test/client_server_test.cc
test/test.cc

index cfca6867f652d3fc9d2d5be7320d75128060cffe..dea4def3a09a510cefd73cd50aa9c0c633a9bf77 100644 (file)
@@ -34,8 +34,6 @@
 class Image;
 class Log;
 class DelayLine;
-class TimedSubtitle;
-class Subtitle;
 class FilterGraph;
 
 /** @class Decoder.
index 3714c1542952a22c3d57e0ee0447d0f6eddaf3e5..fddb7029484c23695b6be457c5843d0813754fd1 100644 (file)
@@ -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<TimedSubtitle> ts;
-               try {
-                       subtitle (shared_ptr<TimedSubtitle> (new TimedSubtitle (sub)));
-               } catch (...) {
-                       /* some problem with the subtitle; we probably didn't understand it */
+       if (sub.num_rects <= 0) {
+               subtitle (shared_ptr<Image> (), dcpomatic::Rect<double> (), 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<double> (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> 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<TimedSubtitle> ());
+               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<double> (
+                       static_cast<double> (rect->x) / vs.width,
+                       static_cast<double> (rect->y) / vs.height,
+                       static_cast<double> (rect->w) / vs.width,
+                       static_cast<double> (rect->h) / vs.height
+                       ),
+               from,
+               to
+               );
+                         
        
        avsubtitle_free (&sub);
 }
index ac30f4ff05f23992ba6dd0f2f8394468d960c7a2..c11bcbb8d5b7c8076e71446ffa77659c921e5386 100644 (file)
@@ -336,7 +336,7 @@ Image::make_black ()
 }
 
 void
-Image::alpha_blend (shared_ptr<const Image> other, Position position)
+Image::alpha_blend (shared_ptr<const Image> other, Position<int> 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<const Image> other, Position position)
 }
 
 void
-Image::copy (shared_ptr<const Image> other, Position position)
+Image::copy (shared_ptr<const Image> other, Position<int> position)
 {
        /* Only implemented for RGB24 onto RGB24 so far */
        assert (_pixel_format == PIX_FMT_RGB24 && other->pixel_format() == PIX_FMT_RGB24);
index 5407ce66e502f8fc7a74d092549a2090eecf81fe..d40ba77b4b9413c30f0c3848ad825bea7b1eae7c 100644 (file)
@@ -32,6 +32,7 @@ extern "C" {
 #include <libavfilter/avfilter.h>
 }
 #include "util.h"
+#include "position.h"
 
 class Scaler;
 class SimpleImage;
@@ -75,8 +76,8 @@ public:
        boost::shared_ptr<Image> scale_and_convert_to_rgb (libdcp::Size, Scaler const *, bool) const;
        boost::shared_ptr<Image> scale (libdcp::Size, Scaler const *, bool aligned) const;
        boost::shared_ptr<Image> post_process (std::string, bool aligned) const;
-       void alpha_blend (boost::shared_ptr<const Image> image, Position pos);
-       void copy (boost::shared_ptr<const Image> image, Position pos);
+       void alpha_blend (boost::shared_ptr<const Image> image, Position<int> pos);
+       void copy (boost::shared_ptr<const Image> image, Position<int> pos);
        boost::shared_ptr<Image> crop (Crop c, bool aligned) const;
        
        void make_black ();
index c615f0a8963212b659b443f47ac23145365b16c1..58ba57bdcd2b25dde49a8d08fe6601f8923ac32a 100644 (file)
@@ -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<Piece> weak_piece, shared_ptr<const Image> image
 
        Time time = content->start() + (frame * frc.factor() * TIME_HZ / _film->dcp_video_frame_rate());
        
-       if (_film->with_subtitles ()) {
-               shared_ptr<Subtitle> 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<Image> 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<Piece> weak_piece, shared_ptr<const Image> image
                assert (image_size.height <= _video_container_size.height);
                shared_ptr<Image> 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<int> ((_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<Content> 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<Piece> weak_piece, shared_ptr<TimedSubtitle> sub)
+Player::process_subtitle (weak_ptr<Piece> weak_piece, shared_ptr<Image> image, dcpomatic::Rect<double> rect, Time from, Time to)
 {
-       shared_ptr<Piece> 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> piece = _in_subtitle.piece.lock ();
        if (!piece) {
                return;
        }
@@ -522,8 +524,31 @@ Player::process_subtitle (weak_ptr<Piece> weak_piece, shared_ptr<TimedSubtitle>
        shared_ptr<SubtitleContent> sc = dynamic_pointer_cast<SubtitleContent> (piece->content);
        assert (sc);
 
-       _subtitle = sub;
-       _subtitle_content_time = piece->content->start ();
-       _subtitle_offset = sc->subtitle_offset ();
-       _subtitle_scale = sc->subtitle_scale ();
+       dcpomatic::Rect<double> 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 ();
 }
index 32ef25d47142a1e1489f7e49250164b08f2babdb..5a4ee97becdc561b72cad6e59a36f97e77f02a80 100644 (file)
@@ -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<Piece>, boost::shared_ptr<const Image>, bool, VideoContent::Frame);
        void process_audio (boost::weak_ptr<Piece>, boost::shared_ptr<const AudioBuffers>, AudioContent::Frame);
-       void process_subtitle (boost::weak_ptr<Piece>, boost::shared_ptr<TimedSubtitle>);
+       void process_subtitle (boost::weak_ptr<Piece>, boost::shared_ptr<Image>, dcpomatic::Rect<double>, Time, Time);
        void setup_pieces ();
        void playlist_changed ();
        void content_changed (boost::weak_ptr<Content>, int);
@@ -88,6 +88,7 @@ private:
        void emit_silence (OutputAudioFrame);
        boost::shared_ptr<Resampler> resampler (boost::shared_ptr<AudioContent>);
        void film_changed (Film::Property);
+       void update_subtitle ();
 
        boost::shared_ptr<const Film> _film;
        boost::shared_ptr<const Playlist> _playlist;
@@ -110,10 +111,20 @@ private:
        boost::shared_ptr<Image> _black_frame;
        std::map<boost::shared_ptr<AudioContent>, boost::shared_ptr<Resampler> > _resamplers;
 
-       boost::shared_ptr<TimedSubtitle> _subtitle;
-       Time _subtitle_content_time;
-       int _subtitle_offset;
-       float _subtitle_scale;
+       struct {
+               boost::weak_ptr<Piece> piece;
+               boost::shared_ptr<Image> image;
+               dcpomatic::Rect<double> rect;
+               Time from;
+               Time to;
+       } _in_subtitle;
+
+       struct {
+               boost::shared_ptr<Image> image;
+               Position<int> position;
+               Time from;
+               Time to;
+       } _out_subtitle;
 };
 
 #endif
diff --git a/src/lib/position.h b/src/lib/position.h
new file mode 100644 (file)
index 0000000..f904fe6
--- /dev/null
@@ -0,0 +1,46 @@
+/*
+    Copyright (C) 2013 Carl Hetherington <cth@carlh.net>
+
+    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 T>
+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 (file)
index 0000000..df18698
--- /dev/null
@@ -0,0 +1,79 @@
+/*
+    Copyright (C) 2013 Carl Hetherington <cth@carlh.net>
+
+    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 T>     
+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<T> position () const {
+               return Position<T> (x, y);
+       }
+
+       Rect<T> intersection (Rect<T> 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<T> p) const {
+               return (p.x >= x && p.x <= (x + width) && p.y >= y && p.y <= (y + height));
+       }
+};
+
+}
+
+#endif
index 5ca04c69249c2292b005432d0605ae021a72e546..40d1c4c0ca9d769a036ab21240d26686382d6ab0 100644 (file)
@@ -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 (file)
index 7013f1d..0000000
+++ /dev/null
@@ -1,149 +0,0 @@
-/*
-    Copyright (C) 2012 Carl Hetherington <cth@carlh.net>
-
-    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<double> (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> 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<Image> 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 (file)
index 47735c4..0000000
+++ /dev/null
@@ -1,82 +0,0 @@
-/*
-    Copyright (C) 2012 Carl Hetherington <cth@carlh.net>
-
-    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 <list>
-#include <boost/shared_ptr.hpp>
-#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<Image> i);
-
-       void set_position (Position p) {
-               _position = p;
-       }
-
-       Position position () const {
-               return _position;
-       }
-       
-       boost::shared_ptr<Image> image () const {
-               return _image;
-       }
-
-       dcpomatic::Rect area () const;
-       
-private:
-       Position _position;
-       boost::shared_ptr<Image> _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> subtitle () const {
-               return _subtitle;
-       }
-
-private:
-       /** the subtitle */
-       boost::shared_ptr<Subtitle> _subtitle;
-       /** display from time from the start of the content */
-       Time _from;
-       /** display to time from the start of the content */
-       Time _to;
-};
index c8de9887e66a778e43e3a50c79d6e77ee6a6c2f4..9fefbbfcda7258c5ff66ec01d80658bf46761bfd 100644 (file)
@@ -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);
index 5eb4e500dacd1a7bca230d5bd41b249d110bef63..1092b7b1cc7e32440515d653bc817f9005ecb680 100644 (file)
@@ -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
index 0ffe5e50158e1a70a9bf242b8dc43b3b00c07a1a..c06f3d718a812e9403266e3ccf91f5c494fa69b8 100644 (file)
@@ -19,7 +19,6 @@
 
 #include <boost/shared_ptr.hpp>
 #include "subtitle_decoder.h"
-#include "subtitle.h"
 
 using boost::shared_ptr;
 
@@ -31,11 +30,10 @@ SubtitleDecoder::SubtitleDecoder (shared_ptr<const Film> 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<TimedSubtitle> s)
+SubtitleDecoder::subtitle (shared_ptr<Image> image, dcpomatic::Rect<double> rect, Time from, Time to)
 {
-       Subtitle (s);
+       Subtitle (image, rect, from, to);
 }
index 0c299f61f24a62a47190a61637a6d81e28e601a5..628f4d60d6da6b61a49fefcc26671bdcac4cd047 100644 (file)
@@ -19,6 +19,8 @@
 
 #include <boost/signals2.hpp>
 #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<const Film>);
 
-       boost::signals2::signal<void (boost::shared_ptr<TimedSubtitle>)> Subtitle;
+       boost::signals2::signal<void (boost::shared_ptr<Image>, dcpomatic::Rect<double>, Time, Time)> Subtitle;
 
 protected:
-       void subtitle (boost::shared_ptr<TimedSubtitle>);
+       void subtitle (boost::shared_ptr<Image>, dcpomatic::Rect<double>, Time, Time);
 };
index 78cb4cd6490990bee12d75526c4a6178530152ff..035c8363db10a1d8ba67c40134811fa9467b4611 100644 (file)
@@ -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));
-}
index 33f8239d88cbee89ace3e07b51acd94d67b27fd9..67384103d2145ab42b1f888459cd94890ecb7f5b 100644 (file)
@@ -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
index 0616cd43778f3ade0238bd1933516487699f47d3..457cfe47b1e3de06671b646d7ddaf48926c2f1c8 100644 (file)
 */
 
 #include "video_decoder.h"
-#include "subtitle.h"
-#include "film.h"
 #include "image.h"
-#include "ratio.h"
 
 #include "i18n.h"
 
index f646d9781b50fd256ce2e4288e3876aea0c271db..5c381b69cfc414a2a8dc71889637b281c1282776 100644 (file)
@@ -44,7 +44,6 @@ sources = """
           sndfile_content.cc
           sndfile_decoder.cc
           sound_processor.cc
-          subtitle.cc
           subtitle_content.cc
           subtitle_decoder.cc
           timer.cc
index f63121201c675e113759f7c5718d1bb9aec76920..e3c4af12c5ede493617fd9d12f7fbb750e9a2a75 100644 (file)
@@ -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<Content> 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);
        }
index bd2d314a4ef8e1e5c2a949e6189078de31bda100..f9223f19dd34c4e8c91a65740f6df1d9ddc4b806 100644 (file)
@@ -55,7 +55,7 @@ public:
                _timeline.force_redraw (bbox ());
        }
 
-       virtual dcpomatic::Rect bbox () const = 0;
+       virtual dcpomatic::Rect<int> 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<int> _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<int> bbox () const
        {
                shared_ptr<const Film> film = _timeline.film ();
                shared_ptr<const Content> content = _content.lock ();
                if (!film || !content) {
-                       return dcpomatic::Rect ();
+                       return dcpomatic::Rect<int> ();
                }
                
-               return dcpomatic::Rect (
+               return dcpomatic::Rect<int> (
                        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<int> bbox () const
        {
-               return dcpomatic::Rect (0, _y - 4, _timeline.width(), 24);
+               return dcpomatic::Rect<int> (0, _y - 4, _timeline.width(), 24);
        }
 
        void set_y (int y)
@@ -476,7 +476,7 @@ void
 Timeline::left_down (wxMouseEvent& ev)
 {
        list<shared_ptr<View> >::iterator i = _views.begin();
-       Position const p (ev.GetX(), ev.GetY());
+       Position<int> 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<int> const & r)
 {
        RefreshRect (wxRect (r.x, r.y, r.width, r.height), false);
 }
index 5c25a6426c97306f9cd2895fd6c43b253ad104cc..3e984bfe1dcab4512c21928bb40104c2e322ee83 100644 (file)
@@ -22,6 +22,7 @@
 #include <boost/signals2.hpp>
 #include <wx/wx.h>
 #include "util.h"
+#include "rect.h"
 
 class Film;
 class View;
@@ -36,7 +37,7 @@ public:
 
        boost::shared_ptr<const Film> film () const;
 
-       void force_redraw (dcpomatic::Rect const &);
+       void force_redraw (dcpomatic::Rect<int> 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<int> tracks_position () const {
+               return Position<int> (8, 8);
        }
 
        int tracks () const;
index 51b52331af8c84c938132f29d86ebef06cab4d6b..2321902862e870693f461916d802479bd8519f42 100644 (file)
@@ -56,7 +56,7 @@ BOOST_AUTO_TEST_CASE (client_server_test)
                p += sub_image->stride()[0];
        }
 
-       shared_ptr<Subtitle> subtitle (new Subtitle (Position (50, 60), sub_image));
+//     shared_ptr<Subtitle> subtitle (new Subtitle (Position<int> (50, 60), sub_image));
 
        shared_ptr<FileLog> log (new FileLog ("build/test/client_server_test.log"));
 
index d6c7842d711692cc2acd39d296a41916af6cba57..0a682383a2aea7139b0aca6f044a89583a86e1e5 100644 (file)
@@ -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"