Suspend scale / crop / window / subtitle overlay until we decide that a frame is...
authorCarl Hetherington <cth@carlh.net>
Wed, 4 Dec 2013 21:55:06 +0000 (21:55 +0000)
committerCarl Hetherington <cth@carlh.net>
Wed, 4 Dec 2013 21:55:06 +0000 (21:55 +0000)
ChangeLog
src/lib/encoder.cc
src/lib/encoder.h
src/lib/player.cc
src/lib/player.h
src/lib/transcoder.cc
src/tools/server_test.cc
src/wx/film_viewer.cc
src/wx/film_viewer.h
test/play_test.cc

index 13483cc3c994430dbd1857e1d3e9d2c5a6a79c29..1b251eaaac7510ef54fcb74c1afc4babe703f5b7 100644 (file)
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,5 +1,8 @@
 2013-12-04  Carl Hetherington  <cth@carlh.net>
 
+       * Only do scale/crop/window/subtitle overlay if a frame is going
+       to be encoded for the DCP.
+
        * Several optimisations to video processing, which should
        speed up the player a bit.
 
index 059c4014cf40b2e6be8862f1ea112854c2663096..f8a5971911278b96eb5332691c23f52de7aca2f3 100644 (file)
@@ -34,6 +34,7 @@
 #include "cross.h"
 #include "writer.h"
 #include "server_finder.h"
+#include "player.h"
 
 #include "i18n.h"
 
@@ -181,7 +182,7 @@ Encoder::frame_done ()
 }
 
 void
-Encoder::process_video (shared_ptr<const Image> image, Eyes eyes, ColourConversion conversion, bool same)
+Encoder::process_video (shared_ptr<PlayerImage> image, Eyes eyes, ColourConversion conversion, bool same)
 {
        boost::mutex::scoped_lock lock (_mutex);
 
@@ -215,7 +216,7 @@ Encoder::process_video (shared_ptr<const Image> image, Eyes eyes, ColourConversi
                TIMING ("adding to queue of %1", _queue.size ());
                _queue.push_back (shared_ptr<DCPVideoFrame> (
                                          new DCPVideoFrame (
-                                                 image, _video_frames_out, eyes, conversion, _film->video_frame_rate(),
+                                                 image->image(), _video_frames_out, eyes, conversion, _film->video_frame_rate(),
                                                  _film->j2k_bandwidth(), _film->log()
                                                  )
                                          ));
index 686aaa2f25e4977d16644813016e0f0550e208c3..d43e4e1d33c7d24833568813a840275894aeea29 100644 (file)
@@ -47,6 +47,7 @@ class EncodedData;
 class Writer;
 class Job;
 class ServerFinder;
+class PlayerImage;
 
 /** @class Encoder
  *  @brief Encoder to J2K and WAV for DCP.
@@ -68,7 +69,7 @@ public:
         *  @param i Video frame image.
         *  @param same true if i is the same as the last time we were called.
         */
-       void process_video (boost::shared_ptr<const Image> i, Eyes eyes, ColourConversion, bool same);
+       void process_video (boost::shared_ptr<PlayerImage> i, Eyes eyes, ColourConversion, bool same);
 
        /** Call with some audio data */
        void process_audio (boost::shared_ptr<const AudioBuffers>);
index 978db035fe796e271fef8578753e44535b8654c1..f4e181daf302ad1163476ab9cd2c35e13ffd309b 100644 (file)
@@ -273,23 +273,32 @@ Player::process_video (weak_ptr<Piece> weak_piece, shared_ptr<const Image> image
        Time const time = content->position() + relative_time + extra - content->trim_start ();
        float const ratio = content->ratio() ? content->ratio()->ratio() : content->video_size_after_crop().ratio();
        libdcp::Size const image_size = fit_ratio_within (ratio, _video_container_size);
-       
-       shared_ptr<Image> work_image = image->crop_scale_window (content->crop(), image_size, _video_container_size, _film->scaler(), PIX_FMT_RGB24, false);
 
-       Position<int> const container_offset (
-               (_video_container_size.width - image_size.width) / 2,
-               (_video_container_size.height - image_size.width) / 2
+       shared_ptr<PlayerImage> pi (
+               new PlayerImage (
+                       image,
+                       content->crop(),
+                       image_size,
+                       _video_container_size,
+                       _film->scaler()
+                       )
                );
-
+       
        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 + container_offset);
-       }
 
+               Position<int> const container_offset (
+                       (_video_container_size.width - image_size.width) / 2,
+                       (_video_container_size.height - image_size.width) / 2
+                       );
+
+               pi->set_subtitle (_out_subtitle.image, _out_subtitle.position + container_offset);
+       }
+                                           
 #ifdef DCPOMATIC_DEBUG
        _last_video = piece->content;
 #endif
 
-       Video (work_image, eyes, content->colour_conversion(), same, time);
+       Video (pi, eyes, content->colour_conversion(), same, time);
 
        _last_emit_was_black = false;
        _video_position = piece->video_position = (time + TIME_HZ / _film->video_frame_rate());
@@ -530,8 +539,19 @@ void
 Player::set_video_container_size (libdcp::Size s)
 {
        _video_container_size = s;
-       _black_frame.reset (new Image (PIX_FMT_RGB24, _video_container_size, true));
-       _black_frame->make_black ();
+
+       shared_ptr<Image> im (new Image (PIX_FMT_RGB24, _video_container_size, true));
+       im->make_black ();
+       
+       _black_frame.reset (
+               new PlayerImage (
+                       im,
+                       Crop(),
+                       _video_container_size,
+                       _video_container_size,
+                       Scaler::from_id ("bicubic")
+                       )
+               );
 }
 
 shared_ptr<Resampler>
@@ -679,3 +699,40 @@ Player::repeat_last_video ()
 
        return true;
 }
