Basic GUI for export.
authorCarl Hetherington <cth@carlh.net>
Tue, 9 May 2017 15:38:36 +0000 (16:38 +0100)
committerCarl Hetherington <cth@carlh.net>
Tue, 9 May 2017 15:38:36 +0000 (16:38 +0100)
14 files changed:
src/lib/encoder.cc
src/lib/encoder.h
src/lib/event_history.cc [new file with mode: 0644]
src/lib/event_history.h [new file with mode: 0644]
src/lib/ffmpeg_transcoder.cc
src/lib/ffmpeg_transcoder.h
src/lib/wscript
src/tools/dcpomatic.cc
src/wx/config_dialog.cc
src/wx/export_dialog.cc [new file with mode: 0644]
src/wx/export_dialog.h [new file with mode: 0644]
src/wx/file_picker_ctrl.cc
src/wx/file_picker_ctrl.h
src/wx/wscript

index 276ef8d3adccf1578223231e79c0818020f2bab0..e82c4af7e3e1637c40240a106a65f6be65e051e6 100644 (file)
@@ -54,14 +54,13 @@ using boost::weak_ptr;
 using boost::optional;
 using dcp::Data;
 
-int const Encoder::_history_size = 200;
-
 /** @param film Film that we are encoding.
  *  @param writer Writer that we are using.
  */
 Encoder::Encoder (shared_ptr<const Film> film, shared_ptr<Writer> writer)
        : _film (film)
        , _writer (writer)
+       , _history (200)
 {
        servers_list_changed ();
 }
@@ -152,15 +151,7 @@ Encoder::end ()
 float
 Encoder::current_encoding_rate () const
 {
-       boost::mutex::scoped_lock lock (_state_mutex);
-       if (int (_time_history.size()) < _history_size) {
-               return 0;
-       }
-
-       struct timeval now;
-       gettimeofday (&now, 0);
-
-       return _history_size / (seconds (now) - seconds (_time_history.back ()));
+       return _history.rate ();
 }
 
 /** @return Number of video frames that have been queued for encoding */
@@ -178,14 +169,7 @@ Encoder::video_frames_enqueued () const
 void
 Encoder::frame_done ()
 {
-       boost::mutex::scoped_lock lock (_state_mutex);
-
-       struct timeval tv;
-       gettimeofday (&tv, 0);
-       _time_history.push_front (tv);
-       if (int (_time_history.size()) > _history_size) {
-               _time_history.pop_back ();
-       }
+       _history.event ();
 }
 
 /** Called to request encoding of the next video frame in the DCP.  This is called in order,
index fe18f8b2d5a7a8330b0b93217973b96216206085..7e9bd497a619665f03b55f6b6feb32d2c81ff631 100644 (file)
@@ -27,6 +27,7 @@
 
 #include "util.h"
 #include "cross.h"
+#include "event_history.h"
 #include "exception_store.h"
 #include <boost/shared_ptr.hpp>
 #include <boost/thread/mutex.hpp>
@@ -84,14 +85,7 @@ private:
        /** Film that we are encoding */
        boost::shared_ptr<const Film> _film;
 
-       /** Mutex for _time_history */
-       mutable boost::mutex _state_mutex;
-       /** List of the times of completion of the last _history_size frames;
-           first is the most recently completed.
-       */
-       std::list<struct timeval> _time_history;
-       /** Number of frames that we should keep history for */
-       static int const _history_size;
+       EventHistory _history;
 
        /** Mutex for _threads */
        mutable boost::mutex _threads_mutex;
