From: Carl Hetherington Date: Wed, 3 Apr 2013 23:13:27 +0000 (+0100) Subject: More various bits. X-Git-Tag: v2.0.48~1337^2~476 X-Git-Url: https://git.carlh.net/gitweb/?a=commitdiff_plain;h=190c074cc1508c0aa429452ea920f8f94ef0d0f2;p=dcpomatic.git More various bits. --- diff --git a/src/lib/audio_source.cc b/src/lib/audio_source.cc index 53b0dda15..99b59759d 100644 --- a/src/lib/audio_source.cc +++ b/src/lib/audio_source.cc @@ -21,10 +21,20 @@ #include "audio_sink.h" using boost::shared_ptr; +using boost::weak_ptr; using boost::bind; +static void +process_audio_proxy (weak_ptr sink, shared_ptr audio) +{ + shared_ptr p = sink.lock (); + if (p) { + p->process_audio (audio); + } +} + void AudioSource::connect_audio (shared_ptr s) { - Audio.connect (bind (&AudioSink::process_audio, s, _1)); + Audio.connect (bind (process_audio_proxy, weak_ptr (s), _1)); } diff --git a/src/lib/encoder.cc b/src/lib/encoder.cc index 5c3e56709..a41ebec51 100644 --- a/src/lib/encoder.cc +++ b/src/lib/encoder.cc @@ -193,7 +193,7 @@ Encoder::process_end () * or 0 if not known. */ float -Encoder::current_frames_per_second () const +Encoder::current_encoding_rate () const { boost::mutex::scoped_lock lock (_history_mutex); if (int (_time_history.size()) < _history_size) { diff --git a/src/lib/encoder.h b/src/lib/encoder.h index 2cbd498e8..b85132b72 100644 --- a/src/lib/encoder.h +++ b/src/lib/encoder.h @@ -81,7 +81,7 @@ public: /** Called when a processing run has finished */ virtual void process_end (); - float current_frames_per_second () const; + float current_encoding_rate () const; int video_frames_out () const; private: diff --git a/src/lib/ffmpeg_content.cc b/src/lib/ffmpeg_content.cc index c6344d567..7834cb76e 100644 --- a/src/lib/ffmpeg_content.cc +++ b/src/lib/ffmpeg_content.cc @@ -111,12 +111,10 @@ FFmpegContent::as_xml (xmlpp::Node* node) const void FFmpegContent::examine (shared_ptr film, shared_ptr job, bool quick) { - job->descend (0.5); - Content::examine (film, job, quick); - job->ascend (); - job->set_progress_unknown (); + Content::examine (film, job, quick); + shared_ptr decoder (new FFmpegDecoder (film, shared_from_this (), true, false, false, true)); ContentVideoFrame video_length = 0; @@ -166,6 +164,10 @@ FFmpegContent::summary () const string FFmpegContent::information () const { + if (video_length() == 0 || video_frame_rate() == 0) { + return ""; + } + stringstream s; s << String::compose (_("%1 frames; %2 frames per second"), video_length(), video_frame_rate()) << "\n"; diff --git a/src/lib/ffmpeg_decoder.cc b/src/lib/ffmpeg_decoder.cc index 3a185bd6a..fdc5189a6 100644 --- a/src/lib/ffmpeg_decoder.cc +++ b/src/lib/ffmpeg_decoder.cc @@ -61,6 +61,8 @@ using boost::optional; using boost::dynamic_pointer_cast; using libdcp::Size; +boost::mutex FFmpegDecoder::_mutex; + FFmpegDecoder::FFmpegDecoder (shared_ptr f, shared_ptr c, bool video, bool audio, bool subtitles, bool video_sync) : Decoder (f) , VideoDecoder (f) @@ -92,10 +94,12 @@ FFmpegDecoder::FFmpegDecoder (shared_ptr f, shared_ptrstreams[_video_stream]->codec; _video_codec = avcodec_find_decoder (_video_codec_context->codec_id); @@ -175,6 +181,8 @@ FFmpegDecoder::setup_video () void FFmpegDecoder::setup_audio () { + boost::mutex::scoped_lock lm (_mutex); + if (!_ffmpeg_content->audio_stream ()) { return; } @@ -194,6 +202,8 @@ FFmpegDecoder::setup_audio () void FFmpegDecoder::setup_subtitle () { + boost::mutex::scoped_lock lm (_mutex); + if (!_ffmpeg_content->subtitle_stream() || _ffmpeg_content->subtitle_stream()->id >= int (_format_context->nb_streams)) { return; } diff --git a/src/lib/ffmpeg_decoder.h b/src/lib/ffmpeg_decoder.h index 71ecf7906..5023ac56c 100644 --- a/src/lib/ffmpeg_decoder.h +++ b/src/lib/ffmpeg_decoder.h @@ -82,6 +82,10 @@ public: private: + /* No copy construction */ + FFmpegDecoder (FFmpegDecoder const &); + FFmpegDecoder& operator= (FFmpegDecoder const &); + bool do_seek (double p, bool); PixelFormat pixel_format () const; AVSampleFormat audio_sample_format () const; @@ -134,4 +138,10 @@ private: bool _decode_audio; bool _decode_subtitles; bool _video_sync; + + /* It would appear (though not completely verified) that one must have + a mutex around calls to avcodec_open* and avcodec_close... and here + it is. + */ + static boost::mutex _mutex; }; diff --git a/src/lib/film.cc b/src/lib/film.cc index fd72aa1d5..b21b3454d 100644 --- a/src/lib/film.cc +++ b/src/lib/film.cc @@ -550,7 +550,7 @@ Film::file (string f) const int Film::target_audio_sample_rate () const { - if (has_audio ()) { + if (!has_audio ()) { return 0; } diff --git a/src/lib/playlist.cc b/src/lib/playlist.cc index 3da7f938b..dc8ad1ef7 100644 --- a/src/lib/playlist.cc +++ b/src/lib/playlist.cc @@ -25,6 +25,7 @@ #include "ffmpeg_decoder.h" #include "imagemagick_content.h" #include "imagemagick_decoder.h" +#include "job.h" using std::list; using std::cout; @@ -219,7 +220,7 @@ Player::Player (boost::shared_ptr f, boost::shared_ptr job) { - /* XXX */ + /* Assume progress can be divined from how far through the video we are */ + switch (_playlist->video_from ()) { + case Playlist::VIDEO_NONE: + break; + case Playlist::VIDEO_FFMPEG: + if (_playlist->video_length ()) { + job->set_progress (float(_ffmpeg_decoder->video_frame()) / _playlist->video_length ()); + } + break; + case Playlist::VIDEO_IMAGEMAGICK: + { + int n = 0; + for (std::list >::iterator i = _imagemagick_decoders.begin(); i != _imagemagick_decoders.end(); ++i) { + if (_imagemagick_decoder == i) { + job->set_progress (float (n) / _imagemagick_decoders.size ()); + } + ++n; + } + break; + } + } } void diff --git a/src/lib/transcode_job.cc b/src/lib/transcode_job.cc index 8b74f7766..0c3b8c37b 100644 --- a/src/lib/transcode_job.cc +++ b/src/lib/transcode_job.cc @@ -60,8 +60,8 @@ TranscodeJob::run () _film->log()->log (N_("Transcode job starting")); _film->log()->log (String::compose (N_("Audio delay is %1ms"), _film->audio_delay())); - Transcoder w (_film, shared_from_this ()); - w.go (); + _transcoder.reset (new Transcoder (_film, shared_from_this ())); + _transcoder->go (); set_progress (1); set_state (FINISHED_OK); @@ -80,13 +80,11 @@ TranscodeJob::run () string TranscodeJob::status () const { -// if (!_encoder) { -// return _("0%"); -// } + if (!_transcoder) { + return _("0%"); + } - /* XXX */ -// float const fps = _encoder->current_frames_per_second (); - float const fps = 0; + float const fps = _transcoder->current_encoding_rate (); if (fps == 0) { return Job::status (); } @@ -105,28 +103,28 @@ TranscodeJob::status () const int TranscodeJob::remaining_time () const { - return 0; -#if 0 - XXX - float fps = _encoder->current_frames_per_second (); + if (!_transcoder) { + return 0; + } + + float fps = _transcoder->current_encoding_rate (); + if (fps == 0) { return 0; } - if (!_video->length()) { + if (!_film->video_length()) { return 0; } /* Compute approximate proposed length here, as it's only here that we need it */ - int length = _film->length().get(); - FrameRateConversion const frc (_film->source_frame_rate(), _film->dcp_frame_rate()); + int length = _film->video_length(); + FrameRateConversion const frc (_film->video_frame_rate(), _film->dcp_frame_rate()); if (frc.skip) { length /= 2; } /* If we are repeating it shouldn't affect transcode time, so don't take it into account */ - /* We assume that dcp_length() is valid, if it is set */ - int const left = length - _encoder->video_frames_out(); + int const left = length - _transcoder->video_frames_out(); return left / fps; -#endif } diff --git a/src/lib/transcode_job.h b/src/lib/transcode_job.h index def545958..7880a925e 100644 --- a/src/lib/transcode_job.h +++ b/src/lib/transcode_job.h @@ -24,7 +24,7 @@ #include #include "job.h" -class Encoder; +class Transcoder; /** @class TranscodeJob * @brief A job which transcodes from one format to another. @@ -38,6 +38,8 @@ public: void run (); std::string status () const; -protected: +private: int remaining_time () const; + + boost::shared_ptr _transcoder; }; diff --git a/src/lib/transcoder.cc b/src/lib/transcoder.cc index 0ee6f523f..ef3a0e8c1 100644 --- a/src/lib/transcoder.cc +++ b/src/lib/transcoder.cc @@ -99,3 +99,15 @@ Transcoder::go () } _encoder->process_end (); } + +float +Transcoder::current_encoding_rate () const +{ + return _encoder->current_encoding_rate (); +} + +int +Transcoder::video_frames_out () const +{ + return _encoder->video_frames_out (); +} diff --git a/src/lib/transcoder.h b/src/lib/transcoder.h index 2d032fcf6..ecc8ebf62 100644 --- a/src/lib/transcoder.h +++ b/src/lib/transcoder.h @@ -47,6 +47,9 @@ public: void go (); + float current_encoding_rate () const; + int video_frames_out () const; + protected: /** A Job that is running this Transcoder, or 0 */ boost::shared_ptr _job; diff --git a/src/lib/video_source.cc b/src/lib/video_source.cc index 56742e2b4..8101a6d36 100644 --- a/src/lib/video_source.cc +++ b/src/lib/video_source.cc @@ -21,10 +21,23 @@ #include "video_sink.h" using boost::shared_ptr; +using boost::weak_ptr; using boost::bind; +static void +process_video_proxy (weak_ptr sink, shared_ptr i, bool same, shared_ptr s) +{ + boost::shared_ptr p = sink.lock (); + if (p) { + p->process_video (i, same, s); + } +} + void VideoSource::connect_video (shared_ptr s) { - Video.connect (bind (&VideoSink::process_video, s, _1, _2, _3)); + /* If we bind, say, a Playlist (as the VideoSink) to a Decoder (which is owned + by the Playlist) we create a cycle. Use a weak_ptr to break it. + */ + Video.connect (bind (process_video_proxy, boost::weak_ptr (s), _1, _2, _3)); } diff --git a/src/wx/film_editor.cc b/src/wx/film_editor.cc index d55104a95..10cb41df0 100644 --- a/src/wx/film_editor.cc +++ b/src/wx/film_editor.cc @@ -705,16 +705,17 @@ FilmEditor::film_content_changed (int p) setup_show_audio_sensitivity (); } else if (p == VideoContentProperty::VIDEO_LENGTH) { setup_length (); + setup_content_information (); } else if (p == FFmpegContentProperty::AUDIO_STREAM) { if (_film->ffmpeg_audio_stream()) { - checked_set (_ffmpeg_audio_stream, _film->ffmpeg_audio_stream()->id); + checked_set (_ffmpeg_audio_stream, boost::lexical_cast (_film->ffmpeg_audio_stream()->id)); } setup_dcp_name (); setup_audio_details (); setup_show_audio_sensitivity (); } else if (p == FFmpegContentProperty::SUBTITLE_STREAM) { if (_film->ffmpeg_subtitle_stream()) { - checked_set (_ffmpeg_subtitle_stream, _film->ffmpeg_subtitle_stream()->id); + checked_set (_ffmpeg_subtitle_stream, boost::lexical_cast (_film->ffmpeg_subtitle_stream()->id)); } } } @@ -1117,7 +1118,7 @@ FilmEditor::setup_audio_details () } else { s << _film->audio_channels() << " " << wx_to_std (_("channels")); } - s << ", " << _film->audio_channels() << wx_to_std (_("Hz")); + s << ", " << _film->audio_frame_rate() << wx_to_std (_("Hz")); _audio->SetLabel (std_to_wx (s.str ())); } } @@ -1172,11 +1173,26 @@ FilmEditor::setup_show_audio_sensitivity () void FilmEditor::setup_content () { + string selected_summary; + int const s = _content->GetNextItem (-1, wxLIST_NEXT_ALL, wxLIST_STATE_SELECTED); + if (s != -1) { + selected_summary = wx_to_std (_content->GetItemText (s)); + } + _content->DeleteAllItems (); ContentList content = _film->content (); for (ContentList::iterator i = content.begin(); i != content.end(); ++i) { - _content->InsertItem (_content->GetItemCount(), std_to_wx ((*i)->summary ())); + int const t = _content->GetItemCount (); + _content->InsertItem (t, std_to_wx ((*i)->summary ())); + if ((*i)->summary() == selected_summary) { + _content->SetItemState (t, wxLIST_STATE_SELECTED, wxLIST_STATE_SELECTED); + } + } + + if (selected_summary.empty () && !content.empty ()) { + /* Select the first item of content if non was selected before */ + _content->SetItemState (0, wxLIST_STATE_SELECTED, wxLIST_STATE_SELECTED); } } @@ -1246,7 +1262,12 @@ void FilmEditor::content_item_selected (wxListEvent &) { setup_content_button_sensitivity (); + setup_content_information (); +} +void +FilmEditor::setup_content_information () +{ int const s = _content->GetNextItem (-1, wxLIST_NEXT_ALL, wxLIST_STATE_SELECTED); if (s == -1) { _content_information->SetValue (""); diff --git a/src/wx/film_editor.h b/src/wx/film_editor.h index 60da2de4d..97d1e0dd3 100644 --- a/src/wx/film_editor.h +++ b/src/wx/film_editor.h @@ -106,6 +106,7 @@ private: void setup_content_button_sensitivity (); void setup_length (); void setup_format (); + void setup_content_information (); void active_jobs_changed (bool);