+
+PlayerImage::PlayerImage (
+       shared_ptr<const Image> in,
+       Crop crop,
+       libdcp::Size inter_size,
+       libdcp::Size out_size,
+       Scaler const * scaler
+       )
+       : _in (in)
+       , _crop (crop)
+       , _inter_size (inter_size)
+       , _out_size (out_size)
+       , _scaler (scaler)
+{
+
+}
+
+void
+PlayerImage::set_subtitle (shared_ptr<const Image> image, Position<int> pos)
+{
+       _subtitle_image = image;
+       _subtitle_position = pos;
+}
+
+shared_ptr<Image>
+PlayerImage::image ()
+{
+       shared_ptr<Image> out = _in->crop_scale_window (_crop, _inter_size, _out_size, _scaler, PIX_FMT_RGB24, false);
+
+       Position<int> const container_offset ((_out_size.width - _inter_size.width) / 2, (_out_size.height - _inter_size.width) / 2);
+
+       if (_subtitle_image) {
+               out->alpha_blend (_subtitle_image, _subtitle_position);
+       }
+
+       return out;
+}
index 5f7c2e3694217749d0b7846da747b61bb3c061f7..11cc99e7793005630a5e9ce1014e5827bdf55ed4 100644 (file)
@@ -52,6 +52,28 @@ public:
        VideoContent::Frame frame;
        Time extra;
 };
