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 ();
}
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 */
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,
#include "util.h"
#include "cross.h"
+#include "event_history.h"
#include "exception_store.h"
#include <boost/shared_ptr.hpp>
#include <boost/thread/mutex.hpp>
/** 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;
--- /dev/null
+/*
+ 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 ();
+ }
+}
--- /dev/null
+/*
+ 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;
+};
#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;
FFmpegTranscoder::FFmpegTranscoder (shared_ptr<const Film> film, weak_ptr<Job> job)
: Transcoder (film, job)
, _pixel_format (AV_PIX_FMT_YUV422P10)
+ , _history (1000)
{
}
_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");
}
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);
}
av_frame_free (&frame);
+
+ _history.event ();
+
+ shared_ptr<Job> job = _job.lock ();
+ if (job) {
+ job->set_progress (float(time.get()) / _film->length().get());
+ }
}
void
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;
}
*/
#include "transcoder.h"
+#include "event_history.h"
extern "C" {
#include <libavcodec/avcodec.h>
#include <libavformat/avformat.h>
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);
AVFormatContext* _format_context;
AVStream* _video_stream;
AVPixelFormat _pixel_format;
+
+ mutable boost::mutex _mutex;
+ Frame _last_frame;
+
+ EventHistory _history;
+
+ boost::filesystem::path _output;
};
encode_server_finder.cc
encoded_log_entry.cc
environment_info.cc
+ event_history.cc
examine_content_job.cc
exceptions.cc
file_group.cc
#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"
#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>
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,
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);
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 ();
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);
++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;
--- /dev/null
+/*
+ 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 ());
+}
--- /dev/null
+/*
+ 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;
+};
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);
_sizer->Add (_file, 1, wxEXPAND, 0);
SetSizerAndFit (_sizer);
-
_file->Bind (wxEVT_BUTTON, boost::bind (&FilePickerCtrl::browse_clicked, this));
}
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;
+}
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 ();
wxSizer* _sizer;
wxString _prompt;
wxString _wildcard;
+ bool _open;
};
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