using std::setfill;
using std::min;
using std::make_pair;
-using std::cout;
using boost::shared_ptr;
using boost::lexical_cast;
using boost::to_upper_copy;
, _frames_per_second (0)
, _dirty (false)
{
+ set_dci_date_today ();
+
/* Make state.directory a complete path without ..s (where possible)
(Code swiped from Adam Bowen on stackoverflow)
*/
}
_log = new FileLog (file ("log"));
- set_dci_date_today ();
}
Film::Film (Film const & o)
, _colour_lut (o._colour_lut)
, _j2k_bandwidth (o._j2k_bandwidth)
, _dci_metadata (o._dci_metadata)
+ , _dci_date (o._dci_date)
, _size (o._size)
, _length (o._length)
, _dcp_intrinsic_duration (o._dcp_intrinsic_duration)
f << "colour_lut " << _colour_lut << "\n";
f << "j2k_bandwidth " << _j2k_bandwidth << "\n";
_dci_metadata.write (f);
+ f << "dci_date " << boost::gregorian::to_iso_string (_dci_date) << "\n";
f << "width " << _size.width << "\n";
f << "height " << _size.height << "\n";
f << "length " << _length.get_value_or(0) << "\n";
_colour_lut = atoi (v.c_str ());
} else if (k == "j2k_bandwidth") {
_j2k_bandwidth = atoi (v.c_str ());
+ } else if (k == "dci_date") {
+ _dci_date = boost::gregorian::from_undelimited_string (v);
}
_dci_metadata.read (k, v);
/** @return a DCI-compliant name for a DCP of this film */
string
-Film::dci_name () const
+Film::dci_name (bool if_created_now) const
{
stringstream d;
d << dm.studio << "_";
}
- d << boost::gregorian::to_iso_string (_dci_date) << "_";
+ if (if_created_now) {
+ d << boost::gregorian::to_iso_string (boost::gregorian::day_clock::local_day ()) << "_";
+ } else {
+ d << boost::gregorian::to_iso_string (_dci_date) << "_";
+ }
if (!dm.facility.empty ()) {
d << dm.facility << "_";
/** @return name to give the DCP */
string
-Film::dcp_name () const
+Film::dcp_name (bool if_created_now) const
{
if (use_dci_name()) {
- return dci_name ();
+ return dci_name (if_created_now);
}
return name();
return file (p.string ());
}
+/** Make an educated guess as to whether we have a complete DCP
+ * or not.
+ * @return true if we do.
+ */
+bool
+Film::have_dcp () const
+{
+ try {
+ libdcp::DCP dcp (dir (dcp_name()));
+ dcp.read ();
+ } catch (...) {
+ return false;
+ }
+
+ return true;
+}
void read_metadata ();
libdcp::Size cropped_size (libdcp::Size) const;
- std::string dci_name () const;
- std::string dcp_name () const;
+ std::string dci_name (bool if_created_now) const;
+ std::string dcp_name (bool if_created_now = false) const;
boost::optional<int> dcp_intrinsic_duration () const {
return _dcp_intrinsic_duration;
void set_dci_date_today ();
+ bool have_dcp () const;
+
/** Identifiers for the parts of our state;
used for signalling changes.
*/
/** Any running ExamineContentJob, or 0 */
boost::shared_ptr<ExamineContentJob> _examine_content_job;
- /** The date that we should use in a DCI name */
- boost::gregorian::date _dci_date;
-
void signal_changed (Property);
void examine_content_finished ();
std::string video_state_identifier () const;
/** DCI naming stuff */
DCIMetadata _dci_metadata;
+ /** The date that we should use in a DCI name */
+ boost::gregorian::date _dci_date;
/* Data which are cached to speed things up */
mutable boost::mutex _state_mutex;
friend class paths_test;
+ friend class film_metadata_test;
};
#endif
static shared_ptr<Film> film;
static std::string log_level;
static std::string film_to_load;
+static wxMenu* jobs_menu = 0;
static void set_menu_sensitivity ();
wxMenu* edit = new wxMenu;
add_item (edit, "&Preferences...", ID_edit_preferences, ALWAYS);
- wxMenu* jobs = new wxMenu;
- add_item (jobs, "&Make DCP", ID_jobs_make_dcp, NEEDS_FILM);
- add_item (jobs, "&Send DCP to TMS", ID_jobs_send_dcp_to_tms, NEEDS_FILM);
- jobs->AppendSeparator ();
- add_item (jobs, "&Examine content", ID_jobs_examine_content, NEEDS_FILM);
- add_item (jobs, "Make DCP from existing &transcode", ID_jobs_make_dcp_from_existing_transcode, NEEDS_FILM);
+ jobs_menu = new wxMenu;
+ add_item (jobs_menu, "&Make DCP", ID_jobs_make_dcp, NEEDS_FILM);
+ add_item (jobs_menu, "&Send DCP to TMS", ID_jobs_send_dcp_to_tms, NEEDS_FILM);
+ jobs_menu->AppendSeparator ();
+ add_item (jobs_menu, "&Examine content", ID_jobs_examine_content, NEEDS_FILM);
+ add_item (jobs_menu, "Make DCP from existing &transcode", ID_jobs_make_dcp_from_existing_transcode, NEEDS_FILM);
wxMenu* help = new wxMenu;
add_item (help, "About", ID_help_about, ALWAYS);
m->Append (file, _("&File"));
m->Append (edit, _("&Edit"));
- m->Append (jobs, _("&Jobs"));
+ m->Append (jobs_menu, _("&Jobs"));
m->Append (help, _("&Help"));
}
Connect (ID_jobs_make_dcp_from_existing_transcode, wxEVT_COMMAND_MENU_SELECTED, wxCommandEventHandler (Frame::jobs_make_dcp_from_existing_transcode));
Connect (ID_help_about, wxEVT_COMMAND_MENU_SELECTED, wxCommandEventHandler (Frame::help_about));
+ Connect (wxID_ANY, wxEVT_MENU_OPEN, wxMenuEventHandler (Frame::menu_opened));
+
wxPanel* panel = new wxPanel (this);
wxSizer* s = new wxBoxSizer (wxHORIZONTAL);
s->Add (panel, 1, wxEXPAND);
set_film ();
}
+private:
+
+ void menu_opened (wxMenuEvent& ev)
+ {
+ if (ev.GetMenu() != jobs_menu) {
+ return;
+ }
+
+ bool const have_dcp = film && film->have_dcp();
+ jobs_menu->Enable (ID_jobs_send_dcp_to_tms, have_dcp);
+ }
+
void set_film ()
{
film_viewer->set_film (film);
} else {
checked_set (_format, n);
}
- _dcp_name->SetLabel (std_to_wx (_film->dcp_name ()));
+ setup_dcp_name ();
break;
}
case Film::CROP:
}
case Film::NAME:
checked_set (_name, _film->name());
- _film->set_dci_date_today ();
- _dcp_name->SetLabel (std_to_wx (_film->dcp_name ()));
+ setup_dcp_name ();
break;
case Film::FRAMES_PER_SECOND:
s << fixed << setprecision(2) << _film->frames_per_second();
break;
case Film::DCP_CONTENT_TYPE:
checked_set (_dcp_content_type, DCPContentType::as_index (_film->dcp_content_type ()));
- _dcp_name->SetLabel (std_to_wx (_film->dcp_name ()));
+ setup_dcp_name ();
break;
case Film::DCP_AB:
checked_set (_dcp_ab, _film->dcp_ab ());
case Film::WITH_SUBTITLES:
checked_set (_with_subtitles, _film->with_subtitles ());
setup_subtitle_control_sensitivity ();
- _dcp_name->SetLabel (std_to_wx (_film->dcp_name ()));
+ setup_dcp_name ();
break;
case Film::SUBTITLE_OFFSET:
checked_set (_subtitle_offset, _film->subtitle_offset ());
break;
case Film::USE_DCI_NAME:
checked_set (_use_dci_name, _film->use_dci_name ());
- _dcp_name->SetLabel (std_to_wx (_film->dcp_name ()));
+ setup_dcp_name ();
break;
case Film::DCI_METADATA:
- _dcp_name->SetLabel (std_to_wx (_film->dcp_name ()));
+ setup_dcp_name ();
break;
case Film::CONTENT_AUDIO_STREAM:
if (_film->content_audio_stream()) {
checked_set (_audio_stream, _film->content_audio_stream()->to_string());
}
- _dcp_name->SetLabel (std_to_wx (_film->dcp_name ()));
+ setup_dcp_name ();
setup_audio_details ();
setup_audio_control_sensitivity ();
break;
case Film::USE_CONTENT_AUDIO:
checked_set (_use_content_audio, _film->use_content_audio());
checked_set (_use_external_audio, !_film->use_content_audio());
- _dcp_name->SetLabel (std_to_wx (_film->dcp_name ()));
+ setup_dcp_name ();
setup_audio_details ();
setup_audio_control_sensitivity ();
break;
_film->set_external_audio (a);
}
+
+void
+FilmEditor::setup_dcp_name ()
+{
+ _dcp_name->SetLabel (std_to_wx (_film->dcp_name (true)));
+}
void setup_audio_control_sensitivity ();
void setup_streams ();
void setup_audio_details ();
+ void setup_dcp_name ();
wxControl* video_control (wxControl *);
wxControl* still_control (wxControl *);
studio
facility
package_type
+dci_date 20130211
width 0
height 0
length 0
#include <iostream>
#include <boost/filesystem.hpp>
#include <boost/algorithm/string/predicate.hpp>
+#include <boost/date_time.hpp>
#include "format.h"
#include "film.h"
#include "filter.h"
Config::instance()->set_default_dci_metadata (DCIMetadata ());
}
+boost::filesystem::path
+test_film_dir (string name)
+{
+ boost::filesystem::path p;
+ p /= "build";
+ p /= "test";
+ p /= name;
+ return p;
+}
+
shared_ptr<Film>
new_test_film (string name)
{
- string const d = String::compose ("build/test/%1", name);
- if (boost::filesystem::exists (d)) {
- boost::filesystem::remove_all (d);
+ boost::filesystem::path p = test_film_dir (name);
+ if (boost::filesystem::exists (p)) {
+ boost::filesystem::remove_all (p);
}
- return shared_ptr<Film> (new Film (d, false));
+
+ return shared_ptr<Film> (new Film (p.string(), false));
}
BOOST_CHECK_THROW (new Film (test_film, true), OpenFileError);
shared_ptr<Film> f (new Film (test_film, false));
+ f->_dci_date = boost::gregorian::from_undelimited_string ("20130211");
BOOST_CHECK (f->format() == 0);
BOOST_CHECK (f->dcp_content_type() == 0);
BOOST_CHECK (f->filters ().empty());
film->set_format (Format::from_nickname ("Flat"));
film->set_dcp_content_type (DCPContentType::from_pretty_name ("Test"));
film->make_dcp (true);
+ film->write_metadata ();
while (JobManager::instance()->work_to_do ()) {
dvdomatic_sleep (1);
BOOST_CHECK_EQUAL (JobManager::instance()->errors(), false);
}
+/** Test Film::have_dcp(). Requires the output from make_dcp_test above */
+BOOST_AUTO_TEST_CASE (have_dcp_test)
+{
+ boost::filesystem::path p = test_film_dir ("make_dcp_test");
+ Film f (p.string ());
+ BOOST_CHECK (f.have_dcp());
+
+ p /= f.dcp_name();
+ p /= "video.mxf";
+ boost::filesystem::remove (p);
+ BOOST_CHECK (!f.have_dcp ());
+}
+
BOOST_AUTO_TEST_CASE (make_dcp_with_range_test)
{
shared_ptr<Film> film = new_test_film ("make_dcp_with_range_test");