40 #include "compose.hpp"
46 LIBDCP_DISABLE_WARNINGS
47 #include <libxml++/libxml++.h>
48 LIBDCP_ENABLE_WARNINGS
49 #include <boost/algorithm/string.hpp>
61 using namespace boost;
66 return (a.width == b.width && a.height == b.height);
82 split (b, s, is_any_of (
" "));
84 boost::throw_exception (
XMLError(
"malformed fraction " + s +
" in XML node"));
86 numerator = raw_convert<int> (b[0]);
87 denominator = raw_convert<int> (b[1]);
92 Fraction::as_string ()
const
94 return String::compose (
"%1 %2", numerator, denominator);
101 return (a.numerator == b.numerator && a.denominator == b.denominator);
108 return (a.numerator != b.numerator || a.denominator != b.denominator);
130 if (sscanf (argb_hex.c_str(),
"%2x%2x%2x%2x", &alpha, &
r, &
g, &
b) != 4) {
131 boost::throw_exception (
XMLError (
"could not parse colour string"));
140 snprintf (buffer,
sizeof(buffer),
"FF%02X%02X%02X",
r,
g,
b);
149 snprintf (buffer,
sizeof(buffer),
"%02X%02X%02X",
r,
g,
b);
157 return (a.
r == b.
r && a.
g == b.
g && a.
b == b.
b);
169 dcp::effect_to_string (Effect e)
180 boost::throw_exception (
MiscError(
"unknown effect type"));
185 dcp::string_to_effect (
string s)
189 }
else if (s ==
"border") {
190 return Effect::BORDER;
191 }
else if (s ==
"shadow") {
192 return Effect::SHADOW;
195 boost::throw_exception (
ReadError(
"unknown subtitle effect type"));
200 dcp::halign_to_string (
HAlign h)
211 boost::throw_exception (
MiscError(
"unknown subtitle halign type"));
216 dcp::string_to_halign (
string s)
220 }
else if (s ==
"center") {
222 }
else if (s ==
"right") {
226 boost::throw_exception (
ReadError(
"unknown subtitle halign type"));
231 dcp::valign_to_string (
VAlign v)
242 boost::throw_exception (
MiscError(
"unknown subtitle valign type"));
247 dcp::string_to_valign (
string s)
251 }
else if (s ==
"center") {
253 }
else if (s ==
"bottom") {
257 boost::throw_exception (
ReadError(
"unknown subtitle valign type"));
275 boost::throw_exception (
MiscError(
"unknown subtitle direction type"));
280 dcp::string_to_direction (
string s)
282 if (s ==
"ltr" || s ==
"horizontal") {
284 }
else if (s ==
"rtl") {
286 }
else if (s ==
"ttb" || s ==
"vertical") {
288 }
else if (s ==
"btt") {
292 boost::throw_exception (
ReadError(
"unknown subtitle direction type"));
305 case ContentKind::FEATURE:
307 case ContentKind::SHORT:
309 case ContentKind::TRAILER:
311 case ContentKind::TEST:
313 case ContentKind::TRANSITIONAL:
314 return "transitional";
315 case ContentKind::RATING:
317 case ContentKind::TEASER:
319 case ContentKind::POLICY:
321 case ContentKind::PUBLIC_SERVICE_ANNOUNCEMENT:
323 case ContentKind::ADVERTISEMENT:
324 return "advertisement";
325 case ContentKind::EPISODE:
327 case ContentKind::PROMO:
343 transform (kind.begin(), kind.end(), kind.begin(), ::tolower);
345 if (kind ==
"feature") {
346 return ContentKind::FEATURE;
347 }
else if (kind ==
"short") {
348 return ContentKind::SHORT;
349 }
else if (kind ==
"trailer") {
350 return ContentKind::TRAILER;
351 }
else if (kind ==
"test") {
352 return ContentKind::TEST;
353 }
else if (kind ==
"transitional") {
354 return ContentKind::TRANSITIONAL;
355 }
else if (kind ==
"rating") {
356 return ContentKind::RATING;
357 }
else if (kind ==
"teaser") {
358 return ContentKind::TEASER;
359 }
else if (kind ==
"policy") {
360 return ContentKind::POLICY;
361 }
else if (kind ==
"psa") {
362 return ContentKind::PUBLIC_SERVICE_ANNOUNCEMENT;
363 }
else if (kind ==
"advertisement") {
364 return ContentKind::ADVERTISEMENT;
365 }
else if (kind ==
"episode") {
366 return ContentKind::EPISODE;
367 }
else if (kind ==
"promo") {
368 return ContentKind::PROMO;
406 dcp::marker_from_string (
string s)
410 }
else if (s ==
"LFOC") {
412 }
else if (s ==
"FFTC") {
414 }
else if (s ==
"LFTC") {
416 }
else if (s ==
"FFOI") {
418 }
else if (s ==
"LFOI") {
420 }
else if (s ==
"FFEC") {
422 }
else if (s ==
"LFEC") {
424 }
else if (s ==
"FFMC") {
426 }
else if (s ==
"LFMC") {
434 ContentVersion::ContentVersion ()
435 : id (
"urn:uuid:" + make_uuid())
441 ContentVersion::ContentVersion (cxml::ConstNodePtr node)
442 : id(node->string_child(
"Id"))
443 , label_text(node->string_child(
"LabelText"))
449 ContentVersion::ContentVersion (
string label_text_)
450 : id (
"urn:uuid:" + make_uuid())
451 , label_text (label_text_)
458 ContentVersion::as_xml (xmlpp::Element* parent)
const
460 auto cv = parent->add_child(
"ContentVersion");
461 cv->add_child(
"Id")->add_child_text(
id);
462 cv->add_child(
"LabelText")->add_child_text(label_text);
466 Luminance::Luminance (cxml::ConstNodePtr node)
468 , _unit(string_to_unit(node->string_attribute(
"units")))
474 Luminance::Luminance (
float value, Unit unit)
482 Luminance::set_value (
float v)
485 throw dcp::MiscError (String::compose(
"Invalid luminance value %1", v));
493 Luminance::as_xml (xmlpp::Element* parent,
string ns)
const
495 auto lum = parent->add_child(
"Luminance", ns);
496 lum->set_attribute(
"units", unit_to_string(_unit));
497 lum->add_child_text(raw_convert<string>(_value, 3));
502 Luminance::unit_to_string (Unit u)
505 case Unit::CANDELA_PER_SQUARE_METRE:
506 return "candela-per-square-metre";
507 case Unit::FOOT_LAMBERT:
508 return "foot-lambert";
518 Luminance::string_to_unit (
string u)
520 if (u ==
"candela-per-square-metre") {
521 return Unit::CANDELA_PER_SQUARE_METRE;
522 }
else if (u ==
"foot-lambert") {
523 return Unit::FOOT_LAMBERT;
526 throw XMLError (String::compose(
"Invalid luminance unit %1", u));
531 Luminance::value_in_foot_lamberts ()
const
534 case Unit::CANDELA_PER_SQUARE_METRE:
535 return _value / 3.426;
536 case Unit::FOOT_LAMBERT:
547 return fabs(a.value() - b.value()) < 0.001 && a.unit() == b.unit();
551 MainSoundConfiguration::MainSoundConfiguration (
string s)
553 vector<string> parts;
554 boost::split (parts, s, boost::is_any_of(
"/"));
555 if (parts.size() != 2) {
559 if (parts[0] ==
"51") {
560 _field = MCASoundField::FIVE_POINT_ONE;
561 }
else if (parts[0] ==
"71") {
562 _field = MCASoundField::SEVEN_POINT_ONE;
567 vector<string> channels;
568 boost::split (channels, parts[1], boost::is_any_of(
","));
570 if (channels.size() > 16) {
574 for (
auto i: channels) {
576 _channels.push_back(optional<Channel>());
578 _channels.push_back(mca_id_to_channel(i));
584 MainSoundConfiguration::MainSoundConfiguration (MCASoundField field,
int channels)
587 _channels.resize (channels);
592 MainSoundConfiguration::to_string ()
const
595 if (_field == MCASoundField::FIVE_POINT_ONE) {
601 for (
auto i: _channels) {
605 c += channel_to_mca_id(*i, _field) +
",";
609 if (c.length() > 0) {
610 c = c.substr(0, c.length() - 1);
618 MainSoundConfiguration::mapping (
int index)
const
620 DCP_ASSERT (
static_cast<size_t>(index) < _channels.size());
621 return _channels[index];
626 MainSoundConfiguration::set_mapping (
int index,
Channel c)
628 DCP_ASSERT (
static_cast<size_t>(index) < _channels.size());
629 _channels[index] = c;
634 dcp::status_to_string (
Status s)
650 dcp::string_to_status (
string s)
654 }
else if (s ==
"temp") {
656 }
else if (s ==
"pre") {
665 dcp::mca_id_to_channel (
string id)
669 }
else if (
id ==
"R") {
671 }
else if (
id ==
"C") {
673 }
else if (
id ==
"LFE") {
675 }
else if (
id ==
"Ls" ||
id ==
"Lss") {
677 }
else if (
id ==
"Rs" ||
id ==
"Rss") {
679 }
else if (
id ==
"HI") {
681 }
else if (
id ==
"VIN") {
683 }
else if (
id ==
"Lrs") {
685 }
else if (
id ==
"Rrs") {
687 }
else if (
id ==
"DBOX") {
688 return Channel::MOTION_DATA;
689 }
else if (
id ==
"FSKSync") {
690 return Channel::SYNC_SIGNAL;
691 }
else if (
id ==
"SLVS") {
692 return Channel::SIGN_LANGUAGE;
700 dcp::channel_to_mca_id (
Channel c, MCASoundField field)
712 return field == MCASoundField::FIVE_POINT_ONE ?
"Ls" :
"Lss";
714 return field == MCASoundField::FIVE_POINT_ONE ?
"Rs" :
"Rss";
723 case Channel::MOTION_DATA:
725 case Channel::SYNC_SIGNAL:
727 case Channel::SIGN_LANGUAGE:
738 dcp::channel_to_mca_name (
Channel c, MCASoundField field)
750 return field == MCASoundField::FIVE_POINT_ONE ?
"Left Surround" :
"Left Side Surround";
752 return field == MCASoundField::FIVE_POINT_ONE ?
"Right Surround" :
"Right Side Surround";
754 return "Hearing Impaired";
756 return "Visually Impaired-Narrative";
758 return "Left Rear Surround";
760 return "Right Rear Surround";
761 case Channel::MOTION_DATA:
762 return "D-BOX Motion Code Primary Stream";
763 case Channel::SYNC_SIGNAL:
765 case Channel::SIGN_LANGUAGE:
766 return "Sign Language Video Stream";
776 dcp::channel_to_mca_universal_label (
Channel c, MCASoundField field, ASDCP::Dictionary
const* dict)
778 static byte_t sync_signal[] = {
779 0x06, 0x0e, 0x2b, 0x34, 0x04, 0x01, 0x01, 0x0d, 0x03, 0x02, 0x01, 0x10, 0x00, 0x00, 0x00, 0x00
782 static byte_t sign_language[] = {
783 0x06, 0x0e, 0x2b, 0x34, 0x04, 0x01, 0x01, 0x0d, 0x0d, 0x0f, 0x03, 0x02, 0x01, 0x01, 0x00, 0x00
788 return dict->ul(ASDCP::MDD_DCAudioChannel_L);
790 return dict->ul(ASDCP::MDD_DCAudioChannel_R);
792 return dict->ul(ASDCP::MDD_DCAudioChannel_C);
794 return dict->ul(ASDCP::MDD_DCAudioChannel_LFE);
796 return dict->ul(field == MCASoundField::FIVE_POINT_ONE ? ASDCP::MDD_DCAudioChannel_Ls : ASDCP::MDD_DCAudioChannel_Lss);
798 return dict->ul(field == MCASoundField::FIVE_POINT_ONE ? ASDCP::MDD_DCAudioChannel_Rs : ASDCP::MDD_DCAudioChannel_Rss);
800 return dict->ul(ASDCP::MDD_DCAudioChannel_HI);
802 return dict->ul(ASDCP::MDD_DCAudioChannel_VIN);
804 return dict->ul(ASDCP::MDD_DCAudioChannel_Lrs);
806 return dict->ul(ASDCP::MDD_DCAudioChannel_Rrs);
807 case Channel::MOTION_DATA:
808 return dict->ul(ASDCP::MDD_DBOXMotionCodePrimaryStream);
809 case Channel::SYNC_SIGNAL:
810 return ASDCP::UL(sync_signal);
811 case Channel::SIGN_LANGUAGE:
812 return ASDCP::UL(sign_language);
822 dcp::used_audio_channels ()
835 Channel::MOTION_DATA,
836 Channel::SYNC_SIGNAL,
837 Channel::SIGN_LANGUAGE
int g
green component, from 0 to 255
int b
blue component, from 0 to 255
int r
red component, from 0 to 255
std::string to_argb_string() const
std::string to_rgb_string() const
A fraction (i.e. a thing with an integer numerator and an integer denominator).
A miscellaneous exception.
Any error that occurs when reading data from a DCP.
Exceptions thrown by libdcp.
Namespace for everything in libdcp.
@ FFOI
first frame of intermission
@ FFEC
first frame of end credits
@ LFMC
last frame of moving credits
@ LFOI
last frame of intermission
@ FFMC
first frame of moving credits
@ FFTC
first frame of title credits
@ LFOC
last frame of composition
@ FFOC
first frame of composition
@ LFEC
last frame of end credits
@ LFTC
last frame of title credits
@ RIGHT
horizontal position is distance from right of screen to right of subtitle
@ LEFT
horizontal position is distance from left of screen to left of subtitle
@ CENTER
horizontal position is distance from centre of screen to centre of subtitle
std::string content_kind_to_string(ContentKind kind)
@ BOTTOM
vertical position is distance from bottom of screen to bottom of subtitle
@ TOP
vertical position is distance from top of screen to top of subtitle
@ CENTER
vertical position is distance from centre of screen to centre of subtitle
ContentKind content_kind_from_string(std::string kind)
@ LFE
low-frequency effects (sub)
P raw_convert(Q, int precision=16, bool fixed=false)
@ TEMP
temporary version (picture/sound unfinished)
@ PRE
pre-release (picture/sound finished)
Methods for conversion to/from string.
The integer, two-dimensional size of something.