Asset::write_to_pkl (xmlpp::Node* node, Standard standard) const
{
DCP_ASSERT (!_file.empty ());
-
+
xmlpp::Node* asset = node->add_child ("Asset");
asset->add_child("Id")->add_child_text ("urn:uuid:" + _id);
asset->add_child("AnnotationText")->add_child_text (_id);
boost::filesystem::canonical (root),
boost::filesystem::canonical (_file)
);
-
+
if (!path) {
throw MiscError (String::compose ("Asset %1 is not within the directory %2", _file, root));
}
-
+
chunk->add_child("Path")->add_child_text (path.get().string ());
chunk->add_child("VolumeIndex")->add_child_text ("1");
chunk->add_child("Offset")->add_child_text ("0");
Asset::hash (function<void (float)> progress) const
{
DCP_ASSERT (!_file.empty ());
-
+
if (_hash.empty ()) {
_hash = make_digest (_file, progress);
}
_file = boost::filesystem::absolute (file);
_hash.clear ();
}
-
+
/** @file src/asset.h
* @brief Asset class.
- */
+ */
#ifndef LIBDCP_ASSET_H
#define LIBDCP_ASSET_H
if (ASDCP_FAILURE (_encryption_context->InitKey (mxf->key()->value ()))) {
throw MiscError ("could not set up encryption context");
}
-
+
uint8_t cbc_buffer[ASDCP::CBC_BLOCK_SIZE];
-
+
Kumu::FortunaRNG rng;
if (ASDCP_FAILURE (_encryption_context->SetIVec (rng.FillRandom (cbc_buffer, ASDCP::CBC_BLOCK_SIZE)))) {
throw MiscError ("could not set up CBC initialization vector");
}
/* Decode the base64 of the public key */
-
+
unsigned char buffer[512];
int const N = dcp::base64_decode (pub, buffer, 1024);
string dig = Kumu::base64encode (digest, SHA_DIGEST_LENGTH, digest_base64, 64);
#ifdef LIBDCP_WINDOWS
boost::replace_all (dig, "/", "\\/");
-#else
+#else
boost::replace_all (dig, "/", "\\\\/");
-#endif
+#endif
return dig;
}
{
boost::filesystem::path directory = boost::filesystem::temp_directory_path() / boost::filesystem::unique_path ();
boost::filesystem::create_directories (directory);
-
+
boost::filesystem::path const cwd = boost::filesystem::current_path ();
boost::filesystem::current_path (directory);
<< "OU = Organization unit\n"
<< "CN = Entity and dnQualifier\n";
}
-
+
string const inter_subject = "/O=" + organisation +
"/OU=" + organisational_unit +
"/CN=" + intermediate_common_name +
command (s.str().c_str());
}
-
+
command (
quoted_openssl +
" x509 -req -sha256 -days 3649 -CA ca.self-signed.pem -CAkey ca.key -set_serial 6"
std::string intermediate_common_name = ".smpte-430-2.INTERMEDIATE.NOT_FOR_PRODUCTION",
std::string leaf_common_name = "CS.smpte-430-2.LEAF.NOT_FOR_PRODUCTION"
);
-
+
}
: _certificate (c)
, _public_key (0)
{
-
+
}
/** Load an X509 certificate from a string.
_certificate = 0;
RSA_free (_public_key);
_public_key = 0;
-
+
read_string (other.certificate (true));
return *this;
Certificate::certificate (bool with_begin_end) const
{
DCP_ASSERT (_certificate);
-
+
BIO* bio = BIO_new (BIO_s_mem ());
if (!bio) {
throw MiscError ("could not create memory BIO");
}
-
+
PEM_write_bio_X509 (bio, _certificate);
string s;
boost::replace_all (s, "-----BEGIN CERTIFICATE-----\n", "");
boost::replace_all (s, "\n-----END CERTIFICATE-----\n", "");
}
-
+
return s;
}
DCP_ASSERT (p != -1);
return asn_to_utf8 (X509_NAME_ENTRY_get_data (X509_NAME_get_entry (n, p)));
}
-
+
string
Certificate::name_for_xml (X509_NAME* name)
{
ASN1_INTEGER* s = X509_get_serialNumber (_certificate);
DCP_ASSERT (s);
-
+
BIGNUM* b = ASN1_INTEGER_to_BN (s, 0);
char* c = BN_bn2dec (b);
BN_free (b);
-
+
string st (c);
OPENSSL_free (c);
Certificate::thumbprint () const
{
DCP_ASSERT (_certificate);
-
+
uint8_t buffer[8192];
uint8_t* p = buffer;
i2d_X509_CINF (_certificate->cert_info, &p);
private:
void read_string (std::string);
-
+
static std::string name_for_xml (X509_NAME *);
static std::string asn_to_utf8 (ASN1_STRING *);
static std::string get_name_part (X509_NAME *, int);
Certificate leaf () const;
typedef std::list<Certificate> List;
-
+
List leaf_to_root () const;
List root_to_leaf () const;
, _adjusted_white (adjusted_white)
, _out (out)
{
-
+
}
bool
/* backsubstitute to get the inverse */
lu_substitute (A, pm, xyz_to_rgb);
-
+
return xyz_to_rgb;
}
public:
ColourConversion ()
{}
-
+
ColourConversion (
boost::shared_ptr<const TransferFunction> in,
YUVToRGB yuv_to_rgb,
boost::optional<Chromaticity> adjusted_white () const {
return _adjusted_white;
}
-
+
boost::shared_ptr<const TransferFunction> out () const {
return _out;
}
void unset_adjusted_white () {
_adjusted_white = boost::optional<Chromaticity> ();
}
-
+
void set_out (boost::shared_ptr<const TransferFunction> f) {
_out = f;
}
extern double const xyz_to_rgb[3][3];
extern double const rgb_to_xyz[3][3];
-}
+}
}
if (signer) {
root->set_namespace_declaration ("http://www.w3.org/2000/09/xmldsig#", "dsig");
}
-
+
root->add_child("Id")->add_child_text ("urn:uuid:" + _id);
root->add_child("AnnotationText")->add_child_text (_annotation_text);
root->add_child("IssueDate")->add_child_text (_metadata.issue_date);
return c;
}
-
+
bool
CPL::equals (shared_ptr<const Asset> other, EqualityOptions opt, NoteHandler note) const
{
if (!other_cpl) {
return false;
}
-
+
if (_annotation_text != other_cpl->_annotation_text && !opt.cpl_annotation_texts_can_differ) {
stringstream s;
s << "CPL: annotation texts differ: " << _annotation_text << " vs " << other_cpl->_annotation_text << "\n";
note (DCP_ERROR, String::compose ("CPL: reel counts differ (%1 vs %2)", _reels.size(), other_cpl->_reels.size()));
return false;
}
-
+
list<shared_ptr<Reel> >::const_iterator a = _reels.begin ();
list<shared_ptr<Reel> >::const_iterator b = other_cpl->_reels.begin ();
-
+
while (a != _reels.end ()) {
if (!(*a)->equals (*b, opt, note)) {
return false;
DCP_ASSERT (false);
}
}
-
+
#include <list>
namespace dcp {
-
+
class ReelAsset;
class Reel;
class XMLMetadata;
class MXFMetadata;
class Signer;
class DecryptedKDM;
-
+
/** @class CPL
* @brief A Composition Playlist.
*/
std::string annotation_text () const {
return _annotation_text;
}
-
+
/** @return contents of the <ContentTitleText> node */
std::string content_title_text () const {
return _content_title_text;
void set_content_version_label_text (std::string text) {
_content_version_label_text = text;
}
-
+
/** @return the type of the content, used by media servers
* to categorise things (e.g. feature, trailer, etc.)
*/
#include <boost/shared_array.hpp>
namespace dcp {
-
+
class Data
{
public:
Data () {}
-
+
Data (boost::shared_array<uint8_t> data_, boost::uintmax_t size_)
: data (data_)
, size (size_)
{}
-
+
boost::shared_array<uint8_t> data;
boost::uintmax_t size;
};
namespace dcp
{
-class Content;
+class Content;
class Reel;
class CPL;
class XMLMetadata;
/** @class DCP
* @brief A class to create or read a DCP.
*/
-
+
class DCP : public boost::noncopyable
{
public:
DCP (boost::filesystem::path directory);
typedef std::list<boost::shared_ptr<DCPReadError> > ReadErrors;
-
+
/** Read the DCP's structure into this object.
* @param keep_going true to try to keep going in the face of (some) errors.
* @param errors List of errors that will be added to if keep_going is true.
XMLMetadata metadata,
boost::shared_ptr<const Signer> signer
) const;
-
+
void write_volindex (Standard standard) const;
/** Write the ASSETMAP file.
{
s = floor (seconds);
tcr = tcr_;
-
+
e = int (round ((seconds - s) * tcr));
if (s >= 60) {
if (b.size() != 4) {
boost::throw_exception (DCPReadError ("unrecognised time specification"));
}
-
+
h = raw_convert<int> (b[0]);
m = raw_convert<int> (b[1]);
s = raw_convert<int> (b[2]);
} else {
r.tcr = a.tcr;
}
-
+
r.e = a.e - b.e;
if (r.e < 0) {
r.e += r.tcr;
extern bool operator> (Time const & a, Time const & b);
extern bool operator>= (Time const & a, Time const & b);
extern std::ostream & operator<< (std::ostream & s, Time const & t);
-extern Time operator+ (Time a, Time b);
+extern Time operator+ (Time a, Time b);
extern Time operator- (Time a, Time b);
extern float operator/ (Time a, Time const & b);
get_uuid (unsigned char ** p)
{
stringstream g;
-
+
for (int i = 0; i < 16; ++i) {
g << setw(2) << setfill('0') << hex << static_cast<int> (**p);
(*p)++;
if (!bio) {
throw MiscError ("could not create memory BIO");
}
-
+
RSA* rsa = PEM_read_bio_RSAPrivateKey (bio, 0, 0, 0);
if (!rsa) {
throw FileError ("could not read RSA private key file", private_key, errno);
}
default:
DCP_ASSERT (false);
- }
-
+ }
+
delete[] decrypted;
}
base64_decode (signer->certificates().leaf().thumbprint (), p, 20);
p += 20;
-
+
put_uuid (&p, i.cpl_id ());
put (&p, i.type ());
put_uuid (&p, i.id ());
put (&p, _not_valid_before.as_string ());
put (&p, _not_valid_after.as_string ());
put (&p, i.key().value(), ASDCP::KeyLen);
-
+
/* Encrypt using the projector's public key */
RSA* rsa = recipient.public_key ();
unsigned char encrypted[RSA_size(rsa)];
if (encrypted_len == -1) {
throw MiscError (String::compose ("Could not encrypt KDM (%1)", ERR_error_string (ERR_get_error(), 0)));
}
-
+
/* Lazy overallocation */
char out[encrypted_len * 2];
Kumu::base64encode (encrypted, encrypted_len, out, encrypted_len * 2);
}
lines << out[i];
}
-
+
keys.push_back (lines.str ());
}
return _cpl_id;
}
-private:
+private:
std::string _type;
std::string _id;
Key _key;
namespace dcp {
-/** Namespace for classes used to hold our data; they are internal to this .cc file */
+/** Namespace for classes used to hold our data; they are internal to this .cc file */
namespace data {
class Signer
{
public:
Signer () {}
-
+
Signer (shared_ptr<const cxml::Node> node)
: x509_issuer_name (node->string_child ("X509IssuerName"))
, x509_serial_number (node->string_child ("X509SerialNumber"))
{
-
+
}
void as_xml (xmlpp::Element* node) const
node->add_child("X509IssuerName", "ds")->add_child_text (x509_issuer_name);
node->add_child("X509SerialNumber", "ds")->add_child_text (x509_serial_number);
}
-
+
string x509_issuer_name;
string x509_serial_number;
};
{
public:
X509Data () {}
-
+
X509Data (boost::shared_ptr<const cxml::Node> node)
: x509_issuer_serial (Signer (node->node_child ("X509IssuerSerial")))
, x509_certificate (node->string_child ("X509Certificate"))
x509_issuer_serial.as_xml (node->add_child ("X509IssuerSerial", "ds"));
node->add_child("X509Certificate", "ds")->add_child_text (x509_certificate);
}
-
+
Signer x509_issuer_serial;
std::string x509_certificate;
};
-
+
class Reference
{
public:
Reference () {}
-
+
Reference (string u)
: uri (u)
{}
{
}
-
+
void as_xml (xmlpp::Element* node) const
{
node->set_attribute ("URI", uri);
node->add_child("DigestMethod", "ds")->set_attribute ("Algorithm", "http://www.w3.org/2001/04/xmlenc#sha256");
node->add_child("DigestValue", "ds")->add_child_text (digest_value);
}
-
+
string uri;
string digest_value;
};
node->add_child ("SignatureMethod", "ds")->set_attribute (
"Algorithm", "http://www.w3.org/2001/04/xmldsig-more#rsa-sha256"
);
-
+
authenticated_public.as_xml (node->add_child ("Reference", "ds"));
authenticated_private.as_xml (node->add_child ("Reference", "ds"));
}
-
+
private:
Reference authenticated_public;
Reference authenticated_private;
};
-
+
class Signature
{
public:
{
signed_info.as_xml (node->add_child ("SignedInfo", "ds"));
node->add_child("SignatureValue", "ds")->add_child_text (signature_value);
-
+
xmlpp::Element* key_info_node = node->add_child ("KeyInfo", "ds");
for (std::list<X509Data>::const_iterator i = x509_data.begin(); i != x509_data.end(); ++i) {
i->as_xml (key_info_node->add_child ("X509Data", "ds"));
{
public:
AuthenticatedPrivate () {}
-
+
AuthenticatedPrivate (shared_ptr<const cxml::Node> node)
{
list<shared_ptr<cxml::Node> > encrypted_key_nodes = node->node_children ("EncryptedKey");
cipher_data->add_child("CipherValue", "enc")->add_child_text (*i);
}
}
-
+
list<string> encrypted_key;
};
{
public:
TypedKeyId () {}
-
+
TypedKeyId (shared_ptr<const cxml::Node> node)
: key_type (node->string_child ("KeyType"))
, key_id (node->string_child ("KeyId").substr (9))
{
public:
KeyIdList () {}
-
+
KeyIdList (shared_ptr<const cxml::Node> node)
{
list<shared_ptr<cxml::Node> > typed_key_id_nodes = node->node_children ("TypedKeyId");
{
public:
AuthorizedDeviceInfo () {}
-
+
AuthorizedDeviceInfo (shared_ptr<const cxml::Node> node)
: device_list_identifier (node->string_child ("DeviceListIdentifier").substr (9))
, device_list_description (node->string_child ("DeviceListDescription"))
{
public:
X509IssuerSerial () {}
-
+
X509IssuerSerial (shared_ptr<const cxml::Node> node)
: x509_issuer_name (node->string_child ("X509IssuerName"))
, x509_serial_number (node->string_child ("X509SerialNumber"))
{
public:
Recipient () {}
-
+
Recipient (shared_ptr<const cxml::Node> node)
: x509_issuer_serial (node->node_child ("X509IssuerSerial"))
, x509_subject_name (node->string_child ("X509SubjectName"))
x509_issuer_serial.as_xml (node->add_child ("X509IssuerSerial"));
node->add_child("X509SubjectName")->add_child_text (x509_subject_name);
}
-
+
X509IssuerSerial x509_issuer_serial;
string x509_subject_name;
};
{
public:
KDMRequiredExtensions () {}
-
+
KDMRequiredExtensions (shared_ptr<const cxml::Node> node)
: recipient (node->node_child ("Recipient"))
, composition_playlist_id (node->string_child ("CompositionPlaylistId").substr (9))
void as_xml (xmlpp::Element* node) const
{
node->set_attribute ("xmlns", "http://www.smpte-ra.org/schemas/430-1/2006/KDM");
-
+
recipient.as_xml (node->add_child ("Recipient"));
node->add_child("CompositionPlaylistId")->add_child_text ("urn:uuid:" + composition_playlist_id);
if (content_authenticator) {
node->add_child("ContentKeysNotValidAfter")->add_child_text (not_valid_after.as_string ());
authorized_device_info.as_xml (node->add_child ("AuthorizedDeviceInfo"));
key_id_list.as_xml (node->add_child ("KeyIdList"));
-
+
xmlpp::Element* forensic_mark_flag_list = node->add_child ("ForensicMarkFlagList");
forensic_mark_flag_list->add_child("ForensicMarkFlag")->add_child_text ("http://www.smpte-ra.org/430-1/2006/KDM#mrkflg-picture-disable");
forensic_mark_flag_list->add_child("ForensicMarkFlag")->add_child_text ("http://www.smpte-ra.org/430-1/2006/KDM#mrkflg-audio-disable");
}
-
+
Recipient recipient;
string composition_playlist_id;
boost::optional<string> content_authenticator;
{
public:
RequiredExtensions () {}
-
+
RequiredExtensions (shared_ptr<const cxml::Node> node)
: kdm_required_extensions (node->node_child ("KDMRequiredExtensions"))
{
{
kdm_required_extensions.as_xml (node->add_child ("KDMRequiredExtensions"));
}
-
+
KDMRequiredExtensions kdm_required_extensions;
};
: message_id (make_uuid ())
, issue_date (LocalTime().as_string ())
{}
-
+
AuthenticatedPublic (shared_ptr<const cxml::Node> node)
: message_id (node->string_child ("MessageId").substr (9))
, annotation_text (node->string_child ("AnnotationText"))
void as_xml (xmlpp::Element* node, map<string, xmlpp::Attribute *>& references) const
{
references["ID_AuthenticatedPublic"] = node->set_attribute ("Id", "ID_AuthenticatedPublic");
-
+
node->add_child("MessageId")->add_child_text ("urn:uuid:" + message_id);
node->add_child("MessageType")->add_child_text ("http://www.smpte-ra.org/430-1/2006/KDM#kdm-key-type");
node->add_child("AnnotationText")->add_child_text (annotation_text);
{
}
-
+
EncryptedKDMData (shared_ptr<const cxml::Node> node)
: authenticated_public (node->node_child ("AuthenticatedPublic"))
, authenticated_private (node->node_child ("AuthenticatedPrivate"))
, signature (node->node_child ("Signature"))
{
-
+
}
shared_ptr<xmlpp::Document> as_xml () const
: _data (new data::EncryptedKDMData)
{
/* Fill our XML-ish description in with the juicy bits that the caller has given */
-
+
data::AuthenticatedPublic& aup = _data->authenticated_public;
aup.signer.x509_issuer_name = signer->certificates().leaf().issuer ();
aup.signer.x509_serial_number = signer->certificates().leaf().serial ();
fwrite (x.c_str(), 1, x.length(), f);
fclose (f);
}
-
+
string
EncryptedKDM::as_xml () const
{
class EncryptedKDMData;
}
-class Signer;
+class Signer;
class Certificate;
/** @class EncryptedKDM
* keys (also key id, CPL id etc.)
*/
std::list<std::string> keys () const;
-
+
private:
friend class DecryptedKDM;
std::list<std::pair<std::string, std::string> > key_ids,
std::list<std::string> keys
);
-
+
data::EncryptedKDMData* _data;
};
case UNKNOWN:
break;
}
-
+
_message = String::compose ("Missing asset %1%2", path.string(), type_name);
}
StringError (std::string message)
: _message (message)
{}
-
+
~StringError () throw () {}
/** @return error message */
: FileError (message, filename, number)
{}
};
-
+
/** @class MiscError
* @brief A miscellaneous exception
*/
MAIN_SUBTITLE, //< main subtitle is missing
UNKNOWN //< something is missing but we don't know what
};
-
+
MissingAssetError (boost::filesystem::path, AssetType = UNKNOWN);
~MissingAssetError () throw () {}
{
public:
FontAsset (boost::filesystem::path file);
-
+
private:
std::string pkl_type (Standard standard) const;
};
FontNode::FontNode (cxml::ConstNodePtr node, int tcr)
{
text = node->content ();
-
+
id = node->optional_string_attribute ("Id");
size = node->optional_number_attribute<int64_t> ("Size").get_value_or (0);
aspect_adjust = node->optional_number_attribute<float> ("AspectAdjust");
BOOST_FOREACH (cxml::NodePtr& i, f) {
font_nodes.push_back (shared_ptr<FontNode> (new FontNode (i, tcr)));
}
-
+
list<cxml::NodePtr> t = node->node_children ("Text");
BOOST_FOREACH (cxml::NodePtr& i, t) {
text_nodes.push_back (shared_ptr<TextNode> (new TextNode (i, tcr)));
FontNode ()
: size (0)
{}
-
+
FontNode (cxml::ConstNodePtr node, int tcr);
FontNode (std::list<boost::shared_ptr<FontNode> > const & font_nodes);
boost::optional<Colour> colour;
boost::optional<Effect> effect;
boost::optional<Colour> effect_colour;
-
+
std::list<boost::shared_ptr<SubtitleNode> > subtitle_nodes;
std::list<boost::shared_ptr<FontNode> > font_nodes;
std::list<boost::shared_ptr<TextNode> > text_nodes;
x = node->optional_string_attribute ("ID");
}
id = x.get_value_or ("");
-
+
uri = node->string_attribute ("URI");
}
#include <boost/optional.hpp>
namespace dcp {
-
+
class InteropLoadFontNode : public LoadFontNode
{
public:
InteropSubtitleAsset::InteropSubtitleAsset ()
{
-
+
}
Glib::ustring
if (!SubtitleAsset::equals (other_asset, options, note)) {
return false;
}
-
+
shared_ptr<const InteropSubtitleAsset> other = dynamic_pointer_cast<const InteropSubtitleAsset> (other_asset);
if (!other) {
return false;
if (!f) {
throw FileError ("Could not open file for writing", p, -1);
}
-
+
Glib::ustring const s = xml_as_string ();
fwrite (s.c_str(), 1, s.bytes(), f);
fclose (f);
std::list<boost::shared_ptr<LoadFontNode> > load_font_nodes () const;
void add_font (std::string id, boost::filesystem::path file);
-
+
Glib::ustring xml_as_string () const;
void write (boost::filesystem::path path) const;
void resolve_fonts (std::list<boost::shared_ptr<Object> > objects);
}
protected:
-
+
std::string pkl_type (Standard) const {
return "text/xml";
}
if (this == &other) {
return *this;
}
-
+
memcpy (_value, other._value, ASDCP::KeyLen);
return *this;
}
Key::hex () const
{
stringstream g;
-
+
for (unsigned int i = 0; i < ASDCP::KeyLen; ++i) {
g << setw(2) << setfill('0') << std::hex << static_cast<int> (_value[i]);
}
{}
virtual ~LoadFontNode () {}
-
+
std::string id;
};
{
/* 2013-01-05T18:06:59+04:00 or 2013-01-05T18:06:59.123+04:00 */
/* 0123456789012345678901234 or 01234567890123456789012345678 */
-
+
if (s.length() < 25) {
throw TimeFormatError (s);
}
bool operator== (LocalTime const & other) const;
bool operator!= (LocalTime const & other) const;
-
+
private:
friend class ::local_time_test;
XMLMetadata ();
void set_issue_date_now ();
-
+
std::string issuer;
std::string creator;
std::string issue_date;
}
bool about_equal (boost::shared_ptr<const TransferFunction>, double epsilon) const;
-
+
protected:
double * make_lut (int bit_depth, bool inverse) const;
-
+
private:
double _power;
double _threshold;
if (ASDCP_FAILURE (r)) {
boost::throw_exception (MXFFileError ("could not open MXF file for reading", file.string(), r));
}
-
+
ASDCP::JP2K::PictureDescriptor desc;
if (ASDCP_FAILURE (reader.FillPictureDescriptor (desc))) {
boost::throw_exception (DCPReadError ("could not read video MXF information"));
}
read_picture_descriptor (desc);
-
+
ASDCP::WriterInfo info;
if (ASDCP_FAILURE (reader.FillWriterInfo (info))) {
boost::throw_exception (DCPReadError ("could not read video MXF information"));
MonoPictureAsset::MonoPictureAsset (Fraction edit_rate)
: PictureAsset (edit_rate)
{
-
+
}
shared_ptr<const MonoPictureFrame>
if (ASDCP_FAILURE (r)) {
boost::throw_exception (MXFFileError ("could not open MXF file for reading", _file.string(), r));
}
-
+
ASDCP::JP2K::MXFReader reader_B;
r = reader_B.OpenRead (other->file().string().c_str());
if (ASDCP_FAILURE (r)) {
boost::throw_exception (MXFFileError ("could not open MXF file for reading", other->file().string(), r));
}
-
+
ASDCP::JP2K::PictureDescriptor desc_A;
if (ASDCP_FAILURE (reader_A.FillPictureDescriptor (desc_A))) {
boost::throw_exception (DCPReadError ("could not read video MXF information"));
if (ASDCP_FAILURE (reader_B.FillPictureDescriptor (desc_B))) {
boost::throw_exception (DCPReadError ("could not read video MXF information"));
}
-
+
if (!descriptor_equals (desc_A, desc_B, note)) {
return false;
}
if (i >= other_picture->intrinsic_duration()) {
return false;
}
-
+
note (DCP_PROGRESS, String::compose ("Comparing video frame %1 of %2", i, _intrinsic_duration));
shared_ptr<const MonoPictureFrame> frame_A = get_frame (i);
shared_ptr<const MonoPictureFrame> frame_B = other_picture->get_frame (i);
-
+
if (!frame_buffer_equals (
i, opt, note,
frame_A->j2k_data(), frame_A->j2k_size(),
namespace dcp {
-class MonoPictureAssetWriter;
+class MonoPictureAssetWriter;
/** @class MonoPictureAsset
* @brief A 2D (monoscopic) picture asset.
EqualityOptions opt,
NoteHandler note
) const;
-
+
boost::shared_ptr<const MonoPictureFrame> get_frame (int n) const;
private:
std::string cpl_node_name () const;
};
-}
+}
#endif
/* do this with an opaque pointer so we don't have to include
ASDCP headers
*/
-
+
struct ASDCPState;
boost::shared_ptr<ASDCPState> _state;
};
/* No key ID so far; we now need one */
_key_id = make_uuid ();
}
-
+
_decryption_context = new ASDCP::AESDecContext;
if (ASDCP_FAILURE (_decryption_context->InitKey (_key->value ()))) {
throw MiscError ("could not set up decryption context");
}
_metadata.read (info);
-
+
Kumu::bin2UUIDhex (info.AssetUUID, ASDCP::UUIDlen, buffer, sizeof (buffer));
return buffer;
}
{
class MXFMetadata;
-class PictureAssetWriter;
+class PictureAssetWriter;
/** @class MXF
* @brief Parent for classes which represent MXF files.
MXFMetadata metadata () const {
return _metadata;
}
-
+
protected:
template <class P, class Q>
friend void start (PictureAssetWriter* writer, boost::shared_ptr<P> state, Standard standard, Q* mxf, uint8_t* data, int size);
protected:
friend class ::write_subtitle_test;
-
+
/** ID */
std::string _id;
};
-
+
}
#endif
OpenJPEGImage::OpenJPEGImage (Size size)
{
opj_image_cmptparm_t cmptparm[3];
-
+
for (int i = 0; i < 3; ++i) {
cmptparm[i].dx = 1;
cmptparm[i].dy = 1;
// a.CodingStyleDefault != b.CodingStyleDefault ||
// a.QuantizationDefault != b.QuantizationDefault
) {
-
+
note (DCP_ERROR, "video MXF picture descriptors differ");
return false;
}
if (a.ContainerDuration != b.ContainerDuration) {
note (DCP_ERROR, "video container durations differ");
}
-
+
// for (unsigned int j = 0; j < ASDCP::JP2K::MaxComponents; ++j) {
// if (a.ImageComponents[j] != b.ImageComponents[j]) {
// notes.pack_start ("video MXF picture descriptors differ");
/* Easy result; the J2K data is identical */
return true;
}
-
+
/* Decompress the images to bitmaps */
shared_ptr<OpenJPEGImage> image_A = decompress_j2k (const_cast<uint8_t*> (data_A), size_A, 0);
shared_ptr<OpenJPEGImage> image_B = decompress_j2k (const_cast<uint8_t*> (data_B), size_B, 0);
-
+
/* Compare them */
-
+
vector<int> abs_diffs (image_A->size().width * image_A->size().height * 3);
int d = 0;
int max_diff = 0;
-
+
for (int c = 0; c < 3; ++c) {
-
+
if (image_A->size() != image_B->size()) {
note (DCP_ERROR, String::compose ("image sizes for frame %1 differ", frame));
return false;
}
-
+
int const pixels = image_A->size().width * image_A->size().height;
for (int j = 0; j < pixels; ++j) {
int const t = abs (image_A->data(c)[j] - image_B->data(c)[j]);
max_diff = max (max_diff, t);
}
}
-
+
uint64_t total = 0;
for (vector<int>::iterator j = abs_diffs.begin(); j != abs_diffs.end(); ++j) {
total += *j;
}
-
+
double const mean = double (total) / abs_diffs.size ();
-
+
uint64_t total_squared_deviation = 0;
for (vector<int>::iterator j = abs_diffs.begin(); j != abs_diffs.end(); ++j) {
total_squared_deviation += pow (*j - mean, 2);
}
-
+
double const std_dev = sqrt (double (total_squared_deviation) / abs_diffs.size());
-
+
note (DCP_NOTE, String::compose ("mean difference %1, deviation %2", mean, std_dev));
-
+
if (mean > opt.max_mean_pixel_error) {
note (
DCP_ERROR,
String::compose ("mean %1 out of range %2 in frame %3", mean, opt.max_mean_pixel_error, frame)
);
-
+
return false;
}
DCP_ERROR,
String::compose ("standard deviation %1 out of range %2 in frame %3", std_dev, opt.max_std_dev_pixel_error, frame)
);
-
+
return false;
}
namespace dcp
{
-class MonoPictureFrame;
+class MonoPictureFrame;
class StereoPictureFrame;
class PictureAssetWriter;
private:
std::string pkl_type (Standard standard) const;
};
-
+
}
namespace dcp {
-class PictureAsset;
+class PictureAsset;
/** @class FrameInfo
* @brief Information about a single frame (either a monoscopic frame or a left *or* right eye stereoscopic frame)
: offset (0)
, size (0)
{}
-
+
FrameInfo (uint64_t o, uint64_t s, std::string h)
: offset (o)
, size (s)
ASDCPStateBase ()
: frame_buffer (4 * Kumu::Megabyte)
{}
-
+
ASDCP::JP2K::CodestreamParser j2k_parser;
ASDCP::JP2K::FrameBuffer frame_buffer;
ASDCP::WriterInfo writer_info;
void dcp::start (PictureAssetWriter* writer, shared_ptr<P> state, Standard standard, Q* asset, uint8_t* data, int size)
{
asset->set_file (writer->_file);
-
+
if (ASDCP_FAILURE (state->j2k_parser.OpenReadFrame (data, size, state->frame_buffer))) {
boost::throw_exception (MiscError ("could not parse J2K frame"));
}
asset->set_size (Size (state->picture_descriptor.StoredWidth, state->picture_descriptor.StoredHeight));
asset->set_screen_aspect_ratio (Fraction (state->picture_descriptor.AspectRatio.Numerator, state->picture_descriptor.AspectRatio.Denominator));
-
+
asset->fill_writer_info (&state->writer_info, asset->id(), standard);
-
+
Kumu::Result_t r = state->mxf_writer.OpenWrite (
asset->file().string().c_str(),
state->writer_info,
if (main_picture) {
_main_picture.reset (new ReelMonoPictureAsset (main_picture));
}
-
+
shared_ptr<cxml::Node> main_stereoscopic_picture = asset_list->optional_node_child ("MainStereoscopicPicture");
if (main_stereoscopic_picture) {
_main_picture.reset (new ReelStereoPictureAsset (main_stereoscopic_picture));
}
-
+
shared_ptr<cxml::Node> main_sound = asset_list->optional_node_child ("MainSound");
if (main_sound) {
_main_sound.reset (new ReelSoundAsset (main_sound));
}
-
+
shared_ptr<cxml::Node> main_subtitle = asset_list->optional_node_child ("MainSubtitle");
if (main_subtitle) {
_main_subtitle.reset (new ReelSubtitleAsset (main_subtitle));
xmlpp::Element* reel = node->add_child ("Reel");
reel->add_child("Id")->add_child_text ("urn:uuid:" + make_uuid());
xmlpp::Element* asset_list = reel->add_child ("AssetList");
-
+
if (_main_picture && dynamic_pointer_cast<ReelMonoPictureAsset> (_main_picture)) {
/* Mono pictures come before other stuff... */
_main_picture->write_to_cpl (asset_list, standard);
_main_picture->write_to_cpl (asset_list, standard);
}
}
-
+
bool
Reel::equals (boost::shared_ptr<const Reel> other, EqualityOptions opt, NoteHandler note) const
{
note (DCP_ERROR, "Reel: assets differ");
return false;
}
-
+
if (_main_picture && !_main_picture->equals (other->_main_picture, opt, note)) {
return false;
}
note (DCP_ERROR, "Reel: assets differ");
return false;
}
-
+
if (_main_sound && !_main_sound->equals (other->_main_sound, opt, note)) {
return false;
}
note (DCP_ERROR, "Reel: assets differ");
return false;
}
-
+
if (_main_subtitle && !_main_subtitle->equals (other->_main_subtitle, opt, note)) {
return false;
}
class ReelSubtitleAsset;
class Content;
-/** @brief A reel within a DCP; the part which actually refers to picture, sound and subtitle data */
+/** @brief A reel within a DCP; the part which actually refers to picture, sound and subtitle data */
class Reel : public Object
{
public:
Reel () {}
-
+
Reel (
boost::shared_ptr<ReelPictureAsset> picture,
boost::shared_ptr<ReelSoundAsset> sound,
{}
Reel (boost::shared_ptr<const cxml::Node>);
-
+
boost::shared_ptr<ReelPictureAsset> main_picture () const {
return _main_picture;
}
boost::shared_ptr<ReelSoundAsset> main_sound () const {
return _main_sound;
}
-
+
boost::shared_ptr<ReelSubtitleAsset> main_subtitle () const {
return _main_subtitle;
}
Ref<Asset>& asset_ref () {
return _asset_ref;
}
-
+
int64_t entry_point () const {
return _entry_point;
}
namespace dcp {
-class MonoPictureAsset;
+class MonoPictureAsset;
/** @class ReelMonoPictureAsset
* @brief Part of a Reel's description which refers to a monoscopic picture asset.
/** @return the 4-character key type for this MXF (MDIK, MDAK, etc.) */
virtual std::string key_type () const = 0;
-
+
/** @return true if a KeyId is specified for this asset, implying
* that its content is encrypted.
*/
, _frame_rate (asset->frame_rate ())
, _screen_aspect_ratio (asset->screen_aspect_ratio ())
{
-
+
}
ReelPictureAsset::ReelPictureAsset (shared_ptr<const cxml::Node> node)
/* Find <MainPicture> */
xmlpp::Node* mp = find_child (node, cpl_node_name ());
-
+
mp->add_child ("FrameRate")->add_child_text (String::compose ("%1 %2", _frame_rate.numerator, _frame_rate.denominator));
if (standard == INTEROP) {
stringstream s;
if (!ReelAsset::equals (other, opt, note)) {
return false;
}
-
+
shared_ptr<const ReelPictureAsset> rpa = dynamic_pointer_cast<const ReelPictureAsset> (other);
if (!rpa) {
return false;
private:
std::string key_type () const;
-
+
Fraction _frame_rate;
Fraction _screen_aspect_ratio;
};
boost::shared_ptr<const SoundAsset> asset () const {
return boost::dynamic_pointer_cast<const SoundAsset> (_asset_ref.object ());
}
-
+
private:
std::string key_type () const;
std::string cpl_node_name () const;
namespace dcp {
-class StereoPictureAsset;
+class StereoPictureAsset;
/** @class ReelStereoPictureAsset
* @brief Part of a Reel's description which refers to a stereoscopic picture asset.
return boost::dynamic_pointer_cast<SubtitleAsset> (_asset_ref.object ());
}
-private:
+private:
std::string cpl_node_name () const;
};
if (!_object) {
throw UnresolvedRefError (_id);
}
-
+
return _object;
}
if (!_object) {
throw UnresolvedRefError (_id);
}
-
+
return _object.get ();
}
struct {
double x, y, z;
} s;
-
+
struct {
double r, g, b;
} d;
-
+
int* xyz_x = xyz_image->data (0);
int* xyz_y = xyz_image->data (1);
int* xyz_z = xyz_image->data (2);
int const height = xyz_image->size().height;
int const width = xyz_image->size().width;
-
+
for (int y = 0; y < height; ++y) {
uint8_t* argb_line = argb;
for (int x = 0; x < width; ++x) {
DCP_ASSERT (*xyz_x >= 0 && *xyz_y >= 0 && *xyz_z >= 0 && *xyz_x < 4096 && *xyz_y < 4096 && *xyz_z < 4096);
-
+
/* In gamma LUT */
s.x = lut_in[*xyz_x++];
s.y = lut_in[*xyz_y++];
d.r = ((s.x * matrix(0, 0)) + (s.y * matrix(0, 1)) + (s.z * matrix(0, 2)));
d.g = ((s.x * matrix(1, 0)) + (s.y * matrix(1, 1)) + (s.z * matrix(1, 2)));
d.b = ((s.x * matrix(2, 0)) + (s.y * matrix(2, 1)) + (s.z * matrix(2, 2)));
-
+
d.r = min (d.r, 1.0);
d.r = max (d.r, 0.0);
-
+
d.g = min (d.g, 1.0);
d.g = max (d.g, 0.0);
-
+
d.b = min (d.b, 1.0);
d.b = max (d.b, 0.0);
-
+
/* Out gamma LUT */
*argb_line++ = lut_out[int(rint(d.b * max_colour))] * 0xff;
*argb_line++ = lut_out[int(rint(d.g * max_colour))] * 0xff;
struct {
double x, y, z;
} s;
-
+
struct {
double r, g, b;
} d;
}
cz = max (min (cz, 4095), 0);
}
-
+
/* In gamma LUT */
s.x = lut_in[cx];
s.y = lut_in[cy];
d.r = ((s.x * matrix(0, 0)) + (s.y * matrix(0, 1)) + (s.z * matrix(0, 2)));
d.g = ((s.x * matrix(1, 0)) + (s.y * matrix(1, 1)) + (s.z * matrix(1, 2)));
d.b = ((s.x * matrix(2, 0)) + (s.y * matrix(2, 1)) + (s.z * matrix(2, 2)));
-
+
d.r = min (d.r, 1.0);
d.r = max (d.r, 0.0);
-
+
d.g = min (d.g, 1.0);
d.g = max (d.g, 0.0);
-
+
d.b = min (d.b, 1.0);
d.b = max (d.b, 0.0);
struct {
double x, y, z;
} e;
-
+
double const * lut_in = conversion.in()->lut (12, false);
double const * lut_out = conversion.out()->lut (16, true);
boost::numeric::ublas::matrix<double> const rgb_to_xyz = conversion.rgb_to_xyz ();
e.x = ((d.x * bradford(0, 0)) + (d.y * bradford(0, 1)) + (d.z * bradford(0, 2)));
e.y = ((d.x * bradford(1, 0)) + (d.y * bradford(1, 1)) + (d.z * bradford(1, 2)));
e.z = ((d.x * bradford(2, 0)) + (d.y * bradford(2, 1)) + (d.z * bradford(2, 2)));
-
+
/* DCI companding */
e.x = e.x * DCI_COEFFICIENT * 65535;
e.y = e.y * DCI_COEFFICIENT * 65535;
if (e.x < 0 || e.y < 0 || e.z < 0 || e.x > 65535 || e.y > 65535 || e.z > 65535) {
++clamped;
}
-
+
e.x = max (0.0, e.x);
e.y = max (0.0, e.y);
e.z = max (0.0, e.z);
++jn;
}
}
-
+
return xyz_12;
}
namespace dcp {
-class ARGBImage;
+class ARGBImage;
class OpenJPEGImage;
class Image;
class ColourConversion;
-
+
extern void xyz_to_rgba (
boost::shared_ptr<const OpenJPEGImage>,
ColourConversion const & conversion,
uint8_t* rgba
);
-
+
extern void xyz_to_rgb (
boost::shared_ptr<const OpenJPEGImage>,
ColourConversion const & conversion,
int stride,
boost::optional<NoteHandler> note = boost::optional<NoteHandler> ()
);
-
+
extern boost::shared_ptr<OpenJPEGImage> rgb_to_xyz (
uint8_t const * rgb,
dcp::Size size,
ColourConversion const & conversion,
boost::optional<NoteHandler> note = boost::optional<NoteHandler> ()
);
-
+
extern boost::shared_ptr<OpenJPEGImage> xyz_to_xyz (uint8_t const * xyz, dcp::Size size, int stride);
-
+
}
Signer::sign (xmlpp::Element* parent, Standard standard) const
{
/* <Signer> */
-
+
xmlpp::Element* signer = parent->add_child("Signer");
xmlpp::Element* data = signer->add_child("X509Data", "dsig");
xmlpp::Element* serial_element = data->add_child("X509IssuerSerial", "dsig");
data->add_child("X509SubjectName", "dsig")->add_child_text (_certificates.leaf().subject());
/* <Signature> */
-
+
xmlpp::Element* signature = parent->add_child("Signature", "dsig");
-
+
xmlpp::Element* signed_info = signature->add_child ("SignedInfo", "dsig");
signed_info->add_child("CanonicalizationMethod", "dsig")->set_attribute ("Algorithm", "http://www.w3.org/TR/2001/REC-xml-c14n-20010315");
-
+
if (standard == INTEROP) {
signed_info->add_child("SignatureMethod", "dsig")->set_attribute("Algorithm", "http://www.w3.org/2000/09/xmldsig#rsa-sha1");
} else {
signed_info->add_child("SignatureMethod", "dsig")->set_attribute("Algorithm", "http://www.w3.org/2001/04/xmldsig-more#rsa-sha256");
}
-
+
xmlpp::Element* reference = signed_info->add_child("Reference", "dsig");
reference->set_attribute ("URI", "");
CertificateChain::List c = _certificates.leaf_to_root ();
for (CertificateChain::List::iterator i = c.begin(); i != c.end(); ++i) {
xmlpp::Element* data = key_info->add_child("X509Data", ns);
-
+
{
xmlpp::Element* serial = data->add_child("X509IssuerSerial", ns);
serial->add_child("X509IssuerName", ns)->add_child_text (i->issuer ());
serial->add_child("X509SerialNumber", ns)->add_child_text (i->serial ());
}
-
+
data->add_child("X509Certificate", ns)->add_child_text (i->certificate());
}
signature_context->signKey = xmlSecCryptoAppKeyLoadMemory (
reinterpret_cast<const unsigned char *> (_key.c_str()), _key.size(), xmlSecKeyDataFormatPem, 0, 0, 0
);
-
+
if (signature_context->signKey == 0) {
throw FileError ("could not load private key file", _key, 0);
}
if (!bio) {
throw MiscError ("could not create memory BIO");
}
-
+
RSA* private_key = PEM_read_bio_RSAPrivateKey (bio, 0, 0, 0);
RSA* public_key = _certificates.leaf().public_key ();
bool const valid = !BN_cmp (private_key->n, public_key->n);
std::string intermediate_common_name,
std::string leaf_common_name
);
-
+
/** @param c Certificate chain to sign with.
* @param k Key to sign with as a PEM-format string.
*/
CertificateChain& certificates () {
return _certificates;
}
-
+
std::string key () const {
return _key;
}
}
bool valid () const;
-
-private:
+
+private:
void create (boost::filesystem::path directory);
-
+
/** Certificate chain to sign with */
CertificateChain _certificates;
/** Key to sign with as a PEM-format string */
: LoadFontNode (node->string_attribute ("ID"))
, urn (node->content().substr (9))
{
-
+
}
bool
}
namespace dcp {
-
+
/** @class SMPTELoadFontNode
* @brief Parser for LoadFont nodes from SMPTE subtitle XML.
*/
bool operator== (SMPTELoadFontNode const & a, SMPTELoadFontNode const & b);
bool operator!= (SMPTELoadFontNode const & a, SMPTELoadFontNode const & b);
-
+
}
: _edit_rate (24, 1)
, _time_code_rate (24)
{
-
+
}
/** Construct a SMPTESubtitleAsset by reading an MXF file.
}
/* Read the subtitle XML */
-
+
string s;
reader.ReadTimedTextResource (s, 0, 0);
stringstream t;
t << s;
shared_ptr<cxml::Document> xml (new cxml::Document ("SubtitleReel"));
xml->read_stream (t);
-
+
ASDCP::WriterInfo info;
reader.FillWriterInfo (info);
_id = read_writer_info (info);
BOOST_FOREACH (cxml::NodePtr& i, f) {
font_nodes.push_back (shared_ptr<FontNode> (new FontNode (i, _time_code_rate)));
}
-
+
parse_subtitles (xml, font_nodes);
/* Read fonts */
}
}
}
-
-
+
+
}
list<shared_ptr<LoadFontNode> >
load_font->add_child_text (i->urn);
load_font->set_attribute ("ID", i->id);
}
-
+
subtitles_as_xml (root->add_child ("SubtitleList", "dcst"), _time_code_rate, "dcst");
-
+
return doc.write_to_string_formatted ("UTF-8");
}
{
ASDCP::WriterInfo writer_info;
fill_writer_info (&writer_info, _id, SMPTE);
-
+
ASDCP::TimedText::TimedTextDescriptor descriptor;
descriptor.EditRate = ASDCP::Rational (_edit_rate.numerator, _edit_rate.denominator);
descriptor.EncodingName = "UTF-8";
descriptor.ResourceList.push_back (res);
}
}
-
+
descriptor.NamespaceName = "dcst";
memcpy (descriptor.AssetID, writer_info.AssetUUID, ASDCP::UUIDlen);
descriptor.ContainerDuration = latest_subtitle_out().as_editable_units (_edit_rate.numerator / _edit_rate.denominator);
note (DCP_ERROR, "Subtitle content title texts differ");
return false;
}
-
+
if (_language != other->_language) {
note (DCP_ERROR, "Subtitle languages differ");
return false;
note (DCP_ERROR, "Subtitle annotation texts differ");
return false;
}
-
+
if (_issue_date != other->_issue_date) {
if (options.issue_dates_can_differ) {
note (DCP_NOTE, "Subtitle issue dates differ");
return false;
}
}
-
+
if (_reel_number != other->_reel_number) {
note (DCP_ERROR, "Subtitle reel numbers differ");
return false;
}
-
+
if (_edit_rate != other->_edit_rate) {
note (DCP_ERROR, "Subtitle edit rates differ");
return false;
note (DCP_ERROR, "Subtitle time code rates differ");
return false;
}
-
+
if (_start_time != other->_start_time) {
note (DCP_ERROR, "Subtitle start times differ");
return false;
{
public:
SMPTESubtitleAsset ();
-
+
/** @param file File name
*/
SMPTESubtitleAsset (boost::filesystem::path file);
EqualityOptions,
NoteHandler note
) const;
-
+
std::list<boost::shared_ptr<LoadFontNode> > load_font_nodes () const;
Glib::ustring xml_as_string () const;
boost::optional<Time> start_time () const {
return _start_time;
}
-
+
static bool valid_mxf (boost::filesystem::path);
protected:
-
+
std::string pkl_type (Standard) const {
return "application/mxf";
}
-
+
private:
std::string _content_title_text;
boost::optional<std::string> _language;
Fraction _edit_rate;
int _time_code_rate;
boost::optional<Time> _start_time;
-
+
std::list<boost::shared_ptr<SMPTELoadFontNode> > _load_font_nodes;
};
if (ASDCP_FAILURE (reader_B.FillAudioDescriptor (desc_B))) {
boost::throw_exception (DCPReadError ("could not read audio MXF information"));
}
-
+
if (
desc_A.EditRate != desc_B.EditRate ||
desc_A.AudioSamplingRate != desc_B.AudioSamplingRate ||
desc_A.ContainerDuration != desc_B.ContainerDuration
// desc_A.ChannelFormat != desc_B.ChannelFormat ||
) {
-
+
note (DCP_ERROR, "audio MXF picture descriptors differ");
return false;
}
-
+
ASDCP::PCM::FrameBuffer buffer_A (1 * Kumu::Megabyte);
ASDCP::PCM::FrameBuffer buffer_B (1 * Kumu::Megabyte);
-
+
for (int i = 0; i < _intrinsic_duration; ++i) {
if (ASDCP_FAILURE (reader_A.ReadFrame (i, buffer_A))) {
boost::throw_exception (DCPReadError ("could not read audio frame"));
}
-
+
if (ASDCP_FAILURE (reader_B.ReadFrame (i, buffer_B))) {
boost::throw_exception (DCPReadError ("could not read audio frame"));
}
-
+
if (buffer_A.Size() != buffer_B.Size()) {
note (DCP_ERROR, String::compose ("sizes of audio data for frame %1 differ", i));
return false;
}
-
+
if (memcmp (buffer_A.RoData(), buffer_B.RoData(), buffer_A.Size()) != 0) {
for (uint32_t i = 0; i < buffer_A.Size(); ++i) {
int const d = abs (buffer_A.RoData()[i] - buffer_B.RoData()[i]);
SoundAsset (Fraction edit_rate, int sampling_rate, int channels);
boost::shared_ptr<SoundAssetWriter> start_write (boost::filesystem::path file, Standard standard);
-
+
bool equals (
boost::shared_ptr<const Asset> other,
EqualityOptions opt,
int64_t intrinsic_duration () const {
return _intrinsic_duration;
}
-
+
private:
friend class SoundAssetWriter;
-
+
std::string pkl_type (Standard standard) const;
Fraction _edit_rate;
_state->audio_desc.AvgBps = _sound_asset->sampling_rate() * _state->audio_desc.BlockAlign;
_state->audio_desc.LinkedTrackID = 0;
_state->audio_desc.ChannelFormat = ASDCP::PCM::CF_NONE;
-
+
_state->frame_buffer.Capacity (ASDCP::PCM::CalcFrameBufferSize (_state->audio_desc));
_state->frame_buffer.Size (ASDCP::PCM::CalcFrameBufferSize (_state->audio_desc));
memset (_state->frame_buffer.Data(), 0, _state->frame_buffer.Capacity());
-
+
_sound_asset->fill_writer_info (&_state->writer_info, _sound_asset->id(), standard);
-
+
Kumu::Result_t r = _state->mxf_writer.OpenWrite (file.string().c_str(), _state->writer_info, _state->audio_desc);
if (ASDCP_FAILURE (r)) {
boost::throw_exception (FileError ("could not open audio MXF for writing", file.string(), r));
SoundAssetWriter::write (float const * const * data, int frames)
{
DCP_ASSERT (!_finalized);
-
+
for (int i = 0; i < frames; ++i) {
byte_t* out = _state->frame_buffer.Data() + _frame_buffer_offset;
if (_frame_buffer_offset > 0) {
write_current_frame ();
}
-
+
if (ASDCP_FAILURE (_state->mxf_writer.Finalize())) {
boost::throw_exception (MiscError ("could not finalise audio MXF"));
}
/* do this with an opaque pointer so we don't have to include
ASDCP headers
*/
-
+
struct ASDCPState;
boost::shared_ptr<ASDCPState> _state;
if (ASDCP_FAILURE (r)) {
boost::throw_exception (MXFFileError ("could not open MXF file for reading", file.string(), r));
}
-
+
ASDCP::JP2K::PictureDescriptor desc;
if (ASDCP_FAILURE (reader.FillPictureDescriptor (desc))) {
boost::throw_exception (DCPReadError ("could not read video MXF information"));
if (ASDCP_FAILURE (r)) {
boost::throw_exception (MXFFileError ("could not open MXF file for reading", file().string(), r));
}
-
+
ASDCP::JP2K::MXFSReader reader_B;
r = reader_B.OpenRead (other->file().string().c_str());
if (ASDCP_FAILURE (r)) {
boost::throw_exception (MXFFileError ("could not open MXF file for reading", file().string(), r));
}
-
+
ASDCP::JP2K::PictureDescriptor desc_A;
if (ASDCP_FAILURE (reader_A.FillPictureDescriptor (desc_A))) {
boost::throw_exception (DCPReadError ("could not read video MXF information"));
if (ASDCP_FAILURE (reader_B.FillPictureDescriptor (desc_B))) {
boost::throw_exception (DCPReadError ("could not read video MXF information"));
}
-
+
if (!descriptor_equals (desc_A, desc_B, note)) {
return false;
}
-
+
shared_ptr<const StereoPictureAsset> other_picture = dynamic_pointer_cast<const StereoPictureAsset> (other);
DCP_ASSERT (other_picture);
note (DCP_ERROR, e.what ());
return false;
}
-
+
if (!frame_buffer_equals (
i, opt, note,
frame_A->left_j2k_data(), frame_A->left_j2k_size(),
)) {
return false;
}
-
+
if (!frame_buffer_equals (
i, opt, note,
frame_A->right_j2k_data(), frame_A->right_j2k_size(),
#include "picture_asset.h"
namespace dcp {
-
-/** A 3D (stereoscopic) picture asset */
+
+/** A 3D (stereoscopic) picture asset */
class StereoPictureAsset : public PictureAsset
{
public:
EqualityOptions opt,
NoteHandler note
) const;
-
+
boost::shared_ptr<const StereoPictureFrame> get_frame (int n) const;
};
if (_next_eye == EYE_LEFT) {
++_frames_written;
}
-
+
return FrameInfo (before_offset, _state->mxf_writer.Tell() - before_offset, hash);
}
/* do this with an opaque pointer so we don't have to include
ASDCP headers
*/
-
+
struct ASDCPState;
boost::shared_ptr<ASDCPState> _state;
case RIGHT:
return decompress_j2k (const_cast<uint8_t*> (_buffer->Right.RoData()), _buffer->Right.Size(), reduce);
}
-
+
return shared_ptr<OpenJPEGImage> ();
}
class OpenJPEGImage;
-/** A single frame of a 3D (stereoscopic) picture asset */
+/** A single frame of a 3D (stereoscopic) picture asset */
class StereoPictureFrame : public boost::noncopyable
{
public:
uint8_t const * left_j2k_data () const;
uint8_t* left_j2k_data ();
int left_j2k_size () const;
-
+
uint8_t const * right_j2k_data () const;
uint8_t* right_j2k_data ();
int right_j2k_size () const;
examine_font_nodes (xml, (*j)->font_nodes, parse_state);
parse_state.subtitle_nodes.pop_back ();
}
-
+
examine_font_nodes (xml, (*i)->font_nodes, parse_state);
examine_text_nodes (xml, (*i)->text_nodes, parse_state);
-
+
parse_state.font_nodes.pop_back ();
}
}
if (empty_or_white_space (text)) {
return;
}
-
+
if (parse_state.text_nodes.empty() || parse_state.subtitle_nodes.empty ()) {
return;
}
DCP_ASSERT (!parse_state.text_nodes.empty ());
DCP_ASSERT (!parse_state.subtitle_nodes.empty ());
-
+
dcp::FontNode effective_font (parse_state.font_nodes);
dcp::TextNode effective_text (*parse_state.text_nodes.back ());
dcp::SubtitleNode effective_subtitle (*parse_state.subtitle_nodes.back ());
if (!Asset::equals (other_asset, options, note)) {
return false;
}
-
+
shared_ptr<const SubtitleAsset> other = dynamic_pointer_cast<const SubtitleAsset> (other_asset);
if (!other) {
return false;
if (i->h_position() > ALIGN_EPSILON) {
text->set_attribute ("HPosition", raw_convert<string> (i->h_position() * 100, 6));
}
- text->set_attribute ("VAlign", valign_to_string (i->v_align()));
+ text->set_attribute ("VAlign", valign_to_string (i->v_align()));
text->set_attribute ("VPosition", raw_convert<string> (i->v_position() * 100, 6));
text->add_child_text (i->text());
}
shared_array<uint8_t> data (new uint8_t[size]);
size_t const read = fread (data.get(), 1, size, f);
fclose (f);
-
+
if (read != size) {
throw FileError ("could not read font file", file, -1);
}
namespace dcp
{
-class SubtitleString;
+class SubtitleString;
class FontNode;
class TextNode;
class SubtitleNode;
protected:
friend struct ::interop_dcp_font_test;
friend struct ::smpte_dcp_font_test;
-
+
void parse_subtitles (boost::shared_ptr<cxml::Document> xml, std::list<boost::shared_ptr<FontNode> > font_nodes);
void subtitles_as_xml (xmlpp::Element* root, int time_code_rate, std::string xmlns) const;
void add_font_data (std::string id, boost::filesystem::path file);
class FileData : public Data {
public:
FileData () {}
-
+
FileData (boost::shared_array<uint8_t> data_, boost::uintmax_t size_)
: Data (data_, size_)
{}
-
+
/** .ttf file that this data was last written to */
mutable boost::optional<boost::filesystem::path> file;
};
* For SMPTE, the string is the font's URN from the subtitle file.
*/
std::map<std::string, FileData> _fonts;
-
+
private:
/** @struct ParseState
* @brief A struct to hold state when parsing a subtitle XML file.
};
void maybe_add_subtitle (std::string text, ParseState const & parse_state);
-
+
void examine_font_nodes (
boost::shared_ptr<const cxml::Node> xml,
std::list<boost::shared_ptr<FontNode> > const & font_nodes,
ParseState& parse_state
);
-
+
void examine_text_nodes (
boost::shared_ptr<const cxml::Node> xml,
std::list<boost::shared_ptr<TextNode> > const & text_nodes,
for (list<cxml::NodePtr>::iterator i = t.begin(); i != t.end(); ++i) {
text_nodes.push_back (shared_ptr<TextNode> (new TextNode (*i, tcr)));
}
-
+
fade_up_time = fade_time (node, "FadeUpTime", tcr);
fade_down_time = fade_time (node, "FadeDownTime", tcr);
}
{
string const u = node->optional_string_attribute (name).get_value_or ("");
Time t;
-
+
if (u.empty ()) {
t = Time (0, 0, 0, 20, 250);
} else if (u.find (":") != string::npos) {
namespace dcp {
-class FontNode;
+class FontNode;
class TextNode;
class SubtitleNode
height is 11 inches, so a 72pt font would be 1/11th of the screen
height.
*/
-
+
return _size * screen_height / (11 * 72);
}
} else {
s << "non-italic";
}
-
+
s << ", size " << sub.size() << ", aspect " << sub.aspect_adjust() << ", colour " << sub.colour()
<< ", vpos " << sub.v_position() << ", valign " << ((int) sub.v_align())
<< ", hpos " << sub.h_position() << ", halign " << ((int) sub.h_align())
Colour _colour;
/** Size in points as if the screen height is 11 inches, so a 72pt font
* would be 1/11th of the screen height.
- */
+ */
int _size;
float _aspect_adjust;
Time _in;
if (hp) {
h_position = hp.get () / 100;
}
-
+
optional<string> ha = node->optional_string_attribute ("HAlign");
if (!ha) {
ha = node->optional_string_attribute ("Halign");
if (ha) {
h_align = string_to_halign (ha.get ());
}
-
+
optional<float> vp = node->optional_number_attribute<float> ("VPosition");
if (!vp) {
vp = node->optional_number_attribute<float> ("Vposition");
if (vp) {
v_position = vp.get () / 100;
}
-
+
optional<string> va = node->optional_string_attribute ("VAlign");
if (!va) {
va = node->optional_string_attribute ("Valign");
, v_position (0)
, v_align (VALIGN_TOP)
{}
-
+
TextNode (boost::shared_ptr<const cxml::Node> node, int tcr);
float h_position;
TransferFunction::lut (int bit_depth, bool inverse) const
{
boost::mutex::scoped_lock lm (_mutex);
-
+
map<pair<int, bool>, double*>::const_iterator i = _luts.find (make_pair (bit_depth, inverse));
if (i != _luts.end ()) {
return i->second;
} else if (s == "right") {
return HALIGN_RIGHT;
}
-
+
boost::throw_exception (DCPReadError ("unknown subtitle halign type"));
}
} else if (s == "bottom") {
return VALIGN_BOTTOM;
}
-
+
boost::throw_exception (DCPReadError ("unknown subtitle valign type"));
}
float ratio () const {
return float (width) / height;
}
-
+
int width;
int height;
};
extern bool operator== (Fraction const & a, Fraction const & b);
extern bool operator!= (Fraction const & a, Fraction const & b);
-extern std::ostream& operator<< (std::ostream& s, Fraction const & f);
+extern std::ostream& operator<< (std::ostream& s, Fraction const & f);
/** @struct EqualityOptions
* @brief A class to describe what "equality" means for a particular test.
struct EqualityOptions
{
/** Construct an EqualityOptions where nothing at all can differ */
- EqualityOptions ()
+ EqualityOptions ()
: max_mean_pixel_error (0)
, max_std_dev_pixel_error (0)
, max_audio_sample_error (0)
if (ASDCP_FAILURE (r)) {
boost::throw_exception (FileError ("could not open file to compute digest", filename, r));
}
-
+
SHA_CTX sha;
SHA1_Init (&sha);
while (1) {
ui32_t read = 0;
Kumu::Result_t r = reader.Read (read_buffer.Data(), read_buffer.Capacity(), &read);
-
+
if (r == Kumu::RESULT_ENDOFFILE) {
break;
} else if (ASDCP_FAILURE (r)) {
boost::throw_exception (FileError ("could not read file to compute digest", filename, r));
}
-
+
SHA1_Update (&sha, read_buffer.Data(), read);
if (progress) {
dcp::content_kind_from_string (string kind)
{
transform (kind.begin(), kind.end(), kind.begin(), ::tolower);
-
+
if (kind == "feature") {
return FEATURE;
} else if (kind == "short") {
0x20,
0x20
};
-
+
OPJ_CODEC_FORMAT format = CODEC_J2K;
if (size >= int (sizeof (jp2_magic)) && memcmp (data, jp2_magic, sizeof (jp2_magic)) == 0) {
format = CODEC_JP2;
}
-
+
opj_dinfo_t* decoder = opj_create_decompress (format);
if (!decoder) {
boost::throw_exception (DCPReadError ("could not create JPEG2000 decompresser"));
if (xmlSecCryptoDLLoadLibrary(BAD_CAST XMLSEC_CRYPTO) < 0) {
throw MiscError ("unable to load default xmlsec-crypto library");
}
-#endif
+#endif
if (xmlSecCryptoAppInit(0) < 0) {
throw MiscError ("could not initialise crypto");
*p++ = in[i];
}
}
-
+
BIO* bmem = BIO_new_mem_buf (in_buffer, p - in_buffer);
bmem = BIO_push (b64, bmem);
int const N = BIO_read (bmem, out, out_length);
if (len > max_length) {
throw MiscError ("Unexpectedly long file");
}
-
+
char* c = new char[len + 1];
-
+
FILE* f = fopen_boost (p, "r");
if (!f) {
return "";
class CertificateChain;
class GammaLUT;
class OpenJPEGImage;
-
+
extern bool operator== (Size const & a, Size const & b);
extern bool operator!= (Size const & a, Size const & b);
extern std::ostream& operator<< (std::ostream& s, Size const & a);
return out;
}
-
+
}
#endif
extern char const * version;
extern char const * git_commit;
extern bool built_with_debug;
-
+
}
boost::shared_ptr<T> type_child (boost::shared_ptr<const cxml::Node> node, std::string name) {
return boost::shared_ptr<T> (new T (node->node_child (name)));
}
-
+
template <class T>
boost::shared_ptr<T>
optional_type_child (boost::shared_ptr<const cxml::Node> node, std::string name)
{
return type_children<T> (*node.get(), name);
}
-
+
template <class T>
std::list<boost::shared_ptr<T> >
type_grand_children (cxml::Node const & node, std::string name, std::string sub)
{
return type_grand_children<T> (*node.get(), name, sub);
}
-
+
}
#endif
/* Leaf */
BOOST_CHECK_EQUAL (*i, c.leaf ());
-
+
BOOST_CHECK_EQUAL (
c.leaf().issuer(),
"dnQualifier=6eat8r33US71avuQEojmH\\+bjk84=,CN=.smpte-430-2.INTERMEDIATE.NOT_FOR_PRODUCTION,OU=example.org,O=example.org"
c.leaf().subject(),
"dnQualifier=QFVlym7fuql6bPOnY38aaO1ZPW4=,CN=CS.smpte-430-2.LEAF.NOT_FOR_PRODUCTION,OU=example.org,O=example.org"
);
-
+
++i;
/* Intermediate */
i->subject(),
"dnQualifier=6eat8r33US71avuQEojmH\\+bjk84=,CN=.smpte-430-2.INTERMEDIATE.NOT_FOR_PRODUCTION,OU=example.org,O=example.org"
);
-
+
++i;
/* Root */
dcp::CertificateChain good2;
good2.add (dcp::Certificate (dcp::file_to_string ("test/ref/crypt/ca.self-signed.pem")));
BOOST_CHECK (good2.valid ());
-
+
dcp::CertificateChain bad1;
bad1.add (dcp::Certificate (dcp::file_to_string ("test/ref/crypt/intermediate.signed.pem")));
bad1.add (dcp::Certificate (dcp::file_to_string ("test/ref/crypt/leaf.signed.pem")));
BOOST_CHECK_EQUAL (z.g, 0);
BOOST_CHECK_EQUAL (z.b, 0);
BOOST_CHECK_EQUAL (z.to_argb_string(), "FF000000");
-
+
dcp::Colour c ("FFFF0000");
BOOST_CHECK_EQUAL (c.r, 255);
xmlpp::Document doc;
xmlpp::Element* el = doc.create_root_node ("Test");
pa->write_to_cpl (el, dcp::INTEROP);
-
+
cxml::Node node (el);
BOOST_CHECK_EQUAL (node.node_child("MainPicture")->string_child ("ScreenAspectRatio"), "1.85");
}
xmlpp::Document doc;
xmlpp::Element* el = doc.create_root_node ("Test");
pa->write_to_cpl (el, dcp::INTEROP);
-
+
cxml::Node node (el);
BOOST_CHECK_EQUAL (node.node_child("MainPicture")->string_child ("ScreenAspectRatio"), "2.39");
}
break;
}
}
-
+
sound_writer->finalize ();
-
+
cpl->add (shared_ptr<dcp::Reel> (
new dcp::Reel (
shared_ptr<dcp::ReelMonoPictureAsset> (new dcp::ReelMonoPictureAsset (mp, 0)),
shared_ptr<dcp::ReelSubtitleAsset> ()
)
));
-
+
d.add (cpl);
d.write_xml (dcp::SMPTE, xml_meta);
break;
}
}
-
+
sound_writer->finalize ();
-
+
cpl->add (shared_ptr<dcp::Reel> (
new dcp::Reel (
shared_ptr<dcp::ReelStereoPictureAsset> (new dcp::ReelStereoPictureAsset (mp, 0)),
shared_ptr<dcp::ReelSubtitleAsset> ()
)
));
-
+
d.add (cpl);
d.write_xml (dcp::SMPTE, xml_meta);
A.read ();
dcp::DCP B ("test/ref/DCP/dcp_test1");
B.read ();
-
+
BOOST_CHECK (A.equals (B, dcp::EqualityOptions(), boost::bind (¬e, _1, _2)));
}
A.read ();
dcp::DCP B ("test/ref/DCP/dcp_test2");
B.read ();
-
+
BOOST_CHECK (!A.equals (B, dcp::EqualityOptions(), boost::bind (¬e, _1, _2)));
}
),
dcp::file_to_string ("test/data/private.key")
);
-
+
encrypted.add (kdm);
pair<uint8_t *, dcp::Size> plaintext_frame = get_frame (plaintext);
/* Check that plaintext and encrypted are the same */
BOOST_CHECK_EQUAL (plaintext_frame.second, encrypted_frame.second);
-
+
BOOST_CHECK_EQUAL (
memcmp (
plaintext_frame.first,
{
boost::filesystem::remove_all ("build/test/signer");
boost::filesystem::create_directory ("build/test/signer");
-
+
Kumu::libdcp_test = true;
dcp::MXFMetadata mxf_metadata;
xml_metadata.issuer = "OpenDCP 0.0.25";
xml_metadata.creator = "OpenDCP 0.0.25";
xml_metadata.issue_date = "2012-07-17T04:45:18+00:00";
-
+
boost::filesystem::remove_all ("build/test/DCP/encryption_test");
boost::filesystem::create_directories ("build/test/DCP/encryption_test");
dcp::DCP d ("build/test/DCP/encryption_test");
shared_ptr<dcp::CPL> cpl (new dcp::CPL ("A Test DCP", dcp::FEATURE));
dcp::Key key;
-
+
shared_ptr<dcp::MonoPictureAsset> mp (new dcp::MonoPictureAsset (dcp::Fraction (24, 1)));
mp->set_metadata (mxf_metadata);
mp->set_key (key);
ms->set_metadata (mxf_metadata);
ms->set_key (key);
shared_ptr<dcp::SoundAssetWriter> sound_writer = ms->start_write ("build/test/DCP/encryption_test/audio.mxf", dcp::SMPTE);
-
+
SF_INFO info;
info.format = 0;
SNDFILE* sndfile = sf_open ("test/data/1s_24-bit_48k_silence.wav", SFM_READ, &info);
break;
}
}
-
- sound_writer->finalize ();
+
+ sound_writer->finalize ();
cpl->add (shared_ptr<dcp::Reel> (new dcp::Reel (
shared_ptr<dcp::ReelMonoPictureAsset> (new dcp::ReelMonoPictureAsset (mp, 0)),
cpl->set_content_version_id ("urn:uri:81fb54df-e1bf-4647-8788-ea7ba154375b_2012-07-17T04:45:18+00:00");
cpl->set_content_version_label_text ("81fb54df-e1bf-4647-8788-ea7ba154375b_2012-07-17T04:45:18+00:00");
cpl->set_metadata (xml_metadata);
-
+
d.add (cpl);
d.write_xml (dcp::SMPTE, xml_metadata, signer);
);
kdm.encrypt (signer, signer->certificates().leaf(), dcp::MODIFIED_TRANSITIONAL_1).as_xml ("build/test/encryption_test.kdm.xml");
-
+
int r = system (
"xmllint --path schema --nonet --noout --schema schema/SMPTE-430-1-2006-Amd-1-2009-KDM.xsd build/test/encryption_test.kdm.xml "
"> build/test/xmllint.log 2>&1 < /dev/null"
);
-#ifdef LIBDCP_POSIX
+#ifdef LIBDCP_POSIX
BOOST_CHECK_EQUAL (WEXITSTATUS (r), 0);
#else
BOOST_CHECK_EQUAL (r, 0);
-#endif
-
+#endif
+
r = system ("xmlsec1 verify "
"--pubkey-cert-pem test/ref/crypt/leaf.signed.pem "
"--trusted-pem test/ref/crypt/intermediate.signed.pem "
"--id-attr:Id http://www.smpte-ra.org/schemas/430-3/2006/ETM:AuthenticatedPublic "
"--id-attr:Id http://www.smpte-ra.org/schemas/430-3/2006/ETM:AuthenticatedPrivate "
"build/test/encryption_test.kdm.xml > build/test/xmlsec1.log 2>&1 < /dev/null");
-
-#ifdef LIBDCP_POSIX
+
+#ifdef LIBDCP_POSIX
BOOST_CHECK_EQUAL (WEXITSTATUS (r), 0);
#else
BOOST_CHECK_EQUAL (r, 0);
-#endif
+#endif
}
);
list<dcp::DecryptedKDMKey> keys = kdm.keys ();
-
+
BOOST_CHECK_EQUAL (keys.size(), 2);
BOOST_CHECK_EQUAL (keys.front().cpl_id(), "eece17de-77e8-4a55-9347-b6bab5724b9f");
"xmldiff -c test/data/kdm_TONEPLATES-SMPTE-ENC_.smpte-430-2.ROOT.NOT_FOR_PRODUCTION_20130706_20230702_CAR_OV_t1_8971c838.xml build/kdm.xml"
);
-#ifdef LIBDCP_WINDOWS
+#ifdef LIBDCP_WINDOWS
BOOST_CHECK_EQUAL (r, 0);
-#else
+#else
BOOST_CHECK_EQUAL (WEXITSTATUS (r), 0);
-#endif
+#endif
}
BOOST_CHECK_THROW (dcp::LocalTime ("2013!01-05T18:06:59+04:00"), dcp::TimeFormatError);
/* Correctly-formatted */
-
+
{
dcp::LocalTime t ("2013-01-05T18:06:59+04:00");
BOOST_CHECK_EQUAL (t._year, 2013);
dcp::Time (0, 0, 0, 1, 250),
dcp::Time (0, 0, 0, 1, 250)
));
-
+
s = subs.subtitles_during (dcp::Time (0, 0, 7, 190, 250), dcp::Time (0, 0, 7, 191, 250));
BOOST_REQUIRE_EQUAL (s.size(), 2);
BOOST_CHECK_EQUAL (s.front(), dcp::SubtitleString (
#ifdef LIBDCP_POSIX
/* XXX: fix this posix-only stuff */
Kumu::ResetTestRNG ();
-#endif
-
+#endif
+
boost::filesystem::remove_all ("build/test/baz");
boost::filesystem::create_directories ("build/test/baz");
shared_ptr<dcp::MonoPictureAsset> mp (new dcp::MonoPictureAsset (dcp::Fraction (24, 1)));
fclose (f);
}
-#ifdef LIBDCP_POSIX
+#ifdef LIBDCP_POSIX
Kumu::ResetTestRNG ();
-#endif
+#endif
mp.reset (new dcp::MonoPictureAsset (dcp::Fraction (24, 1)));
writer = mp->start_write ("build/test/baz/video2.mxf", dcp::SMPTE, true);
for (int i = 4; i < 24; ++i) {
writer->write (data, size);
}
-
+
writer->finalize ();
}
cerr << "Syntax: " << argv[0] << " <dcp>\n";
exit (EXIT_FAILURE);
}
-
+
DCP* dcp = new DCP (argv[1]);
dcp->read (true);
-
+
list<shared_ptr<CPL> > cpls = dcp->cpls ();
for (list<boost::shared_ptr<CPL> >::iterator i = cpls.begin(); i != cpls.end(); ++i) {
-
+
list<shared_ptr<Reel> > reels = (*i)->reels ();
for (list<shared_ptr<Reel> >::iterator j = reels.begin(); j != reels.end(); ++j) {
-
+
if ((*j)->main_subtitle()) {
(*j)->main_subtitle()->subtitle_asset()->write ((*j)->main_subtitle()->subtitle_asset()->file ());
}
cerr << e.what() << " when reading " << argv[1] << "\n";
exit (EXIT_FAILURE);
}
-
+
return 0;
}
BOOST_AUTO_TEST_CASE (xyz_rgb_range_test)
{
shared_ptr<dcp::OpenJPEGImage> xyz (new dcp::OpenJPEGImage (dcp::Size (2, 2)));
-
+
xyz->data(0)[0] = -4;
xyz->data(0)[1] = 6901;
xyz->data(0)[2] = 0;
scoped_array<uint8_t> back (new uint8_t[size.width * size.height * 6]);
dcp::xyz_to_rgb (xyz, dcp::ColourConversion::srgb_to_xyz (), back.get(), size.width * 6);
-#if 0
+#if 0
uint16_t* p = reinterpret_cast<uint16_t*> (rgb.get ());
uint16_t* q = reinterpret_cast<uint16_t*> (back.get ());
for (int i = 0; i < (size.width * size.height); ++i) {
/* XXX: doesn't quite work */
// BOOST_REQUIRE_EQUAL (*p++, *q++);
}
-#endif
+#endif
}
scoped_array<uint8_t> frame_A (new uint8_t[xyz_A->size().width * xyz_A->size().height * 4]);
dcp::xyz_to_rgba (xyz_A, dcp::ColourConversion::srgb_to_xyz(), frame_A.get());
-
+
scoped_array<uint8_t> frame_B (new uint8_t[xyz_B->size().width * xyz_B->size().height * 4]);
dcp::xyz_to_rgba (xyz_B, dcp::ColourConversion::srgb_to_xyz(), frame_B.get());
BOOST_CHECK (ref_file);
FILE* check_file = dcp::fopen_boost (check, "rb");
BOOST_CHECK (check_file);
-
+
int const buffer_size = 65536;
uint8_t* ref_buffer = new uint8_t[buffer_size];
uint8_t* check_buffer = new uint8_t[buffer_size];
stringstream error;
error << "File " << check.string() << " differs from reference " << ref.string();
-
+
while (N) {
uintmax_t this_time = min (uintmax_t (buffer_size), N);
size_t r = fread (ref_buffer, 1, this_time, ref_file);
if (memcmp (ref_buffer, check_buffer, this_time)) {
break;
}
-
+
N -= this_time;
}
BOOST_AUTO_TEST_CASE (base64_decode_test)
{
int const N = 256;
-
+
ifstream f ("test/data/base64_test");
BOOST_CHECK (f.good ());
string s;
{
boost::filesystem::path root = "a";
root /= "b";
-
+
boost::filesystem::path file = "a";
file /= "b";
file /= "c";
-
+
boost::optional<boost::filesystem::path> rel = dcp::relative_to_root (root, file);
BOOST_CHECK (rel);
BOOST_CHECK_EQUAL (rel.get(), boost::filesystem::path ("c"));
boost::filesystem::path root = "a";
root /= "b";
root /= "c";
-
+
boost::filesystem::path file = "a";
file /= "b";
-
+
boost::optional<boost::filesystem::path> rel = dcp::relative_to_root (root, file);
BOOST_CHECK (!rel);
}
{
boost::filesystem::path root = "a";
-
+
boost::filesystem::path file = "a";
file /= "b";
file /= "c";
-
+
boost::optional<boost::filesystem::path> rel = dcp::relative_to_root (root, file);
BOOST_CHECK (rel);
dcp::Time (5, 6, 7, 8, 24)
)
);
-
+
c._id = "a6c58cff-3e1e-4b38-acec-a42224475ef6";
check_xml (
DCP::ReadErrors::iterator tmp = i;
++tmp;
-
+
if (ignore_missing_assets && dynamic_pointer_cast<MissingAssetError> (*i)) {
errors.erase (i);
}
bool keep_going = false;
bool ignore_missing_assets = false;
optional<string> key;
-
+
int option_index = 0;
while (1) {
static struct option long_options[] = {
main (int argc, char* argv[])
{
bool extract_fonts = true;
-
+
int option_index = 0;
while (1) {
static struct option long_options[] = {
if (!reel->main_subtitle()) {
return;
}
-
+
list<SubtitleString> subs = reel->main_subtitle()->subtitle_asset()->subtitles ();
cout << " Subtitle: " << subs.size() << " subtitles";
shared_ptr<InteropSubtitleAsset> iop = dynamic_pointer_cast<InteropSubtitleAsset> (reel->main_subtitle()->subtitle_asset());
bool subtitles = false;
bool keep_going = false;
bool ignore_missing_assets = false;
-
+
int option_index = 0;
while (1) {
static struct option long_options[] = {
cerr << "Could not read DCP " << argv[optind] << "; " << e.what() << "\n";
exit (EXIT_FAILURE);
}
-
+
cout << "DCP: " << boost::filesystem::path(argv[optind]).filename().string() << "\n";
dcp::filter_errors (errors, ignore_missing_assets);
for (list<shared_ptr<CPL> >::iterator i = cpls.begin(); i != cpls.end(); ++i) {
cout << " CPL: " << (*i)->annotation_text() << "\n";
-
+
list<shared_ptr<Reel> > reels = (*i)->reels ();
int R = 1;