summaryrefslogtreecommitdiff
path: root/src/lib
diff options
context:
space:
mode:
authorCarl Hetherington <cth@carlh.net>2018-10-09 19:19:45 +0100
committerCarl Hetherington <cth@carlh.net>2018-10-09 20:11:33 +0100
commit2eab969654eca2ef4b222790c8b730a6eb709565 (patch)
treebe8b463ce2c56692275e550fd419b7bce707d414 /src/lib
parentbc5b4d4dc178dad75eacb02fd2d4e98c7d3801ec (diff)
swaroop: required monitors checks.
Diffstat (limited to 'src/lib')
-rw-r--r--src/lib/config.cc6
-rw-r--r--src/lib/config.h10
-rw-r--r--src/lib/edid.cc131
-rw-r--r--src/lib/edid.h50
-rw-r--r--src/lib/monitor_checker.cc102
-rw-r--r--src/lib/monitor_checker.h45
-rw-r--r--src/lib/wscript2
7 files changed, 346 insertions, 0 deletions
diff --git a/src/lib/config.cc b/src/lib/config.cc
index 6e06f78e4..1d83f0a25 100644
--- a/src/lib/config.cc
+++ b/src/lib/config.cc
@@ -522,6 +522,9 @@ try
_player_watermark_theatre = f.optional_string_child("PlayerWatermarkTheatre").get_value_or("");
_player_watermark_period = f.optional_number_child<int>("PlayerWatermarkPeriod").get_value_or(1);
_player_watermark_duration = f.optional_number_child<int>("PlayerWatermarkDuration").get_value_or(150);
+ BOOST_FOREACH (cxml::ConstNodePtr i, f.node_children("RequiredMonitor")) {
+ _required_monitors.push_back(Monitor(i));
+ }
#endif
/* Replace any cinemas from config.xml with those from the configured file */
@@ -928,6 +931,9 @@ Config::write_config () const
root->add_child("PlayerWatermarkTheatre")->add_child_text(_player_watermark_theatre);
root->add_child("PlayerWatermarkPeriod")->add_child_text(raw_convert<string>(_player_watermark_period));
root->add_child("PlayerWatermarkDuration")->add_child_text(raw_convert<string>(_player_watermark_duration));
+ BOOST_FOREACH (Monitor i, _required_monitors) {
+ i.as_xml(root->add_child("RequiredMonitor"));
+ }
#endif
try {
diff --git a/src/lib/config.h b/src/lib/config.h
index 629828da9..a470bf391 100644
--- a/src/lib/config.h
+++ b/src/lib/config.h
@@ -27,6 +27,7 @@
#include "isdcf_metadata.h"
#include "types.h"
+#include "edid.h"
#include <dcp/name_format.h>
#include <dcp/certificate_chain.h>
#include <dcp/encrypted_kdm.h>
@@ -513,6 +514,10 @@ public:
int player_watermark_duration () const {
return _player_watermark_duration;
}
+
+ std::vector<Monitor> required_monitors () const {
+ return _required_monitors;
+ }
#endif
/* SET (mostly) */
@@ -989,6 +994,10 @@ public:
void set_player_watermark_duration (int milliseconds) {
maybe_set (_player_watermark_duration, milliseconds);
}
+
+ void set_required_monitors (std::vector<Monitor> monitors) {
+ maybe_set (_required_monitors, monitors);
+ }
#endif
void changed (Property p = OTHER);
@@ -1192,6 +1201,7 @@ private:
int _player_watermark_period;
/** watermark duration in milliseconds */
int _player_watermark_duration;
+ std::vector<Monitor> _required_monitors;
#endif
static int const _current_version;
diff --git a/src/lib/edid.cc b/src/lib/edid.cc
new file mode 100644
index 000000000..3df65d325
--- /dev/null
+++ b/src/lib/edid.cc
@@ -0,0 +1,131 @@
+/*
+ Copyright (C) 2018 Carl Hetherington <cth@carlh.net>
+
+ 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 <http://www.gnu.org/licenses/>.
+
+*/
+
+#include "compose.hpp"
+#include "edid.h"
+#include <dcp/raw_convert.h>
+#include <libxml++/libxml++.h>
+#include <boost/filesystem.hpp>
+#include <boost/algorithm/string.hpp>
+#include <iostream>
+
+#define EDID_SYS_PATH "/sys/class/drm"
+static uint8_t const edid_header[] = { 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00 };
+
+using std::vector;
+using std::string;
+using std::cout;
+
+vector<Monitor>
+get_monitors()
+{
+ using namespace boost::filesystem;
+ using namespace boost::algorithm;
+
+ vector<Monitor> monitors;
+
+ int card = 0;
+ while (true) {
+ path card_dir = String::compose("%1/card%2", EDID_SYS_PATH, card);
+ if (!is_directory(card_dir)) {
+ break;
+ }
+
+ for (directory_iterator i = directory_iterator(card_dir); i != directory_iterator(); ++i) {
+ if (!starts_with(i->path().filename().string(), String::compose("card%1", card))) {
+ continue;
+ }
+
+ FILE* edid_file = fopen(path(i->path() / "edid").string().c_str(), "r");
+ if (!edid_file) {
+ continue;
+ }
+
+ uint8_t edid[128];
+ int const N = fread(edid, 1, sizeof(edid), edid_file);
+ fclose(edid_file);
+ if (N != 128) {
+ continue;
+ }
+
+ if (memcmp(edid, edid_header, 8) != 0) {
+ continue;
+ }
+
+ Monitor mon;
+
+ uint16_t mid = (edid[8] << 8) | edid[9];
+ mon.manufacturer_id += char(((mid >> 10) & 0x1f) + 'A' - 1);
+ mon.manufacturer_id += char(((mid >> 5) & 0x1f) + 'A' - 1);
+ mon.manufacturer_id += char(((mid >> 0) & 0x1f) + 'A' - 1);
+
+ mon.manufacturer_product_code = (edid[11] << 8) | edid[10];
+
+ mon.serial_number = (edid[15] << 24) | (edid[14] << 16) | (edid[13] << 8) | edid[12];
+ mon.week_of_manufacture = edid[16];
+ mon.year_of_manufacture = edid[17];
+ monitors.push_back (mon);
+ }
+
+ ++card;
+ }
+
+ return monitors;
+}
+
+Monitor::Monitor ()
+ : manufacturer_product_code (0)
+ , serial_number (0)
+ , week_of_manufacture (0)
+ , year_of_manufacture (0)
+{
+
+}
+
+Monitor::Monitor (cxml::ConstNodePtr node)
+ : manufacturer_id(node->string_child("ManufacturerId"))
+ , manufacturer_product_code(node->number_child<uint32_t>("ManufacturerProductCode"))
+ , serial_number(node->number_child<uint32_t>("SerialNumber"))
+ , week_of_manufacture(node->number_child<int>("WeekOfManufacture"))
+ , year_of_manufacture(node->number_child<int>("YearOfManufacture"))
+
+{
+
+}
+
+void
+Monitor::as_xml (xmlpp::Node* parent) const
+{
+ parent->add_child("ManufacturerId")->add_child_text(manufacturer_id);
+ parent->add_child("ManufacturerProductCode")->add_child_text(dcp::raw_convert<string>(manufacturer_product_code));
+ parent->add_child("SerialNumber")->add_child_text(dcp::raw_convert<string>(serial_number));
+ parent->add_child("WeekOfManufacture")->add_child_text(dcp::raw_convert<string>(week_of_manufacture));
+ parent->add_child("YearOfManufacture")->add_child_text(dcp::raw_convert<string>(year_of_manufacture));
+}
+
+bool
+operator== (Monitor const & a, Monitor const & b)
+{
+ return a.manufacturer_id == b.manufacturer_id &&
+ a.manufacturer_product_code == b.manufacturer_product_code &&
+ a.serial_number == b.serial_number &&
+ a.week_of_manufacture == b.week_of_manufacture &&
+ a.year_of_manufacture == b.year_of_manufacture;
+}
diff --git a/src/lib/edid.h b/src/lib/edid.h
new file mode 100644
index 000000000..e29c77cdc
--- /dev/null
+++ b/src/lib/edid.h
@@ -0,0 +1,50 @@
+/*
+ Copyright (C) 2018 Carl Hetherington <cth@carlh.net>
+
+ 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 <http://www.gnu.org/licenses/>.
+
+*/
+
+#ifndef DCPOMATIC_EDID_H
+#define DCPOMATIC_EDID_H
+
+#include <libcxml/cxml.h>
+#include <vector>
+#include <string>
+
+namespace xmlpp {
+ class Node;
+}
+
+class Monitor
+{
+public:
+ Monitor ();
+ Monitor (cxml::ConstNodePtr node);
+ void as_xml (xmlpp::Node* parent) const;
+
+ std::string manufacturer_id;
+ uint16_t manufacturer_product_code;
+ uint32_t serial_number;
+ uint8_t week_of_manufacture;
+ uint8_t year_of_manufacture;
+};
+
+bool operator== (Monitor const & a, Monitor const & b);
+
+extern std::vector<Monitor> get_monitors();
+
+#endif
diff --git a/src/lib/monitor_checker.cc b/src/lib/monitor_checker.cc
new file mode 100644
index 000000000..c506cd09e
--- /dev/null
+++ b/src/lib/monitor_checker.cc
@@ -0,0 +1,102 @@
+/*
+ Copyright (C) 2018 Carl Hetherington <cth@carlh.net>
+
+ 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 <http://www.gnu.org/licenses/>.
+
+*/
+
+#include "monitor_checker.h"
+#include "config.h"
+#include "cross.h"
+
+using boost::bind;
+using boost::ref;
+
+MonitorChecker* MonitorChecker::_instance = 0;
+
+MonitorChecker::MonitorChecker ()
+ : _thread (0)
+ , _terminate (false)
+ , _ok (true)
+{
+
+}
+
+void
+MonitorChecker::run ()
+{
+ _thread = new boost::thread (boost::bind (&MonitorChecker::thread, this));
+}
+
+MonitorChecker::~MonitorChecker ()
+{
+ {
+ boost::mutex::scoped_lock lm (_mutex);
+ _terminate = true;
+ }
+
+ if (_thread) {
+ /* Ideally this would be a DCPOMATIC_ASSERT(_thread->joinable()) but we
+ can't throw exceptions from a destructor.
+ */
+ _thread->interrupt ();
+ try {
+ if (_thread->joinable ()) {
+ _thread->join ();
+ }
+ } catch (boost::thread_interrupted& e) {
+ /* No problem */
+ }
+ }
+ delete _thread;
+}
+
+void
+MonitorChecker::thread ()
+{
+ while (true) {
+ boost::mutex::scoped_lock lm (_mutex);
+ if (_terminate) {
+ break;
+ }
+
+ bool const was_ok = _ok;
+ _ok = Config::instance()->required_monitors().empty() || get_monitors() == Config::instance()->required_monitors();
+ if (was_ok != _ok) {
+ emit (bind(boost::ref(StateChanged)));
+ }
+
+ lm.unlock ();
+ dcpomatic_sleep (60);
+ }
+}
+
+bool
+MonitorChecker::ok () const
+{
+ boost::mutex::scoped_lock lm (_mutex);
+ return _ok;
+}
+
+MonitorChecker *
+MonitorChecker::instance ()
+{
+ if (!_instance) {
+ _instance = new MonitorChecker ();
+ }
+
+ return _instance;
+}
diff --git a/src/lib/monitor_checker.h b/src/lib/monitor_checker.h
new file mode 100644
index 000000000..4f856f41f
--- /dev/null
+++ b/src/lib/monitor_checker.h
@@ -0,0 +1,45 @@
+/*
+ Copyright (C) 2018 Carl Hetherington <cth@carlh.net>
+
+ 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 <http://www.gnu.org/licenses/>.
+
+*/
+
+#include "signaller.h"
+#include <boost/signals2.hpp>
+
+class MonitorChecker : public Signaller, public boost::noncopyable
+{
+public:
+ ~MonitorChecker ();
+
+ void run ();
+
+ bool ok () const;
+ boost::signals2::signal<void (void)> StateChanged;
+
+ static MonitorChecker* instance ();
+private:
+ static MonitorChecker* _instance;
+
+ MonitorChecker ();
+ void thread ();
+
+ boost::thread* _thread;
+ mutable boost::mutex _mutex;
+ bool _terminate;
+ bool _ok;
+};
diff --git a/src/lib/wscript b/src/lib/wscript
index 609ddb322..5e5a86884 100644
--- a/src/lib/wscript
+++ b/src/lib/wscript
@@ -70,6 +70,7 @@ sources = """
digester.cc
dkdm_wrapper.cc
dolby_cp750.cc
+ edid.cc
emailer.cc
empty.cc
encoder.cc
@@ -115,6 +116,7 @@ sources = """
log_entry.cc
magick_image_proxy.cc
mid_side_decoder.cc
+ monitor_checker.cc
overlaps.cc
player.cc
player_text.cc