From 0e2c7f060529d93035e89b06d4aa687830a5e0ad Mon Sep 17 00:00:00 2001 From: Carl Hetherington Date: Tue, 22 Oct 2013 16:48:45 +0100 Subject: [PATCH] Hacks. --- src/lib/audio_decoder.cc | 12 ++++- src/lib/audio_decoder.h | 5 +- src/lib/ffmpeg_decoder.cc | 2 +- src/lib/player.cc | 103 ++++++++++++++++++++++++++++++------- src/lib/player.h | 21 +++++--- src/lib/sndfile_decoder.cc | 2 +- src/lib/util.cc | 2 +- src/wx/film_viewer.cc | 26 +++------- src/wx/film_viewer.h | 2 - 9 files changed, 121 insertions(+), 54 deletions(-) diff --git a/src/lib/audio_decoder.cc b/src/lib/audio_decoder.cc index 1f5868583..c9fbddda1 100644 --- a/src/lib/audio_decoder.cc +++ b/src/lib/audio_decoder.cc @@ -32,8 +32,9 @@ using std::cout; using boost::optional; using boost::shared_ptr; -AudioDecoder::AudioDecoder (shared_ptr film) +AudioDecoder::AudioDecoder (shared_ptr film, shared_ptr content) : Decoder (film) + , _audio_content (content) , _audio_position (0) { @@ -45,3 +46,12 @@ AudioDecoder::audio (shared_ptr 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; +} diff --git a/src/lib/audio_decoder.h b/src/lib/audio_decoder.h index 2ad53da8b..ab6c4b8a9 100644 --- a/src/lib/audio_decoder.h +++ b/src/lib/audio_decoder.h @@ -36,7 +36,9 @@ class AudioBuffers; class AudioDecoder : public virtual Decoder { public: - AudioDecoder (boost::shared_ptr); + AudioDecoder (boost::shared_ptr, boost::shared_ptr); + + bool has_audio () const; /** Emitted when some audio data is ready */ boost::signals2::signal, AudioContent::Frame)> Audio; @@ -44,6 +46,7 @@ public: protected: void audio (boost::shared_ptr, AudioContent::Frame); + boost::shared_ptr _audio_content; AudioContent::Frame _audio_position; }; diff --git a/src/lib/ffmpeg_decoder.cc b/src/lib/ffmpeg_decoder.cc index 8da607e7e..45c242237 100644 --- a/src/lib/ffmpeg_decoder.cc +++ b/src/lib/ffmpeg_decoder.cc @@ -61,7 +61,7 @@ using libdcp::Size; FFmpegDecoder::FFmpegDecoder (shared_ptr f, shared_ptr c, bool video, bool audio) : Decoder (f) , VideoDecoder (f, c) - , AudioDecoder (f) + , AudioDecoder (f, c) , SubtitleDecoder (f) , FFmpeg (c) , _subtitle_codec_context (0) diff --git a/src/lib/player.cc b/src/lib/player.cc index 8f6a8bb35..73c873c59 100644 --- a/src/lib/player.cc +++ b/src/lib/player.cc @@ -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 c, shared_ptr 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; shared_ptr decoder; Time video_position; Time audio_position; + + IncomingVideo repeat_video; + int repeat_to_do; + int repeat_done; }; Player::Player (shared_ptr f, shared_ptr p) @@ -116,6 +157,7 @@ Player::pass () for (list >::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 weak_piece, shared_ptr image, Eyes eyes, bool same, VideoContent::Frame frame) +Player::process_video (weak_ptr weak_piece, shared_ptr 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 = weak_piece.lock (); if (!piece) { @@ -225,7 +280,7 @@ Player::process_video (weak_ptr weak_piece, shared_ptr 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 weak_piece, shared_ptr 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((*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 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; diff --git a/src/lib/player.h b/src/lib/player.h index 7cce7e723..424a39216 100644 --- a/src/lib/player.h +++ b/src/lib/player.h @@ -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 weak_piece; + boost::shared_ptr image; + Eyes eyes; + bool same; + VideoContent::Frame frame; +}; class Player : public boost::enable_shared_from_this, public boost::noncopyable { @@ -83,8 +93,9 @@ public: private: friend class PlayerWrapper; + friend class Piece; - void process_video (boost::weak_ptr, boost::shared_ptr, Eyes, bool, VideoContent::Frame); + void process_video (boost::weak_ptr, boost::shared_ptr, Eyes, bool, VideoContent::Frame, Time); void process_audio (boost::weak_ptr, boost::shared_ptr, AudioContent::Frame); void process_subtitle (boost::weak_ptr, boost::shared_ptr, dcpomatic::Rect, Time, Time); void setup_pieces (); @@ -140,13 +151,7 @@ private: bool _last_emit_was_black; - struct { - boost::weak_ptr weak_piece; - boost::shared_ptr 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; diff --git a/src/lib/sndfile_decoder.cc b/src/lib/sndfile_decoder.cc index 1fc1ecaf2..09ccf4fbc 100644 --- a/src/lib/sndfile_decoder.cc +++ b/src/lib/sndfile_decoder.cc @@ -35,7 +35,7 @@ using boost::shared_ptr; SndfileDecoder::SndfileDecoder (shared_ptr f, shared_ptr c) : Decoder (f) - , AudioDecoder (f) + , AudioDecoder (f, c) , _sndfile_content (c) , _deinterleave_buffer (0) { diff --git a/src/lib/util.cc b/src/lib/util.cc index 4880e5ced..15efcc099 100644 --- a/src/lib/util.cc +++ b/src/lib/util.cc @@ -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); diff --git a/src/wx/film_viewer.cc b/src/wx/film_viewer.cc index 945644fb1..a1a47a943 100644 --- a/src/wx/film_viewer.cc +++ b/src/wx/film_viewer.cc @@ -120,8 +120,7 @@ FilmViewer::set_film (shared_ptr f) _film = f; _frame.reset (); - _queue.clear (); - + _slider->SetValue (0); set_position_text (0); @@ -286,12 +285,6 @@ FilmViewer::process_video (shared_ptr 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 (); diff --git a/src/wx/film_viewer.h b/src/wx/film_viewer.h index 7bda9617e..2337da6b0 100644 --- a/src/wx/film_viewer.h +++ b/src/wx/film_viewer.h @@ -89,6 +89,4 @@ private: libdcp::Size _out_size; /** Size of the panel that we have available */ libdcp::Size _panel_size; - - std::list, Time> > _queue; }; -- 2.30.2