More various bits.
authorCarl Hetherington <cth@carlh.net>
Wed, 3 Apr 2013 23:13:27 +0000 (00:13 +0100)
committerCarl Hetherington <cth@carlh.net>
Wed, 3 Apr 2013 23:13:27 +0000 (00:13 +0100)
15 files changed:
src/lib/audio_source.cc
src/lib/encoder.cc
src/lib/encoder.h
src/lib/ffmpeg_content.cc
src/lib/ffmpeg_decoder.cc
src/lib/ffmpeg_decoder.h
src/lib/film.cc
src/lib/playlist.cc
src/lib/transcode_job.cc
src/lib/transcode_job.h
src/lib/transcoder.cc
src/lib/transcoder.h
src/lib/video_source.cc
src/wx/film_editor.cc
src/wx/film_editor.h

index 53b0dda1500a705ac314d9a5c5bd314c896140ba..99b59759d07eac7250126429515f7c00863f9677 100644 (file)
 #include "audio_sink.h"
 
 using boost::shared_ptr;
+using boost::weak_ptr;
 using boost::bind;
 
+static void
+process_audio_proxy (weak_ptr<AudioSink> sink, shared_ptr<AudioBuffers> audio)
+{
+       shared_ptr<AudioSink> p = sink.lock ();
+       if (p) {
+               p->process_audio (audio);
+       }
+}
+
 void
 AudioSource::connect_audio (shared_ptr<AudioSink> s)
 {
-       Audio.connect (bind (&AudioSink::process_audio, s, _1));
+       Audio.connect (bind (process_audio_proxy, weak_ptr<AudioSink> (s), _1));
 }
index 5c3e5670920a0f7dfb6d0efcdd66aae70e05b21d..a41ebec513cfaf5df4a54ea183ab8e65646b14e0 100644 (file)
@@ -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) {
index 2cbd498e866f0b2db6e36ddc7cd5661ba7660c73..b85132b7270fcc642f1baec01cd4dd4c50ffc094 100644 (file)
@@ -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:
index c6344d5671488a294e2465669e32fe83f9f92a12..7834cb76e825cc1b6987f469de747d3661029977 100644 (file)
@@ -111,12 +111,10 @@ FFmpegContent::as_xml (xmlpp::Node* node) const
 void
 FFmpegContent::examine (shared_ptr<Film> film, shared_ptr<Job> 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<FFmpegDecoder> 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";
index 3a185bd6af3e9d9aca23d8a5a3fa7868ffd64f8f..fdc5189a6370df5e61ec80c531be8c32a1d98e5a 100644 (file)
@@ -61,6 +61,8 @@ using boost::optional;
 using boost::dynamic_pointer_cast;
 using libdcp::Size;
 
+boost::mutex FFmpegDecoder::_mutex;
+
 FFmpegDecoder::FFmpegDecoder (shared_ptr<const Film> f, shared_ptr<const FFmpegContent> c, bool video, bool audio, bool subtitles, bool video_sync)
        : Decoder (f)
        , VideoDecoder (f)
@@ -92,10 +94,12 @@ FFmpegDecoder::FFmpegDecoder (shared_ptr<const Film> f, shared_ptr<const FFmpegC
 
 FFmpegDecoder::~FFmpegDecoder ()
 {
+       boost::mutex::scoped_lock lm (_mutex);
+       
        if (_audio_codec_context) {
                avcodec_close (_audio_codec_context);
        }
-       
+
        if (_video_codec_context) {
                avcodec_close (_video_codec_context);
        }
@@ -160,6 +164,8 @@ FFmpegDecoder::setup_general ()
 void
 FFmpegDecoder::setup_video ()
 {
+       boost::mutex::scoped_lock lm (_mutex);
+       
        _video_codec_context = _format_context->streams[_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;
        }
index 71ecf79065384aa1d7c14e23e9915af2971798e3..5023ac56ce8e72d98acf5eb45ba13fa7da421d98 100644 (file)
@@ -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;
 };
index fd72aa1d5e373ffe78f1622d908caf0088ef8959..b21b3454d8a4a0ec1a376cd0aad4c7b7850d3bf0 100644 (file)
@@ -550,7 +550,7 @@ Film::file (string f) const
 int
 Film::target_audio_sample_rate () const
 {
-       if (has_audio ()) {
+       if (!has_audio ()) {
                return 0;
        }
        
index 3da7f938bbce13af7a3b971787b810f20c16b1ce..dc8ad1ef74bb1032a30aa5772ed45f1194fcc865 100644 (file)
@@ -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<const Film> f, boost::shared_ptr<const Playlis
 {
 
 }
-               
+
 void
 Player::disable_video ()
 {
@@ -278,7 +279,27 @@ Player::pass ()
 void
 Player::set_progress (shared_ptr<Job> 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<boost::shared_ptr<ImageMagickDecoder> >::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
index 8b74f776630a2346455160b50751bb8445fea4c0..0c3b8c37b978b9d5c94c058cfafbde11db552ec0 100644 (file)
@@ -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 
 }
index def545958f4ff0c52a0626e2ae5b1a2106ccdf6f..7880a925ebb56e4921fea0b2745ab1b3f1882788 100644 (file)
@@ -24,7 +24,7 @@
 #include <boost/shared_ptr.hpp>
 #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> _transcoder;
 };
index 0ee6f523fe7776e57837ad3e7a14419072a3692e..ef3a0e8c1af6c52edcd2920fab34861b8220e457 100644 (file)
@@ -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 ();
+}
index 2d032fcf640538ca06f99780f2be9a97b4fb7004..ecc8ebf629a2b245a4c9b0ae22862aebed3fe96b 100644 (file)
@@ -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> _job;
index 56742e2b4729a988680ee50bf5536e8682fbba16..8101a6d3696d67ca0834e075925ce4e72dff92a6 100644 (file)
 #include "video_sink.h"
 
 using boost::shared_ptr;
+using boost::weak_ptr;
 using boost::bind;
 
+static void
+process_video_proxy (weak_ptr<VideoSink> sink, shared_ptr<Image> i, bool same, shared_ptr<Subtitle> s)
+{
+       boost::shared_ptr<VideoSink> p = sink.lock ();
+       if (p) {
+               p->process_video (i, same, s);
+       }
+}
+
 void
 VideoSource::connect_video (shared_ptr<VideoSink> 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<VideoSink> (s), _1, _2, _3));
 }
index d55104a95280c4298e31eb6ab87c30ebf86414cc..10cb41df0a230e06f15213a2c220f5452008733d 100644 (file)
@@ -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<string> (_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<string> (_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 ("");
index 60da2de4d785c82f52235e3f4dc03e74a483afac..97d1e0dd3dd2b728951d5688788e2ac6278e0965 100644 (file)
@@ -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);