#include "lib/job_manager.h"
#include "lib/job.h"
#include "lib/video_content.h"
-#include "lib/subtitle_content.h"
+#include "lib/text_content.h"
#include "lib/ratio.h"
#include "lib/verify_dcp_job.h"
#include "lib/dcp_examiner.h"
+#include "lib/examine_content_job.h"
+#include "lib/server.h"
+#include "lib/dcpomatic_socket.h"
#include "wx/wx_signal_manager.h"
#include "wx/wx_util.h"
#include "wx/about_dialog.h"
using std::exception;
using std::vector;
using boost::shared_ptr;
+using boost::scoped_array;
using boost::optional;
using boost::dynamic_pointer_cast;
+using boost::thread;
+using boost::bind;
enum {
ID_file_open = 1,
ID_file_close = 100,
ID_view_cpl,
/* Allow spare IDs for CPLs */
- ID_view_scale_appropriate = 200,
+ ID_view_closed_captions = 200,
+ ID_view_scale_appropriate,
ID_view_scale_full,
ID_view_scale_half,
ID_view_scale_quarter,
Bind (wxEVT_MENU, boost::bind (&DOMFrame::file_close, this), ID_file_close);
Bind (wxEVT_MENU, boost::bind (&DOMFrame::file_exit, this), wxID_EXIT);
Bind (wxEVT_MENU, boost::bind (&DOMFrame::edit_preferences, this), wxID_PREFERENCES);
+ Bind (wxEVT_MENU, boost::bind (&DOMFrame::view_closed_captions, this), ID_view_closed_captions);
Bind (wxEVT_MENU, boost::bind (&DOMFrame::view_cpl, this, _1), ID_view_cpl, ID_view_cpl + MAX_CPLS);
Bind (wxEVT_MENU, boost::bind (&DOMFrame::set_decode_reduction, this, optional<int>(0)), ID_view_scale_full);
Bind (wxEVT_MENU, boost::bind (&DOMFrame::set_decode_reduction, this, optional<int>(1)), ID_view_scale_half);
}
_film->examine_and_add_content (dcp, true);
-
- JobManager* jm = JobManager::instance ();
-
- wxProgressDialog* progress = new wxProgressDialog (_("DCP-o-matic Player"), _("Loading DCP"));
-
- while (jm->work_to_do() || signal_manager->ui_idle()) {
- dcpomatic_sleep (1);
- progress->Pulse ();
- }
-
- progress->Destroy ();
-
- DCPOMATIC_ASSERT (!jm->get().empty());
-
- shared_ptr<Job> last = jm->get().back();
- if (last->finished_in_error()) {
- error_dialog(this, std_to_wx(last->error_summary()) + ".\n", std_to_wx(last->error_details()));
+ bool const ok = progress (_("Loading DCP"));
+ if (!ok || !report_errors_from_last_job()) {
return;
}
- if (dcp->subtitle) {
- dcp->subtitle->set_use (true);
- }
+ setup_from_dcp (dcp);
if (dcp->three_d()) {
_film->set_three_d (true);
}
- Ratio const * r = Ratio::nearest_from_ratio(dcp->video->size().ratio());
- if (r) {
- _film->set_container(r);
- }
-
_viewer->set_film (_film);
_viewer->set_position (DCPTime ());
_info->triggered_update ();
DCPExaminer ex (dcp);
int id = ID_view_cpl;
BOOST_FOREACH (shared_ptr<dcp::CPL> i, ex.cpls()) {
- wxMenuItem* j = _cpl_menu->AppendRadioItem(id, i->id());
- if (!dcp->cpl() || i->id() == *dcp->cpl()) {
- j->Check(true);
- }
+ wxMenuItem* j = _cpl_menu->AppendRadioItem(
+ id,
+ wxString::Format("%s (%s)", std_to_wx(i->annotation_text()).data(), std_to_wx(i->id()).data())
+ );
+ j->Check(!dcp->cpl() || i->id() == *dcp->cpl());
++id;
}
}
wxMenu* view = new wxMenu;
optional<int> c = Config::instance()->decode_reduction();
_view_cpl = view->Append(ID_view_cpl, _("CPL"), _cpl_menu);
+ view->Append(ID_view_closed_captions, _("Closed captions..."));
view->AppendSeparator();
view->AppendRadioItem(ID_view_scale_appropriate, _("Set decode resolution to match display"))->Check(!static_cast<bool>(c));
view->AppendRadioItem(ID_view_scale_full, _("Decode at full resolution"))->Check(c && c.get() == 0);
shared_ptr<DCPContent> dcp = boost::dynamic_pointer_cast<DCPContent>(_film->content().front());
DCPOMATIC_ASSERT (dcp);
dcp->add_ov (wx_to_std(c->GetPath()));
- dcp->examine (shared_ptr<Job>());
- /* Maybe we just gained some subtitles */
- if (dcp->subtitle) {
- dcp->subtitle->set_use (true);
+ JobManager::instance()->add(shared_ptr<Job>(new ExamineContentJob (_film, dcp)));
+ bool const ok = progress (_("Loading DCP"));
+ if (!ok || !report_errors_from_last_job()) {
+ return;
}
+ setup_from_dcp (dcp);
}
c->Destroy ();
dcp->examine (shared_ptr<Job>());
}
+ void view_closed_captions ()
+ {
+ _viewer->show_closed_captions ();
+ }
+
void tools_verify ()
{
shared_ptr<DCPContent> dcp = boost::dynamic_pointer_cast<DCPContent>(_film->content().front());
JobManager* jm = JobManager::instance ();
jm->add (shared_ptr<Job> (new VerifyDCPJob (dcp->directories())));
-
- wxProgressDialog* progress = new wxProgressDialog (_("DCP-o-matic Player"), _("Verifying DCP"));
-
- while (jm->work_to_do() || signal_manager->ui_idle()) {
- dcpomatic_sleep (1);
- progress->Pulse ();
+ bool const ok = progress (_("Verifying DCP"));
+ if (!ok) {
+ return;
}
- progress->Destroy ();
-
DCPOMATIC_ASSERT (!jm->get().empty());
shared_ptr<VerifyDCPJob> last = dynamic_pointer_cast<VerifyDCPJob> (jm->get().back());
DCPOMATIC_ASSERT (last);
_viewer->forward_frame ();
}
+private:
+
+ /** @return false if the task was cancelled */
+ bool progress (wxString task)
+ {
+ JobManager* jm = JobManager::instance ();
+
+ wxProgressDialog* progress = new wxProgressDialog (_("DCP-o-matic Player"), task, 100, 0, wxPD_CAN_ABORT);
+
+ bool ok = true;
+
+ while (jm->work_to_do() || signal_manager->ui_idle()) {
+ dcpomatic_sleep (1);
+ if (!progress->Pulse()) {
+ /* user pressed cancel */
+ BOOST_FOREACH (shared_ptr<Job> i, jm->get()) {
+ i->cancel();
+ }
+ ok = false;
+ break;
+ }
+ }
+
+ progress->Destroy ();
+ return ok;
+ }
+
+ bool report_errors_from_last_job ()
+ {
+ JobManager* jm = JobManager::instance ();
+
+ DCPOMATIC_ASSERT (!jm->get().empty());
+
+ shared_ptr<Job> last = jm->get().back();
+ if (last->finished_in_error()) {
+ error_dialog(this, std_to_wx(last->error_summary()) + ".\n", std_to_wx(last->error_details()));
+ return false;
+ }
+
+ return true;
+ }
+
+ void setup_from_dcp (shared_ptr<DCPContent> dcp)
+ {
+ BOOST_FOREACH (shared_ptr<TextContent> i, dcp->text) {
+ i->set_use (true);
+ }
+
+ if (dcp->video) {
+ Ratio const * r = Ratio::nearest_from_ratio(dcp->video->size().ratio());
+ if (r) {
+ _film->set_container(r);
+ }
+ }
+ }
+
bool _update_news_requested;
PlayerInformation* _info;
wxPreferencesEditor* _config_dialog;
{ wxCMD_LINE_NONE, "", "", "", wxCmdLineParamType (0), 0 }
};
+class PlayServer : public Server
+{
+public:
+ explicit PlayServer (DOMFrame* frame)
+ : Server (PLAYER_PLAY_PORT)
+ , _frame (frame)
+ {}
+
+ void handle (shared_ptr<Socket> socket)
+ {
+ try {
+ int const length = socket->read_uint32 ();
+ scoped_array<char> buffer (new char[length]);
+ socket->read (reinterpret_cast<uint8_t*> (buffer.get()), length);
+ string s (buffer.get());
+ signal_manager->when_idle (bind (&DOMFrame::load_dcp, _frame, s));
+ socket->write (reinterpret_cast<uint8_t const *> ("OK"), 3);
+ } catch (...) {
+
+ }
+ }
+
+private:
+ DOMFrame* _frame;
+};
+
/** @class App
* @brief The magic App class for wxWidgets.
*/
signal_manager = new wxSignalManager (this);
+ PlayServer* server = new PlayServer (_frame);
+ new thread (boost::bind (&PlayServer::run, server));
+
if (!_dcp_to_load.empty() && boost::filesystem::is_directory (_dcp_to_load)) {
try {
_frame->load_dcp (_dcp_to_load);