note (ERROR, "asset edit rates differ");
return false;
}
-
+
if (_intrinsic_duration != other->_intrinsic_duration) {
note (ERROR, "asset intrinsic durations differ");
}
int duration () const {
return _duration;
}
-
+
int intrinsic_duration () const {
return _intrinsic_duration;
}
-
+
int edit_rate () const {
return _edit_rate;
}
void set_entry_point (int e) {
_entry_point = e;
}
-
+
void set_duration (int d) {
_duration = d;
}
/** @return Interop PKL asdcpKind for the <Type> tag e.g. Picture, Sound etc. */
virtual std::string asdcp_kind () const = 0;
-
+
std::string digest () const;
/** Directory that our MXF or XML file is in */
/** Length to present in frames */
int _duration;
-private:
+private:
/** Digest of our MXF or XML file */
mutable std::string _digest;
};
: _certificate (c)
, _public_key (0)
{
-
+
}
Certificate::Certificate (boost::filesystem::path filename)
if (!f) {
throw FileError ("could not open file", filename, errno);
}
-
+
if (!PEM_read_X509 (f, &_certificate, 0, 0)) {
throw MiscError ("could not read X509 certificate");
}
_certificate = 0;
RSA_free (_public_key);
_public_key = 0;
-
+
read_string (other.certificate ());
return *this;
Certificate::certificate (bool with_begin_end) const
{
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;
}
ASN1_INTEGER* s = X509_get_serialNumber (_certificate);
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
{
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);
extern double const rec601_to_xyz[3][3];
extern double const rec709_to_xyz[3][3];
-}
+}
}
} catch (FileError& e) {
boost::throw_exception (FileError ("could not load CPL file", file, e.number ()));
}
-
+
/* Now cherry-pick the required bits into our own data structure */
-
+
_name = cpl->annotation_text;
_content_kind = cpl->content_kind;
} else {
p = (*i)->asset_list->main_stereoscopic_picture;
}
-
+
_fps = p->edit_rate.numerator;
_length += p->duration;
throw;
}
}
-
+
} else {
try {
pair<string, shared_ptr<const parse::AssetMapAsset> > asset = asset_from_id (asset_maps, p->id);
/* Trim urn:uuid: */
picture->set_key_id (p->key_id.substr (9));
}
-
+
} catch (MXFFileError) {
if (require_mxfs) {
throw;
}
}
-
+
}
-
+
if ((*i)->asset_list->main_sound) {
-
+
try {
pair<string, shared_ptr<const parse::AssetMapAsset> > asset = asset_from_id (asset_maps, (*i)->asset_list->main_sound->id);
-
+
sound.reset (new SoundAsset (asset.first, asset.second->chunks.front()->path));
shared_ptr<parse::MainSound> s = (*i)->asset_list->main_sound;
}
if ((*i)->asset_list->main_subtitle) {
-
+
pair<string, shared_ptr<const parse::AssetMapAsset> > asset = asset_from_id (asset_maps, (*i)->asset_list->main_subtitle->id);
subtitle.reset (new SubtitleAsset (asset.first, asset.second->chunks.front()->path));
subtitle->set_edit_rate (_fps);
subtitle->set_duration ((*i)->asset_list->main_subtitle->duration);
}
-
+
_reels.push_back (shared_ptr<Reel> (new Reel (picture, sound, subtitle)));
}
}
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 (_name);
root->add_child("IssueDate")->add_child_text (metadata.issue_date);
root->add_child("RatingList");
xmlpp::Element* reel_list = root->add_child ("ReelList");
-
+
for (list<shared_ptr<Reel> >::const_iterator i = _reels.begin(); i != _reels.end(); ++i) {
(*i)->write_to_cpl (reel_list);
}
chunk->add_child("Offset")->add_child_text("0");
chunk->add_child("Length")->add_child_text (raw_convert<string> (_length));
}
-
-
-
+
+
+
bool
CPL::equals (CPL const & other, EqualityOptions opt, boost::function<void (NoteType, string)> note) const
{
note (ERROR, String::compose ("reel counts differ (%1 vs %2)", _reels.size(), other._reels.size()));
return false;
}
-
+
list<shared_ptr<Reel> >::const_iterator a = _reels.begin ();
list<shared_ptr<Reel> >::const_iterator b = other._reels.begin ();
-
+
while (a != _reels.end ()) {
if (!(*a)->equals (*b, opt, note)) {
return false;
class AssetMap;
class AssetMapAsset;
}
-
+
class Asset;
class Reel;
class XMLMetadata;
class MXFMetadata;
class Signer;
class KDM;
-
+
/** @brief A CPL within a DCP */
class CPL
{
CPL (boost::filesystem::path, std::string file, std::list<PathAssetMap> asset_maps, bool require_mxfs = true);
void add_reel (boost::shared_ptr<Reel> reel);
-
+
/** @return the length in frames */
int length () const {
return _length;
}
boost::filesystem::path filename () const;
-
+
bool equals (CPL const & other, EqualityOptions options, boost::function<void (NoteType, std::string)> note) const;
-
+
void write_xml (bool, XMLMetadata const &, boost::shared_ptr<const Signer>) const;
void write_to_assetmap (xmlpp::Node *) const;
void write_to_pkl (xmlpp::Node *, bool) const;
void add_kdm (KDM const &);
-
+
private:
std::pair<std::string, boost::shared_ptr<const parse::AssetMapAsset> > asset_from_id (std::list<PathAssetMap>, std::string id) const;
-
+
boost::filesystem::path _directory;
/** the name of the DCP */
std::string _name;
string pkl_uuid = make_uuid ();
string pkl_path = write_pkl (pkl_uuid, interop, metadata, signer);
-
+
write_volindex (interop);
write_assetmap (pkl_uuid, boost::filesystem::file_size (pkl_path), interop, metadata);
}
DCP::write_pkl (string pkl_uuid, bool interop, XMLMetadata const & metadata, shared_ptr<const Signer> signer) const
{
assert (!_cpls.empty ());
-
+
boost::filesystem::path p;
p /= _directory;
stringstream s;
} else {
pkl = doc.create_root_node("PackingList", "http://www.smpte-ra.org/schemas/429-8/2007/PKL");
}
-
+
if (signer) {
pkl->set_namespace_declaration ("http://www.w3.org/2000/09/xmldsig#", "dsig");
}
for (list<shared_ptr<const Asset> >::const_iterator i = a.begin(); i != a.end(); ++i) {
(*i)->write_to_pkl (asset_list, interop);
}
-
+
for (list<shared_ptr<CPL> >::const_iterator i = _cpls.begin(); i != _cpls.end(); ++i) {
(*i)->write_to_pkl (asset_list, interop);
}
if (signer) {
signer->sign (pkl, interop);
}
-
+
doc.write_to_file (p.string (), "UTF-8");
return p.string ();
}
root->add_child("IssueDate")->add_child_text (metadata.issue_date);
root->add_child("Issuer")->add_child_text (metadata.issuer);
}
-
+
xmlpp::Node* asset_list = root->add_child ("AssetList");
xmlpp::Node* asset = asset_list->add_child ("Asset");
chunk->add_child("VolumeIndex")->add_child_text ("1");
chunk->add_child("Offset")->add_child_text ("0");
chunk->add_child("Length")->add_child_text (raw_convert<string> (pkl_length));
-
+
for (list<shared_ptr<CPL> >::const_iterator i = _cpls.begin(); i != _cpls.end(); ++i) {
(*i)->write_to_assetmap (asset_list);
}
boost::throw_exception (FileError ("could not find AssetMap file", p, -1));
}
}
-
+
} catch (FileError& e) {
boost::throw_exception (FileError ("could not load AssetMap file", e.filename(), e.number ()));
}
boost::filesystem::path t = _directory;
t /= (*i)->chunks.front()->path;
-
+
if (boost::algorithm::ends_with (t.string(), ".mxf") || boost::algorithm::ends_with (t.string(), ".ttf")) {
continue;
}
}
}
}
-
+
if (_files.cpls.empty ()) {
boost::throw_exception (DCPReadError ("no CPL files found"));
}
DCP::add_kdm (KDM const & kdm)
{
list<KDMKey> keys = kdm.keys ();
-
+
for (list<shared_ptr<CPL> >::iterator i = _cpls.begin(); i != _cpls.end(); ++i) {
for (list<KDMKey>::iterator j = keys.begin(); j != keys.end(); ++j) {
if (j->cpl_id() == (*i)->id()) {
(*i)->add_kdm (kdm);
- }
+ }
}
}
}
namespace libdcp
{
-class Asset;
+class Asset;
class PictureAsset;
class SoundAsset;
class SubtitleAsset;
/** @class DCP
* @brief A class to create or read a DCP.
*/
-
+
class DCP : public boost::noncopyable
{
public:
* @param pkl_uuid UUID to use.
*/
std::string write_pkl (std::string pkl_uuid, bool, XMLMetadata const &, boost::shared_ptr<const Signer>) const;
-
+
/** Write the VOLINDEX file */
void write_volindex (bool) const;
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 += a.tcr;
/** @class Time
* @brief A representation of time within a DCP.
*/
-
+
class Time
{
public:
, e (e_)
, tcr (tcr_)
{}
-
+
Time (std::string time, int tcr_);
-
+
int h; ///< hours
int m; ///< minutes
int s; ///< seconds
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);
: FileError (message, filename, number)
{}
};
-
+
/** @brief A miscellaneous exception */
class MiscError : public StringError
{
MiscError (std::string const & message)
: StringError (message)
{}
-
+
~MiscError () throw () {}
};
DCPReadError (std::string const & message)
: StringError (message)
{}
-
+
~DCPReadError () throw () {}
};
NotEncryptedError (std::string const & asset);
~NotEncryptedError () throw () {}
};
-
+
}
#endif
Image (Size);
Image (Image const &);
Image (boost::shared_ptr<const Image>);
-
+
virtual ~Image () {}
virtual uint8_t** data () const = 0;
virtual int* stride () const = 0;
protected:
void swap (Image &);
-
+
Size _size;
};
: _xml_kdm (new xml::DCinemaSecurityMessage (kdm))
{
/* Read the private key */
-
+
FILE* private_key_file = fopen_boost (private_key, "r");
if (!private_key_file) {
throw FileError ("could not find RSA private key file", private_key, errno);
}
-
+
RSA* rsa = PEM_read_RSAPrivateKey (private_key_file, 0, 0, 0);
- fclose (private_key_file);
+ fclose (private_key_file);
if (!rsa) {
throw FileError ("could not read RSA private key file", private_key, errno);
}
*/
parse::CPL cpl (cpl_file);
-
+
xml::AuthenticatedPublic& apu = _xml_kdm->authenticated_public;
/* AuthenticatedPublic */
if ((*i)->asset_list->main_picture->key_id.empty ()) {
throw NotEncryptedError ("MainPicture");
}
-
+
KDMKey kkey (
signer, cpl.id.substr (9), "MDIK", (*i)->asset_list->main_picture->key_id.substr (9),
not_valid_before, not_valid_after, key
_keys.push_back (kkey);
_xml_kdm->authenticated_private.encrypted_keys.push_back (kkey.encrypted_base64 (recipient_cert));
}
-
+
if ((*i)->asset_list->main_sound) {
if ((*i)->asset_list->main_sound->key_id.empty ()) {
throw NotEncryptedError ("MainSound");
}
-
+
KDMKey kkey (
signer, cpl.id.substr (9), "MDAK", (*i)->asset_list->main_sound->key_id.substr (9),
not_valid_before, not_valid_after, key
);
-
+
_keys.push_back (kkey);
_xml_kdm->authenticated_private.encrypted_keys.push_back (kkey.encrypted_base64 (recipient_cert));
}
return *this;
}
-
+
void
KDM::as_xml (boost::filesystem::path path) const
{
assert (_key_type.length() == 4);
assert (_not_valid_before.length() == 25);
assert (_not_valid_after.length() == 25);
-
+
/* XXX: SMPTE only */
uint8_t block[138];
uint8_t* p = block;
KDMKey::get_uuid (unsigned char const ** p) const
{
stringstream g;
-
+
for (int i = 0; i < 16; ++i) {
g << setw(2) << setfill('0') << hex << static_cast<int> (**p);
(*p)++;
boost::posix_time::ptime until,
Key key
);
-
+
KDMKey (KDMKey const &);
KDMKey& operator= (KDMKey const &);
std::string cpl_id () const {
return _cpl_id;
}
-
+
/** @return ID of the key */
std::string key_id () const {
return _key_id;
* @return The data block encrypted with a certificate's public key and converted to base 64.
*/
std::string encrypted_base64 (boost::shared_ptr<const Certificate> cert) const;
-
+
private:
friend class ::kdm_key_test;
-
+
void get (uint8_t *, uint8_t const **, int) const;
std::string get (uint8_t const **, int) const;
std::string get_uuid (uint8_t const **) const;
void put_uuid (uint8_t **, std::string) const;
friend bool operator== (KDMKey const &, KDMKey const &);
-
+
uint8_t _signer_thumbprint[20];
std::string _cpl_id;
std::string _key_type;
DCI_SPECIFIC
};
-
+
/** Create a new KDM.
* @param cpl CPL file that the KDM is for.
* @param signer Certificate chain to sign the KDM with.
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 ~LUT() {
delete[] _lut;
}
-
+
float const * lut() const {
return _lut;
}
XMLMetadata ();
void set_issue_date_now ();
-
+
std::string issuer;
std::string creator;
std::string issue_date;
if (ASDCP_FAILURE (r)) {
boost::throw_exception (FileError ("could not open JPEG2000 file for reading", get_path(0), r));
}
-
+
ASDCP::JP2K::PictureDescriptor picture_desc;
j2k_parser.FillPictureDescriptor (picture_desc);
picture_desc.EditRate = ASDCP::Rational (_edit_rate, 1);
-
+
ASDCP::WriterInfo writer_info;
fill_writer_info (&writer_info);
-
+
ASDCP::JP2K::MXFWriter mxf_writer;
r = mxf_writer.OpenWrite (path().string().c_str(), writer_info, picture_desc, 16384, false);
if (ASDCP_FAILURE (r)) {
(*_progress) (0.5 * float (i) / _intrinsic_duration);
}
}
-
+
r = mxf_writer.Finalize();
if (ASDCP_FAILURE (r)) {
boost::throw_exception (MXFFileError ("error in finalising video MXF", path().string(), r));
if (ASDCP_FAILURE (r)) {
boost::throw_exception (MXFFileError ("could not open MXF file for reading", path().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", path().string(), r));
}
-
+
ASDCP::JP2K::MXFReader reader_B;
r = reader_B.OpenRead (other->path().string().c_str());
if (ASDCP_FAILURE (r)) {
boost::throw_exception (MXFFileError ("could not open MXF file for reading", path().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 (PROGRESS, "Comparing video frame " + lexical_cast<string> (i) + " of " + lexical_cast<string> (_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(),
int edit_rate_factor () const;
};
-}
+}
#endif
MonoPictureAssetWriter::finalize ()
{
assert (!_finalized);
-
+
Kumu::Result_t r = _state->mxf_writer.Finalize();
if (ASDCP_FAILURE (r)) {
boost::throw_exception (MXFFileError ("error in finalizing video MXF", _asset->path().string(), r));
/* do this with an opaque pointer so we don't have to include
ASDCP headers
*/
-
+
struct ASDCPState;
boost::shared_ptr<ASDCPState> _state;
};
class ARGBFrame;
-/** A single frame of a 2D (monoscopic) picture asset */
+/** A single frame of a 2D (monoscopic) picture asset */
class MonoPictureFrame
{
public:
if (!Asset::equals (other, opt, note)) {
return false;
}
-
+
shared_ptr<const MXFAsset> other_mxf = dynamic_pointer_cast<const MXFAsset> (other);
if (!other_mxf) {
note (ERROR, "comparing an MXF asset with a non-MXF asset");
return false;
}
-
+
if (_file_name != other_mxf->_file_name) {
note (ERROR, "MXF names differ");
if (!opt.mxf_names_can_differ) {
return false;
}
}
-
+
return true;
}
/* 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");
if (ASDCP_FAILURE (_encryption_context->InitKey (_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");
namespace libdcp
{
-class MXFMetadata;
+class MXFMetadata;
-/** @brief Parent class for assets which have MXF files */
+/** @brief Parent class for assets which have MXF files */
class MXFAsset : public Asset
{
public:
* @param file_name Name of MXF file.
*/
MXFAsset (boost::filesystem::path directory, boost::filesystem::path file_name);
-
+
~MXFAsset ();
virtual bool equals (boost::shared_ptr<const Asset> other, EqualityOptions opt, boost::function<void (NoteType, std::string)> note) const;
virtual void write_to_cpl (xmlpp::Element *) const;
virtual std::string key_type () const = 0;
-
+
/** Fill in a ADSCP::WriteInfo struct.
* @param w struct to fill in.
*/
std::string key_id () const {
return _key_id;
}
-
+
void set_key (Key);
boost::optional<Key> key () const {
virtual std::pair<std::string, std::string> cpl_node_attribute () const {
return std::make_pair ("", "");
}
-
+
/** Signal to emit to report progress, or 0 */
boost::signals2::signal<void (float)>* _progress;
ASDCP::AESEncContext* _encryption_context;
PictureAsset::write_to_cpl (xmlpp::Element* node) const
{
MXFAsset::write_to_cpl (node);
-
+
xmlpp::Node::NodeList c = node->get_children ();
xmlpp::Node::NodeList::iterator i = c.begin();
while (i != c.end() && (*i)->get_name() != cpl_node_name ()) {
// a.CodingStyleDefault != b.CodingStyleDefault ||
// a.QuantizationDefault != b.QuantizationDefault
) {
-
+
note (ERROR, "video MXF picture descriptors differ");
return false;
}
if (a.ContainerDuration != b.ContainerDuration) {
note (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<XYZFrame> image_A = decompress_j2k (const_cast<uint8_t*> (data_A), size_A, 0);
shared_ptr<XYZFrame> 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 (ERROR, "image sizes for frame " + lexical_cast<string>(frame) + " differ");
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 (NOTE, "mean difference " + lexical_cast<string> (mean) + ", deviation " + lexical_cast<string> (std_dev));
-
+
if (mean > opt.max_mean_pixel_error) {
note (
ERROR,
" out of range " + lexical_cast<string>(opt.max_mean_pixel_error) +
" in frame " + lexical_cast<string>(frame)
);
-
+
return false;
}
" out of range " + lexical_cast<string>(opt.max_std_dev_pixel_error) +
" in frame " + lexical_cast<string>(frame)
);
-
+
return false;
}
namespace libdcp
{
-class MonoPictureFrame;
+class MonoPictureFrame;
class StereoPictureFrame;
class PictureAssetWriter;
{
public:
/** Construct a PictureAsset.
- *
+ *
* @param directory Directory where MXF file is.
* @param mxf_name Name of MXF file.
*/
* Interop mode (set_interop)
* Edit rate (set_edit_rate)
* MXF Metadata (set_metadata)
- *
+ *
* @param overwrite true to overwrite an existing MXF file; in this mode, writing can be resumed to a partially-written MXF; false if the
* MXF file does not exist.
*/
virtual void read () = 0;
virtual void create (std::vector<boost::filesystem::path> const &) {}
virtual void create (boost::function<boost::filesystem::path (int)>) {}
-
+
Size size () const {
return _size;
}
std::string key_type () const;
virtual int edit_rate_factor () const = 0;
};
-
+
}
namespace libdcp {
-class PictureAsset;
+class PictureAsset;
-/** Information about a single frame (either a monoscopic frame or a left *or* right eye stereoscopic frame) */
+/** Information about a single frame (either a monoscopic frame or a left *or* right eye stereoscopic frame) */
struct FrameInfo
{
FrameInfo ()
: offset (0)
, size (0)
{}
-
+
FrameInfo (uint64_t o, uint64_t s, std::string h)
: offset (o)
, size (s)
virtual FrameInfo write (uint8_t *, int) = 0;
virtual void finalize () = 0;
virtual void fake_write (int) = 0;
-
+
protected:
template <class P, class Q>
friend void start (PictureAssetWriter *, boost::shared_ptr<P>, Q *, uint8_t *, int);
PictureAssetWriter (PictureAsset *, bool);
PictureAsset* _asset;
-
+
/** Number of picture frames written to the asset so far. For stereo assets
* this will be incremented for each eye (i.e. there will be twice the number
* of frames as in a mono asset).
ASDCPStateBase ()
: frame_buffer (4 * Kumu::Megabyte)
{}
-
+
ASDCP::JP2K::CodestreamParser j2k_parser;
ASDCP::JP2K::FrameBuffer frame_buffer;
ASDCP::WriterInfo writer_info;
state->j2k_parser.FillPictureDescriptor (state->picture_descriptor);
state->picture_descriptor.EditRate = ASDCP::Rational (asset->edit_rate(), 1);
-
+
asset->fill_writer_info (&state->writer_info);
-
+
Kumu::Result_t r = state->mxf_writer.OpenWrite (
asset->path().string().c_str(),
state->writer_info,
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<MonoPictureAsset> (_main_picture)) {
/* Mono pictures come before other stuff... */
_main_picture->write_to_cpl (asset_list);
_main_picture->write_to_cpl (asset_list);
}
}
-
+
bool
Reel::equals (boost::shared_ptr<const Reel> other, EqualityOptions opt, boost::function<void (NoteType, string)> note) const
{
note (ERROR, "reel has different assets");
return false;
}
-
+
if (_main_picture && !_main_picture->equals (other->_main_picture, opt, note)) {
return false;
}
note (ERROR, "reel has different assets");
return false;
}
-
+
if (_main_sound && !_main_sound->equals (other->_main_sound, opt, note)) {
return false;
}
note (ERROR, "reel has different assets");
return false;
}
-
+
if (_main_subtitle && !_main_subtitle->equals (other->_main_subtitle, opt, note)) {
return false;
}
Reel::add_kdm (KDM const & kdm)
{
list<KDMKey> keys = kdm.keys ();
-
+
for (list<KDMKey>::iterator i = keys.begin(); i != keys.end(); ++i) {
if (i->key_id() == _main_picture->key_id()) {
_main_picture->set_key (i->key ());
class PictureAsset;
class SoundAsset;
class SubtitleAsset;
-class KDM;
+class KDM;
-/** @brief A reel within a DCP; the part which actually contains picture, sound and subtitle data */
+/** @brief A reel within a DCP; the part which actually contains picture, sound and subtitle data */
class Reel
{
public:
, _main_sound (sound)
, _main_subtitle (subtitle)
{}
-
+
boost::shared_ptr<const PictureAsset> main_picture () const {
return _main_picture;
}
boost::shared_ptr<const SoundAsset> main_sound () const {
return _main_sound;
}
-
+
boost::shared_ptr<const SubtitleAsset> main_subtitle () const {
return _main_subtitle;
}
bool encrypted () const;
void set_mxf_keys (libdcp::Key);
-
+
bool equals (boost::shared_ptr<const Reel> other, EqualityOptions opt, boost::function<void (NoteType, std::string)> notes) const;
void add_kdm (KDM const &);
struct {
double x, y, z;
} s;
-
+
struct {
double r, g, b;
} d;
-
+
int* xyz_x = xyz_frame->data (0);
int* xyz_y = xyz_frame->data (1);
int* xyz_z = xyz_frame->data (2);
shared_ptr<ARGBFrame> argb_frame (new ARGBFrame (xyz_frame->size ()));
uint8_t* argb = argb_frame->data ();
-
+
for (int y = 0; y < xyz_frame->size().height; ++y) {
uint8_t* argb_line = argb;
for (int x = 0; x < xyz_frame->size().width; ++x) {
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->lut()[*xyz_x++];
s.y = lut_in->lut()[*xyz_y++];
d.r = ((s.x * colour_matrix::xyz_to_rgb[0][0]) + (s.y * colour_matrix::xyz_to_rgb[0][1]) + (s.z * colour_matrix::xyz_to_rgb[0][2]));
d.g = ((s.x * colour_matrix::xyz_to_rgb[1][0]) + (s.y * colour_matrix::xyz_to_rgb[1][1]) + (s.z * colour_matrix::xyz_to_rgb[1][2]));
d.b = ((s.x * colour_matrix::xyz_to_rgb[2][0]) + (s.y * colour_matrix::xyz_to_rgb[2][1]) + (s.z * colour_matrix::xyz_to_rgb[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->lut()[(int) (d.b * max_colour)] * 0xff;
*argb_line++ = lut_out->lut()[(int) (d.g * max_colour)] * 0xff;
*argb_line++ = lut_out->lut()[(int) (d.r * max_colour)] * 0xff;
*argb_line++ = 0xff;
}
-
+
argb += argb_frame->stride ();
}
{
assert (lut_in->bit_depth() == 12);
assert (lut_out->bit_depth() == 16);
-
+
shared_ptr<XYZFrame> xyz (new XYZFrame (rgb->size ()));
struct {
s.r = lut_in->lut()[*p++ >> 4];
s.g = lut_in->lut()[*p++ >> 4];
s.b = lut_in->lut()[*p++ >> 4];
-
+
/* RGB to XYZ Matrix */
d.x = ((s.r * rgb_to_xyz[0][0]) +
(s.g * rgb_to_xyz[0][1]) +
(s.b * rgb_to_xyz[0][2]));
-
+
d.y = ((s.r * rgb_to_xyz[1][0]) +
(s.g * rgb_to_xyz[1][1]) +
(s.b * rgb_to_xyz[1][2]));
-
+
d.z = ((s.r * rgb_to_xyz[2][0]) +
(s.g * rgb_to_xyz[2][1]) +
(s.b * rgb_to_xyz[2][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;
assert (e.x >= 0 && e.x < 65536);
assert (e.y >= 0 && e.y < 65536);
assert (e.z >= 0 && e.z < 65536);
-
+
/* Out gamma LUT */
xyz->data(0)[jn] = lut_out->lut()[(int) e.x] * 4096;
xyz->data(1)[jn] = lut_out->lut()[(int) e.y] * 4096;
++jn;
}
}
-
+
return xyz_12;
}
namespace libdcp {
-class ARGBFrame;
+class ARGBFrame;
class XYZFrame;
class LUT;
class Image;
-
+
extern boost::shared_ptr<ARGBFrame> xyz_to_rgb (
boost::shared_ptr<const XYZFrame>, boost::shared_ptr<const LUT>, boost::shared_ptr<const LUT>
);
);
extern boost::shared_ptr<XYZFrame> xyz_to_xyz (boost::shared_ptr<const Image>);
-
+
}
add_signer (parent, "dsig");
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 (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", "");
list<shared_ptr<Certificate> > c = _certificates.leaf_to_root ();
for (list<shared_ptr<Certificate> >::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());
}
{
xmlpp::Element* data = signer->add_child("X509Data", ns);
-
+
{
xmlpp::Element* serial_element = data->add_child("X509IssuerSerial", ns);
serial_element->add_child("X509IssuerName", ns)->add_child_text (_certificates.leaf()->issuer());
serial_element->add_child("X509SerialNumber", ns)->add_child_text (_certificates.leaf()->serial());
}
-
+
data->add_child("X509SubjectName", ns)->add_child_text (_certificates.leaf()->subject());
}
}
CertificateChain const & certificates () const {
return _certificates;
}
-
-private:
+
+private:
void add_signer (xmlpp::Element* parent, std::string ns) const;
-
+
CertificateChain _certificates;
/** Filename of signer key */
boost::filesystem::path _key;
* @param openssl openssl binary name (or full path if openssl is not on the system path).
* @return SHA1 digest of corresponding public key, with escaped / characters.
*/
-
+
static string
public_key_digest (boost::filesystem::path private_key, boost::filesystem::path openssl)
{
}
/* Decode the base64 of the public key */
-
+
unsigned char buffer[512];
int const N = libdcp::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;
}
<< "OU = Organization unit\n"
<< "CN = Entity and dnQualifier\n";
}
-
+
string const inter_subject = "/O=example.org/OU=example.org/CN=.smpte-430-2.INTERMEDIATE.NOT_FOR_PRODUCTION/dnQualifier="
+ public_key_digest ("intermediate.key", openssl);
command (s.str().c_str());
}
-
+
command (
quoted_openssl +
" x509 -req -sha256 -days 3649 -CA ca.self-signed.pem -CAkey ca.key -set_serial 6"
if (ASDCP_FAILURE (r)) {
boost::throw_exception (FileError ("could not open WAV file for reading", get_path(LEFT), r));
}
-
+
ASDCP::PCM::AudioDescriptor audio_desc;
pcm_parser_channel[0]->FillAudioDescriptor (audio_desc);
audio_desc.ChannelCount = 0;
for (int i = 0; i < _channels; ++i) {
boost::filesystem::path const path = get_path (channels[i]);
-
+
Kumu::Result_t r = pcm_parser_channel[i]->OpenRead (path.string().c_str(), asdcp_edit_rate);
if (ASDCP_FAILURE (r)) {
boost::throw_exception (FileError ("could not open WAV file for reading", path, r));
if (ASDCP_FAILURE (r)) {
boost::throw_exception (FileError ("could not open audio MXF for writing", path().string(), r));
}
-
+
for (int i = 0; i < _intrinsic_duration; ++i) {
for (int j = 0; j < _channels; ++j) {
if (!MXFAsset::equals (other, opt, note)) {
return false;
}
-
+
ASDCP::PCM::MXFReader reader_A;
Kumu::Result_t r = reader_A.OpenRead (path().string().c_str());
if (ASDCP_FAILURE (r)) {
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 (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 (ERROR, "sizes of audio data for frame " + lexical_cast<string>(i) + " differ");
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]);
, _frame_buffer_offset (0)
{
_state->encryption_context = a->encryption_context ();
-
+
/* Derived from ASDCP::Wav::SimpleWaveHeader::FillADesc */
_state->audio_desc.EditRate = ASDCP::Rational (_asset->edit_rate(), 1);
_state->audio_desc.AudioSamplingRate = ASDCP::Rational (_asset->sampling_rate(), 1);
in ASDCP's WriteMXFFooter, but it stops a valgrind warning.
*/
_state->audio_desc.ContainerDuration = 0;
-
+
_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());
-
+
_asset->fill_writer_info (&_state->writer_info);
-
+
Kumu::Result_t r = _state->mxf_writer.OpenWrite (_asset->path().string().c_str(), _state->writer_info, _state->audio_desc);
if (ASDCP_FAILURE (r)) {
boost::throw_exception (FileError ("could not open audio MXF for writing", _asset->path().string(), r));
if (_frame_buffer_offset > 0) {
write_current_frame ();
}
-
+
if (ASDCP_FAILURE (_state->mxf_writer.Finalize())) {
boost::throw_exception (MiscError ("could not finalise audio MXF"));
}
/* no copy construction */
SoundAssetWriter (SoundAssetWriter const &);
SoundAssetWriter& operator= (SoundAssetWriter const &);
-
+
void write_current_frame ();
/* do this with an opaque pointer so we don't have to include
ASDCP headers
*/
-
+
struct ASDCPState;
boost::shared_ptr<ASDCPState> _state;
void create (boost::function<boost::filesystem::path (Channel)> get_path);
boost::shared_ptr<SoundAssetWriter> start_write ();
-
+
bool equals (boost::shared_ptr<const Asset> other, EqualityOptions opt, boost::function<void (NoteType, std::string)> note) const;
boost::shared_ptr<const SoundFrame> get_frame (int n) const;
void set_channels (int c) {
_channels = c;
}
-
+
int channels () const {
return _channels;
}
std::string asdcp_kind () const {
return "Sound";
}
-
+
private:
std::string key_type () const;
void construct (boost::function<boost::filesystem::path (Channel)> get_path);
if (ASDCP_FAILURE (r)) {
boost::throw_exception (MXFFileError ("could not open MXF file for reading", path().string(), r));
}
-
+
ASDCP::JP2K::MXFSReader reader_B;
r = reader_B.OpenRead (other->path().string().c_str());
if (ASDCP_FAILURE (r)) {
boost::throw_exception (MXFFileError ("could not open MXF file for reading", other->path().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);
assert (other_picture);
for (int i = 0; i < _intrinsic_duration; ++i) {
shared_ptr<const StereoPictureFrame> frame_A = get_frame (i);
shared_ptr<const StereoPictureFrame> frame_B = other_picture->get_frame (i);
-
+
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(),
StereoPictureAsset::StereoPictureAsset (boost::filesystem::path directory, boost::filesystem::path mxf_name)
: PictureAsset (directory, mxf_name)
{
-
+
}
void
if (ASDCP_FAILURE (r)) {
boost::throw_exception (MXFFileError ("could not open MXF file for reading", path().string(), r));
}
-
+
ASDCP::JP2K::PictureDescriptor desc;
if (ASDCP_FAILURE (reader.FillPictureDescriptor (desc))) {
boost::throw_exception (DCPReadError ("could not read video MXF information"));
#include "picture_asset.h"
namespace libdcp {
-
-/** A 3D (stereoscopic) picture asset */
+
+/** A 3D (stereoscopic) picture asset */
class StereoPictureAsset : public PictureAsset
{
public:
StereoPictureAsset (boost::filesystem::path directory, boost::filesystem::path mxf_name);
void read ();
-
+
/** Start a progressive write to a StereoPictureAsset */
boost::shared_ptr<PictureAssetWriter> start_write (bool);
StereoPictureAssetWriter::finalize ()
{
assert (!_finalized);
-
+
Kumu::Result_t r = _state->mxf_writer.Finalize();
if (ASDCP_FAILURE (r)) {
boost::throw_exception (MXFFileError ("error in finalizing video MXF", _asset->path().string(), r));
/* do this with an opaque pointer so we don't have to include
ASDCP headers
*/
-
+
struct ASDCPState;
boost::shared_ptr<ASDCPState> _state;
xyz_frame = decompress_j2k (const_cast<uint8_t*> (_buffer->Right.RoData()), _buffer->Right.Size(), reduce);
break;
}
-
+
return xyz_to_rgb (xyz_frame, GammaLUT::cache.get (12, DCI_GAMMA), GammaLUT::cache.get (12, 1 / srgb_gamma));
}
class ARGBFrame;
-/** A single frame of a 3D (stereoscopic) picture asset */
+/** A single frame of a 3D (stereoscopic) picture asset */
class StereoPictureFrame
{
public:
shared_ptr<cxml::Document> xml (new cxml::Document ("SubtitleReel"));
xml->read_file (xml_file);
read_xml (xml, true);
- }
+ }
}
void
SubtitleAsset::read_xml (shared_ptr<cxml::Document> xml, bool smpte)
{
/* XXX: hacks aplenty in here; need separate parsers for DCSubtitle (Interop) and SubtitleReel (SMPTE) */
-
+
/* DCSubtitle */
optional<string> x = xml->optional_string_child ("SubtitleID");
if (!x) {
if (empty_or_white_space (text)) {
return;
}
-
+
if (parse_state.text_nodes.empty() || parse_state.subtitle_nodes.empty ()) {
return;
}
assert (!parse_state.text_nodes.empty ());
assert (!parse_state.subtitle_nodes.empty ());
-
+
libdcp::parse::Font effective_font (parse_state.font_nodes);
libdcp::parse::Text effective_text (*parse_state.text_nodes.back ());
libdcp::parse::Subtitle effective_subtitle (*parse_state.subtitle_nodes.back ());
effective_subtitle.fade_down_time
)
);
-
+
_subtitles.push_back (parse_state.current);
}
-
+
if (effective_font.italic.get()) {
parse_state.current->set_text (parse_state.current->text() + "<i>" + text + "</i>");
} else {
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() << ", color " << sub.color()
<< ", vpos " << sub.v_position() << ", valign " << ((int) sub.v_align()) << ", halign " << ((int) sub.h_align()) << "; "
<< "effect " << ((int) sub.effect()) << ", effect color " << sub.effect_color();
}
xmlpp::Element* text = subtitle->add_child ("Text");
- text->set_attribute ("VAlign", valign_to_string ((*i)->v_align()));
+ text->set_attribute ("VAlign", valign_to_string ((*i)->v_align()));
text->set_attribute ("HAlign", halign_to_string ((*i)->h_align()));
text->set_attribute ("VPosition", raw_convert<string> ((*i)->v_position()));
text->add_child_text ((*i)->text());
int size () const {
return _size;
}
-
+
int size_in_pixels (int screen_height) const;
private:
Color _color;
/** 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;
Time _in;
Time _out;
} else if (s == "bottom") {
return VERTICAL_BOTTOM;
}
-
+
boost::throw_exception (DCPReadError ("unknown subtitle valign type"));
}
} else if (s == "right") {
return HORIZONTAL_RIGHT;
}
-
+
boost::throw_exception (DCPReadError ("unknown subtitle halign type"));
}
EYE_LEFT,
EYE_RIGHT
};
-
+
class Fraction
{
public:
extern bool operator== (Fraction const & a, Fraction const & b);
extern bool operator!= (Fraction const & a, Fraction const & b);
-
+
struct EqualityOptions {
- EqualityOptions ()
+ EqualityOptions ()
: max_mean_pixel_error (0)
, max_std_dev_pixel_error (0)
, max_audio_sample_error (0)
bool mxf_names_can_differ;
};
-/* Win32 defines this */
+/* Win32 defines this */
#undef ERROR
enum NoteType {
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) {
libdcp::content_kind_from_string (string type)
{
transform (type.begin(), type.end(), type.begin(), ::tolower);
-
+
if (type == "feature") {
return FEATURE;
} else if (type == "short") {
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);
float ratio () const {
return float (width) / height;
}
-
+
int width;
int height;
};
-
+
extern bool operator== (Size const & a, Size const & b);
extern bool operator!= (Size const & a, Size const & b);
extern std::string utc_offset_to_string (boost::posix_time::time_duration);
extern std::string ptime_to_string (boost::posix_time::ptime);
extern FILE * fopen_boost (boost::filesystem::path, std::string);
-
+
}
#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
XYZFrame::XYZFrame (Size size)
{
opj_image_cmptparm_t cmptparm[3];
-
+
for (int i = 0; i < 3; ++i) {
cmptparm[i].dx = 1;
cmptparm[i].dy = 1;
/* Leaf */
BOOST_CHECK_EQUAL (*i, c.leaf ());
-
+
BOOST_CHECK_EQUAL (
c.leaf()->issuer(),
"dnQualifier=bmtwThq3srgxIAeRMjX6BFhgLDw=,CN=.smpte-430-2.INTERMEDIATE.NOT_FOR_PRODUCTION,OU=example.org,O=example.org"
c.leaf()->subject(),
"dnQualifier=d95fGDzERNdxfYPgphvAR8A18L4=,CN=CS.smpte-430-2.LEAF.NOT_FOR_PRODUCTION,OU=example.org,O=example.org"
);
-
+
++i;
/* Intermediate */
(*i)->subject(),
"dnQualifier=bmtwThq3srgxIAeRMjX6BFhgLDw=,CN=.smpte-430-2.INTERMEDIATE.NOT_FOR_PRODUCTION,OU=example.org,O=example.org"
);
-
+
++i;
/* Root */
xmlpp::Document doc;
xmlpp::Element* el = doc.create_root_node ("Test");
mp->write_to_cpl (el);
-
+
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");
mp->write_to_cpl (el);
-
+
cxml::Node node (el);
BOOST_CHECK_EQUAL (node.node_child("MainPicture")->string_child ("ScreenAspectRatio"), "2.39");
}
ms->set_channels (2);
ms->set_metadata (mxf_meta);
ms->create (wav);
-
+
cpl->add_reel (shared_ptr<libdcp::Reel> (new libdcp::Reel (mp, ms, shared_ptr<libdcp::SubtitleAsset> ())));
d.add_cpl (cpl);
boost::filesystem::remove_all ("build/test/signer");
boost::filesystem::create_directory ("build/test/signer");
libdcp::make_signer_chain ("build/test/signer", "openssl");
-
+
Kumu::libdcp_test = true;
libdcp::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/bar");
boost::filesystem::create_directories ("build/test/DCP/bar");
libdcp::DCP d ("build/test/DCP/bar");
shared_ptr<libdcp::CPL> cpl (new libdcp::CPL ("build/test/DCP/bar", "A Test DCP", libdcp::FEATURE, 24, 24));
libdcp::Key key;
-
+
shared_ptr<libdcp::MonoPictureAsset> mp (new libdcp::MonoPictureAsset ("build/test/DCP/bar", "video.mxf"));
mp->set_progress (&d.Progress);
mp->set_edit_rate (24);
ms->set_metadata (mxf_metadata);
ms->set_key (key);
ms->create (wav);
-
+
cpl->add_reel (shared_ptr<libdcp::Reel> (new libdcp::Reel (mp, ms, shared_ptr<libdcp::SubtitleAsset> ())));
d.add_cpl (cpl);
);
kdm.as_xml ("build/test/bar.kdm.xml");
-
+
int r = system (
"xmllint --path schema --nonet --noout --schema schema/SMPTE-430-1-2006-Amd-1-2009-KDM.xsd build/test/bar.kdm.xml "
"> build/test/xmllint.log 2>&1 < /dev/null"
);
-#ifdef DCPOMATIC_POSIX
+#ifdef DCPOMATIC_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/bar.kdm.xml > build/test/xmlsec1.log 2>&1 < /dev/null");
-
-#ifdef DCPOMATIC_POSIX
+
+#ifdef DCPOMATIC_POSIX
BOOST_CHECK_EQUAL (WEXITSTATUS (r), 0);
#else
BOOST_CHECK_EQUAL (r, 0);
-#endif
+#endif
}
/* Trying to create video/audio MXFs using a non-existant file should throw an exception */
libdcp::MonoPictureAsset pa ("build/test/fred", "video.mxf");
BOOST_CHECK_THROW (pa.create (p), libdcp::FileError);
-
+
libdcp::SoundAsset sa ("build/test/fred", "audio.mxf");
sa.set_channels (1);
BOOST_CHECK_THROW (sa.create (p), libdcp::FileError);
);
list<libdcp::KDMKey> 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
}
#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<libdcp::MonoPictureAsset> mp (new libdcp::MonoPictureAsset ("build/test/baz", "video1.mxf"));
fclose (f);
}
-#ifdef LIBDCP_POSIX
+#ifdef LIBDCP_POSIX
Kumu::ResetTestRNG ();
-#endif
+#endif
mp.reset (new libdcp::MonoPictureAsset ("build/test/baz", "video2.mxf"));
mp->set_edit_rate (24);
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 (false);
-
+
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()->write_xml ();
}
cerr << e.what() << " when reading " << argv[1] << "\n";
exit (EXIT_FAILURE);
}
-
+
return 0;
}
boost::filesystem::remove_all ("build/test/signer");
boost::filesystem::create_directory ("build/test/signer");
libdcp::make_signer_chain ("build/test/signer", "openssl");
-
+
libdcp::CertificateChain chain;
chain.add (shared_ptr<libdcp::Certificate> (new libdcp::Certificate (boost::filesystem::path ("build/test/signer/ca.self-signed.pem"))));
chain.add (shared_ptr<libdcp::Certificate> (new libdcp::Certificate (boost::filesystem::path ("build/test/signer/intermediate.signed.pem"))));
cerr << "Syntax: " << argv[0] << " <subtitle file>\n";
exit (EXIT_FAILURE);
}
-
+
libdcp::SubtitleAsset s ("foo", "bar", "baz");
s.read_xml (argv[1]);
cout << s.xml_as_string ();
libdcp::Time (0, 0, 0, 1, 250),
libdcp::Time (0, 0, 0, 1, 250)
));
-
+
s = subs.subtitles_during (libdcp::Time (0, 0, 7, 190, 250), libdcp::Time (0, 0, 7, 191, 250));
BOOST_CHECK_EQUAL (s.size(), 2);
BOOST_CHECK_EQUAL (*(s.front().get()), libdcp::Subtitle (
BOOST_AUTO_TEST_CASE (base64_decode_test)
{
int const N = 256;
-
+
ifstream f ("test/data/base64_test");
BOOST_CHECK (f.good ());
string s;