+
+/** A wrapper for an Image which contains some pending operations; these may
+ *  not be necessary if the receiver of the PlayerImage throws it away.
+ */
+class PlayerImage
+{
+public:
+       PlayerImage (boost::shared_ptr<const Image>, Crop, libdcp::Size, libdcp::Size, Scaler const *);
+
+       void set_subtitle (boost::shared_ptr<const Image>, Position<int>);
+       
+       boost::shared_ptr<Image> image ();
+
+private:
+       boost::shared_ptr<const Image> _in;
+       Crop _crop;
+       libdcp::Size _inter_size;
+       libdcp::Size _out_size;
+       Scaler const * _scaler;
+       boost::shared_ptr<const Image> _subtitle_image;
+       Position<int> _subtitle_position;
+};
  
 class Player : public boost::enable_shared_from_this<Player>, public boost::noncopyable
 {
@@ -79,7 +101,7 @@ public:
         *  Fourth parameter is true if the image is the same as the last one that was emitted.
         *  Fifth parameter is the time.
         */
-       boost::signals2::signal<void (boost::shared_ptr<const Image>, Eyes, ColourConversion, bool, Time)> Video;
+       boost::signals2::signal<void (boost::shared_ptr<PlayerImage>, Eyes, ColourConversion, bool, Time)> Video;
        
        /** Emitted when some audio data is ready */
        boost::signals2::signal<void (boost::shared_ptr<const AudioBuffers>, Time)> Audio;
@@ -128,7 +150,7 @@ private:
        AudioMerger<Time, AudioContent::Frame> _audio_merger;
 
        libdcp::Size _video_container_size;
-       boost::shared_ptr<Image> _black_frame;
+       boost::shared_ptr<PlayerImage> _black_frame;
        std::map<boost::shared_ptr<AudioContent>, boost::shared_ptr<Resampler> > _resamplers;
 
        struct {
index 826cba4fc61aa8755b7665dff5b97ee705166e04..1c8f7e3eb0b021d03f6c62a0076ce4cd41f56188 100644 (file)
@@ -40,7 +40,7 @@ using boost::weak_ptr;
 using boost::dynamic_pointer_cast;
 
 static void
-video_proxy (weak_ptr<Encoder> encoder, shared_ptr<const Image> image, Eyes eyes, ColourConversion conversion, bool same)
+video_proxy (weak_ptr<Encoder> encoder, shared_ptr<PlayerImage> image, Eyes eyes, ColourConversion conversion, bool same)
 {
        shared_ptr<Encoder> e = encoder.lock ();
        if (e) {
index 029e626147c9b8b68203aa14fde38bcba598a752..f0a44954ff2ee2ed88d9dcaef2de1044a7f42f09 100644 (file)
@@ -47,10 +47,10 @@ static shared_ptr<FileLog> log_ (new FileLog ("servomatictest.log"));
 static int frame = 0;
 
 void
-process_video (shared_ptr<const Image> image, Eyes eyes, ColourConversion conversion, Time)
+process_video (shared_ptr<PlayerImage> image, Eyes eyes, ColourConversion conversion, Time)
 {
-       shared_ptr<DCPVideoFrame> local  (new DCPVideoFrame (image, frame, eyes, conversion, film->video_frame_rate(), 250000000, log_));
-       shared_ptr<DCPVideoFrame> remote (new DCPVideoFrame (image, frame, eyes, conversion, film->video_frame_rate(), 250000000, log_));
+       shared_ptr<DCPVideoFrame> local  (new DCPVideoFrame (image->image(), frame, eyes, conversion, film->video_frame_rate(), 250000000, log_));
+       shared_ptr<DCPVideoFrame> remote (new DCPVideoFrame (image->image(), frame, eyes, conversion, film->video_frame_rate(), 250000000, log_));
 
        cout << "Frame " << frame << ": ";
        cout.flush ();
index b4935dcf4a4a696acfba35066a355bcc993304ca..fbca835c2bc2126513b9eb1b0eb49efce3fa1e29 100644 (file)
@@ -275,13 +275,13 @@ FilmViewer::check_play_state ()
 }
 
 void
-FilmViewer::process_video (shared_ptr<const Image> image, Eyes eyes, Time t)
+FilmViewer::process_video (shared_ptr<PlayerImage> image, Eyes eyes, Time t)
 {
        if (eyes == EYES_RIGHT) {
                return;
        }
        
-       _frame = image;
+       _frame = image->image ();
        _got_frame = true;
 
        set_position_text (t);
index 2337da6b0def299515654a3b957da6b3a3982568..c99c7344047448b088115a9e085bb5eb389937fa 100644 (file)
@@ -28,6 +28,7 @@ class wxToggleButton;
 class FFmpegPlayer;
 class Image;
 class RGBPlusAlphaImage;
+class PlayerImage;
 
 /** @class FilmViewer
  *  @brief A wx widget to view a preview of a Film.
@@ -58,7 +59,7 @@ private:
        void slider_moved ();
        void play_clicked ();
        void timer ();
-       void process_video (boost::shared_ptr<const Image>, Eyes, Time);
+       void process_video (boost::shared_ptr<PlayerImage>, Eyes, Time);
        void calculate_sizes ();
        void check_play_state ();
        void fetch_current_frame_again ();
index cb5b6cbb8cd2f1ff0349a9b93b211755e3b78583..dfa597431fee6b818d42e195f3676af6bf6229e8 100644 (file)
@@ -46,11 +46,11 @@ public:
                _player->Video.connect (bind (&PlayerWrapper::process_video, this, _1, _2, _5));
        }
 
-       void process_video (shared_ptr<const Image> i, bool, Time t)
+       void process_video (shared_ptr<PlayerImage> i, bool, Time t)
        {
                Video v;
                v.content = _player->_last_video;
-               v.image = i;
+               v.image = i->image ();
                v.time = t;
                _queue.push_front (v);
        }