X-Git-Url: https://main.carlh.net/gitweb/?p=dcpomatic.git;a=blobdiff_plain;f=src%2Fwx%2Fswaroop_controls.cc;h=5ce6c45fc7a637f6e6c1e99124d596f7698cb422;hp=5e386ae9bae5631ac75893482a86434ca5f9eb73;hb=2ecead272e146c78850e333fa408395d51fdd132;hpb=6b32680c18988808e56b053979816e53190c0568 diff --git a/src/wx/swaroop_controls.cc b/src/wx/swaroop_controls.cc index 5e386ae9b..5ce6c45fc 100644 --- a/src/wx/swaroop_controls.cc +++ b/src/wx/swaroop_controls.cc @@ -1,5 +1,5 @@ /* - Copyright (C) 2018 Carl Hetherington + Copyright (C) 2018-2019 Carl Hetherington This file is part of DCP-o-matic. @@ -27,16 +27,23 @@ #include "lib/player_video.h" #include "lib/dcp_content.h" #include "lib/cross.h" +#include "lib/scoped_temporary.h" +#include "lib/internet.h" +#include "lib/ffmpeg_content.h" +#include "lib/compose.hpp" #include +#include #include #include using std::string; using std::cout; using std::exception; +using std::sort; using boost::shared_ptr; using boost::dynamic_pointer_cast; using boost::optional; +using namespace dcpomatic; SwaroopControls::SwaroopControls (wxWindow* parent, shared_ptr viewer) : Controls (parent, viewer, false) @@ -97,9 +104,6 @@ SwaroopControls::SwaroopControls (wxWindow* parent, shared_ptr viewe _v_sizer->Add (e_sizer, 1, wxEXPAND); - _log = new wxTextCtrl (this, wxID_ANY, wxT(""), wxDefaultPosition, wxSize(-1, 200), wxTE_READONLY | wxTE_MULTILINE); - _v_sizer->Add (_log, 0, wxALL | wxEXPAND, DCPOMATIC_SIZER_GAP); - _play_button->Bind (wxEVT_BUTTON, boost::bind(&SwaroopControls::play_clicked, this)); _pause_button->Bind (wxEVT_BUTTON, boost::bind(&SwaroopControls::pause_clicked, this)); _stop_button->Bind (wxEVT_BUTTON, boost::bind(&SwaroopControls::stop_clicked, this)); @@ -114,13 +118,17 @@ SwaroopControls::SwaroopControls (wxWindow* parent, shared_ptr viewe _content_view->update (); update_playlist_directory (); + + _viewer->set_background_image (true); } void SwaroopControls::check_restart () { + cout << "check_restart called\n"; FILE* f = fopen_boost (Config::path("position"), "r"); if (!f) { + cout << "could not open position file (" << errno << ")\n"; return; } @@ -129,12 +137,15 @@ SwaroopControls::check_restart () int64_t time; fscanf (f, "%63s %d %ld", id, &index, &time); + cout << "Looking for playlist " << id << " to restart.\n"; + for (size_t i = 0; i < _playlists.size(); ++i) { if (_playlists[i].id() == id) { - _selected_playlist = i; - _selected_playlist_position = index; + cout << "Found playlist " << id << "\n"; + select_playlist (i, index); update_current_content (); _viewer->seek (DCPTime(time), false); + _viewer->start (); } } @@ -144,7 +155,8 @@ SwaroopControls::check_restart () void SwaroopControls::viewer_position_changed () { - if (!_selected_playlist || !_viewer->playing() || _viewer->position().get() % DCPTime::HZ) { + /* Write position every two minutes if we're playing */ + if (!_selected_playlist || !_viewer->playing() || _viewer->position().get() % (2 * 60 * DCPTime::HZ)) { return; } @@ -154,7 +166,11 @@ SwaroopControls::viewer_position_changed () + " " + dcp::raw_convert(_selected_playlist_position) + " " + dcp::raw_convert(_viewer->position().get()); - fwrite (p.c_str(), p.length(), 1, f); + checked_fwrite (p.c_str(), p.length(), f, Config::path("position")); +#ifdef DCPOMATIC_LINUX + fflush (f); + fsync (fileno(f)); +#endif fclose (f); } } @@ -165,8 +181,10 @@ SwaroopControls::started () Controls::started (); _play_button->Enable (false); _pause_button->Enable (true); + _viewer->set_background_image (false); } +/** Called when the viewer finishes a single piece of content, or it is explicitly stopped */ void SwaroopControls::stopped () { @@ -175,6 +193,29 @@ SwaroopControls::stopped () _pause_button->Enable (false); } +void +SwaroopControls::deselect_playlist () +{ + long int const selected = _spl_view->GetNextItem (-1, wxLIST_NEXT_ALL, wxLIST_STATE_SELECTED); + if (selected != -1) { + _selected_playlist = boost::none; + _spl_view->SetItemState (selected, 0, wxLIST_STATE_SELECTED); + } + ResetFilm (shared_ptr(new Film(optional()))); +} + +void +SwaroopControls::decrement_allowed_shows () +{ + if (_selected_playlist) { + SPL& spl = _playlists[*_selected_playlist]; + spl.decrement_allowed_shows(); + if (spl.path()) { + spl.write (*spl.path()); + } + } +} + void SwaroopControls::play_clicked () { @@ -206,6 +247,13 @@ SwaroopControls::stop_clicked () { _viewer->stop (); _viewer->seek (DCPTime(), true); + if (_selected_playlist) { + _selected_playlist_position = 0; + update_current_content (); + } + _viewer->set_background_image (true); + decrement_allowed_shows (); + deselect_playlist (); } bool @@ -245,6 +293,11 @@ SwaroopControls::next_clicked () void SwaroopControls::log (wxString s) { + optional log = Config::instance()->player_activity_log_file(); + if (!log) { + return; + } + struct timeval time; gettimeofday (&time, 0); char buffer[64]; @@ -252,7 +305,12 @@ SwaroopControls::log (wxString s) struct tm* t = localtime (&sec); strftime (buffer, 64, "%c", t); wxString ts = std_to_wx(string(buffer)) + N_(": "); - _log->SetValue(_log->GetValue() + ts + s + "\n"); + FILE* f = fopen_boost (*log, "a"); + if (!f) { + return; + } + fprintf (f, "%s%s\n", wx_to_std(ts).c_str(), wx_to_std(s).c_str()); + fclose (f); } void @@ -271,6 +329,13 @@ SwaroopControls::add_playlist_to_list (SPL spl) _spl_view->InsertItem (it); } +struct SPLComparator +{ + bool operator() (SPL const & a, SPL const & b) { + return a.name() < b.name(); + } +}; + void SwaroopControls::update_playlist_directory () { @@ -290,14 +355,85 @@ SwaroopControls::update_playlist_directory () SPL spl; spl.read (i->path(), _content_view); _playlists.push_back (spl); - add_playlist_to_list (spl); } } catch (exception& e) { /* Never mind */ } } + + sort (_playlists.begin(), _playlists.end(), SPLComparator()); + BOOST_FOREACH (SPL i, _playlists) { + add_playlist_to_list (i); + } + + _selected_playlist = boost::none; +} + +optional +SwaroopControls::get_kdm_from_url (shared_ptr dcp) +{ + ScopedTemporary temp; + string url = Config::instance()->kdm_server_url(); + boost::algorithm::replace_all (url, "{CPL}", *dcp->cpl()); + optional kdm; + if (dcp->cpl() && !get_from_url(url, false, false, temp)) { + try { + kdm = dcp::EncryptedKDM (dcp::file_to_string(temp.file())); + if (kdm->cpl_id() != dcp->cpl()) { + kdm = boost::none; + } + } catch (std::exception& e) { + /* Hey well */ + } + } + return kdm; +} + +optional +SwaroopControls::get_kdm_from_directory (shared_ptr dcp) +{ + using namespace boost::filesystem; + optional kdm_dir = Config::instance()->player_kdm_directory(); + if (!kdm_dir) { + return optional(); + } + for (directory_iterator i = directory_iterator(*kdm_dir); i != directory_iterator(); ++i) { + try { + if (file_size(i->path()) < MAX_KDM_SIZE) { + dcp::EncryptedKDM kdm (dcp::file_to_string(i->path())); + if (kdm.cpl_id() == dcp->cpl()) { + return kdm; + } + } + } catch (std::exception& e) { + /* Hey well */ + } + } + return optional(); } +optional +SwaroopControls::get_kdm_from_directory (shared_ptr ffmpeg) +{ + using namespace boost::filesystem; + optional kdm_dir = Config::instance()->player_kdm_directory(); + if (!kdm_dir) { + return optional(); + } + for (directory_iterator i = directory_iterator(*kdm_dir); i != directory_iterator(); ++i) { + try { + if (file_size(i->path()) < MAX_KDM_SIZE) { + EncryptedECinemaKDM kdm (dcp::file_to_string(i->path())); + if (kdm.id() == ffmpeg->id().get_value_or("")) { + return kdm; + } + } + } catch (std::exception& e) { + /* Hey well */ + } + } + return optional(); +} void SwaroopControls::spl_selection_changed () { @@ -310,8 +446,7 @@ SwaroopControls::spl_selection_changed () if (_playlists[selected].missing()) { error_dialog (this, "This playlist cannot be loaded as some content is missing."); - _selected_playlist = boost::none; - _spl_view->SetItemState (selected, 0, wxLIST_STATE_SELECTED); + deselect_playlist (); return; } @@ -320,6 +455,65 @@ SwaroopControls::spl_selection_changed () return; } + if (!_playlists[selected].have_allowed_shows()) { + error_dialog (this, "There are no more allowed shows of this playlist."); + return; + } + + select_playlist (selected, 0); +} + +void +SwaroopControls::select_playlist (int selected, int position) +{ + log (wxString::Format("load-playlist %s", std_to_wx(_playlists[selected].name()).data())); + + wxProgressDialog dialog (_("DCP-o-matic"), "Loading playlist and KDMs"); + + BOOST_FOREACH (SPLEntry const & i, _playlists[selected].get()) { + dialog.Pulse (); + shared_ptr dcp = dynamic_pointer_cast (i.content); + if (dcp && dcp->needs_kdm()) { + optional kdm; + kdm = get_kdm_from_url (dcp); + if (!kdm) { + kdm = get_kdm_from_directory (dcp); + } + if (kdm) { + try { + dcp->add_kdm (*kdm); + dcp->examine (_film, shared_ptr()); + } catch (KDMError& e) { + error_dialog (this, "Could not load KDM."); + } + } + if (dcp->needs_kdm()) { + /* We didn't get a KDM for this */ + error_dialog (this, "This playlist cannot be loaded as a KDM is missing or incorrect."); + deselect_playlist (); + return; + } + } + shared_ptr ffmpeg = dynamic_pointer_cast (i.content); + if (ffmpeg && ffmpeg->encrypted()) { + optional kdm = get_kdm_from_directory (ffmpeg); + if (kdm) { + try { + ffmpeg->add_kdm (*kdm); + ffmpeg->examine (_film, shared_ptr()); + } catch (KDMError& e) { + error_dialog (this, "This playlist cannot be loaded as a KDM is missing or incorrect."); + deselect_playlist (); + return; + } + } else { + error_dialog (this, "This playlist cannot be loaded as a KDM is missing or incorrect."); + deselect_playlist (); + return; + } + } + } + _current_spl_view->DeleteAllItems (); int N = 0; @@ -333,8 +527,10 @@ SwaroopControls::spl_selection_changed () } _selected_playlist = selected; - _selected_playlist_position = 0; + _selected_playlist_position = position; + dialog.Pulse (); reset_film (); + dialog.Pulse (); update_current_content (); } @@ -371,19 +567,18 @@ SwaroopControls::update_current_content () { DCPOMATIC_ASSERT (_selected_playlist); - bool const was_playing = _viewer->stop (); + wxProgressDialog dialog (_("DCP-o-matic"), "Loading content"); SPLEntry const & e = _playlists[*_selected_playlist].get()[_selected_playlist_position]; _current_disable_timeline = e.disable_timeline; _current_disable_next = !e.skippable; setup_sensitivity (); + dialog.Pulse (); reset_film (); - if (was_playing) { - _viewer->start (); - } } +/** One piece of content in our SPL has finished playing */ void SwaroopControls::viewer_finished () { @@ -391,5 +586,22 @@ SwaroopControls::viewer_finished () return; } - next_clicked (); + bool const stop = _playlists[*_selected_playlist].get()[_selected_playlist_position].stop_after_play; + + _selected_playlist_position++; + if (_selected_playlist_position < int(_playlists[*_selected_playlist].get().size())) { + /* Next piece of content on the SPL */ + update_current_content (); + if (!stop) { + _viewer->start (); + } + } else { + /* Finished the whole SPL */ + _selected_playlist_position = 0; + _viewer->set_background_image (true); + ResetFilm (shared_ptr(new Film(optional()))); + decrement_allowed_shows (); + _play_button->Enable (true); + _pause_button->Enable (false); + } }