X-Git-Url: https://main.carlh.net/gitweb/?a=blobdiff_plain;f=src%2Fwx%2Fswaroop_controls.cc;h=abf6fc58c87d1be095ed0b683a1ba0252c809cf6;hb=1e62cf13bc31aa9c13fcc6c2738a6012e3e7ce99;hp=2f51fed3f3833d840005f2120fb2159f351d4f19;hpb=29436ead35fbb6041fd24115623cad7638693d8e;p=dcpomatic.git diff --git a/src/wx/swaroop_controls.cc b/src/wx/swaroop_controls.cc index 2f51fed3f..abf6fc58c 100644 --- a/src/wx/swaroop_controls.cc +++ b/src/wx/swaroop_controls.cc @@ -26,12 +26,18 @@ #include "static_text.h" #include "lib/player_video.h" #include "lib/dcp_content.h" +#include "lib/cross.h" +#include "lib/scoped_temporary.h" +#include "lib/internet.h" +#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; @@ -41,11 +47,16 @@ SwaroopControls::SwaroopControls (wxWindow* parent, shared_ptr viewe , _play_button (new Button(this, _("Play"))) , _pause_button (new Button(this, _("Pause"))) , _stop_button (new Button(this, _("Stop"))) + , _next_button (new Button(this, "Next")) + , _previous_button (new Button(this, "Previous")) , _current_disable_timeline (false) + , _current_disable_next (false) { + _button_sizer->Add (_previous_button, 0, wxEXPAND); _button_sizer->Add (_play_button, 0, wxEXPAND); _button_sizer->Add (_pause_button, 0, wxEXPAND); _button_sizer->Add (_stop_button, 0, wxEXPAND); + _button_sizer->Add (_next_button, 0, wxEXPAND); _spl_view = new wxListCtrl (this, wxID_ANY, wxDefaultPosition, wxDefaultSize, wxLC_REPORT | wxLC_NO_HEADER); _spl_view->AppendColumn (wxT(""), wxLIST_FORMAT_LEFT, 740); @@ -85,7 +96,7 @@ SwaroopControls::SwaroopControls (wxWindow* parent, shared_ptr viewe _current_spl_view = new wxListCtrl (this, wxID_ANY, wxDefaultPosition, wxDefaultSize, wxLC_REPORT | wxLC_NO_HEADER); _current_spl_view->AppendColumn (wxT(""), wxLIST_FORMAT_LEFT, 500); _current_spl_view->AppendColumn (wxT(""), wxLIST_FORMAT_LEFT, 80); - e_sizer->Add (left_sizer, 0, wxALL | wxEXPAND, DCPOMATIC_SIZER_GAP); + e_sizer->Add (left_sizer, 1, wxALL | wxEXPAND, DCPOMATIC_SIZER_GAP); e_sizer->Add (_current_spl_view, 1, wxALL | wxEXPAND, DCPOMATIC_SIZER_GAP); _v_sizer->Add (e_sizer, 1, wxEXPAND); @@ -93,17 +104,68 @@ SwaroopControls::SwaroopControls (wxWindow* parent, shared_ptr viewe _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)); - _spl_view->Bind (wxEVT_LIST_ITEM_SELECTED, boost::bind(&SwaroopControls::spl_selection_changed, this)); - _spl_view->Bind (wxEVT_LIST_ITEM_DESELECTED, boost::bind(&SwaroopControls::spl_selection_changed, this)); - _viewer->ImageChanged.connect (boost::bind(&SwaroopControls::image_changed, this, _1)); + _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)); + _next_button->Bind (wxEVT_BUTTON, boost::bind(&SwaroopControls::next_clicked, this)); + _previous_button->Bind (wxEVT_BUTTON, boost::bind(&SwaroopControls::previous_clicked, this)); + _spl_view->Bind (wxEVT_LIST_ITEM_SELECTED, boost::bind(&SwaroopControls::spl_selection_changed, this)); + _spl_view->Bind (wxEVT_LIST_ITEM_DESELECTED, boost::bind(&SwaroopControls::spl_selection_changed, this)); + _viewer->Finished.connect (boost::bind(&SwaroopControls::viewer_finished, this)); + _viewer->PositionChanged.connect (boost::bind(&SwaroopControls::viewer_position_changed, this)); _refresh_spl_view->Bind (wxEVT_BUTTON, boost::bind(&SwaroopControls::update_playlist_directory, this)); _refresh_content_view->Bind (wxEVT_BUTTON, boost::bind(&ContentView::update, _content_view)); _content_view->update (); update_playlist_directory (); + + _viewer->set_background_image (true); +} + +void +SwaroopControls::check_restart () +{ + FILE* f = fopen_boost (Config::path("position"), "r"); + if (!f) { + return; + } + + char id[64]; + int index; + int64_t time; + fscanf (f, "%63s %d %ld", id, &index, &time); + + for (size_t i = 0; i < _playlists.size(); ++i) { + if (_playlists[i].id() == id) { + select_playlist (i, index); + update_current_content (); + _viewer->seek (DCPTime(time), false); + _viewer->start (); + } + } + + fclose (f); +} + +void +SwaroopControls::viewer_position_changed () +{ + if (!_selected_playlist || !_viewer->playing() || _viewer->position().get() % DCPTime::HZ) { + return; + } + + FILE* f = fopen_boost (Config::path("position"), "w"); + if (f) { + string const p = _playlists[*_selected_playlist].id() + + " " + dcp::raw_convert(_selected_playlist_position) + + " " + dcp::raw_convert(_viewer->position().get()); + + checked_fwrite (p.c_str(), p.length(), f, Config::path("position")); +#ifdef DCPOMATIC_LINUX + fsync (fileno(f)); +#endif + fclose (f); + } } void @@ -112,6 +174,7 @@ SwaroopControls::started () Controls::started (); _play_button->Enable (false); _pause_button->Enable (true); + _viewer->set_background_image (false); } void @@ -135,10 +198,11 @@ SwaroopControls::setup_sensitivity () bool const active_job = _active_job && *_active_job != "examine_content"; bool const c = _film && !_film->content().empty() && !active_job; _play_button->Enable (c && !_viewer->playing()); - _pause_button->Enable (c && (!_current_kind || _current_kind != dcp::ADVERTISEMENT) && _viewer->playing()); - _stop_button->Enable (c && (!_current_kind || _current_kind != dcp::ADVERTISEMENT)); - _slider->Enable (c && (!_current_kind || _current_kind != dcp::ADVERTISEMENT) && !_current_disable_timeline); + _pause_button->Enable (_viewer->playing()); + _slider->Enable (!_current_disable_timeline); _spl_view->Enable (!_viewer->playing()); + _next_button->Enable (!_current_disable_next && can_do_next()); + _previous_button->Enable (can_do_previous()); } void @@ -152,58 +216,67 @@ SwaroopControls::stop_clicked () { _viewer->stop (); _viewer->seek (DCPTime(), true); + if (_selected_playlist) { + _selected_playlist_position = 0; + update_current_content (); + } + _viewer->set_background_image (true); } -void -SwaroopControls::log (wxString s) +bool +SwaroopControls::can_do_previous () { - struct timeval time; - gettimeofday (&time, 0); - char buffer[64]; - time_t const sec = time.tv_sec; - 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"); + return _selected_playlist && (_selected_playlist_position - 1) >= 0; } void -SwaroopControls::image_changed (boost::weak_ptr weak_pv) +SwaroopControls::previous_clicked () { - shared_ptr pv = weak_pv.lock (); - if (!pv) { + if (!can_do_previous ()) { return; } - shared_ptr c = pv->content().lock(); - if (!c) { - return; - } + _selected_playlist_position--; + update_current_content (); +} + +bool +SwaroopControls::can_do_next () +{ + return _selected_playlist && (_selected_playlist_position + 1) < int(_playlists[*_selected_playlist].get().size()); +} - if (c == _current_content.lock()) { +void +SwaroopControls::next_clicked () +{ + if (!can_do_next ()) { return; } - _current_content = c; + _selected_playlist_position++; + update_current_content (); +} - if (_selected_playlist) { - BOOST_FOREACH (SPLEntry i, _playlists[*_selected_playlist].get()) { - if (i.content == c) { - _current_disable_timeline = i.disable_timeline; - setup_sensitivity (); - } - } - } +void +SwaroopControls::log (wxString s) +{ + struct timeval time; + gettimeofday (&time, 0); + char buffer[64]; + time_t const sec = time.tv_sec; + 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"); - shared_ptr dc = dynamic_pointer_cast (c); - if (!dc) { + optional log = Config::instance()->player_log_file(); + if (!log) { return; } - if (!_current_kind || *_current_kind != dc->content_kind()) { - _current_kind = dc->content_kind (); - setup_sensitivity (); - } + FILE* f = fopen_boost (*log, "a"); + fprintf (f, "%s%s\n", wx_to_std(ts).c_str(), wx_to_std(s).c_str()); + fclose (f); } void @@ -214,10 +287,21 @@ SwaroopControls::add_playlist_to_list (SPL spl) wxListItem it; it.SetId(N); it.SetColumn(0); - it.SetText (std_to_wx(spl.name())); + string t = spl.name(); + if (spl.missing()) { + t += " (content missing)"; + } + it.SetText (std_to_wx(t)); _spl_view->InsertItem (it); } +struct SPLComparator +{ + bool operator() (SPL const & a, SPL const & b) { + return a.name() < b.name(); + } +}; + void SwaroopControls::update_playlist_directory () { @@ -237,28 +321,123 @@ 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, 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(); } void SwaroopControls::spl_selection_changed () { - _current_spl_view->DeleteAllItems (); - long int selected = _spl_view->GetNextItem (-1, wxLIST_NEXT_ALL, wxLIST_STATE_SELECTED); if (selected == -1) { + _current_spl_view->DeleteAllItems (); _selected_playlist = boost::none; return; } - wxProgressDialog progress (_("DCP-o-matic"), _("Loading playlist")); + 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); + return; + } - shared_ptr film (new Film(optional())); + if (_playlists[selected].get().empty()) { + error_dialog (this, "This playlist is empty."); + 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."); + _selected_playlist = boost::none; + _spl_view->SetItemState (selected, 0, wxLIST_STATE_SELECTED); + return; + } + } + } + + _current_spl_view->DeleteAllItems (); int N = 0; BOOST_FOREACH (SPLEntry i, _playlists[selected].get()) { @@ -267,15 +446,23 @@ SwaroopControls::spl_selection_changed () it.SetColumn (0); it.SetText (std_to_wx(i.name)); _current_spl_view->InsertItem (it); - film->add_content (i.content); ++N; - if (!progress.Pulse()) { - /* user pressed cancel */ - return; - } } _selected_playlist = selected; + _selected_playlist_position = position; + dialog.Pulse (); + reset_film (); + dialog.Pulse (); + update_current_content (); +} + +void +SwaroopControls::reset_film () +{ + DCPOMATIC_ASSERT (_selected_playlist); + shared_ptr film (new Film(optional())); + film->add_content (_playlists[*_selected_playlist].get()[_selected_playlist_position].content); ResetFilm (film); } @@ -297,3 +484,41 @@ SwaroopControls::set_film (shared_ptr film) Controls::set_film (film); setup_sensitivity (); } + +void +SwaroopControls::update_current_content () +{ + DCPOMATIC_ASSERT (_selected_playlist); + + 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 (); +} + +void +SwaroopControls::viewer_finished () +{ + if (!_selected_playlist) { + return; + } + + 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())) { + update_current_content (); + if (!stop) { + _viewer->start (); + } + } else { + _selected_playlist_position = 0; + _viewer->set_background_image (true); + ResetFilm (shared_ptr(new Film(optional()))); + } +}