diff --git a/src/lib/event_history.cc b/src/lib/event_history.cc
new file mode 100644 (file)
index 0000000..eb3438a
--- /dev/null
@@ -0,0 +1,56 @@
+/*
+    Copyright (C) 2017 Carl Hetherington <cth@carlh.net>
+
+    This file is part of DCP-o-matic.
+
+    DCP-o-matic is free software; you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation; either version 2 of the License, or
+    (at your option) any later version.
+
+    DCP-o-matic is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with DCP-o-matic.  If not, see <http://www.gnu.org/licenses/>.
+
+*/
+
+#include "event_history.h"
+#include "util.h"
+#include <boost/thread/mutex.hpp>
+
+EventHistory::EventHistory (int size)
+       : _size (size)
+{
+
+}
+
+float
+EventHistory::rate () const
+{
+       boost::mutex::scoped_lock lock (_mutex);
+       if (int (_history.size()) < _size) {
+               return 0;
+       }
+
+       struct timeval now;
+       gettimeofday (&now, 0);
+
+       return _size / (seconds (now) - seconds (_history.back ()));
+}
+
+void
+EventHistory::event ()
+{
+       boost::mutex::scoped_lock lock (_mutex);
+
+       struct timeval tv;
+       gettimeofday (&tv, 0);
+       _history.push_front (tv);
+       if (int (_history.size()) > _size) {
+               _history.pop_back ();
+       }
+}
diff --git a/src/lib/event_history.h b/src/lib/event_history.h
new file mode 100644 (file)
index 0000000..5b0f9a6
--- /dev/null
@@ -0,0 +1,41 @@
+/*
+    Copyright (C) 2017 Carl Hetherington <cth@carlh.net>
+
+    This file is part of DCP-o-matic.
+
+    DCP-o-matic is free software; you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation; either version 2 of the License, or
+    (at your option) any later version.
+
+    DCP-o-matic is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with DCP-o-matic.  If not, see <http://www.gnu.org/licenses/>.
+
+*/
+
+#include <boost/thread/mutex.hpp>
+#include <list>
+
+class EventHistory
+{
+public:
+       EventHistory (int size);
+
+       float rate () const;
+       void event ();
+
+private:
+       /** Mutex for _history */
+       mutable boost::mutex _mutex;
+       /** List of the times of the last _history_size events
+           first is the most recently completed.
+       */
+       std::list<struct timeval> _history;
+       /** Number of events that we should keep history for */
+       int const _size;
+};
index 21a626462cd1ebe1bcffe6fa27c232db64f15c7d..3ebd0e8170a9e306961ac59a5b9fc2fcf8764052 100644 (file)
 #include "log.h"
 #include "image.h"
 #include "compose.hpp"
+#include <iostream>
 
 #include "i18n.h"
 
 using std::string;
 using std::runtime_error;
+using std::cout;
 using boost::shared_ptr;
 using boost::bind;
 using boost::weak_ptr;
@@ -44,6 +46,7 @@ force_pixel_format (AVPixelFormat, AVPixelFormat out)
 FFmpegTranscoder::FFmpegTranscoder (shared_ptr<const Film> film, weak_ptr<Job> job)
        : Transcoder (film, job)
        , _pixel_format (AV_PIX_FMT_YUV422P10)
+       , _history (1000)
 {
 
 }
@@ -73,7 +76,7 @@ FFmpegTranscoder::go ()
        _codec_context->flags |= CODEC_FLAG_QSCALE | CODEC_FLAG_GLOBAL_HEADER;
 
        boost::filesystem::path filename = _film->file(_film->isdcf_name(true) + ".mov");
-       avformat_alloc_output_context2 (&_format_context, 0, 0, filename.string().c_str());
+       avformat_alloc_output_context2 (&_format_context, 0, 0, _output.string().c_str());
        if (!_format_context) {
                throw runtime_error ("could not allocate FFmpeg format context");
        }
@@ -161,7 +164,11 @@ FFmpegTranscoder::video (shared_ptr<PlayerVideo> video, DCPTime time)
        frame->width = image->size().width;
        frame->height = image->size().height;
        frame->format = _pixel_format;
-       frame->pts = time.frames_round(_film->video_frame_rate()) / (_film->video_frame_rate() * av_q2d (_video_stream->time_base));
+       {
+               boost::mutex::scoped_lock lm (_mutex);
+               _last_frame = time.frames_round(_film->video_frame_rate());
+               frame->pts = _last_frame / (_film->video_frame_rate() * av_q2d (_video_stream->time_base));
+       }
 
        AVPacket packet;
        av_init_packet (&packet);
@@ -181,6 +188,13 @@ FFmpegTranscoder::video (shared_ptr<PlayerVideo> video, DCPTime time)
        }
 
        av_frame_free (&frame);
+
+       _history.event ();
+
+       shared_ptr<Job> job = _job.lock ();
+       if (job) {
+               job->set_progress (float(time.get()) / _film->length().get());
+       }
 }
 
 void
