#include "asset_reader.h"
#include "mxf.h"
#include "exceptions.h"
+#include "decryption_context.h"
#include <asdcp/AS_DCP.h>
using namespace dcp;
AssetReader::AssetReader (MXF const * mxf)
- : _decryption_context (0)
+ : _decryption_context (new DecryptionContext (mxf->key ()))
{
- if (mxf->key()) {
- _decryption_context = new ASDCP::AESDecContext;
- if (ASDCP_FAILURE (_decryption_context->InitKey (mxf->key()->value ()))) {
- throw MiscError ("could not set up decryption context");
- }
- }
-}
-AssetReader::~AssetReader ()
-{
- delete _decryption_context;
}
#define LIBDCP_ASSET_READER_H
#include <boost/noncopyable.hpp>
-
-namespace ASDCP {
- class AESDecContext;
-}
+#include <boost/shared_ptr.hpp>
namespace dcp {
class MXF;
+class DecryptionContext;
class AssetReader : public boost::noncopyable
{
public:
explicit AssetReader (MXF const * mxf);
- virtual ~AssetReader ();
+ virtual ~AssetReader () {}
protected:
- ASDCP::AESDecContext* _decryption_context;
+ boost::shared_ptr<DecryptionContext> _decryption_context;
};
}
#include "colour_conversion.h"
#include "compose.hpp"
#include "j2k.h"
+#include "decryption_context.h"
#include <asdcp/KM_fileio.h>
#include <asdcp/AS_DCP.h>
* @param n Frame within the asset, not taking EntryPoint into account.
* @param c Context for decryption, or 0.
*/
-MonoPictureFrame::MonoPictureFrame (ASDCP::JP2K::MXFReader* reader, int n, ASDCP::AESDecContext* c)
+MonoPictureFrame::MonoPictureFrame (ASDCP::JP2K::MXFReader* reader, int n, shared_ptr<DecryptionContext> c)
{
/* XXX: unfortunate guesswork on this buffer size */
_buffer = new ASDCP::JP2K::FrameBuffer (4 * Kumu::Megabyte);
- if (ASDCP_FAILURE (reader->ReadFrame (n, *_buffer, c))) {
+ if (ASDCP_FAILURE (reader->ReadFrame (n, *_buffer, c->decryption()))) {
boost::throw_exception (DCPReadError (String::compose ("could not read video frame %1", n)));
}
}
namespace dcp {
class OpenJPEGImage;
+class DecryptionContext;
/** @class MonoPictureFrame
* @brief A single frame of a 2D (monoscopic) picture asset.
private:
friend class MonoPictureAssetReader;
- MonoPictureFrame (ASDCP::JP2K::MXFReader* reader, int n, ASDCP::AESDecContext *);
+ MonoPictureFrame (ASDCP::JP2K::MXFReader* reader, int n, boost::shared_ptr<DecryptionContext>);
ASDCP::JP2K::FrameBuffer* _buffer;
};
return _key_id;
}
- void set_key (Key);
+ virtual void set_key (Key);
/** @return encryption/decryption key, if one has been set */
boost::optional<Key> key () const {
/*
- Copyright (C) 2014-2015 Carl Hetherington <cth@carlh.net>
+ Copyright (C) 2014-2016 Carl Hetherington <cth@carlh.net>
This file is part of libdcp.
#include "decrypted_kdm_key.h"
#include "decrypted_kdm.h"
#include "interop_subtitle_asset.h"
+#include "smpte_subtitle_asset.h"
#include "reel_atmos_asset.h"
#include <libxml++/nodes/element.h>
if (_main_sound && i->id() == _main_sound->key_id()) {
_main_sound->asset()->set_key (i->key ());
}
+ if (_main_subtitle && i->id() == _main_subtitle->key_id()) {
+ shared_ptr<SMPTESubtitleAsset> s = dynamic_pointer_cast<SMPTESubtitleAsset> (_main_subtitle->asset());
+ if (s) {
+ s->set_key (i->key ());
+ }
+ }
if (_atmos && i->id() == _atmos->key_id()) {
_atmos->asset()->set_key (i->key ());
}
#include "subtitle_asset.h"
#include "reel_subtitle_asset.h"
+#include "smpte_subtitle_asset.h"
+#include <libxml++/libxml++.h>
using std::string;
using boost::shared_ptr;
+using boost::dynamic_pointer_cast;
+using boost::optional;
using namespace dcp;
ReelSubtitleAsset::ReelSubtitleAsset (boost::shared_ptr<SubtitleAsset> asset, Fraction edit_rate, int64_t intrinsic_duration, int64_t entry_point)
: ReelAsset (asset, edit_rate, intrinsic_duration, entry_point)
+ , ReelMXF (dynamic_pointer_cast<SMPTESubtitleAsset>(asset) ? dynamic_pointer_cast<SMPTESubtitleAsset>(asset)->key_id() : optional<string>())
{
}
ReelSubtitleAsset::ReelSubtitleAsset (boost::shared_ptr<const cxml::Node> node)
: ReelAsset (node)
+ , ReelMXF (node)
{
node->ignore_child ("Language");
node->done ();
{
return "MainSubtitle";
}
+
+string
+ReelSubtitleAsset::key_type () const
+{
+ return "MDSK";
+}
+
+void
+ReelSubtitleAsset::write_to_cpl (xmlpp::Node* node, Standard standard) const
+{
+ ReelAsset::write_to_cpl (node, standard);
+
+ if (key_id ()) {
+ /* Find <MainSubtitle> */
+ xmlpp::Node* ms = find_child (node, cpl_node_name ());
+ /* Find <Hash> */
+ xmlpp::Node* hash = find_child (ms, "Hash");
+ ms->add_child_before (hash, "KeyId")->add_child_text ("urn:uuid:" + key_id().get ());
+ }
+}
#define LIBDCP_REEL_SUBTITLE_ASSET_H
#include "reel_asset.h"
+#include "reel_mxf.h"
#include "subtitle_asset.h"
namespace dcp {
class SubtitleAsset;
/** @class ReelSubtitleAsset
- * @brief Part of a Reel's description which refers to a subtitle XML file.
+ * @brief Part of a Reel's description which refers to a subtitle XML/MXF file.
*/
-class ReelSubtitleAsset : public ReelAsset
+class ReelSubtitleAsset : public ReelAsset, public ReelMXF
{
public:
ReelSubtitleAsset (boost::shared_ptr<SubtitleAsset> asset, Fraction edit_rate, int64_t instrinsic_duration, int64_t entry_point);
explicit ReelSubtitleAsset (boost::shared_ptr<const cxml::Node>);
+ void write_to_cpl (xmlpp::Node* node, Standard standard) const;
+
boost::shared_ptr<SubtitleAsset> asset () const {
return asset_of_type<SubtitleAsset> ();
}
private:
+ std::string key_type () const;
std::string cpl_node_name () const;
};
/*
- Copyright (C) 2012-2015 Carl Hetherington <cth@carlh.net>
+ Copyright (C) 2012-2016 Carl Hetherington <cth@carlh.net>
This file is part of libdcp.
#include "util.h"
#include "compose.hpp"
#include "encryption_context.h"
+#include "decryption_context.h"
#include <asdcp/AS_DCP.h>
#include <asdcp/KM_util.h>
#include <libxml++/libxml++.h>
shared_ptr<cxml::Document> xml (new cxml::Document ("SubtitleReel"));
shared_ptr<ASDCP::TimedText::MXFReader> reader (new ASDCP::TimedText::MXFReader ());
- Kumu::Result_t r = reader->OpenRead (file.string().c_str ());
-
+ Kumu::Result_t r = reader->OpenRead (_file.string().c_str ());
if (!ASDCP_FAILURE (r)) {
- string s;
- reader->ReadTimedTextResource (s, 0, 0);
- xml->read_string (s);
+ /* MXF-wrapped */
ASDCP::WriterInfo info;
reader->FillWriterInfo (info);
_id = read_writer_info (info);
+ if (!_key_id) {
+ /* Not encrypted; read it in now */
+ string s;
+ reader->ReadTimedTextResource (s);
+ xml->read_string (s);
+ parse_xml (xml);
+ read_mxf_descriptor (reader, shared_ptr<DecryptionContext> (new DecryptionContext ()));
+ }
} else {
- reader.reset ();
+ /* Plain XML */
try {
+ xml.reset (new cxml::Document ("SubtitleReel"));
xml->read_file (file);
+ parse_xml (xml);
_id = remove_urn_uuid (xml->string_child ("Id"));
} catch (cxml::Error& e) {
boost::throw_exception (
);
}
}
+}
+void
+SMPTESubtitleAsset::parse_xml (shared_ptr<cxml::Document> xml)
+{
_load_font_nodes = type_children<dcp::SMPTELoadFontNode> (xml, "LoadFont");
_content_title_text = xml->string_child ("ContentTitleText");
parse_subtitles (xml, font_nodes, subtitle_nodes);
- if (reader) {
- ASDCP::TimedText::TimedTextDescriptor descriptor;
- reader->FillTimedTextDescriptor (descriptor);
+ /* Guess intrinsic duration */
+ _intrinsic_duration = latest_subtitle_out().as_editable_units (_edit_rate.numerator / _edit_rate.denominator);
+}
+
+void
+SMPTESubtitleAsset::read_mxf_descriptor (shared_ptr<ASDCP::TimedText::MXFReader> reader, shared_ptr<DecryptionContext> dec)
+{
+ ASDCP::TimedText::TimedTextDescriptor descriptor;
+ reader->FillTimedTextDescriptor (descriptor);
- /* Load fonts */
+ /* Load fonts */
- for (
- ASDCP::TimedText::ResourceList_t::const_iterator i = descriptor.ResourceList.begin();
- i != descriptor.ResourceList.end();
- ++i) {
+ for (
+ ASDCP::TimedText::ResourceList_t::const_iterator i = descriptor.ResourceList.begin();
+ i != descriptor.ResourceList.end();
+ ++i) {
- if (i->Type == ASDCP::TimedText::MT_OPENTYPE) {
- ASDCP::TimedText::FrameBuffer buffer;
- buffer.Capacity (10 * 1024 * 1024);
- reader->ReadAncillaryResource (i->ResourceID, buffer);
+ if (i->Type == ASDCP::TimedText::MT_OPENTYPE) {
+ ASDCP::TimedText::FrameBuffer buffer;
+ buffer.Capacity (10 * 1024 * 1024);
+ reader->ReadAncillaryResource (i->ResourceID, buffer, dec->decryption());
- char id[64];
- Kumu::bin2UUIDhex (i->ResourceID, ASDCP::UUIDlen, id, sizeof (id));
+ char id[64];
+ Kumu::bin2UUIDhex (i->ResourceID, ASDCP::UUIDlen, id, sizeof (id));
- shared_array<uint8_t> data (new uint8_t[buffer.Size()]);
- memcpy (data.get(), buffer.RoData(), buffer.Size());
+ shared_array<uint8_t> data (new uint8_t[buffer.Size()]);
+ memcpy (data.get(), buffer.RoData(), buffer.Size());
- list<shared_ptr<SMPTELoadFontNode> >::const_iterator j = _load_font_nodes.begin ();
- while (j != _load_font_nodes.end() && (*j)->urn != id) {
- ++j;
- }
+ list<shared_ptr<SMPTELoadFontNode> >::const_iterator j = _load_font_nodes.begin ();
+ while (j != _load_font_nodes.end() && (*j)->urn != id) {
+ ++j;
+ }
- if (j != _load_font_nodes.end ()) {
- _fonts.push_back (Font ((*j)->id, (*j)->urn, Data (data, buffer.Size ())));
- }
+ if (j != _load_font_nodes.end ()) {
+ _fonts.push_back (Font ((*j)->id, (*j)->urn, Data (data, buffer.Size ())));
}
}
+ }
- /* Get intrinsic duration */
- _intrinsic_duration = descriptor.ContainerDuration;
- } else {
- /* Guess intrinsic duration */
- _intrinsic_duration = latest_subtitle_out().as_editable_units (_edit_rate.numerator / _edit_rate.denominator);
+ /* Get intrinsic duration */
+ _intrinsic_duration = descriptor.ContainerDuration;
+}
+
+void
+SMPTESubtitleAsset::set_key (Key key)
+{
+ MXF::set_key (key);
+
+ if (!_key_id || _file.empty()) {
+ /* Either we don't have any data to read, or it wasn't
+ encrypted, so we don't need to do anything else.
+ */
+ return;
}
+
+ /* Our data was encrypted; now we can decrypt it */
+
+ shared_ptr<ASDCP::TimedText::MXFReader> reader (new ASDCP::TimedText::MXFReader ());
+ Kumu::Result_t r = reader->OpenRead (_file.string().c_str ());
+ if (ASDCP_FAILURE (r)) {
+ boost::throw_exception (
+ DCPReadError (
+ String::compose ("Could not read encrypted subtitle MXF (%1)", _file, static_cast<int> (r))
+ )
+ );
+ }
+
+ string s;
+ shared_ptr<DecryptionContext> dec (new DecryptionContext (key));
+ reader->ReadTimedTextResource (s, dec->decryption());
+ shared_ptr<cxml::Document> xml (new cxml::Document ("SubtitleReel"));
+ xml->read_string (s);
+ parse_xml (xml);
+ read_mxf_descriptor (reader, dec);
}
list<shared_ptr<LoadFontNode> >
namespace dcp {
class SMPTELoadFontNode;
+class DecryptionContext;
/** @class SMPTESubtitleAsset
* @brief A set of subtitles to be read and/or written in the SMPTE format.
void write (boost::filesystem::path path) const;
void add (SubtitleString);
void add_font (std::string id, boost::filesystem::path file);
+ void set_key (Key key);
void set_content_title_text (std::string t) {
_content_title_text = t;
private:
void read_fonts (boost::shared_ptr<ASDCP::TimedText::MXFReader>);
+ void parse_xml (boost::shared_ptr<cxml::Document> xml);
+ void read_mxf_descriptor (boost::shared_ptr<ASDCP::TimedText::MXFReader> reader, boost::shared_ptr<DecryptionContext> dec);
/** The total length of this content in video frames. The amount of
* content presented may be less than this.
#include "sound_frame.h"
#include "exceptions.h"
+#include "decryption_context.h"
#include <asdcp/AS_DCP.h>
#include <asdcp/KM_fileio.h>
-using namespace std;
using namespace dcp;
+using boost::shared_ptr;
-SoundFrame::SoundFrame (ASDCP::PCM::MXFReader* reader, int n, ASDCP::AESDecContext* c)
+SoundFrame::SoundFrame (ASDCP::PCM::MXFReader* reader, int n, shared_ptr<DecryptionContext> c)
{
/* XXX: unfortunate guesswork on this buffer size */
_buffer = new ASDCP::PCM::FrameBuffer (1 * Kumu::Megabyte);
- if (ASDCP_FAILURE (reader->ReadFrame (n, *_buffer, c))) {
+ if (ASDCP_FAILURE (reader->ReadFrame (n, *_buffer, c->decryption()))) {
boost::throw_exception (DCPReadError ("could not read audio frame"));
}
}
namespace dcp {
+class DecryptionContext;
+
/** @class SoundFrame
* @brief One ‘frame’ of sound data from a SoundAsset.
*/
private:
friend class SoundAssetReader;
- SoundFrame (ASDCP::PCM::MXFReader* reader, int n, ASDCP::AESDecContext *);
+ SoundFrame (ASDCP::PCM::MXFReader* reader, int n, boost::shared_ptr<DecryptionContext>);
/** a buffer to hold the frame */
ASDCP::PCM::FrameBuffer* _buffer;
#include "colour_conversion.h"
#include "compose.hpp"
#include "j2k.h"
+#include "decryption_context.h"
#include <asdcp/AS_DCP.h>
#include <asdcp/KM_fileio.h>
* @param reader Reader for the MXF file.
* @param n Frame within the asset, not taking EntryPoint into account.
*/
-StereoPictureFrame::StereoPictureFrame (ASDCP::JP2K::MXFSReader* reader, int n, ASDCP::AESDecContext* c)
+StereoPictureFrame::StereoPictureFrame (ASDCP::JP2K::MXFSReader* reader, int n, shared_ptr<DecryptionContext> c)
{
/* XXX: unfortunate guesswork on this buffer size */
_buffer = new ASDCP::JP2K::SFrameBuffer (4 * Kumu::Megabyte);
- if (ASDCP_FAILURE (reader->ReadFrame (n, *_buffer, c))) {
+ if (ASDCP_FAILURE (reader->ReadFrame (n, *_buffer, c->decryption()))) {
boost::throw_exception (DCPReadError (String::compose ("could not read video frame %1 of %2", n)));
}
}
namespace dcp {
class OpenJPEGImage;
+class DecryptionContext;
/** A single frame of a 3D (stereoscopic) picture asset */
class StereoPictureFrame : public boost::noncopyable
private:
friend class StereoPictureAssetReader;
- StereoPictureFrame (ASDCP::JP2K::MXFSReader* reader, int n, ASDCP::AESDecContext *);
+ StereoPictureFrame (ASDCP::JP2K::MXFSReader* reader, int n, boost::shared_ptr<DecryptionContext>);
ASDCP::JP2K::SFrameBuffer* _buffer;
};
dcp.cc
dcp_time.cc
decrypted_kdm.cc
+ decryption_context.cc
decrypted_kdm_key.cc
encrypted_kdm.cc
encryption_context.cc