Basic return of subtitles.
authorCarl Hetherington <cth@carlh.net>
Wed, 10 Jul 2013 14:04:57 +0000 (15:04 +0100)
committerCarl Hetherington <cth@carlh.net>
Wed, 10 Jul 2013 14:04:57 +0000 (15:04 +0100)
src/lib/ffmpeg_decoder.cc
src/lib/ffmpeg_decoder.h
src/lib/player.cc
src/lib/player.h
src/lib/subtitle.h
src/lib/subtitle_decoder.cc [new file with mode: 0644]
src/lib/subtitle_decoder.h [new file with mode: 0644]
src/lib/video_decoder.cc
src/lib/wscript

index d8ee278b39a3756d5bdb146638286d397a0ed3b0..3714c1542952a22c3d57e0ee0447d0f6eddaf3e5 100644 (file)
@@ -61,6 +61,7 @@ FFmpegDecoder::FFmpegDecoder (shared_ptr<const Film> f, shared_ptr<const FFmpegC
        : Decoder (f)
        , VideoDecoder (f)
        , AudioDecoder (f)
+       , SubtitleDecoder (f)
        , FFmpeg (c)
        , _subtitle_codec_context (0)
        , _subtitle_codec (0)
@@ -142,27 +143,7 @@ FFmpegDecoder::pass ()
        } else if (_ffmpeg_content->audio_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<TimedSubtitle> ts;
-                               try {
-                                       subtitle (shared_ptr<TimedSubtitle> (new TimedSubtitle (sub)));
-                               } catch (...) {
-                                       /* some problem with the subtitle; we probably didn't understand it */
-                               }
-                       } else {
-                               subtitle (shared_ptr<TimedSubtitle> ());
-                       }
-                       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<TimedSubtitle> ts;
+               try {
+                       subtitle (shared_ptr<TimedSubtitle> (new TimedSubtitle (sub)));
+               } catch (...) {
+                       /* some problem with the subtitle; we probably didn't understand it */
+               }
+       } else {
+               subtitle (shared_ptr<TimedSubtitle> ());
+       }
+       
+       avsubtitle_free (&sub);
+}
index eebf75445c24ec402b8d89a678a64df28b009827..8819954db0ef06c02c810b8647b6ea6719607c36 100644 (file)
@@ -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<const Film>, boost::shared_ptr<const FFmpegContent>, 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<AudioBuffers> deinterleave_audio (uint8_t** data, int size);
index 6b7dc27223938e3faa0460eaf83a8af3d5ca160c..2bafbdcd5736469d42ef187d3feca6c01cc44e1d 100644 (file)
@@ -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<Piece> weak_piece, shared_ptr<const Image> image
                return;
        }
 
-       image = image->crop (content->crop(), true);
+       shared_ptr<Image> 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<Subtitle> 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<Image> im = sub->image()->scale (tx.size(), film->scaler(), true);
-                       image->alpha_blend (im, tx.position());
+                       shared_ptr<Image> 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<Image> 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<Piece> weak_piece, shared_ptr<TimedSubtitle> sub)
+{
+       shared_ptr<Piece> piece = weak_piece.lock ();
+       if (!piece) {
+               return;
+       }
+
+       _subtitle = sub;
+       _subtitle_offset = piece->content->start ();
+}
index 15fa4dbd6ce5c1d118683e26bc5278e96cf31eef..f96d5ac695f37ee8d4a2c9aba445286bd638a616 100644 (file)
@@ -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<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 setup_pieces ();
        void playlist_changed ();
        void content_changed (boost::weak_ptr<Content>, int);
@@ -107,6 +109,9 @@ private:
        libdcp::Size _video_container_size;
        boost::shared_ptr<Image> _black_frame;
        std::map<boost::shared_ptr<AudioContent>, boost::shared_ptr<Resampler> > _resamplers;
+
+       boost::shared_ptr<TimedSubtitle> _subtitle;
+       Time _subtitle_offset;
 };
 
 #endif
index 1020397cced8e44a4967615bc8f49fd932a50898..47735c453767a2ce425ca16d1171f13734fe6f83 100644 (file)
@@ -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 (file)
index 0000000..0ffe5e5
--- /dev/null
@@ -0,0 +1,41 @@
+/*
+    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.
+
+*/
+
+#include <boost/shared_ptr.hpp>
+#include "subtitle_decoder.h"
+#include "subtitle.h"
+
+using boost::shared_ptr;
+
+SubtitleDecoder::SubtitleDecoder (shared_ptr<const Film> 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<TimedSubtitle> s)
+{
+       Subtitle (s);
+}
diff --git a/src/lib/subtitle_decoder.h b/src/lib/subtitle_decoder.h
new file mode 100644 (file)
index 0000000..0c299f6
--- /dev/null
@@ -0,0 +1,35 @@
+/*
+    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.
+
+*/
+
+#include <boost/signals2.hpp>
+#include "decoder.h"
+
+class Film;
+class TimedSubtitle;
+
+class SubtitleDecoder : public virtual Decoder
+{
+public:
+       SubtitleDecoder (boost::shared_ptr<const Film>);
+
+       boost::signals2::signal<void (boost::shared_ptr<TimedSubtitle>)> Subtitle;
+
+protected:
+       void subtitle (boost::shared_ptr<TimedSubtitle>);
+};
index f61e63d4d1a4c312c99054c436bfee462f2afdab..0616cd43778f3ade0238bd1933516487699f47d3 100644 (file)
@@ -42,21 +42,3 @@ VideoDecoder::video (shared_ptr<const Image> 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<TimedSubtitle> 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
-
index 2f86539841da3efade020391e8b9a97aeb8972a6..34d44ec5b21a6cd62e9d6fcc1388aac8370ceabb 100644 (file)
@@ -44,6 +44,7 @@ sources = """
           sndfile_content.cc
           sndfile_decoder.cc
           sound_processor.cc
+          subtitle_decoder.cc
           subtitle.cc
           timer.cc
           transcode_job.cc