@@ -198,13 +212,12 @@ FFmpegTranscoder::subtitle (PlayerSubtitles subs, DCPTimePeriod period)
 float
 FFmpegTranscoder::current_encoding_rate () const
 {
-       /* XXX */
-       return 1;
+       return _history.rate ();
 }
 
 int
 FFmpegTranscoder::video_frames_enqueued () const
 {
-       /* XXX */
-       return 1;
+       boost::mutex::scoped_lock lm (_mutex);
+       return _last_frame;
 }
index aa65b5933ebcf9649659d28a8f7313a60cd23da2..02f0bb82e66310004628436f96ef58def2665f8a 100644 (file)
@@ -19,6 +19,7 @@
 */
 
 #include "transcoder.h"
+#include "event_history.h"
 extern "C" {
 #include <libavcodec/avcodec.h>
 #include <libavformat/avformat.h>
@@ -37,6 +38,10 @@ public:
                return false;
        }
 
+       void set_output (boost::filesystem::path o) {
+               _output = o;
+       }
+
 private:
        void video (boost::shared_ptr<PlayerVideo>, DCPTime);
        void audio (boost::shared_ptr<AudioBuffers>, DCPTime);
@@ -46,4 +51,11 @@ private:
        AVFormatContext* _format_context;
        AVStream* _video_stream;
        AVPixelFormat _pixel_format;
+
+       mutable boost::mutex _mutex;
+       Frame _last_frame;
+
+       EventHistory _history;
+
+       boost::filesystem::path _output;
 };
