Hacks.
authorCarl Hetherington <cth@carlh.net>
Tue, 22 Oct 2013 15:48:45 +0000 (16:48 +0100)
committerCarl Hetherington <cth@carlh.net>
Tue, 22 Oct 2013 15:48:45 +0000 (16:48 +0100)
src/lib/audio_decoder.cc
src/lib/audio_decoder.h
src/lib/ffmpeg_decoder.cc
src/lib/player.cc
src/lib/player.h
src/lib/sndfile_decoder.cc
src/lib/util.cc
src/wx/film_viewer.cc
src/wx/film_viewer.h

index 1f5868583675314df9158517d6159c2c13bce7ef..c9fbddda1c4b120033ec1c3d630f7956966e405c 100644 (file)
@@ -32,8 +32,9 @@ using std::cout;
 using boost::optional;
 using boost::shared_ptr;
 
-AudioDecoder::AudioDecoder (shared_ptr<const Film> film)
+AudioDecoder::AudioDecoder (shared_ptr<const Film> film, shared_ptr<const AudioContent> content)
        : Decoder (film)
+       , _audio_content (content)
        , _audio_position (0)
 {
 
@@ -45,3 +46,12 @@ AudioDecoder::audio (shared_ptr<const AudioBuffers> data, AudioContent::Frame fr
        Audio (data, frame);
        _audio_position = frame + data->frames ();
 }
+
+/** This is a bit odd, but necessary when we have (e.g.) FFmpegDecoders with no audio.
+ *  The player needs to know that there is no audio otherwise it will keep prompting the XXX
+ */
+bool
+AudioDecoder::has_audio () const
+{
+       return _audio_content->channels () > 0;
+}
index 2ad53da8bf42684e544e753bc6b0ca4708c72d19..ab6c4b8a931e12cfe892c8cb74d86ae7162d1a10 100644 (file)
@@ -36,7 +36,9 @@ class AudioBuffers;
 class AudioDecoder : public virtual Decoder
 {
 public:
-       AudioDecoder (boost::shared_ptr<const Film>);
+       AudioDecoder (boost::shared_ptr<const Film>, boost::shared_ptr<const AudioContent>);
+
+       bool has_audio () const;
 
        /** Emitted when some audio data is ready */
        boost::signals2::signal<void (boost::shared_ptr<const AudioBuffers>, AudioContent::Frame)> Audio;
@@ -44,6 +46,7 @@ public:
 protected:
 
        void audio (boost::shared_ptr<const AudioBuffers>, AudioContent::Frame);
+       boost::shared_ptr<const AudioContent> _audio_content;
        AudioContent::Frame _audio_position;
 };
 
index 8da607e7eb62861812d035d88461f39fc83c1bcd..45c242237e6b50f3c504389c3e8a765cec3d522f 100644 (file)
@@ -61,7 +61,7 @@ using libdcp::Size;
 FFmpegDecoder::FFmpegDecoder (shared_ptr<const Film> f, shared_ptr<const FFmpegContent> c, bool video, bool audio)
        : Decoder (f)
        , VideoDecoder (f, c)
-       , AudioDecoder (f)
+       , AudioDecoder (f, c)
        , SubtitleDecoder (f)
        , FFmpeg (c)
        , _subtitle_codec_context (0)
index 8f6a8bb355bdc447504e261c69a3beaa68114f71..73c873c59f1a00944879e56f28bd0b0ca3034c00 100644 (file)
@@ -55,6 +55,8 @@ public:
                : content (c)
                , video_position (c->position ())
                , audio_position (c->position ())
+               , repeat_to_do (0)
+               , repeat_done (0)
        {}
        
        Piece (shared_ptr<Content> c, shared_ptr<Decoder> d)
@@ -63,11 +65,50 @@ public:
                , video_position (c->position ())
                , audio_position (c->position ())
        {}
+
+       void set_repeat (IncomingVideo video, int num)
+       {
+               cout << "Set repeat " << num << "\n";
+               repeat_video = video;
+               repeat_to_do = num;
+               repeat_done = 0;
+       }
+
+       void reset_repeat ()
+       {
+               repeat_video.image.reset ();
+               repeat_to_do = 0;
+               repeat_done = 0;
+       }
+
+       bool repeating () const
+       {
+               return repeat_done != repeat_to_do;
+       }
+
+       void repeat (Player* player)
+       {
+               cout << "repeating; " << repeat_done << "\n";
+               player->process_video (
+                       repeat_video.weak_piece,
+                       repeat_video.image,
+                       repeat_video.eyes,
+                       repeat_video.same,
+                       repeat_video.frame,
+                       (repeat_done + 1) * (TIME_HZ / player->_film->video_frame_rate ())
+                       );
+
+               ++repeat_done;
+       }
        
        shared_ptr<Content> content;
        shared_ptr<Decoder> decoder;
        Time video_position;
        Time audio_position;
+
+       IncomingVideo repeat_video;
+       int repeat_to_do;
+       int repeat_done;
 };
 
 Player::Player (shared_ptr<const Film> f, shared_ptr<const Playlist> p)
