/* If you are using an installed libdcp, these #includes would need to be changed to
#include <libdcp/dcp.h>
-#include <libdcp/cpl.h>
-#include <libdcp/mono_picture_asset.h>
+#include <libdcp/picture_mxf.h>
... etc. ...
*/
#include "dcp.h"
+#include "cpl.h"
+#include "reel.h"
+#include "reel_picture_asset.h"
+#include "mono_picture_frame.h"
+#include "mono_picture_mxf.h"
+#include "stereo_picture_mxf.h"
+#include "sound_mxf.h"
+#include "subtitle_content.h"
+#include "argb_frame.h"
+#include <Magick++.h>
/** @file examples/read_dcp.cc
* @brief Shows how to read a DCP.
}
std::cout << "DCP has " << dcp.cpls().size() << " CPLs.\n";
- std::cout << "DCP has " << dcp.assets().size() << " assets.\n";
+ std::list<boost::shared_ptr<dcp::Asset> > assets = dcp.assets ();
+ std::cout << "DCP has " << assets.size() << " assets.\n";
+ for (std::list<boost::shared_ptr<dcp::Asset> >::const_iterator i = assets.begin(); i != assets.end(); ++i) {
+ if (boost::dynamic_pointer_cast<dcp::MonoPictureMXF> (*i)) {
+ std::cout << "2D picture\n";
+ } else if (boost::dynamic_pointer_cast<dcp::StereoPictureMXF> (*i)) {
+ std::cout << "3D picture\n";
+ } else if (boost::dynamic_pointer_cast<dcp::SoundMXF> (*i)) {
+ std::cout << "Sound\n";
+ } else if (boost::dynamic_pointer_cast<dcp::SubtitleContent> (*i)) {
+ std::cout << "Subtitle\n";
+ } else if (boost::dynamic_pointer_cast<dcp::CPL> (*i)) {
+ std::cout << "CPL\n";
+ }
+ std::cout << "\t" << (*i)->file().leaf().string() << "\n";
+ }
+
+ /* Take the first CPL */
+ boost::shared_ptr<dcp::CPL> cpl = dcp.cpls().front ();
+
+ /* Get the MXF of the picture asset in the first reel */
+ boost::shared_ptr<dcp::MonoPictureMXF> picture_mxf = boost::dynamic_pointer_cast<dcp::MonoPictureMXF> (cpl->reels().front()->main_picture()->mxf ());
+
+ /* Get the 1000th frame of it */
+ boost::shared_ptr<const dcp::MonoPictureFrame> picture_frame_j2k = picture_mxf->get_frame(999);
+
+ /* Get a ARGB copy of it */
+ boost::shared_ptr<dcp::ARGBFrame> picture_frame_rgb = picture_frame_j2k->argb_frame ();
+
+ Magick::Image image (picture_frame_rgb->size().width, picture_frame_rgb->size().height, "BGRA", Magick::CharPixel, picture_frame_rgb->data ());
+ image.write ("frame.png");
return 0;
}
obj = bld(features = 'cxx cxxprogram')
obj.name = 'read_dcp'
obj.use = 'libdcp'
- obj.uselib = 'OPENJPEG CXML'
+ obj.uselib = 'OPENJPEG CXML MAGICK'
obj.source = 'read_dcp.cc'
obj.target = 'read_dcp'
obj.install_path = ''
#include "KM_util.h"
#include <libxml++/nodes/element.h>
#include <boost/filesystem.hpp>
-#include <boost/lexical_cast.hpp>
#include <boost/function.hpp>
#include <iostream>
/** Construct a CPL object from a XML file */
CPL::CPL (boost::filesystem::path file)
- : _content_kind (FEATURE)
+ : Asset (file)
+ , _content_kind (FEATURE)
{
cxml::Document f ("CompositionPlaylist");
f.read_file (file);
_id = f.string_child ("Id");
+ if (_id.length() > 9) {
+ _id = _id.substr (9);
+ }
_annotation_text = f.optional_string_child ("AnnotationText").get_value_or ("");
_issue_date = f.string_child ("IssueDate");
_creator = f.optional_string_child ("Creator").get_value_or ("");
_content_title_text = f.string_child ("ContentTitleText");
_content_kind = content_kind_from_string (f.string_child ("ContentKind"));
- shared_ptr<cxml::Node> content_version = f.node_child ("ContentVersion");
+ shared_ptr<cxml::Node> content_version = f.optional_node_child ("ContentVersion");
if (content_version) {
_content_version_id = content_version->optional_string_child ("Id").get_value_or ("");
_content_version_label_text = content_version->string_child ("LabelText");
CPL::add (KDM const & kdm)
{
for (list<shared_ptr<Reel> >::const_iterator i = _reels.begin(); i != _reels.end(); ++i) {
- (*i)->add_kdm (kdm);
+ (*i)->add (kdm);
}
}
(*i)->set_mxf_keys (key);
}
}
+
+void
+CPL::resolve_refs (list<shared_ptr<Object> > objects)
+{
+ for (list<shared_ptr<Reel> >::const_iterator i = _reels.begin(); i != _reels.end(); ++i) {
+ (*i)->resolve_refs (objects);
+ }
+}
XMLMetadata,
boost::shared_ptr<const Signer>
) const;
+
+ void resolve_refs (std::list<boost::shared_ptr<Object> >);
private:
std::string _annotation_text; ///< <AnnotationText>
#include <xmlsec/app.h>
#include <libxml++/libxml++.h>
#include <boost/filesystem.hpp>
-#include <boost/lexical_cast.hpp>
#include <boost/algorithm/string.hpp>
#include <boost/lexical_cast.hpp>
#include <sstream>
using std::map;
using boost::shared_ptr;
using boost::lexical_cast;
-using boost::dynamic_pointer_cast;
using namespace dcp;
DCP::DCP (boost::filesystem::path directory)
cxml::Document asset_map ("AssetMap");
asset_map.read_file (asset_map_file);
- list<shared_ptr<cxml::Node> > assets = asset_map.node_child("AssetList")->node_children ("Asset");
+ list<shared_ptr<cxml::Node> > asset_nodes = asset_map.node_child("AssetList")->node_children ("Asset");
map<string, boost::filesystem::path> paths;
- for (list<shared_ptr<cxml::Node> >::const_iterator i = assets.begin(); i != assets.end(); ++i) {
+ for (list<shared_ptr<cxml::Node> >::const_iterator i = asset_nodes.begin(); i != asset_nodes.end(); ++i) {
if ((*i)->node_child("ChunkList")->node_children("Chunk").size() != 1) {
boost::throw_exception (XMLError ("unsupported asset chunk count"));
}
/* Read all the assets from the asset map */
for (map<string, boost::filesystem::path>::const_iterator i = paths.begin(); i != paths.end(); ++i) {
- if (boost::algorithm::ends_with (i->second.string(), ".xml")) {
+ boost::filesystem::path path = _directory / i->second;
+ if (boost::algorithm::ends_with (path.string(), ".xml")) {
xmlpp::DomParser* p = new xmlpp::DomParser;
try {
- p->parse_file (i->second.string());
+ p->parse_file (path.string());
} catch (std::exception& e) {
delete p;
continue;
delete p;
if (root == "CompositionPlaylist") {
- _assets.push_back (shared_ptr<CPL> (new CPL (i->second)));
+ _assets.push_back (shared_ptr<CPL> (new CPL (path)));
} else if (root == "DCSubtitle") {
- _assets.push_back (shared_ptr<SubtitleContent> (new SubtitleContent (i->second)));
+ _assets.push_back (shared_ptr<SubtitleContent> (new SubtitleContent (path)));
}
- } else if (boost::algorithm::ends_with (i->second.string(), ".mxf")) {
+ } else if (boost::algorithm::ends_with (path.string(), ".mxf")) {
ASDCP::EssenceType_t type;
- if (ASDCP::EssenceType (i->second.string().c_str(), type) != ASDCP::RESULT_OK) {
+ if (ASDCP::EssenceType (path.string().c_str(), type) != ASDCP::RESULT_OK) {
throw DCPReadError ("Could not find essence type");
}
switch (type) {
case ASDCP::ESS_MPEG2_VES:
throw DCPReadError ("MPEG2 video essences are not supported");
case ASDCP::ESS_JPEG_2000:
- _assets.push_back (shared_ptr<MonoPictureMXF> (new MonoPictureMXF (i->second)));
+ _assets.push_back (shared_ptr<MonoPictureMXF> (new MonoPictureMXF (path)));
break;
case ASDCP::ESS_PCM_24b_48k:
case ASDCP::ESS_PCM_24b_96k:
- _assets.push_back (shared_ptr<SoundMXF> (new SoundMXF (i->second)));
+ _assets.push_back (shared_ptr<SoundMXF> (new SoundMXF (path)));
break;
case ASDCP::ESS_JPEG_2000_S:
- _assets.push_back (shared_ptr<StereoPictureMXF> (new StereoPictureMXF (i->second)));
+ _assets.push_back (shared_ptr<StereoPictureMXF> (new StereoPictureMXF (path)));
break;
default:
throw DCPReadError ("Unknown MXF essence type");
}
}
}
+
+ list<shared_ptr<CPL> > cpl = cpls ();
+ for (list<shared_ptr<CPL> >::const_iterator i = cpl.begin(); i != cpl.end(); ++i) {
+ (*i)->resolve_refs (list_of_type<Asset, Object> (assets ()));
+ }
}
bool
pkl->add_child("Id")->add_child_text ("urn:uuid:" + pkl_uuid);
/* XXX: this is a bit of a hack */
- list<shared_ptr<Asset> >::const_iterator i = _assets.begin();
- shared_ptr<CPL> first_cpl;
- while (i != _assets.end()) {
- first_cpl = dynamic_pointer_cast<CPL> (*i);
- if (first_cpl) {
- break;
- }
- }
-
- assert (first_cpl);
- pkl->add_child("AnnotationText")->add_child_text (first_cpl->annotation_text ());
+ assert (cpls().size() > 0);
+ pkl->add_child("AnnotationText")->add_child_text (cpls().front()->annotation_text ());
pkl->add_child("IssueDate")->add_child_text (metadata.issue_date);
pkl->add_child("Issuer")->add_child_text (metadata.issuer);
pkl->add_child("Creator")->add_child_text (metadata.creator);
xmlpp::Element* asset_list = pkl->add_child("AssetList");
-
for (list<shared_ptr<Asset> >::const_iterator i = _assets.begin(); i != _assets.end(); ++i) {
- shared_ptr<Content> c = dynamic_pointer_cast<Content> (*i);
- if (c) {
- c->write_to_pkl (asset_list);
- }
+ (*i)->write_to_pkl (asset_list);
}
if (signer) {
write_volindex (standard);
write_assetmap (standard, pkl_uuid, boost::filesystem::file_size (pkl_path), metadata);
- for (list<shared_ptr<Asset> >::const_iterator i = _assets.begin(); i != _assets.end(); ++i) {
- shared_ptr<CPL> c = dynamic_pointer_cast<CPL> (*i);
- if (c) {
- string const filename = c->id() + "_cpl.xml";
- c->write_xml (_directory / filename, standard, metadata, signer);
- }
+ list<shared_ptr<CPL> > cpl = cpls ();
+ for (list<shared_ptr<CPL> >::const_iterator i = cpl.begin(); i != cpl.end(); ++i) {
+ string const filename = (*i)->id() + "_cpl.xml";
+ (*i)->write_xml (_directory / filename, standard, metadata, signer);
}
}
list<shared_ptr<CPL> >
DCP::cpls () const
{
- list<shared_ptr<CPL> > cpls;
- for (list<shared_ptr<Asset> >::const_iterator i = _assets.begin(); i != _assets.end(); ++i) {
- shared_ptr<CPL> c = dynamic_pointer_cast<CPL> (*i);
- if (c) {
- cpls.push_back (c);
- }
- }
-
- return cpls;
+ return list_of_type<Asset, CPL> (_assets);
}
-
-
#include "KM_fileio.h"
#include "exceptions.h"
#include "mono_picture_frame.h"
+#include "compose.hpp"
using std::string;
using std::vector;
using boost::shared_ptr;
using boost::dynamic_pointer_cast;
-using boost::lexical_cast;
using namespace dcp;
MonoPictureMXF::MonoPictureMXF (boost::filesystem::path file)
}
read_picture_descriptor (desc);
+
+ ASDCP::WriterInfo info;
+ if (ASDCP_FAILURE (reader.FillWriterInfo (info))) {
+ boost::throw_exception (DCPReadError ("could not read video MXF information"));
+ }
+
+ read_writer_info (info);
}
MonoPictureMXF::MonoPictureMXF (Fraction edit_rate)
return false;
}
- note (PROGRESS, "Comparing video frame " + lexical_cast<string> (i) + " of " + lexical_cast<string> (_intrinsic_duration));
+ note (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);
using std::ostream;
using std::string;
using boost::shared_ptr;
-using boost::lexical_cast;
using namespace dcp;
struct MonoPictureMXFWriter::ASDCPState : public ASDCPStateBase
#include "kdm.h"
#include <libxml++/nodes/element.h>
#include <boost/filesystem.hpp>
-#include <boost/lexical_cast.hpp>
#include <iostream>
using std::string;
throw MiscError ("could not set up CBC initialization vector");
}
}
+
+void
+MXF::read_writer_info (ASDCP::WriterInfo const & info)
+{
+ char buffer[64];
+ Kumu::bin2UUIDhex (info.AssetUUID, 16, buffer, 64);
+ _id = buffer;
+}
}
protected:
+ void read_writer_info (ASDCP::WriterInfo const &);
+
/** Signal to emit to report progress, or 0 */
boost::signals2::signal<void (float)>* _progress;
ASDCP::AESEncContext* _encryption_context;
#include "exceptions.h"
#include "xyz_frame.h"
#include "picture_mxf_writer.h"
+#include "compose.hpp"
#include "AS_DCP.h"
#include "KM_fileio.h"
#include <libxml++/nodes/element.h>
#include <openjpeg.h>
#include <boost/filesystem.hpp>
-#include <boost/lexical_cast.hpp>
#include <list>
#include <stdexcept>
#include <iostream>
using std::istream;
using std::cout;
using boost::shared_ptr;
-using boost::dynamic_pointer_cast;
-using boost::lexical_cast;
using namespace dcp;
PictureMXF::PictureMXF (boost::filesystem::path file)
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");
+ note (ERROR, String::compose ("image sizes for frame %1 differ", frame));
return false;
}
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));
+ note (NOTE, String::compose ("mean difference %1, deviation %2", mean, std_dev));
if (mean > opt.max_mean_pixel_error) {
note (
ERROR,
- "mean " + lexical_cast<string>(mean) +
- " out of range " + lexical_cast<string>(opt.max_mean_pixel_error) +
- " in frame " + lexical_cast<string>(frame)
+ String::compose ("mean %1 out of range %2 in frame %3", mean, opt.max_mean_pixel_error, frame)
);
return false;
if (std_dev > opt.max_std_dev_pixel_error) {
note (
ERROR,
- "standard deviation " + lexical_cast<string>(std_dev) +
- " out of range " + lexical_cast<string>(opt.max_std_dev_pixel_error) +
- " in frame " + lexical_cast<string>(frame)
+ String::compose ("standard deviation %1 out of range %2 in frame %3", std_dev, opt.max_std_dev_pixel_error, frame)
);
return false;
}
void
-Reel::add_kdm (KDM const & kdm)
+Reel::add (KDM const & kdm)
{
list<KDMKey> keys = kdm.keys ();
_main_subtitle = su;
}
}
+
+void
+Reel::resolve_refs (list<shared_ptr<Object> > objects)
+{
+ if (_main_picture) {
+ _main_picture->content().resolve (objects);
+ }
+
+ if (_main_sound) {
+ _main_sound->content().resolve (objects);
+ }
+
+ if (_main_subtitle) {
+ _main_subtitle->content().resolve (objects);
+ }
+}
class ReelPictureAsset;
class ReelSoundAsset;
class ReelSubtitleAsset;
+class Content;
/** @brief A reel within a DCP; the part which actually refers to picture, sound and subtitle data */
class Reel : public Object
bool equals (boost::shared_ptr<const Reel> other, EqualityOptions opt, boost::function<void (NoteType, std::string)> notes) const;
- void add_kdm (KDM const &);
+ void add (KDM const &);
+
+ void resolve_refs (std::list<boost::shared_ptr<Object> >);
private:
boost::shared_ptr<ReelPictureAsset> _main_picture;
if (_key_id.length() > 9) {
_key_id = _key_id.substr (9);
}
-
- node->done ();
}
void
}
/** @return a Ref to our actual content */
- Ref<Content> content () const {
+ Ref<Content>& content () {
return _content;
}
#include "reel_mono_picture_asset.h"
#include "mono_picture_mxf.h"
+#include <libcxml/cxml.h>
using std::string;
using boost::shared_ptr;
ReelMonoPictureAsset::ReelMonoPictureAsset (boost::shared_ptr<const cxml::Node> node)
: ReelPictureAsset (node)
{
-
+ node->done ();
}
string
using std::string;
using std::stringstream;
using boost::shared_ptr;
-using boost::lexical_cast;
using namespace dcp;
ReelPictureAsset::ReelPictureAsset ()
*/
#include "reel_stereo_picture_asset.h"
+#include <libcxml/cxml.h>
using std::string;
using std::pair;
ReelStereoPictureAsset::ReelStereoPictureAsset (boost::shared_ptr<const cxml::Node> node)
: ReelPictureAsset (node)
{
-
+ node->done ();
}
string
#include "exceptions.h"
#include "sound_frame.h"
#include "sound_mxf_writer.h"
+#include "compose.hpp"
#include "KM_fileio.h"
#include "AS_DCP.h"
#include <libxml++/nodes/element.h>
#include <boost/filesystem.hpp>
-#include <boost/lexical_cast.hpp>
#include <iostream>
#include <stdexcept>
using std::vector;
using std::list;
using boost::shared_ptr;
-using boost::lexical_cast;
using namespace dcp;
SoundMXF::SoundMXF (boost::filesystem::path file)
_edit_rate = Fraction (desc.EditRate.Numerator, desc.EditRate.Denominator);
_intrinsic_duration = desc.ContainerDuration;
+
+ ASDCP::WriterInfo info;
+ if (ASDCP_FAILURE (reader.FillWriterInfo (info))) {
+ boost::throw_exception (DCPReadError ("could not read audio MXF information"));
+ }
+
+ read_writer_info (info);
+
}
SoundMXF::SoundMXF (Fraction edit_rate, int sampling_rate, int channels)
}
if (buffer_A.Size() != buffer_B.Size()) {
- note (ERROR, "sizes of audio data for frame " + lexical_cast<string>(i) + " differ");
+ note (ERROR, String::compose ("sizes of audio data for frame %1 differ", i));
return false;
}
for (uint32_t i = 0; i < buffer_A.Size(); ++i) {
int const d = abs (buffer_A.RoData()[i] - buffer_B.RoData()[i]);
if (d > opt.max_audio_sample_error) {
- note (ERROR, "PCM data difference of " + lexical_cast<string> (d));
+ note (ERROR, String::compose ("PCM data difference of %1", d));
return false;
}
}
#include "exceptions.h"
#include "compose.hpp"
#include "AS_DCP.h"
-#include <boost/lexical_cast.hpp>
-using boost::lexical_cast;
using namespace dcp;
struct SoundMXFWriter::ASDCPState
}
read_picture_descriptor (desc);
+
+ ASDCP::WriterInfo info;
+ if (ASDCP_FAILURE (reader.FillWriterInfo (info))) {
+ boost::throw_exception (DCPReadError ("could not read video MXF information"));
+ }
+
+ read_writer_info (info);
}
StereoPictureMXF::StereoPictureMXF (Fraction edit_rate)
#ifndef LIBDCP_TYPES_H
#define LIBDCP_TYPES_H
-#include <string>
#include <boost/shared_ptr.hpp>
+#include <string>
namespace dcp
{
#include "certificates.h"
#include "gamma_lut.h"
#include "xyz_frame.h"
+#include "compose.hpp"
#include "KM_util.h"
#include "KM_fileio.h"
#include "AS_DCP.h"
#include <libxml++/document.h>
#include <openssl/sha.h>
#include <boost/filesystem.hpp>
-#include <boost/lexical_cast.hpp>
#include <stdexcept>
#include <sstream>
#include <iostream>
using std::setw;
using std::setfill;
using boost::shared_ptr;
-using boost::lexical_cast;
using namespace dcp;
/** Create a UUID.
if (!image) {
opj_destroy_decompress (decoder);
opj_cio_close (cio);
- boost::throw_exception (DCPReadError ("could not decode JPEG2000 codestream of " + lexical_cast<string> (size) + " bytes."));
+ boost::throw_exception (DCPReadError (String::compose ("could not decode JPEG2000 codestream of %1 bytes.", size)));
}
opj_destroy_decompress (decoder);
extern std::string utc_offset_to_string (int);
extern std::string ptime_to_string (boost::posix_time::ptime);
extern FILE * fopen_boost (boost::filesystem::path, std::string);
+
+template <class F, class T>
+std::list<boost::shared_ptr<T> >
+list_of_type (std::list<boost::shared_ptr<F> > const & from)
+{
+ std::list<boost::shared_ptr<T> > out;
+ for (typename std::list<boost::shared_ptr<F> >::const_iterator i = from.begin(); i != from.end(); ++i) {
+ boost::shared_ptr<T> check = boost::dynamic_pointer_cast<T> (*i);
+ if (check) {
+ out.push_back (check);
+ }
+ }
+
+ return out;
+}
}
conf.check_cfg(package='xmlsec1', args='--cflags --libs', uselib_store='XMLSEC1', mandatory=True)
# Remove erroneous escaping of quotes from xmlsec1 defines
conf.env.DEFINES_XMLSEC1 = [f.replace('\\', '') for f in conf.env.DEFINES_XMLSEC1]
+ conf.check_cfg(package='', path='Magick++-config', args='--cppflags --cxxflags --libs', uselib_store='MAGICK', mandatory=False)
if conf.options.static:
conf.check_cc(fragment="""