From 8c365af343a15bee11af53fc6bc16487b83260d1 Mon Sep 17 00:00:00 2001 From: Carl Hetherington Date: Fri, 15 Mar 2019 00:52:56 +0000 Subject: [PATCH] Basics of setting and storing SMPTE CPL markers. --- src/lib/film.cc | 34 +++++++++++ src/lib/film.h | 8 ++- src/wx/dcp_panel.cc | 35 ++++++++++- src/wx/dcp_panel.h | 10 ++- src/wx/film_editor.cc | 2 +- src/wx/markers_dialog.cc | 127 +++++++++++++++++++++++++++++++++++++++ src/wx/markers_dialog.h | 38 ++++++++++++ src/wx/wscript | 1 + 8 files changed, 247 insertions(+), 8 deletions(-) create mode 100644 src/wx/markers_dialog.cc create mode 100644 src/wx/markers_dialog.h diff --git a/src/lib/film.cc b/src/lib/film.cc index aa16fdad8..b40b439f5 100644 --- a/src/lib/film.cc +++ b/src/lib/film.cc @@ -403,6 +403,11 @@ Film::metadata (bool with_content_paths) const root->add_child("UploadAfterMakeDCP")->add_child_text (_upload_after_make_dcp ? "1" : "0"); root->add_child("ReencodeJ2K")->add_child_text (_reencode_j2k ? "1" : "0"); root->add_child("UserExplicitVideoFrameRate")->add_child_text(_user_explicit_video_frame_rate ? "1" : "0"); + for (map::const_iterator i = _markers.begin(); i != _markers.end(); ++i) { + xmlpp::Element* m = root->add_child("Marker"); + m->set_attribute("Type", dcp::marker_to_string(i->first)); + m->add_child_text(raw_convert(i->second.get())); + } _playlist->as_xml (root->add_child ("Playlist"), with_content_paths); return doc; @@ -531,7 +536,12 @@ Film::read_metadata (optional path) _reencode_j2k = f.optional_bool_child("ReencodeJ2K").get_value_or(false); _user_explicit_video_frame_rate = f.optional_bool_child("UserExplicitVideoFrameRate").get_value_or(false); + BOOST_FOREACH (cxml::ConstNodePtr i, f.node_children("Marker")) { + _markers[dcp::marker_from_string(i->string_attribute("Type"))] = DCPTime(dcp::raw_convert(i->content())); + } + list notes; + /* This method is the only one that can return notes (so far) */ _playlist->set_from_xml (shared_from_this(), f.node_child ("Playlist"), _state_version, notes); /* Write backtraces to this film's directory, until another film is loaded */ @@ -1685,3 +1695,27 @@ Film::closed_caption_tracks () const return tt; } + +void +Film::set_marker (dcp::Marker type, DCPTime time) +{ + ChangeSignaller ch (this, MARKERS); + _markers[type] = time; +} + +void +Film::unset_marker (dcp::Marker type) +{ + ChangeSignaller ch (this, MARKERS); + _markers.erase (type); +} + +optional +Film::marker (dcp::Marker type) const +{ + map::const_iterator i = _markers.find (type); + if (i == _markers.end()) { + return optional(); + } + return i->second; +} diff --git a/src/lib/film.h b/src/lib/film.h index b77ce7a76..dd69c9e68 100644 --- a/src/lib/film.h +++ b/src/lib/film.h @@ -200,7 +200,8 @@ public: REEL_TYPE, REEL_LENGTH, UPLOAD_AFTER_MAKE_DCP, - REENCODE_J2K + REENCODE_J2K, + MARKERS }; @@ -296,6 +297,7 @@ public: return _reencode_j2k; } + boost::optional marker (dcp::Marker type) const; /* SET */ @@ -327,6 +329,8 @@ public: void set_reel_length (int64_t); void set_upload_after_make_dcp (bool); void set_reencode_j2k (bool); + void set_marker (dcp::Marker type, DCPTime time); + void unset_marker (dcp::Marker type); /** Emitted when some property has of the Film is about to change or has changed */ mutable boost::signals2::signal Change; @@ -406,6 +410,7 @@ private: bool _reencode_j2k; /** true if the user has ever explicitly set the video frame rate of this film */ bool _user_explicit_video_frame_rate; + std::map _markers; int _state_version; @@ -414,7 +419,6 @@ private: /** film being used as a template, or 0 */ boost::shared_ptr _template_film; - boost::signals2::scoped_connection _playlist_change_connection; boost::signals2::scoped_connection _playlist_order_changed_connection; boost::signals2::scoped_connection _playlist_content_change_connection; diff --git a/src/wx/dcp_panel.cc b/src/wx/dcp_panel.cc index 3defe75e4..85ed81e46 100644 --- a/src/wx/dcp_panel.cc +++ b/src/wx/dcp_panel.cc @@ -1,5 +1,5 @@ /* - Copyright (C) 2012-2018 Carl Hetherington + Copyright (C) 2012-2019 Carl Hetherington This file is part of DCP-o-matic. @@ -28,6 +28,7 @@ #include "static_text.h" #include "check_box.h" #include "dcpomatic_button.h" +#include "markers_dialog.h" #include "lib/ratio.h" #include "lib/config.h" #include "lib/dcp_content_type.h" @@ -58,11 +59,14 @@ using std::max; using std::make_pair; using boost::lexical_cast; using boost::shared_ptr; +using boost::weak_ptr; using dcp::locale_convert; -DCPPanel::DCPPanel (wxNotebook* n, boost::shared_ptr film) +DCPPanel::DCPPanel (wxNotebook* n, shared_ptr film, weak_ptr viewer) : _audio_dialog (0) + , _markers_dialog (0) , _film (film) + , _viewer (viewer) , _generally_sensitive (true) { _panel = new wxPanel (n); @@ -114,6 +118,8 @@ DCPPanel::DCPPanel (wxNotebook* n, boost::shared_ptr film) _upload_after_make_dcp = new CheckBox (_panel, _("Upload DCP to TMS after it is made")); + _markers = new Button (_panel, _("Edit markers...")); + _notebook = new wxNotebook (_panel, wxID_ANY); _sizer->Add (_notebook, 1, wxEXPAND | wxTOP, 6); @@ -132,6 +138,7 @@ DCPPanel::DCPPanel (wxNotebook* n, boost::shared_ptr film) _reel_length->Bind (wxEVT_SPINCTRL, boost::bind (&DCPPanel::reel_length_changed, this)); _standard->Bind (wxEVT_CHOICE, boost::bind (&DCPPanel::standard_changed, this)); _upload_after_make_dcp->Bind (wxEVT_CHECKBOX, boost::bind (&DCPPanel::upload_after_make_dcp_changed, this)); + _markers->Bind (wxEVT_BUTTON, boost::bind (&DCPPanel::markers_clicked, this)); BOOST_FOREACH (DCPContentType const * i, DCPContentType::all()) { _dcp_content_type->Append (std_to_wx (i->pretty_name ())); @@ -213,6 +220,7 @@ DCPPanel::add_to_grid () _standard_label->Show (full); _standard->Show (full); _upload_after_make_dcp->Show (full); + _markers->Show (full); _reencode_j2k->Show (full); _encrypted->Show (full); @@ -245,6 +253,9 @@ DCPPanel::add_to_grid () _grid->Add (_upload_after_make_dcp, wxGBPosition (r, 0), wxGBSpan (1, 2)); ++r; + + _grid->Add (_markers, wxGBPosition(r, 0), wxGBSpan(1, 2)); + ++r; } } @@ -365,6 +376,18 @@ DCPPanel::upload_after_make_dcp_changed () _film->set_upload_after_make_dcp (_upload_after_make_dcp->GetValue ()); } +void +DCPPanel::markers_clicked () +{ + if (_markers_dialog) { + _markers_dialog->Destroy (); + _markers_dialog = 0; + } + + _markers_dialog = new MarkersDialog (_panel, _film, _viewer); + _markers_dialog->Show(); +} + void DCPPanel::film_changed (int p) { @@ -458,6 +481,7 @@ DCPPanel::film_changed (int p) case Film::INTEROP: checked_set (_standard, _film->interop() ? 1 : 0); setup_dcp_name (); + _markers->Enable (!_film->interop()); break; case Film::AUDIO_PROCESSOR: if (_film->audio_processor ()) { @@ -558,11 +582,15 @@ DCPPanel::dcp_content_type_changed () void DCPPanel::set_film (shared_ptr film) { - /* We are changing film, so destroy any audio dialog for the old one */ + /* We are changing film, so destroy any dialogs for the old one */ if (_audio_dialog) { _audio_dialog->Destroy (); _audio_dialog = 0; } + if (_markers_dialog) { + _markers_dialog->Destroy (); + _markers_dialog = 0; + } _film = film; @@ -626,6 +654,7 @@ DCPPanel::setup_sensitivity () _reel_type->Enable (_generally_sensitive && _film && !_film->references_dcp_video() && !_film->references_dcp_audio()); _reel_length->Enable (_generally_sensitive && _film && _film->reel_type() == REELTYPE_BY_LENGTH); _upload_after_make_dcp->Enable (_generally_sensitive); + _markers->Enable (_generally_sensitive); _frame_rate_choice->Enable (_generally_sensitive && _film && !_film->references_dcp_video()); _frame_rate_spin->Enable (_generally_sensitive && _film && !_film->references_dcp_video()); _audio_channels->Enable (_generally_sensitive && _film && !_film->references_dcp_audio()); diff --git a/src/wx/dcp_panel.h b/src/wx/dcp_panel.h index c43311429..27049962c 100644 --- a/src/wx/dcp_panel.h +++ b/src/wx/dcp_panel.h @@ -1,5 +1,5 @@ /* - Copyright (C) 2012-2018 Carl Hetherington + Copyright (C) 2012-2019 Carl Hetherington This file is part of DCP-o-matic. @@ -35,13 +35,15 @@ class wxSizer; class wxGridBagSizer; class AudioDialog; +class MarkersDialog; class Film; +class FilmViewer; class Ratio; class DCPPanel : public boost::noncopyable { public: - DCPPanel (wxNotebook *, boost::shared_ptr); + DCPPanel (wxNotebook *, boost::shared_ptr, boost::weak_ptr viewer); void set_film (boost::shared_ptr); void set_general_sensitivity (bool); @@ -77,6 +79,7 @@ private: void reel_type_changed (); void reel_length_changed (); void upload_after_make_dcp_changed (); + void markers_clicked (); void reencode_j2k_changed (); void setup_frame_rate_widget (); @@ -144,9 +147,12 @@ private: wxStaticText* _reel_length_gb_label; wxSpinCtrl* _reel_length; wxCheckBox* _upload_after_make_dcp; + wxButton* _markers; AudioDialog* _audio_dialog; + MarkersDialog* _markers_dialog; boost::shared_ptr _film; + boost::weak_ptr _viewer; bool _generally_sensitive; }; diff --git a/src/wx/film_editor.cc b/src/wx/film_editor.cc index a017175f5..ae0868f27 100644 --- a/src/wx/film_editor.cc +++ b/src/wx/film_editor.cc @@ -52,7 +52,7 @@ FilmEditor::FilmEditor (wxWindow* parent, weak_ptr viewer) _content_panel = new ContentPanel (_main_notebook, _film, viewer); _main_notebook->AddPage (_content_panel->window(), _("Content"), true); - _dcp_panel = new DCPPanel (_main_notebook, _film); + _dcp_panel = new DCPPanel (_main_notebook, _film, viewer); _main_notebook->AddPage (_dcp_panel->panel (), _("DCP"), false); JobManager::instance()->ActiveJobsChanged.connect ( diff --git a/src/wx/markers_dialog.cc b/src/wx/markers_dialog.cc new file mode 100644 index 000000000..724cb7d9e --- /dev/null +++ b/src/wx/markers_dialog.cc @@ -0,0 +1,127 @@ +/* + Copyright (C) 2019 Carl Hetherington + + 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 . + +*/ + +#include "markers_dialog.h" +#include "wx_util.h" +#include "timecode.h" +#include "static_text.h" +#include "dcpomatic_button.h" +#include "check_box.h" +#include "film_viewer.h" +#include "lib/film.h" +#include +#include +#include +#include + +using std::cout; +using boost::bind; +using boost::shared_ptr; +using boost::weak_ptr; +using boost::optional; + +class Marker +{ +public: + Marker (wxWindow* parent, wxGridBagSizer* grid, int row, weak_ptr film_, weak_ptr viewer_, wxString name, dcp::Marker type_) + : film (film_) + , viewer (viewer_) + , type (type_) + { + checkbox = new CheckBox(parent, name); + grid->Add (checkbox, wxGBPosition(row, 0), wxDefaultSpan, wxALIGN_CENTER_VERTICAL); + timecode = new Timecode (parent); + grid->Add (timecode, wxGBPosition(row, 1)); + set_button = new Button (parent, _("Set from current position")); + grid->Add (set_button, wxGBPosition(row, 2)); + + shared_ptr f = film.lock (); + DCPOMATIC_ASSERT (f); + + optional t = f->marker (type); + checkbox->SetValue (static_cast(t)); + if (t) { + timecode->set (*t, f->video_frame_rate()); + } + + set_sensitivity (); + + set_button->Bind (wxEVT_BUTTON, bind(&Marker::set, this)); + checkbox->Bind (wxEVT_CHECKBOX, bind(&Marker::set_sensitivity, this)); + timecode->Changed.connect (bind(&Marker::changed, this)); + } + +private: + void set_sensitivity () + { + timecode->Enable (checkbox->GetValue()); + set_button->Enable (checkbox->GetValue()); + } + + void set () + { + shared_ptr f = film.lock (); + DCPOMATIC_ASSERT (f); + shared_ptr v = viewer.lock (); + DCPOMATIC_ASSERT (v); + timecode->set (v->position(), f->video_frame_rate()); + } + + void changed () + { + shared_ptr f = film.lock (); + DCPOMATIC_ASSERT (f); + if (checkbox->GetValue()) { + f->set_marker (type, timecode->get(f->video_frame_rate())); + } else { + f->unset_marker (type); + } + } + + weak_ptr film; + weak_ptr viewer; + dcp::Marker type; + CheckBox* checkbox; + Timecode* timecode; + Button* set_button; +}; + +MarkersDialog::MarkersDialog (wxWindow* parent, weak_ptr film, weak_ptr viewer) + : wxDialog (parent, wxID_ANY, _("Markers")) + , _film (film) +{ + wxSizer* sizer = new wxBoxSizer (wxVERTICAL); + wxGridBagSizer* grid = new wxGridBagSizer (DCPOMATIC_SIZER_X_GAP, DCPOMATIC_SIZER_Y_GAP); + + int r = 0; + _markers.push_back (shared_ptr(new Marker(this, grid, r++, film, viewer, _("First frame of composition"), dcp::FFOC))); + _markers.push_back (shared_ptr(new Marker(this, grid, r++, film, viewer, _("Last frame of composition"), dcp::LFOC))); + _markers.push_back (shared_ptr(new Marker(this, grid, r++, film, viewer, _("First frame of title credits"), dcp::FFTC))); + _markers.push_back (shared_ptr(new Marker(this, grid, r++, film, viewer, _("Last frame of title credits"), dcp::LFTC))); + _markers.push_back (shared_ptr(new Marker(this, grid, r++, film, viewer, _("First frame of intermission"), dcp::FFOI))); + _markers.push_back (shared_ptr(new Marker(this, grid, r++, film, viewer, _("Last frame of intermission"), dcp::LFOI))); + _markers.push_back (shared_ptr(new Marker(this, grid, r++, film, viewer, _("First frame of end credits"), dcp::FFEC))); + _markers.push_back (shared_ptr(new Marker(this, grid, r++, film, viewer, _("Last frame of end credits"), dcp::LFEC))); + _markers.push_back (shared_ptr(new Marker(this, grid, r++, film, viewer, _("First frame of moving credits"), dcp::FFMC))); + _markers.push_back (shared_ptr(new Marker(this, grid, r++, film, viewer, _("Last frame of moving credits"), dcp::LFMC))); + + sizer->Add (grid, 0, wxALL, 8); + SetSizerAndFit (sizer); +} diff --git a/src/wx/markers_dialog.h b/src/wx/markers_dialog.h new file mode 100644 index 000000000..fbbaa1aee --- /dev/null +++ b/src/wx/markers_dialog.h @@ -0,0 +1,38 @@ +/* + Copyright (C) 2019 Carl Hetherington + + 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 . + +*/ + +#include +#include +#include +#include + +class Marker; +class Film; +class FilmViewer; + +class MarkersDialog : public wxDialog +{ +public: + MarkersDialog (wxWindow* parent, boost::weak_ptr film, boost::weak_ptr viewer); + +private: + std::list > _markers; + boost::weak_ptr _film; +}; diff --git a/src/wx/wscript b/src/wx/wscript index 538e7da0e..349842797 100644 --- a/src/wx/wscript +++ b/src/wx/wscript @@ -85,6 +85,7 @@ sources = """ kdm_timing_panel.cc key_dialog.cc make_chain_dialog.cc + markers_dialog.cc message_dialog.cc monitor_dialog.cc move_to_dialog.cc -- 2.30.2