@@ -116,6 +157,7 @@ Player::pass ()
 
        for (list<shared_ptr<Piece> >::iterator i = _pieces.begin(); i != _pieces.end(); ++i) {
                if ((*i)->decoder->done ()) {
+                       cout << "Scan: done.\n";
                        continue;
                }
 
@@ -137,20 +179,31 @@ Player::pass ()
        }
 
        if (!earliest) {
+               cout << "No earliest: out.\n";
                flush ();
                return true;
        }
 
+       cout << "Earliest: " << earliest_t << "\n";
+
        switch (type) {
        case VIDEO:
+               cout << "VIDEO.\n";
                if (earliest_t > _video_position) {
                        emit_black ();
                } else {
-                       earliest->decoder->pass ();
+                       if (earliest->repeating ()) {
+                               cout << "-repeating.\n";
+                               earliest->repeat (this);
+                       } else {
+                               cout << "-passing.\n";
+                               earliest->decoder->pass ();
+                       }
                }
                break;
 
        case AUDIO:
+               cout << "SOUND.\n";
                if (earliest_t > _audio_position) {
                        emit_silence (_film->time_to_audio_frames (earliest_t - _audio_position));
                } else {
@@ -188,14 +241,16 @@ Player::pass ()
 }
 
 void
-Player::process_video (weak_ptr<Piece> weak_piece, shared_ptr<const Image> image, Eyes eyes, bool same, VideoContent::Frame frame)
+Player::process_video (weak_ptr<Piece> weak_piece, shared_ptr<const Image> image, Eyes eyes, bool same, VideoContent::Frame frame, Time extra)
 {
+       cout << "PLAYER RECEIVES A VIDEO FRAME, extra " << extra << "\n";
+       
        /* Keep a note of what came in so that we can repeat it if required */
-       _last_process_video.weak_piece = weak_piece;
-       _last_process_video.image = image;
-       _last_process_video.eyes = eyes;
-       _last_process_video.same = same;
-       _last_process_video.frame = frame;
+       _last_incoming_video.weak_piece = weak_piece;
+       _last_incoming_video.image = image;
+       _last_incoming_video.eyes = eyes;
+       _last_incoming_video.same = same;
+       _last_incoming_video.frame = frame;
        
        shared_ptr<Piece> piece = weak_piece.lock ();
        if (!piece) {
@@ -225,7 +280,7 @@ Player::process_video (weak_ptr<Piece> weak_piece, shared_ptr<const Image> image
        
        work_image = work_image->scale (image_size, _film->scaler(), PIX_FMT_RGB24, true);
 
-       Time time = content->position() + relative_time - content->trim_start ();
+       Time time = content->position() + relative_time + extra - content->trim_start ();
            
        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);
@@ -245,11 +300,16 @@ Player::process_video (weak_ptr<Piece> weak_piece, shared_ptr<const Image> image
 #endif
 
        Video (work_image, eyes, content->colour_conversion(), same, time);
-       time += TIME_HZ / _film->video_frame_rate();
 
+       time += TIME_HZ / _film->video_frame_rate();
        _last_emit_was_black = false;
-
        _video_position = piece->video_position = time;
+
+       cout << "frc.repeat=" << frc.repeat << "; vp now " << _video_position << "\n";
+
+       if (frc.repeat > 1 && !piece->repeating ()) {
+               piece->set_repeat (_last_incoming_video, frc.repeat - 1);
+       }
 }
 
 void
@@ -370,10 +430,12 @@ Player::seek (Time t, bool accurate)
                */
                VideoContent::Frame f = (s + vc->trim_start ()) * _film->video_frame_rate() / (frc.factor() * TIME_HZ);
                dynamic_pointer_cast<VideoDecoder>((*i)->decoder)->seek (f, accurate);
+
+               (*i)->reset_repeat ();
        }
 
        _video_position = _audio_position = t;
-       
+
        /* XXX: don't seek audio because we don't need to... */
 }
 
@@ -397,7 +459,7 @@ Player::setup_pieces ()
                if (fc) {
                        shared_ptr<FFmpegDecoder> fd (new FFmpegDecoder (_film, fc, _video, _audio));
                        
-                       fd->Video.connect (bind (&Player::process_video, this, piece, _1, _2, _3, _4));
+                       fd->Video.connect (bind (&Player::process_video, this, piece, _1, _2, _3, _4, 0));
                        fd->Audio.connect (bind (&Player::process_audio, this, piece, _1, _2));
                        fd->Subtitle.connect (bind (&Player::process_subtitle, this, piece, _1, _2, _3, _4));
 
@@ -418,7 +480,7 @@ Player::setup_pieces ()
 
                        if (!id) {
                                id.reset (new StillImageDecoder (_film, ic));
-                               id->Video.connect (bind (&Player::process_video, this, piece, _1, _2, _3, _4));
+                               id->Video.connect (bind (&Player::process_video, this, piece, _1, _2, _3, _4, 0));
                        }
 
                        piece->decoder = id;
@@ -430,7 +492,7 @@ Player::setup_pieces ()
 
                        if (!md) {
                                md.reset (new MovingImageDecoder (_film, mc));
-                               md->Video.connect (bind (&Player::process_video, this, piece, _1, _2, _3, _4));
+                               md->Video.connect (bind (&Player::process_video, this, piece, _1, _2, _3, _4, 0));
                        }
 
                        piece->decoder = md;
@@ -617,16 +679,17 @@ Player::update_subtitle ()
 bool
 Player::repeat_last_video ()
 {
-       if (!_last_process_video.image) {
+       if (!_last_incoming_video.image) {
                return false;
        }
 
        process_video (
-               _last_process_video.weak_piece,
-               _last_process_video.image,
-               _last_process_video.eyes,
-               _last_process_video.same,
-               _last_process_video.frame
+               _last_incoming_video.weak_piece,
+               _last_incoming_video.image,
+               _last_incoming_video.eyes,
+               _last_incoming_video.same,
+               _last_incoming_video.frame,
+               0
                );
 
        return true;
index 7cce7e7237fd204690c1d246263f06a36656bcd8..424a3921673f3a1ff820ea3c5bffe3eae1a2c3df 100644 (file)
@@ -41,6 +41,16 @@ class Resampler;
 /** @class Player
  *  @brief A class which can `play' a Playlist; emitting its audio and video.
  */
+
+struct IncomingVideo
+{
+public:
+       boost::weak_ptr<Piece> weak_piece;
+       boost::shared_ptr<const Image> image;
+       Eyes eyes;
+       bool same;
+       VideoContent::Frame frame;
+};
  
 class Player : public boost::enable_shared_from_this<Player>, public boost::noncopyable
 {
@@ -83,8 +93,9 @@ public:
 
 private:
        friend class PlayerWrapper;
+       friend class Piece;
 
-       void process_video (boost::weak_ptr<Piece>, boost::shared_ptr<const Image>, Eyes, bool, VideoContent::Frame);
+       void process_video (boost::weak_ptr<Piece>, boost::shared_ptr<const Image>, Eyes, bool, VideoContent::Frame, Time);
        void process_audio (boost::weak_ptr<Piece>, boost::shared_ptr<const AudioBuffers>, AudioContent::Frame);
        void process_subtitle (boost::weak_ptr<Piece>, boost::shared_ptr<Image>, dcpomatic::Rect<double>, Time, Time);
        void setup_pieces ();
@@ -140,13 +151,7 @@ private:
 
        bool _last_emit_was_black;
 
-       struct {
-               boost::weak_ptr<Piece> weak_piece;
-               boost::shared_ptr<const Image> image;
-               Eyes eyes;
-               bool same;
-               VideoContent::Frame frame;
-       } _last_process_video;
+       IncomingVideo _last_incoming_video;
 
        boost::signals2::scoped_connection _playlist_changed_connection;
        boost::signals2::scoped_connection _playlist_content_changed_connection;
index 1fc1ecaf2cc66c1cbcb650f0af9cad0f0d2a82fc..09ccf4fbc1fd9ba5d2bcf3eac9d3aa2ae135b45b 100644 (file)
@@ -35,7 +35,7 @@ using boost::shared_ptr;
 
 SndfileDecoder::SndfileDecoder (shared_ptr<const Film> f, shared_ptr<const SndfileContent> c)
        : Decoder (f)
-       , AudioDecoder (f)
+       , AudioDecoder (f, c)
        , _sndfile_content (c)
        , _deinterleave_buffer (0)
 {
index 4880e5ced50aff09ee504c8fcf68288a3d8e94ec..15efcc099555637ca58b8775305c7f14de83fabc 100644 (file)
@@ -768,7 +768,7 @@ FrameRateConversion::FrameRateConversion (float source, int dcp)
        }
 
        if (source < dcp) {
-               repeat = floor (source / dcp);
+               repeat = floor (dcp / source);
        }
 
        change_speed = !about_equal (source * factor(), dcp);
index 945644fb1ede92c74131d721a283237d5897bba4..a1a47a943a3685811a4b3b6070b4c8aafc281774 100644 (file)
@@ -120,8 +120,7 @@ FilmViewer::set_film (shared_ptr<Film> f)
        _film = f;
 
        _frame.reset ();
-       _queue.clear ();
-
+       
        _slider->SetValue (0);
        set_position_text (0);
        
@@ -286,12 +285,6 @@ FilmViewer::process_video (shared_ptr<const Image> image, Eyes eyes, Time t)
                return;
        }
        
-       if (_got_frame) {
-               /* This is an additional frame emitted by a single pass.  Store it. */
-               _queue.push_front (make_pair (image, t));
-               return;
-       }
-       
        _frame = image;
        _got_frame = true;
 
@@ -335,17 +328,12 @@ FilmViewer::fetch_next_frame ()
 
        _got_frame = false;
        
-       if (!_queue.empty ()) {
-               process_video (_queue.back().first, EYES_BOTH, _queue.back().second);
-               _queue.pop_back ();
-       } else {
-               try {
-                       while (!_got_frame && !_player->pass ()) {}
-               } catch (DecodeError& e) {
-                       _play_button->SetValue (false);
-                       check_play_state ();
-                       error_dialog (this, wxString::Format (_("Could not decode video for view (%s)"), std_to_wx(e.what()).data()));
-               }
+       try {
+               while (!_got_frame && !_player->pass ()) {}
+       } catch (DecodeError& e) {
+               _play_button->SetValue (false);
+               check_play_state ();
+               error_dialog (this, wxString::Format (_("Could not decode video for view (%s)"), std_to_wx(e.what()).data()));
        }
 
        _panel->Refresh ();
index 7bda9617e9bea0aa92beae1e9d540f0f2f807610..2337da6b0def299515654a3b957da6b3a3982568 100644 (file)
@@ -89,6 +89,4 @@ private:
        libdcp::Size _out_size;
        /** Size of the panel that we have available */
        libdcp::Size _panel_size;
-
-       std::list<std::pair<boost::shared_ptr<const Image>, Time> > _queue;
 };