diff options
| author | Carl Hetherington <cth@carlh.net> | 2013-01-14 20:15:43 +0000 |
|---|---|---|
| committer | Carl Hetherington <cth@carlh.net> | 2013-01-14 20:15:43 +0000 |
| commit | ed6a471b61d36a3ba7e8696fa3e5606406c5cf62 (patch) | |
| tree | 3ca098925eb269c4cd41ff22124773ba7d36c14b /src | |
| parent | 67cf9c95d190b1f2a67d73c0a7f712e213b6e71a (diff) | |
| parent | 62ee85a258aa9329544d8542dfbcc40ce8177a7a (diff) | |
Merge master
Diffstat (limited to 'src')
| -rw-r--r-- | src/argb_frame.cc | 6 | ||||
| -rw-r--r-- | src/asset.cc | 2 | ||||
| -rw-r--r-- | src/asset_map.cc | 3 | ||||
| -rw-r--r-- | src/asset_map.h | 9 | ||||
| -rw-r--r-- | src/cpl_file.h | 16 | ||||
| -rw-r--r-- | src/dcp.cc | 11 | ||||
| -rw-r--r-- | src/dcp.h | 9 | ||||
| -rw-r--r-- | src/dcp_time.cc | 2 | ||||
| -rw-r--r-- | src/dcp_time.h | 8 | ||||
| -rw-r--r-- | src/exceptions.h | 1 | ||||
| -rw-r--r-- | src/mxf_asset.h | 1 | ||||
| -rw-r--r-- | src/reel.cc | 3 | ||||
| -rw-r--r-- | src/reel.h | 1 | ||||
| -rw-r--r-- | src/sound_asset.cc | 33 | ||||
| -rw-r--r-- | src/sound_asset.h | 5 | ||||
| -rw-r--r-- | src/types.cc | 15 | ||||
| -rw-r--r-- | src/types.h | 9 | ||||
| -rw-r--r-- | src/util.cc | 64 | ||||
| -rw-r--r-- | src/util.h | 17 | ||||
| -rw-r--r-- | src/version.h | 1 | ||||
| -rw-r--r-- | src/xml.h | 2 |
21 files changed, 157 insertions, 61 deletions
diff --git a/src/argb_frame.cc b/src/argb_frame.cc index 7a9ad2b9..8e54e3b4 100644 --- a/src/argb_frame.cc +++ b/src/argb_frame.cc @@ -21,6 +21,11 @@ using namespace libdcp; +/** Construct an empty ARGBFrame with a given width and height and with + * undefined contents. + * @param width Width in pixels. + * @param height Height in pixels. + */ ARGBFrame::ARGBFrame (int width, int height) : _width (width) , _height (height) @@ -34,6 +39,7 @@ ARGBFrame::~ARGBFrame () delete[] _data; } +/** @return The stride, in bytes; that is, the number of bytes per row of the image */ int ARGBFrame::stride () const { diff --git a/src/asset.cc b/src/asset.cc index 62fdddf6..fa6947d1 100644 --- a/src/asset.cc +++ b/src/asset.cc @@ -86,7 +86,7 @@ string Asset::digest () const { if (_digest.empty ()) { - _digest = make_digest (path().string(), 0); + _digest = make_digest (path().string()); } return _digest; diff --git a/src/asset_map.cc b/src/asset_map.cc index 4fda0a89..8fcc515f 100644 --- a/src/asset_map.cc +++ b/src/asset_map.cc @@ -21,6 +21,7 @@ * @brief Classes used to parse a AssetMap. */ +#include <boost/algorithm/string.hpp> #include "asset_map.h" #include "util.h" @@ -55,7 +56,7 @@ Chunk::Chunk (xmlpp::Node const * node) string const prefix = "file://"; - if (starts_with (path, prefix)) { + if (boost::algorithm::starts_with (path, prefix)) { path = path.substr (prefix.length()); } diff --git a/src/asset_map.h b/src/asset_map.h index 10a0915f..8cf89b4b 100644 --- a/src/asset_map.h +++ b/src/asset_map.h @@ -27,6 +27,9 @@ namespace libdcp { +/** @class Chunk + * @brief A simple parser for and representation of a \<Chunk\> node within an asset map. + */ class Chunk : public XMLNode { public: @@ -39,6 +42,9 @@ public: int64_t length; }; +/** @class AssetMapAsset + * @brief A simple parser for and representation of an \<AssetMap\> node within an asset map. + */ class AssetMapAsset : public XMLNode { public: @@ -50,6 +56,9 @@ public: std::list<boost::shared_ptr<Chunk> > chunks; }; +/** @class AssetMap + * @brief A simple parser for and representation of an asset map file. + */ class AssetMap : public XMLFile { public: diff --git a/src/cpl_file.h b/src/cpl_file.h index 14bcafd0..67b38a0d 100644 --- a/src/cpl_file.h +++ b/src/cpl_file.h @@ -27,6 +27,7 @@ namespace libdcp { +/** @brief A simple parser for and representation of a CPL \<Picture\> node */ class Picture : public XMLNode { public: @@ -44,7 +45,7 @@ public: }; -/** CPL MainPicture node */ +/** @brief A simple parser for and representation of a CPL \<MainPicture\> node */ class MainPicture : public Picture { public: @@ -52,7 +53,7 @@ public: MainPicture (xmlpp::Node const * node); }; -/** CPL MainStereoscopicPicture node */ +/** @brief A simple parser for and representation of a CPL \<MainStereoscopicPicture\> node */ class MainStereoscopicPicture : public Picture { public: @@ -60,7 +61,7 @@ public: MainStereoscopicPicture (xmlpp::Node const * node); }; -/** CPL MainSound node */ +/** @brief A simple parser for and representation of a CPL \<MainSound\> node */ class MainSound : public XMLNode { public: @@ -75,7 +76,7 @@ public: int64_t duration; }; -/** CPL MainSubtitle node */ +/** @brief A simple parser for and representation of a CPL \<MainSubtitle\> node */ class MainSubtitle : public XMLNode { public: @@ -90,7 +91,7 @@ public: int64_t duration; }; -/** CPL AssetList node */ +/** @brief A simple parser for and representation of a CPL \<AssetList\> node */ class CPLAssetList : public XMLNode { public: @@ -103,7 +104,7 @@ public: boost::shared_ptr<MainSubtitle> main_subtitle; }; -/** CPL Reel node */ +/** @brief A simple parser for and representation of a CPL \<Reel\> node */ class CPLReel : public XMLNode { public: @@ -114,7 +115,8 @@ public: boost::shared_ptr<CPLAssetList> asset_list; }; -/** CPL ContentVersion node */ + +/** @brief A simple parser for and representation of a CPL \<ContentVersion\> node */ class ContentVersion : public XMLNode { public: @@ -28,6 +28,7 @@ #include <iostream> #include <boost/filesystem.hpp> #include <boost/lexical_cast.hpp> +#include <boost/algorithm/string.hpp> #include <libxml++/libxml++.h> #include <xmlsec/xmldsig.h> #include <xmlsec/app.h> @@ -208,7 +209,7 @@ DCP::read (bool require_mxfs) boost::filesystem::path t = _directory; t /= (*i)->chunks.front()->path; - if (ends_with (t.string(), ".mxf") || ends_with (t.string(), ".ttf")) { + if (boost::algorithm::ends_with (t.string(), ".mxf") || boost::algorithm::ends_with (t.string(), ".ttf")) { continue; } @@ -318,6 +319,12 @@ CPL::CPL (string directory, string name, ContentKind content_kind, int length, i _uuid = make_uuid (); } +/** Construct a CPL object from a XML file. + * @param directory The directory containing this CPL's DCP. + * @param file The CPL XML filename. + * @param asset_map The corresponding asset map. + * @param require_mxfs true to throw an exception if a required MXF file does not exist. + */ CPL::CPL (string directory, string file, shared_ptr<const AssetMap> asset_map, bool require_mxfs) : _directory (directory) , _content_kind (FEATURE) @@ -475,7 +482,7 @@ CPL::write_xml (shared_ptr<Encryption> crypt) const doc.write_to_file_formatted (p.string(), "UTF-8"); - _digest = make_digest (p.string (), 0); + _digest = make_digest (p.string ()); _length = boost::filesystem::file_size (p.string ()); } @@ -60,6 +60,7 @@ public: std::string signer_key; }; +/** @brief A CPL within a DCP */ class CPL { public: @@ -125,7 +126,9 @@ private: /** reels */ std::list<boost::shared_ptr<const Reel> > _reels; + /** our UUID */ std::string _uuid; + /** a SHA1 digest of our XML */ mutable std::string _digest; }; @@ -167,8 +170,12 @@ public: */ bool equals (DCP const & other, EqualityOptions options, std::list<std::string>& notes) const; + /** Add a CPL to this DCP. + * @param cpl CPL to add. + */ void add_cpl (boost::shared_ptr<CPL> cpl); + /** @return The list of CPLs in this DCP */ std::list<boost::shared_ptr<const CPL> > cpls () const { return _cpls; } @@ -194,6 +201,7 @@ private: */ void write_assetmap (std::string pkl_uuid, int pkl_length) const; + /** @return Assets in all this CPLs in this DCP */ std::list<boost::shared_ptr<const Asset> > assets () const; struct Files { @@ -204,6 +212,7 @@ private: /** the directory that we are writing to */ std::string _directory; + /** our CPLs */ std::list<boost::shared_ptr<const CPL> > _cpls; }; diff --git a/src/dcp_time.cc b/src/dcp_time.cc index c5a7affd..7c7c5298 100644 --- a/src/dcp_time.cc +++ b/src/dcp_time.cc @@ -222,6 +222,7 @@ libdcp::operator/ (Time a, Time const & b) return float (at) / bt; } +/** @return A string of the form h:m:s:t */ string Time::to_string () const { @@ -230,6 +231,7 @@ Time::to_string () const return str.str (); } +/** @return This time in ticks */ int64_t Time::to_ticks () const { diff --git a/src/dcp_time.h b/src/dcp_time.h index eff69579..1b73e3e8 100644 --- a/src/dcp_time.h +++ b/src/dcp_time.h @@ -39,7 +39,13 @@ public: * and a frames per second count. */ Time (int frame, int frames_per_second); - + + /** Construct a Time from hours, minutes, seconds and ticks. + * @param h_ Hours. + * @param m_ Minutes. + * @param s_ Seconds. + * @param t_ Ticks (where 1 tick is 4 milliseconds). + */ Time (int h_, int m_, int s_, int t_) : h (h_) , m (m_) diff --git a/src/exceptions.h b/src/exceptions.h index 25e51c9e..4c53a66d 100644 --- a/src/exceptions.h +++ b/src/exceptions.h @@ -55,6 +55,7 @@ private: std::string _filename; }; +/** @brief An exception related to an MXF file */ class MXFFileError : public FileError { public: diff --git a/src/mxf_asset.h b/src/mxf_asset.h index f68edc61..93fa9013 100644 --- a/src/mxf_asset.h +++ b/src/mxf_asset.h @@ -30,6 +30,7 @@ namespace ASDCP { namespace libdcp { +/** @brief Parent class for assets which have MXF files */ class MXFAsset : public Asset { public: diff --git a/src/reel.cc b/src/reel.cc index d8703dd0..ae3080ad 100644 --- a/src/reel.cc +++ b/src/reel.cc @@ -45,6 +45,9 @@ Reel::write_to_cpl (xmlpp::Node* parent) const if (_main_subtitle) { _main_subtitle->write_to_cpl (asset_list); } + + s << " </AssetList>\n" + << " </Reel>\n"; } bool @@ -31,6 +31,7 @@ class PictureAsset; class SoundAsset; class SubtitleAsset; +/** @brief A reel within a DCP; the part which actually contains picture, sound and subtitle data */ class Reel { public: diff --git a/src/sound_asset.cc b/src/sound_asset.cc index 77267cbd..d964a46d 100644 --- a/src/sound_asset.cc +++ b/src/sound_asset.cc @@ -43,12 +43,22 @@ using boost::lexical_cast; using namespace libdcp; SoundAsset::SoundAsset ( - vector<string> const & files, string directory, string mxf_name, boost::signals2::signal<void (float)>* progress, int fps, int length, bool encrypted + vector<string> const & files, + string directory, + string mxf_name, + boost::signals2::signal<void (float)>* progress, + int fps, + int length, + int start_frame, + bool encrypted ) : MXFAsset (directory, mxf_name, progress, fps, 0, length, encrypted) , _channels (files.size ()) , _sampling_rate (0) + , _start_frame (start_frame) { + assert (_channels); + construct (boost::bind (&SoundAsset::path_from_channel, this, _1, files)); } @@ -57,18 +67,26 @@ SoundAsset::SoundAsset ( string directory, string mxf_name, boost::signals2::signal<void (float)>* progress, - int fps, int length, int channels, bool encrypted + int fps, + int length, + int start_frame, + int channels, + bool encrypted ) : MXFAsset (directory, mxf_name, progress, fps, 0, length, encrypted) , _channels (channels) , _sampling_rate (0) + , _start_frame (start_frame) { + assert (_channels); + construct (get_path); } SoundAsset::SoundAsset (string directory, string mxf_name, int fps, int entry_point, int length) : MXFAsset (directory, mxf_name, 0, fps, entry_point, length, false) , _channels (0) + , _start_frame (0) { ASDCP::PCM::MXFReader reader; if (ASDCP_FAILURE (reader.OpenRead (path().string().c_str()))) { @@ -97,7 +115,7 @@ void SoundAsset::construct (boost::function<string (Channel)> get_path) { ASDCP::Rational asdcp_fps (_fps, 1); - + ASDCP::PCM::WAVParser pcm_parser_channel[_channels]; if (pcm_parser_channel[0].OpenRead (get_path(LEFT).c_str(), asdcp_fps)) { throw FileError ("could not open WAV file for reading", get_path(LEFT)); @@ -154,6 +172,15 @@ SoundAsset::construct (boost::function<string (Channel)> get_path) throw FileError ("could not open audio MXF for writing", path().string()); } + /* Skip through up to our _start_frame; this is pretty inefficient... */ + for (int i = 0; i < _start_frame; ++i) { + for (int j = 0; j < _channels; ++j) { + if (ASDCP_FAILURE (pcm_parser_channel[j].ReadFrame (frame_buffer_channel[j]))) { + throw MiscError ("could not read audio frame"); + } + } + } + for (int i = 0; i < _length; ++i) { for (int j = 0; j < _channels; ++j) { diff --git a/src/sound_asset.h b/src/sound_asset.h index 67115606..2b925641 100644 --- a/src/sound_asset.h +++ b/src/sound_asset.h @@ -44,6 +44,7 @@ public: * @param progress Signal to inform of progress. * @param fps Frames per second. * @param length Length in frames. + * @param start_frame Frame in the source to start writing from. * @param encrypted true if asset should be encrypted. */ SoundAsset ( @@ -53,6 +54,7 @@ public: boost::signals2::signal<void (float)>* progress, int fps, int length, + int start_frame bool encrypted ); @@ -64,6 +66,7 @@ public: * @param progress Signal to inform of progress. * @param fps Frames per second. * @param length Length in frames. + * @param start_frame Frame in the source to start writing from. * @param channels Number of audio channels. * @param encrypted true if asset should be encrypted. */ @@ -74,6 +77,7 @@ public: boost::signals2::signal<void (float)>* progress, int fps, int length, + int start_frame, int channels, bool encrypted ); @@ -112,6 +116,7 @@ private: /** Number of channels in the asset */ int _channels; int _sampling_rate; + int _start_frame; }; } diff --git a/src/types.cc b/src/types.cc index a00e8261..ac01ae45 100644 --- a/src/types.cc +++ b/src/types.cc @@ -49,6 +49,10 @@ Color::Color (int r_, int g_, int b_) } +/** Construct a Color from an ARGB hex string; the alpha value is ignored. + * @param argb_hex A string of the form AARRGGBB, where e.g. RR is a two-character + * hex value. + */ Color::Color (string argb_hex) { int alpha; @@ -57,6 +61,9 @@ Color::Color (string argb_hex) } } +/** @return An ARGB string of the form AARRGGBB, where e.g. RR is a two-character + * hex value. The alpha value will always be FF (ie 255; maximum alpha). + */ string Color::to_argb_string () const { @@ -72,12 +79,20 @@ Color::to_argb_string () const return t; } +/** operator== for Colors. + * @param a First color to compare. + * @param b Second color to compare. + */ bool libdcp::operator== (Color const & a, Color const & b) { return (a.r == b.r && a.g == b.g && a.b == b.b); } +/** operator!= for Colors. + * @param a First color to compare. + * @param b Second color to compare. + */ bool libdcp::operator!= (Color const & a, Color const & b) { diff --git a/src/types.h b/src/types.h index 433a910c..f1b5f640 100644 --- a/src/types.h +++ b/src/types.h @@ -105,6 +105,9 @@ struct EqualityOptions { int max_audio_sample_error; }; +/** @class Color + * @brief An RGB color (aka colour). + */ class Color { public: @@ -112,9 +115,9 @@ public: Color (int r_, int g_, int b_); Color (std::string argb_hex); - int r; - int g; - int b; + int r; ///< red component, from 0 to 255 + int g; ///< green component, from 0 to 255 + int b; ///< blue component, from 0 to 255 std::string to_argb_string () const; }; diff --git a/src/util.cc b/src/util.cc index f2ee35e3..8277b2bf 100644 --- a/src/util.cc +++ b/src/util.cc @@ -51,6 +51,9 @@ using std::list; using boost::shared_ptr; using namespace libdcp; +/** Create a UUID. + * @return UUID. + */ string libdcp::make_uuid () { @@ -61,11 +64,14 @@ libdcp::make_uuid () return string (buffer); } + +/** Create a digest for a file. + * @param filename File name. + * @return Digest. + */ string -libdcp::make_digest (string filename, boost::signals2::signal<void (float)>* progress) +libdcp::make_digest (string filename) { - int const file_size = boost::filesystem::file_size (filename); - Kumu::FileReader reader; if (ASDCP_FAILURE (reader.OpenRead (filename.c_str ()))) { throw FileError ("could not open file to compute digest", filename); @@ -88,10 +94,6 @@ libdcp::make_digest (string filename, boost::signals2::signal<void (float)>* pro SHA1_Update (&sha, read_buffer.Data(), read); done += read; - - if (progress) { - (*progress) (0.5 + (0.5 * done / file_size)); - } } byte_t byte_buffer[20]; @@ -101,6 +103,11 @@ libdcp::make_digest (string filename, boost::signals2::signal<void (float)>* pro return Kumu::base64encode (byte_buffer, 20, digest, 64); } +/** Convert a content kind to a string which can be used in a + * <ContentKind> node. + * @param kind ContentKind. + * @return string. + */ string libdcp::content_kind_to_string (ContentKind kind) { @@ -130,9 +137,16 @@ libdcp::content_kind_to_string (ContentKind kind) assert (false); } +/** Convert a string from a <ContentKind> node to a libdcp ContentKind. + * Reasonably tolerant about varying case. + * @param type Content kind string. + * @return libdcp ContentKind. + */ libdcp::ContentKind libdcp::content_kind_from_string (string type) { + /* XXX: should probably just convert type to lower-case and have done with it */ + if (type == "feature") { return FEATURE; } else if (type == "short") { @@ -157,27 +171,16 @@ libdcp::content_kind_from_string (string type) assert (false); } - -bool -libdcp::starts_with (string big, string little) -{ - if (little.size() > big.size()) { - return false; - } - - return big.substr (0, little.length()) == little; -} - -bool -libdcp::ends_with (string big, string little) -{ - if (little.size() > big.size()) { - return false; - } - - return big.compare (big.length() - little.length(), little.length(), little) == 0; -} +/** Decompress a JPEG2000 image to a bitmap. + * @param data JPEG2000 data. + * @param size Size of data in bytes. + * @param reduce A power of 2 by which to reduce the size of the decoded image; + * e.g. 0 reduces by (2^0 == 1), ie keeping the same size. + * 1 reduces by (2^1 == 2), ie halving the size of the image. + * This is useful for scaling 4K DCP images down to 2K. + * @return openjpeg image, which the caller must call opj_image_destroy() on. + */ opj_image_t * libdcp::decompress_j2k (uint8_t* data, int64_t size, int reduce) { @@ -201,6 +204,10 @@ libdcp::decompress_j2k (uint8_t* data, int64_t size, int reduce) return image; } +/** Convert an openjpeg XYZ image to RGB. + * @param xyz_frame Frame in XYZ. + * @return RGB image. + */ shared_ptr<ARGBFrame> libdcp::xyz_to_rgb (opj_image_t* xyz_frame) { @@ -263,6 +270,9 @@ libdcp::xyz_to_rgb (opj_image_t* xyz_frame) return argb_frame; } +/** @param s A string. + * @return true if the string contains only space, newline or tab characters, or is empty. + */ bool libdcp::empty_or_white_space (string s) { @@ -23,7 +23,6 @@ #include <string> #include <stdint.h> -#include <boost/signals2.hpp> #include <openjpeg.h> #include "types.h" @@ -36,25 +35,11 @@ namespace libdcp { class ARGBFrame; class CertificateChain; -/** Create a UUID. - * @return UUID. - */ extern std::string make_uuid (); - -/** Create a digest for a file. - * @param filename File name. - * @param progress If non-0, a signal which will be emitted periodically to update - * progress; the parameter will start at 0.5 and proceed to 1. - * @return Digest. - */ -extern std::string make_digest (std::string filename, boost::signals2::signal<void (float)>* progress); - +extern std::string make_digest (std::string filename); extern std::string content_kind_to_string (ContentKind kind); extern ContentKind content_kind_from_string (std::string kind); -extern bool starts_with (std::string big, std::string little); -extern bool ends_with (std::string big, std::string little); extern bool empty_or_white_space (std::string s); - extern opj_image_t* decompress_j2k (uint8_t* data, int64_t size, int reduce); extern boost::shared_ptr<ARGBFrame> xyz_to_rgb (opj_image_t* xyz_frame); diff --git a/src/version.h b/src/version.h index 7fd9dc25..52abd13a 100644 --- a/src/version.h +++ b/src/version.h @@ -3,5 +3,6 @@ namespace libdcp { extern char const * version; extern char const * git_commit; +extern bool built_with_debug; } @@ -18,6 +18,7 @@ namespace xmlpp { namespace libdcp { +/** @brief A helper class for XML nodes */ class XMLNode { public: @@ -86,6 +87,7 @@ private: std::list<Glib::ustring> _taken; }; +/** @brief A helper class for XML files */ class XMLFile : public XMLNode { public: |