index 6f57736b74f299e6814b3048e34d77a188e80efc..22f104a14ea141be2f513f1e92113868b16101ef 100644 (file)
@@ -71,6 +71,7 @@ sources = """
           encode_server_finder.cc
           encoded_log_entry.cc
           environment_info.cc
+          event_history.cc
           examine_content_job.cc
           exceptions.cc
           file_group.cc
index 6543db55161ca3b72ac22b9e6334b6476d242b3c..ccaa44edb74742cb288ca38258f222c7ce736a66 100644 (file)
@@ -41,6 +41,7 @@
 #include "wx/save_template_dialog.h"
 #include "wx/templates_dialog.h"
 #include "wx/nag_dialog.h"
+#include "wx/export_dialog.h"
 #include "lib/film.h"
 #include "lib/config.h"
 #include "lib/util.h"
@@ -63,6 +64,8 @@
 #include "lib/dcpomatic_socket.h"
 #include "lib/hints.h"
 #include "lib/dcp_content.h"
+#include "lib/ffmpeg_transcoder.h"
+#include "lib/transcode_job.h"
 #include <dcp/exceptions.h>
 #include <dcp/raw_convert.h>
 #include <wx/generic/aboutdlgg.h>
@@ -192,6 +195,7 @@ enum {
        ID_jobs_make_dcp_batch,
        ID_jobs_make_kdms,
        ID_jobs_make_self_dkdm,
+       ID_jobs_export,
        ID_jobs_send_dcp_to_tms,
        ID_jobs_show_dcp,
        ID_tools_video_waveform,
@@ -269,6 +273,7 @@ public:
                Bind (wxEVT_MENU, boost::bind (&DOMFrame::jobs_make_kdms, this),          ID_jobs_make_kdms);
                Bind (wxEVT_MENU, boost::bind (&DOMFrame::jobs_make_dcp_batch, this),     ID_jobs_make_dcp_batch);
                Bind (wxEVT_MENU, boost::bind (&DOMFrame::jobs_make_self_dkdm, this),     ID_jobs_make_self_dkdm);
+               Bind (wxEVT_MENU, boost::bind (&DOMFrame::jobs_export, this),             ID_jobs_export);
                Bind (wxEVT_MENU, boost::bind (&DOMFrame::jobs_send_dcp_to_tms, this),    ID_jobs_send_dcp_to_tms);
                Bind (wxEVT_MENU, boost::bind (&DOMFrame::jobs_show_dcp, this),           ID_jobs_show_dcp);
                Bind (wxEVT_MENU, boost::bind (&DOMFrame::tools_video_waveform, this),    ID_tools_video_waveform);
@@ -697,6 +702,19 @@ private:
                d->Destroy ();
        }
 
+       void jobs_export ()
+       {
+               ExportDialog* d = new ExportDialog (this);
+               if (d->ShowModal() == wxID_OK) {
+                       shared_ptr<TranscodeJob> job (new TranscodeJob (_film));
+                       shared_ptr<FFmpegTranscoder> tx (new FFmpegTranscoder (_film, job));
+                       tx->set_output (d->path ());
+                       job->set_transcoder (tx);
+                       JobManager::instance()->add (job);
+               }
+               d->Destroy ();
+       }
+
        void content_scale_to_fit_width ()
        {
                ContentList vc = _film_editor->content_panel()->selected_video ();
@@ -981,8 +999,12 @@ private:
                wxMenu* jobs_menu = new wxMenu;
                add_item (jobs_menu, _("&Make DCP\tCtrl-M"), ID_jobs_make_dcp, NEEDS_FILM | NOT_DURING_DCP_CREATION);
                add_item (jobs_menu, _("Make DCP in &batch converter\tCtrl-B"), ID_jobs_make_dcp_batch, NEEDS_FILM | NOT_DURING_DCP_CREATION);
+               jobs_menu->AppendSeparator ();
                add_item (jobs_menu, _("Make &KDMs...\tCtrl-K"), ID_jobs_make_kdms, NEEDS_FILM);
                add_item (jobs_menu, _("Make DKDM for DCP-o-matic..."), ID_jobs_make_self_dkdm, NEEDS_FILM);
+               jobs_menu->AppendSeparator ();
+               add_item (jobs_menu, _("Export..."), ID_jobs_export, NEEDS_FILM);
+               jobs_menu->AppendSeparator ();
                add_item (jobs_menu, _("&Send DCP to TMS"), ID_jobs_send_dcp_to_tms, NEEDS_FILM | NOT_DURING_DCP_CREATION | NEEDS_CPL);
                add_item (jobs_menu, _("S&how DCP"), ID_jobs_show_dcp, NEEDS_FILM | NOT_DURING_DCP_CREATION | NEEDS_CPL);
 
index 49a8a6849a0f1dd59d3dff56160e227c7ae31154..63ce57823c59e792d34fdc1c03e83189d76aa0e9 100644 (file)
@@ -205,7 +205,7 @@ private:
                ++r;
 
                add_label_to_sizer (table, _panel, _("Cinema and screen database file"), true, wxGBPosition (r, 0));
-               _cinemas_file = new FilePickerCtrl (_panel, _("Select cinema and screen database file"), "*.xml");
+               _cinemas_file = new FilePickerCtrl (_panel, _("Select cinema and screen database file"), "*.xml", true);
                table->Add (_cinemas_file, wxGBPosition (r, 1));
                ++r;
 
diff --git a/src/wx/export_dialog.cc b/src/wx/export_dialog.cc
new file mode 100644 (file)
index 0000000..e21a49e
--- /dev/null
@@ -0,0 +1,62 @@
+/*
+    Copyright (C) 2017 Carl Hetherington <cth@carlh.net>
+
+    This file is part of DCP-o-matic.
+
+    DCP-o-matic is free software; you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation; either version 2 of the License, or
+    (at your option) any later version.
+
+    DCP-o-matic is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with DCP-o-matic.  If not, see <http://www.gnu.org/licenses/>.
+
+*/
+
+#include "export_dialog.h"
+#include "file_picker_ctrl.h"
+#include "wx_util.h"
+#include <boost/bind.hpp>
+
+using boost::bind;
+
+ExportDialog::ExportDialog (wxWindow* parent)
+       : TableDialog (parent, _("Export film"), 2, 1, true)
+{
+       add (_("Format"), true);
+       _format = new wxChoice (this, wxID_ANY);
+       add (_format);
+       add (_("Output file"), true);
+       _file = new FilePickerCtrl (this, _("Select output file"), _("MOV files (*.mov)|*.mov"), false);
+       add (_file);
+
+       _format->Append (_("ProRes 422"));
+       _format->SetSelection (0);
+
+       _format->Bind (wxEVT_CHOICE, bind (&ExportDialog::format_changed, this));
+
+       layout ();
+}
+
+void
+ExportDialog::format_changed ()
+{
+       switch (_format->GetSelection()) {
+       case 0:
+               _file->SetWildcard (_("MOV files (*.mov)"));
+               break;
+       }
+
+       _file->SetPath ("");
+}
+
+boost::filesystem::path
+ExportDialog::path () const
+{
+       return wx_to_std (_file->GetPath ());
+}
diff --git a/src/wx/export_dialog.h b/src/wx/export_dialog.h
new file mode 100644 (file)
index 0000000..8f0be71
--- /dev/null
@@ -0,0 +1,39 @@
+/*
+    Copyright (C) 2017 Carl Hetherington <cth@carlh.net>
+
+    This file is part of DCP-o-matic.
+
+    DCP-o-matic is free software; you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation; either version 2 of the License, or
+    (at your option) any later version.
+
+    DCP-o-matic is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with DCP-o-matic.  If not, see <http://www.gnu.org/licenses/>.
+
+*/
+
+#include "table_dialog.h"
+#include <wx/wx.h>
+#include <boost/filesystem.hpp>
+
+class FilePickerCtrl;
+
+class ExportDialog : public TableDialog
+{
+public:
+       ExportDialog (wxWindow* parent);
+
+       boost::filesystem::path path () const;
+
+private:
+       void format_changed ();
+
+       wxChoice* _format;
+       FilePickerCtrl* _file;
+};
index 03b2880fe201d14a15fd92f6b6cae113b033fe50..4cd843feb3755c710c08111416e9f9075206e2ab 100644 (file)
 using namespace std;
 using namespace boost;
 
-FilePickerCtrl::FilePickerCtrl (wxWindow* parent, wxString prompt, wxString wildcard)
+FilePickerCtrl::FilePickerCtrl (wxWindow* parent, wxString prompt, wxString wildcard, bool open)
        : wxPanel (parent)
        , _prompt (prompt)
        , _wildcard (wildcard)
+       , _open (open)
 {
        _sizer = new wxBoxSizer (wxHORIZONTAL);
 
@@ -43,7 +44,6 @@ FilePickerCtrl::FilePickerCtrl (wxWindow* parent, wxString prompt, wxString wild
        _sizer->Add (_file, 1, wxEXPAND, 0);
 
        SetSizerAndFit (_sizer);
-
        _file->Bind (wxEVT_BUTTON, boost::bind (&FilePickerCtrl::browse_clicked, this));
 }
 
@@ -71,10 +71,16 @@ FilePickerCtrl::GetPath () const
 void
 FilePickerCtrl::browse_clicked ()
 {
-       wxFileDialog* d = new wxFileDialog (this, _prompt, wxEmptyString, wxEmptyString, _wildcard);
+       wxFileDialog* d = new wxFileDialog (this, _prompt, wxEmptyString, wxEmptyString, _wildcard, _open ? wxFD_OPEN : wxFD_SAVE | wxFD_OVERWRITE_PROMPT);
        d->SetPath (_path);
        if (d->ShowModal () == wxID_OK) {
                SetPath (d->GetPath ());
        }
        d->Destroy ();
 }
+
+void
+FilePickerCtrl::SetWildcard (wxString w)
+{
+       _wildcard = w;
+}
index 61e7bd55f33ba980648d17bc91f9e4d9a35e9852..d0c4d56c86f789ff50a8edb3856a1d370e1d8e16 100644 (file)
 class FilePickerCtrl : public wxPanel
 {
 public:
-       FilePickerCtrl (wxWindow* parent, wxString prompt, wxString wildcard);
+       FilePickerCtrl (wxWindow* parent, wxString prompt, wxString wildcard, bool open);
 
        wxString GetPath () const;
        void SetPath (wxString);
+       void SetWildcard (wxString);
 
 private:
        void browse_clicked ();
@@ -36,4 +37,5 @@ private:
        wxSizer* _sizer;
        wxString _prompt;
        wxString _wildcard;
+       bool _open;
 };
index 8297f37c9f72f10ea86cc6a33f22bc32e081ff47..abe65734172ac4b601562e003b34b6a988cf0a06 100644 (file)
@@ -49,6 +49,7 @@ sources = """
           dolby_doremi_certificate_panel.cc
           download_certificate_dialog.cc
           download_certificate_panel.cc
+          export_dialog.cc
           file_picker_ctrl.cc
           film_editor.cc
           film_name_location_dialog.cc