From 369ba52fe8b3ddeda734692541471c402016a18d Mon Sep 17 00:00:00 2001 From: Carl Hetherington Date: Thu, 17 Jan 2013 19:44:58 +0000 Subject: Use new Size struct. --- examples/make_dcp.cc | 2 +- src/argb_frame.cc | 14 ++++++-------- src/argb_frame.h | 14 +++++--------- src/picture_asset.cc | 24 +++++++++--------------- src/picture_asset.h | 29 ++++++++++------------------- src/util.cc | 2 +- src/util.h | 23 ++++++++++++++++++++++- test/tests.cc | 5 ++--- tools/dcpinfo.cc | 2 +- 9 files changed, 57 insertions(+), 58 deletions(-) diff --git a/examples/make_dcp.cc b/examples/make_dcp.cc index 68e3f4f9..1f5c74a1 100644 --- a/examples/make_dcp.cc +++ b/examples/make_dcp.cc @@ -73,7 +73,7 @@ main () for 2K projectors. */ boost::shared_ptr picture_asset ( - new libdcp::MonoPictureAsset (video_frame, "My Film DCP", "video.mxf", 0, 24, 48, 1998, 1080) + new libdcp::MonoPictureAsset (video_frame, "My Film DCP", "video.mxf", 0, 24, 48, libdcp::Size (1998, 1080)) ); /* Now we will create a `sound asset', which is made up of a WAV file for each channel of audio. Here we're using diff --git a/src/argb_frame.cc b/src/argb_frame.cc index 8e54e3b4..a48f80bb 100644 --- a/src/argb_frame.cc +++ b/src/argb_frame.cc @@ -21,16 +21,14 @@ using namespace libdcp; -/** Construct an empty ARGBFrame with a given width and height and with +/** Construct an empty ARGBFrame of a given size and with * undefined contents. - * @param width Width in pixels. - * @param height Height in pixels. + * @param size Size in pixels. */ -ARGBFrame::ARGBFrame (int width, int height) - : _width (width) - , _height (height) +ARGBFrame::ARGBFrame (Size size) + : _size (size) { - _data = new uint8_t[width * height * 4]; + _data = new uint8_t[_size.width * _size.height * 4]; } @@ -43,5 +41,5 @@ ARGBFrame::~ARGBFrame () int ARGBFrame::stride () const { - return _width * 4; + return _size.width * 4; } diff --git a/src/argb_frame.h b/src/argb_frame.h index c5c35768..a9946bb0 100644 --- a/src/argb_frame.h +++ b/src/argb_frame.h @@ -22,6 +22,7 @@ */ #include +#include "util.h" namespace libdcp { @@ -44,7 +45,7 @@ namespace libdcp class ARGBFrame { public: - ARGBFrame (int width, int height); + ARGBFrame (Size size); ~ARGBFrame (); uint8_t* data () const { @@ -54,17 +55,12 @@ public: /** Length of one picture row in bytes */ int stride () const; - int width () const { - return _width; - } - - int height () const { - return _height; + Size size () const { + return _size; } private: - int _width; - int _height; + Size _size; uint8_t* _data; }; diff --git a/src/picture_asset.cc b/src/picture_asset.cc index ef5d40d4..72c99bc6 100644 --- a/src/picture_asset.cc +++ b/src/picture_asset.cc @@ -48,8 +48,6 @@ using namespace libdcp; PictureAsset::PictureAsset (string directory, string mxf_name, boost::signals2::signal* progress, int fps, int entry_point, int length) : MXFAsset (directory, mxf_name, progress, fps, entry_point, length) - , _width (0) - , _height (0) { } @@ -65,7 +63,7 @@ PictureAsset::write_to_cpl (ostream& s) const << " 0\n" << " " << _length << "\n" << " " << _fps << " 1\n" - << " " << _width << " " << _height << "\n" + << " " << _size.width << " " << _size.height << "\n" << " \n"; } @@ -137,12 +135,10 @@ MonoPictureAsset::MonoPictureAsset ( boost::signals2::signal* progress, int fps, int length, - int width, - int height) + Size size) : PictureAsset (directory, mxf_name, progress, fps, 0, length) { - _width = width; - _height = height; + _size = size; construct (get_path); } @@ -153,12 +149,10 @@ MonoPictureAsset::MonoPictureAsset ( boost::signals2::signal* progress, int fps, int length, - int width, - int height) + Size size) : PictureAsset (directory, mxf_name, progress, fps, 0, length) { - _width = width; - _height = height; + _size = size; construct (boost::bind (&MonoPictureAsset::path_from_list, this, _1, files)); } @@ -175,8 +169,8 @@ MonoPictureAsset::MonoPictureAsset (string directory, string mxf_name, int fps, throw DCPReadError ("could not read video MXF information"); } - _width = desc.StoredWidth; - _height = desc.StoredHeight; + _size.width = desc.StoredWidth; + _size.height = desc.StoredHeight; } void @@ -375,8 +369,8 @@ StereoPictureAsset::StereoPictureAsset (string directory, string mxf_name, int f throw DCPReadError ("could not read video MXF information"); } - _width = desc.StoredWidth; - _height = desc.StoredHeight; + _size.width = desc.StoredWidth; + _size.height = desc.StoredHeight; } shared_ptr diff --git a/src/picture_asset.h b/src/picture_asset.h index 08eb338a..8bcd0173 100644 --- a/src/picture_asset.h +++ b/src/picture_asset.h @@ -23,6 +23,7 @@ #include #include "mxf_asset.h" +#include "util.h" namespace libdcp { @@ -43,12 +44,8 @@ public: bool equals (boost::shared_ptr other, EqualityOptions opt, std::list& notes) const; - int width () const { - return _width; - } - - int height () const { - return _height; + Size size () const { + return _size; } protected: @@ -57,11 +54,9 @@ protected: int frame, EqualityOptions opt, std::list& notes, uint8_t const * data_A, unsigned int size_A, uint8_t const * data_B, unsigned int size_B ) const; - - /** picture width in pixels */ - int _width; - /** picture height in pixels */ - int _height; + + /** picture size in pixels */ + Size _size; }; /** A 2D (monoscopic) picture asset */ @@ -76,8 +71,7 @@ public: * @param progress Signal to inform of progress. * @param fps Frames per second. * @param length Length in frames. - * @param width Width of images in pixels. - * @param height Height of images in pixels. + * @param size Size of images in pixels. */ MonoPictureAsset ( std::vector const & files, @@ -86,8 +80,7 @@ public: boost::signals2::signal* progress, int fps, int length, - int width, - int height + Size size ); /** Construct a PictureAsset, generating the MXF from the JPEG2000 files. @@ -98,8 +91,7 @@ public: * @param progress Signal to inform of progress. * @param fps Frames per second. * @param length Length in frames. - * @param width Width of images in pixels. - * @param height Height of images in pixels. + * @param size Size of images in pixels. */ MonoPictureAsset ( boost::function get_path, @@ -108,8 +100,7 @@ public: boost::signals2::signal* progress, int fps, int length, - int width, - int height + Size size ); MonoPictureAsset (std::string directory, std::string mxf_name, int fps, int entry_point, int length); diff --git a/src/util.cc b/src/util.cc index 6769cc41..4ddb466c 100644 --- a/src/util.cc +++ b/src/util.cc @@ -216,7 +216,7 @@ libdcp::xyz_to_rgb (opj_image_t* xyz_frame) int* xyz_y = xyz_frame->comps[1].data; int* xyz_z = xyz_frame->comps[2].data; - shared_ptr argb_frame (new ARGBFrame (xyz_frame->x1, xyz_frame->y1)); + shared_ptr argb_frame (new ARGBFrame (Size (xyz_frame->x1, xyz_frame->y1))); uint8_t* argb = argb_frame->data (); diff --git a/src/util.h b/src/util.h index 721d1138..dd153cb3 100644 --- a/src/util.h +++ b/src/util.h @@ -17,18 +17,37 @@ */ +#ifndef LIBDCP_UTIL_H +#define LIBDCP_UTIL_H + /** @file src/util.h * @brief Utility methods. */ #include #include +#include #include #include "types.h" namespace libdcp { -class ARGBFrame; +class ARGBFrame; + +struct Size { + Size () + : width (0) + , height (0) + {} + + Size (int w, int h) + : width (w) + , height (h) + {} + + int width; + int height; +}; extern std::string make_uuid (); extern std::string make_digest (std::string filename); @@ -39,3 +58,5 @@ extern opj_image_t* decompress_j2k (uint8_t* data, int64_t size, int reduce); extern boost::shared_ptr xyz_to_rgb (opj_image_t* xyz_frame); } + +#endif diff --git a/test/tests.cc b/test/tests.cc index be960699..3fb56a28 100644 --- a/test/tests.cc +++ b/test/tests.cc @@ -75,8 +75,7 @@ BOOST_AUTO_TEST_CASE (dcp_test) &d.Progress, 24, 24, - 32, - 32 + libdcp::Size (32, 32) )); shared_ptr ms (new libdcp::SoundAsset ( @@ -102,7 +101,7 @@ BOOST_AUTO_TEST_CASE (error_test) vector p; p.push_back ("frobozz"); - BOOST_CHECK_THROW (new libdcp::MonoPictureAsset (p, "build/test/bar", "video.mxf", &d.Progress, 24, 24, 32, 32), libdcp::FileError); + BOOST_CHECK_THROW (new libdcp::MonoPictureAsset (p, "build/test/bar", "video.mxf", &d.Progress, 24, 24, libdcp::Size (32, 32)), libdcp::FileError); BOOST_CHECK_THROW (new libdcp::SoundAsset (p, "build/test/bar", "audio.mxf", &d.Progress, 24, 24, 0), libdcp::FileError); } diff --git a/tools/dcpinfo.cc b/tools/dcpinfo.cc index 0c4b9b1a..40e2be99 100644 --- a/tools/dcpinfo.cc +++ b/tools/dcpinfo.cc @@ -91,7 +91,7 @@ main (int argc, char* argv[]) cout << " Reel " << R << "\n"; if ((*j)->main_picture()) { - cout << " Picture: " << (*j)->main_picture()->width() << "x" << (*j)->main_picture()->height() << "\n"; + cout << " Picture: " << (*j)->main_picture()->size().width << "x" << (*j)->main_picture()->size().height << "\n"; } if ((*j)->main_sound()) { cout << " Sound: " << (*j)->main_sound()->channels() << " channels at " << (*j)->main_sound()->sampling_rate() << "Hz\n"; -- cgit v1.2.3 From 828c320df8c56208a8834971f5d937ce06a4edf2 Mon Sep 17 00:00:00 2001 From: Carl Hetherington Date: Thu, 17 Jan 2013 20:16:10 +0000 Subject: Pull entry point out of the constructor. --- src/dcp.cc | 10 +++++++--- src/mxf_asset.cc | 10 ++++++++-- src/mxf_asset.h | 5 +++-- src/picture_asset.cc | 16 ++++++++-------- src/picture_asset.h | 6 +++--- src/sound_asset.cc | 8 ++++---- src/sound_asset.h | 1 - 7 files changed, 33 insertions(+), 23 deletions(-) diff --git a/src/dcp.cc b/src/dcp.cc index 6c626939..e148c772 100644 --- a/src/dcp.cc +++ b/src/dcp.cc @@ -363,10 +363,11 @@ CPL::CPL (string directory, string file, shared_ptr asset_map, b _directory, asset_map->asset_from_id (p->id)->chunks.front()->path, _fps, - (*i)->asset_list->main_picture->entry_point, (*i)->asset_list->main_picture->duration ) ); + + picture->set_entry_point ((*i)->asset_list->main_picture->entry_point); } catch (MXFFileError) { if (require_mxfs) { throw; @@ -380,10 +381,12 @@ CPL::CPL (string directory, string file, shared_ptr asset_map, b _directory, asset_map->asset_from_id (p->id)->chunks.front()->path, _fps, - p->entry_point, p->duration ) ); + + picture->set_entry_point (p->entry_point); + } catch (MXFFileError) { if (require_mxfs) { throw; @@ -399,10 +402,11 @@ CPL::CPL (string directory, string file, shared_ptr asset_map, b _directory, asset_map->asset_from_id ((*i)->asset_list->main_sound->id)->chunks.front()->path, _fps, - (*i)->asset_list->main_sound->entry_point, (*i)->asset_list->main_sound->duration ) ); + + sound->set_entry_point ((*i)->asset_list->main_sound->entry_point); } catch (MXFFileError) { if (require_mxfs) { throw; diff --git a/src/mxf_asset.cc b/src/mxf_asset.cc index 95412d0c..7e40f0e0 100644 --- a/src/mxf_asset.cc +++ b/src/mxf_asset.cc @@ -36,16 +36,22 @@ using boost::shared_ptr; using boost::dynamic_pointer_cast; using namespace libdcp; -MXFAsset::MXFAsset (string directory, string file_name, boost::signals2::signal* progress, int fps, int entry_point, int length) +MXFAsset::MXFAsset (string directory, string file_name, boost::signals2::signal* progress, int fps, int length) : Asset (directory, file_name) , _progress (progress) , _fps (fps) - , _entry_point (entry_point) + , _entry_point (0) , _length (length) { } +void +MXFAsset::set_entry_point (int e) +{ + _entry_point = e; +} + void MXFAsset::fill_writer_info (ASDCP::WriterInfo* writer_info) const { diff --git a/src/mxf_asset.h b/src/mxf_asset.h index b1cb87fe..798a7e50 100644 --- a/src/mxf_asset.h +++ b/src/mxf_asset.h @@ -35,10 +35,11 @@ public: * @param file_name Name of MXF file. * @param progress Signal to inform of progress. * @param fps Frames per second. - * @param entry_point The entry point of this MXF; ie the first frame that should be used. * @param length Length in frames. */ - MXFAsset (std::string directory, std::string file_name, boost::signals2::signal* progress, int fps, int entry_point, int length); + MXFAsset (std::string directory, std::string file_name, boost::signals2::signal* progress, int fps, int length); + + void set_entry_point (int e); virtual bool equals (boost::shared_ptr other, EqualityOptions opt, std::list& notes) const; diff --git a/src/picture_asset.cc b/src/picture_asset.cc index 72c99bc6..e5d88a6e 100644 --- a/src/picture_asset.cc +++ b/src/picture_asset.cc @@ -46,8 +46,8 @@ using boost::dynamic_pointer_cast; using boost::lexical_cast; using namespace libdcp; -PictureAsset::PictureAsset (string directory, string mxf_name, boost::signals2::signal* progress, int fps, int entry_point, int length) - : MXFAsset (directory, mxf_name, progress, fps, entry_point, length) +PictureAsset::PictureAsset (string directory, string mxf_name, boost::signals2::signal* progress, int fps, int length) + : MXFAsset (directory, mxf_name, progress, fps, length) { } @@ -136,7 +136,7 @@ MonoPictureAsset::MonoPictureAsset ( int fps, int length, Size size) - : PictureAsset (directory, mxf_name, progress, fps, 0, length) + : PictureAsset (directory, mxf_name, progress, fps, length) { _size = size; construct (get_path); @@ -150,14 +150,14 @@ MonoPictureAsset::MonoPictureAsset ( int fps, int length, Size size) - : PictureAsset (directory, mxf_name, progress, fps, 0, length) + : PictureAsset (directory, mxf_name, progress, fps, length) { _size = size; construct (boost::bind (&MonoPictureAsset::path_from_list, this, _1, files)); } -MonoPictureAsset::MonoPictureAsset (string directory, string mxf_name, int fps, int entry_point, int length) - : PictureAsset (directory, mxf_name, 0, fps, entry_point, length) +MonoPictureAsset::MonoPictureAsset (string directory, string mxf_name, int fps, int length) + : PictureAsset (directory, mxf_name, 0, fps, length) { ASDCP::JP2K::MXFReader reader; if (ASDCP_FAILURE (reader.OpenRead (path().string().c_str()))) { @@ -356,8 +356,8 @@ PictureAsset::frame_buffer_equals ( } -StereoPictureAsset::StereoPictureAsset (string directory, string mxf_name, int fps, int entry_point, int length) - : PictureAsset (directory, mxf_name, 0, fps, entry_point, length) +StereoPictureAsset::StereoPictureAsset (string directory, string mxf_name, int fps, int length) + : PictureAsset (directory, mxf_name, 0, fps, length) { ASDCP::JP2K::MXFSReader reader; if (ASDCP_FAILURE (reader.OpenRead (path().string().c_str()))) { diff --git a/src/picture_asset.h b/src/picture_asset.h index 8bcd0173..4bd7e8e4 100644 --- a/src/picture_asset.h +++ b/src/picture_asset.h @@ -35,7 +35,7 @@ class StereoPictureFrame; class PictureAsset : public MXFAsset { public: - PictureAsset (std::string directory, std::string mxf_name, boost::signals2::signal* progress, int fps, int entry_point, int length); + PictureAsset (std::string directory, std::string mxf_name, boost::signals2::signal* progress, int fps, int length); /** Write details of this asset to a CPL stream. * @param s Stream. @@ -103,7 +103,7 @@ public: Size size ); - MonoPictureAsset (std::string directory, std::string mxf_name, int fps, int entry_point, int length); + MonoPictureAsset (std::string directory, std::string mxf_name, int fps, int length); boost::shared_ptr get_frame (int n) const; bool equals (boost::shared_ptr other, EqualityOptions opt, std::list& notes) const; @@ -117,7 +117,7 @@ private: class StereoPictureAsset : public PictureAsset { public: - StereoPictureAsset (std::string directory, std::string mxf_name, int fps, int entry_point, int length); + StereoPictureAsset (std::string directory, std::string mxf_name, int fps, int length); boost::shared_ptr get_frame (int n) const; bool equals (boost::shared_ptr other, EqualityOptions opt, std::list& notes) const; diff --git a/src/sound_asset.cc b/src/sound_asset.cc index 98266b28..4f527409 100644 --- a/src/sound_asset.cc +++ b/src/sound_asset.cc @@ -44,7 +44,7 @@ using namespace libdcp; SoundAsset::SoundAsset ( vector const & files, string directory, string mxf_name, boost::signals2::signal* progress, int fps, int length, int start_frame ) - : MXFAsset (directory, mxf_name, progress, fps, 0, length) + : MXFAsset (directory, mxf_name, progress, fps, length) , _channels (files.size ()) , _sampling_rate (0) , _start_frame (start_frame) @@ -61,7 +61,7 @@ SoundAsset::SoundAsset ( boost::signals2::signal* progress, int fps, int length, int start_frame, int channels ) - : MXFAsset (directory, mxf_name, progress, fps, 0, length) + : MXFAsset (directory, mxf_name, progress, fps, length) , _channels (channels) , _sampling_rate (0) , _start_frame (start_frame) @@ -71,8 +71,8 @@ SoundAsset::SoundAsset ( 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) +SoundAsset::SoundAsset (string directory, string mxf_name, int fps, int length) + : MXFAsset (directory, mxf_name, 0, fps, length) , _channels (0) , _start_frame (0) { diff --git a/src/sound_asset.h b/src/sound_asset.h index 9fb1d60b..bd1811b1 100644 --- a/src/sound_asset.h +++ b/src/sound_asset.h @@ -82,7 +82,6 @@ public: std::string directory, std::string mxf_name, int fps, - int entry_point, int length ); -- cgit v1.2.3 From f150c837cdc6eeee8f61e743586ddbaf2a8c8010 Mon Sep 17 00:00:00 2001 From: Carl Hetherington Date: Thu, 17 Jan 2013 20:23:43 +0000 Subject: Replace length with intrinsic_duration. --- src/cpl_file.h | 3 +++ src/mxf_asset.cc | 12 ++++++------ src/mxf_asset.h | 10 +++++----- src/picture_asset.cc | 32 ++++++++++++++++---------------- src/picture_asset.h | 14 +++++++------- src/sound_asset.cc | 22 +++++++++++----------- src/sound_asset.h | 10 +++++----- 7 files changed, 53 insertions(+), 50 deletions(-) diff --git a/src/cpl_file.h b/src/cpl_file.h index 67b38a0d..44115401 100644 --- a/src/cpl_file.h +++ b/src/cpl_file.h @@ -37,8 +37,11 @@ public: std::string id; std::string annotation_text; Fraction edit_rate; + /** Duration of the whole thing */ int64_t intrinsic_duration; + /** Start point in frames */ int64_t entry_point; + /** Duration that will actually play */ int64_t duration; Fraction frame_rate; Fraction screen_aspect_ratio; diff --git a/src/mxf_asset.cc b/src/mxf_asset.cc index 7e40f0e0..338d125f 100644 --- a/src/mxf_asset.cc +++ b/src/mxf_asset.cc @@ -36,12 +36,12 @@ using boost::shared_ptr; using boost::dynamic_pointer_cast; using namespace libdcp; -MXFAsset::MXFAsset (string directory, string file_name, boost::signals2::signal* progress, int fps, int length) +MXFAsset::MXFAsset (string directory, string file_name, boost::signals2::signal* progress, int fps, int intrinsic_duration) : Asset (directory, file_name) , _progress (progress) , _fps (fps) , _entry_point (0) - , _length (length) + , _intrinsic_duration (intrinsic_duration) { } @@ -84,8 +84,8 @@ MXFAsset::equals (shared_ptr other, EqualityOptions, list& return false; } - if (_length != other_mxf->_length) { - notes.push_back ("MXF lengths differ"); + if (_intrinsic_duration != other_mxf->_intrinsic_duration) { + notes.push_back ("MXF intrinsic durations differ"); return false; } @@ -93,7 +93,7 @@ MXFAsset::equals (shared_ptr other, EqualityOptions, list& } int -MXFAsset::length () const +MXFAsset::intrinsic_duration () const { - return _length; + return _intrinsic_duration; } diff --git a/src/mxf_asset.h b/src/mxf_asset.h index 798a7e50..10049232 100644 --- a/src/mxf_asset.h +++ b/src/mxf_asset.h @@ -35,15 +35,15 @@ public: * @param file_name Name of MXF file. * @param progress Signal to inform of progress. * @param fps Frames per second. - * @param length Length in frames. + * @param intrinsic_duration Duration of the whole asset in frames. */ - MXFAsset (std::string directory, std::string file_name, boost::signals2::signal* progress, int fps, int length); + MXFAsset (std::string directory, std::string file_name, boost::signals2::signal* progress, int fps, int intrinsic_duration); void set_entry_point (int e); virtual bool equals (boost::shared_ptr other, EqualityOptions opt, std::list& notes) const; - int length () const; + int intrinsic_duration () const; protected: /** Fill in a ADSCP::WriteInfo struct. @@ -56,8 +56,8 @@ protected: /** Frames per second */ int _fps; int _entry_point; - /** Length in frames */ - int _length; + /** Total length in frames */ + int _intrinsic_duration; }; } diff --git a/src/picture_asset.cc b/src/picture_asset.cc index e5d88a6e..905f75f5 100644 --- a/src/picture_asset.cc +++ b/src/picture_asset.cc @@ -46,8 +46,8 @@ using boost::dynamic_pointer_cast; using boost::lexical_cast; using namespace libdcp; -PictureAsset::PictureAsset (string directory, string mxf_name, boost::signals2::signal* progress, int fps, int length) - : MXFAsset (directory, mxf_name, progress, fps, length) +PictureAsset::PictureAsset (string directory, string mxf_name, boost::signals2::signal* progress, int fps, int intrinsic_duration) + : MXFAsset (directory, mxf_name, progress, fps, intrinsic_duration) { } @@ -59,9 +59,9 @@ PictureAsset::write_to_cpl (ostream& s) const << " urn:uuid:" << _uuid << "\n" << " " << _file_name << "\n" << " " << _fps << " 1\n" - << " " << _length << "\n" + << " " << _intrinsic_duration << "\n" << " 0\n" - << " " << _length << "\n" + << " " << _intrinsic_duration << "\n" << " " << _fps << " 1\n" << " " << _size.width << " " << _size.height << "\n" << " \n"; @@ -134,9 +134,9 @@ MonoPictureAsset::MonoPictureAsset ( string mxf_name, boost::signals2::signal* progress, int fps, - int length, + int intrinsic_duration, Size size) - : PictureAsset (directory, mxf_name, progress, fps, length) + : PictureAsset (directory, mxf_name, progress, fps, intrinsic_duration) { _size = size; construct (get_path); @@ -148,16 +148,16 @@ MonoPictureAsset::MonoPictureAsset ( string mxf_name, boost::signals2::signal* progress, int fps, - int length, + int intrinsic_duration, Size size) - : PictureAsset (directory, mxf_name, progress, fps, length) + : PictureAsset (directory, mxf_name, progress, fps, intrinsic_duration) { _size = size; construct (boost::bind (&MonoPictureAsset::path_from_list, this, _1, files)); } -MonoPictureAsset::MonoPictureAsset (string directory, string mxf_name, int fps, int length) - : PictureAsset (directory, mxf_name, 0, fps, length) +MonoPictureAsset::MonoPictureAsset (string directory, string mxf_name, int fps, int intrinsic_duration) + : PictureAsset (directory, mxf_name, 0, fps, intrinsic_duration) { ASDCP::JP2K::MXFReader reader; if (ASDCP_FAILURE (reader.OpenRead (path().string().c_str()))) { @@ -194,7 +194,7 @@ MonoPictureAsset::construct (boost::function get_path) throw MXFFileError ("could not open MXF file for writing", path().string()); } - for (int i = 0; i < _length; ++i) { + for (int i = 0; i < _intrinsic_duration; ++i) { string const path = get_path (i); @@ -208,7 +208,7 @@ MonoPictureAsset::construct (boost::function get_path) } if (_progress) { - (*_progress) (0.5 * float (i) / _length); + (*_progress) (0.5 * float (i) / _intrinsic_duration); } } @@ -240,7 +240,7 @@ MonoPictureAsset::equals (shared_ptr other, EqualityOptions opt, li shared_ptr other_picture = dynamic_pointer_cast (other); assert (other_picture); - for (int i = 0; i < _length; ++i) { + for (int i = 0; i < _intrinsic_duration; ++i) { shared_ptr frame_A = get_frame (i); shared_ptr frame_B = other_picture->get_frame (i); @@ -266,7 +266,7 @@ StereoPictureAsset::equals (shared_ptr other, EqualityOptions opt, shared_ptr other_picture = dynamic_pointer_cast (other); assert (other_picture); - for (int i = 0; i < _length; ++i) { + for (int i = 0; i < _intrinsic_duration; ++i) { shared_ptr frame_A = get_frame (i); shared_ptr frame_B = other_picture->get_frame (i); @@ -356,8 +356,8 @@ PictureAsset::frame_buffer_equals ( } -StereoPictureAsset::StereoPictureAsset (string directory, string mxf_name, int fps, int length) - : PictureAsset (directory, mxf_name, 0, fps, length) +StereoPictureAsset::StereoPictureAsset (string directory, string mxf_name, int fps, int intrinsic_duration) + : PictureAsset (directory, mxf_name, 0, fps, intrinsic_duration) { ASDCP::JP2K::MXFSReader reader; if (ASDCP_FAILURE (reader.OpenRead (path().string().c_str()))) { diff --git a/src/picture_asset.h b/src/picture_asset.h index 4bd7e8e4..d2c6f656 100644 --- a/src/picture_asset.h +++ b/src/picture_asset.h @@ -35,7 +35,7 @@ class StereoPictureFrame; class PictureAsset : public MXFAsset { public: - PictureAsset (std::string directory, std::string mxf_name, boost::signals2::signal* progress, int fps, int length); + PictureAsset (std::string directory, std::string mxf_name, boost::signals2::signal* progress, int fps, int intrinsic_duration); /** Write details of this asset to a CPL stream. * @param s Stream. @@ -70,7 +70,7 @@ public: * @param mxf_name Name of MXF file to create. * @param progress Signal to inform of progress. * @param fps Frames per second. - * @param length Length in frames. + * @param intrinsic_duration Length of the whole asset in frames. * @param size Size of images in pixels. */ MonoPictureAsset ( @@ -79,7 +79,7 @@ public: std::string mxf_name, boost::signals2::signal* progress, int fps, - int length, + int intrinsic_duration, Size size ); @@ -90,7 +90,7 @@ public: * @param mxf_name Name of MXF file to create. * @param progress Signal to inform of progress. * @param fps Frames per second. - * @param length Length in frames. + * @param intrinsic_duration Length of the whole asset in frames. * @param size Size of images in pixels. */ MonoPictureAsset ( @@ -99,11 +99,11 @@ public: std::string mxf_name, boost::signals2::signal* progress, int fps, - int length, + int intrinsic_duration, Size size ); - MonoPictureAsset (std::string directory, std::string mxf_name, int fps, int length); + MonoPictureAsset (std::string directory, std::string mxf_name, int fps, int intrinsic_duration); boost::shared_ptr get_frame (int n) const; bool equals (boost::shared_ptr other, EqualityOptions opt, std::list& notes) const; @@ -117,7 +117,7 @@ private: class StereoPictureAsset : public PictureAsset { public: - StereoPictureAsset (std::string directory, std::string mxf_name, int fps, int length); + StereoPictureAsset (std::string directory, std::string mxf_name, int fps, int intrinsic_duration); boost::shared_ptr get_frame (int n) const; bool equals (boost::shared_ptr other, EqualityOptions opt, std::list& notes) const; diff --git a/src/sound_asset.cc b/src/sound_asset.cc index 4f527409..07132665 100644 --- a/src/sound_asset.cc +++ b/src/sound_asset.cc @@ -42,9 +42,9 @@ using boost::lexical_cast; using namespace libdcp; SoundAsset::SoundAsset ( - vector const & files, string directory, string mxf_name, boost::signals2::signal* progress, int fps, int length, int start_frame + vector const & files, string directory, string mxf_name, boost::signals2::signal* progress, int fps, int intrinsic_duration, int start_frame ) - : MXFAsset (directory, mxf_name, progress, fps, length) + : MXFAsset (directory, mxf_name, progress, fps, intrinsic_duration) , _channels (files.size ()) , _sampling_rate (0) , _start_frame (start_frame) @@ -59,9 +59,9 @@ SoundAsset::SoundAsset ( string directory, string mxf_name, boost::signals2::signal* progress, - int fps, int length, int start_frame, int channels + int fps, int intrinsic_duration, int start_frame, int channels ) - : MXFAsset (directory, mxf_name, progress, fps, length) + : MXFAsset (directory, mxf_name, progress, fps, intrinsic_duration) , _channels (channels) , _sampling_rate (0) , _start_frame (start_frame) @@ -71,8 +71,8 @@ SoundAsset::SoundAsset ( construct (get_path); } -SoundAsset::SoundAsset (string directory, string mxf_name, int fps, int length) - : MXFAsset (directory, mxf_name, 0, fps, length) +SoundAsset::SoundAsset (string directory, string mxf_name, int fps, int intrinsic_duration) + : MXFAsset (directory, mxf_name, 0, fps, intrinsic_duration) , _channels (0) , _start_frame (0) { @@ -169,7 +169,7 @@ SoundAsset::construct (boost::function get_path) } } - for (int i = 0; i < _length; ++i) { + for (int i = 0; i < _intrinsic_duration; ++i) { for (int j = 0; j < _channels; ++j) { memset (frame_buffer_channel[j].Data(), 0, frame_buffer_channel[j].Capacity()); @@ -197,7 +197,7 @@ SoundAsset::construct (boost::function get_path) } if (_progress) { - (*_progress) (0.5 * float (i) / _length); + (*_progress) (0.5 * float (i) / _intrinsic_duration); } } @@ -213,9 +213,9 @@ SoundAsset::write_to_cpl (ostream& s) const << " urn:uuid:" << _uuid << "\n" << " " << _file_name << "\n" << " " << _fps << " 1\n" - << " " << _length << "\n" + << " " << _intrinsic_duration << "\n" << " 0\n" - << " " << _length << "\n" + << " " << _intrinsic_duration << "\n" << " \n"; } @@ -265,7 +265,7 @@ SoundAsset::equals (shared_ptr other, EqualityOptions opt, list* progress, int fps, - int length, + int intrinsic_duration, int start_frame ); @@ -63,7 +63,7 @@ public: * @param mxf_name Name of MXF file to create. * @param progress Signal to inform of progress. * @param fps Frames per second. - * @param length Length in frames. + * @param intrinsic_duration Length of the whole asset in frames. * @param start_frame Frame in the source to start writing from. * @param channels Number of audio channels. */ @@ -73,7 +73,7 @@ public: std::string mxf_name, boost::signals2::signal* progress, int fps, - int length, + int intrinsic_duration, int start_frame, int channels ); @@ -82,7 +82,7 @@ public: std::string directory, std::string mxf_name, int fps, - int length + int intrinsic_duration ); /** Write details of this asset to a CPL stream. -- cgit v1.2.3 From cfda7f5d088f9800d5e9f2d39c4495f31b25f305 Mon Sep 17 00:00:00 2001 From: Carl Hetherington Date: Thu, 17 Jan 2013 20:26:06 +0000 Subject: Add duration, starting off as intrinsic_duration but changeable. --- src/mxf_asset.cc | 12 ++++++++++++ src/mxf_asset.h | 4 ++++ src/picture_asset.cc | 4 ++-- src/sound_asset.cc | 4 ++-- 4 files changed, 20 insertions(+), 4 deletions(-) diff --git a/src/mxf_asset.cc b/src/mxf_asset.cc index 338d125f..77e4b098 100644 --- a/src/mxf_asset.cc +++ b/src/mxf_asset.cc @@ -42,6 +42,7 @@ MXFAsset::MXFAsset (string directory, string file_name, boost::signals2::signal< , _fps (fps) , _entry_point (0) , _intrinsic_duration (intrinsic_duration) + , _duration (intrinsic_duration) { } @@ -52,6 +53,12 @@ MXFAsset::set_entry_point (int e) _entry_point = e; } +void +MXFAsset::set_duration (int d) +{ + _duration = d; +} + void MXFAsset::fill_writer_info (ASDCP::WriterInfo* writer_info) const { @@ -89,6 +96,11 @@ MXFAsset::equals (shared_ptr other, EqualityOptions, list& return false; } + if (_duration != other_mxf->_duration) { + notes.push_back ("MXF durations differ"); + return false; + } + return true; } diff --git a/src/mxf_asset.h b/src/mxf_asset.h index 10049232..95261353 100644 --- a/src/mxf_asset.h +++ b/src/mxf_asset.h @@ -40,6 +40,7 @@ public: MXFAsset (std::string directory, std::string file_name, boost::signals2::signal* progress, int fps, int intrinsic_duration); void set_entry_point (int e); + void set_duration (int d); virtual bool equals (boost::shared_ptr other, EqualityOptions opt, std::list& notes) const; @@ -55,9 +56,12 @@ protected: boost::signals2::signal* _progress; /** Frames per second */ int _fps; + /** Start point to present in frames */ int _entry_point; /** Total length in frames */ int _intrinsic_duration; + /** Length to present in frames */ + int _duration; }; } diff --git a/src/picture_asset.cc b/src/picture_asset.cc index 905f75f5..3058c13d 100644 --- a/src/picture_asset.cc +++ b/src/picture_asset.cc @@ -60,8 +60,8 @@ PictureAsset::write_to_cpl (ostream& s) const << " " << _file_name << "\n" << " " << _fps << " 1\n" << " " << _intrinsic_duration << "\n" - << " 0\n" - << " " << _intrinsic_duration << "\n" + << " " << _entry_point << "\n" + << " " << _duration << "\n" << " " << _fps << " 1\n" << " " << _size.width << " " << _size.height << "\n" << " \n"; diff --git a/src/sound_asset.cc b/src/sound_asset.cc index 07132665..7abd2037 100644 --- a/src/sound_asset.cc +++ b/src/sound_asset.cc @@ -214,8 +214,8 @@ SoundAsset::write_to_cpl (ostream& s) const << " " << _file_name << "\n" << " " << _fps << " 1\n" << " " << _intrinsic_duration << "\n" - << " 0\n" - << " " << _intrinsic_duration << "\n" + << " " << _entry_point << "\n" + << " " << _duration << "\n" << " \n"; } -- cgit v1.2.3 From 7ad5465b35e8fbf4be80ec93553bd73d25f2b29b Mon Sep 17 00:00:00 2001 From: Carl Hetherington Date: Thu, 17 Jan 2013 20:28:51 +0000 Subject: Tidy up slightly. --- src/sound_asset.cc | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/sound_asset.cc b/src/sound_asset.cc index 7abd2037..be77739a 100644 --- a/src/sound_asset.cc +++ b/src/sound_asset.cc @@ -42,7 +42,11 @@ using boost::lexical_cast; using namespace libdcp; SoundAsset::SoundAsset ( - vector const & files, string directory, string mxf_name, boost::signals2::signal* progress, int fps, int intrinsic_duration, int start_frame + vector const & files, + string directory, + string mxf_name, + boost::signals2::signal* progress, + int fps, int intrinsic_duration, int start_frame ) : MXFAsset (directory, mxf_name, progress, fps, intrinsic_duration) , _channels (files.size ()) -- cgit v1.2.3 From c2cf8eb8d22265988bbf81e0331a98a7aa6786ed Mon Sep 17 00:00:00 2001 From: Carl Hetherington Date: Thu, 17 Jan 2013 20:29:51 +0000 Subject: Comment tweaks. --- src/sound_asset.h | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/sound_asset.h b/src/sound_asset.h index 95efccd6..569bb305 100644 --- a/src/sound_asset.h +++ b/src/sound_asset.h @@ -45,6 +45,7 @@ public: * @param fps Frames per second. * @param intrinsic_duration Length of the whole asset in frames. * @param start_frame Frame in the source to start writing from. + * Note that this is different to entry_point in that the asset will contain no data before start_frame. */ SoundAsset ( std::vector const & files, @@ -65,6 +66,7 @@ public: * @param fps Frames per second. * @param intrinsic_duration Length of the whole asset in frames. * @param start_frame Frame in the source to start writing from. + * Note that this is different to entry_point in that the asset will contain no data before start_frame. * @param channels Number of audio channels. */ SoundAsset ( -- cgit v1.2.3 From c289685296d58228df0a88354e966105b242c915 Mon Sep 17 00:00:00 2001 From: Carl Hetherington Date: Thu, 17 Jan 2013 21:30:34 +0000 Subject: Add Size operators; install util.h --- src/util.cc | 11 +++++++++++ src/util.h | 3 +++ src/wscript | 1 + 3 files changed, 15 insertions(+) diff --git a/src/util.cc b/src/util.cc index 4ddb466c..1cbec719 100644 --- a/src/util.cc +++ b/src/util.cc @@ -277,3 +277,14 @@ libdcp::empty_or_white_space (string s) return true; } + +bool libdcp::operator== (libdcp::Size const & a, libdcp::Size const & b) +{ + return (a.width == b.width && a.height == b.height); +} + +bool libdcp::operator!= (libdcp::Size const & a, libdcp::Size const & b) +{ + return !(a == b); +} + diff --git a/src/util.h b/src/util.h index dd153cb3..f5685970 100644 --- a/src/util.h +++ b/src/util.h @@ -49,6 +49,9 @@ struct Size { int height; }; +extern bool operator== (Size const & a, Size const & b); +extern bool operator!= (Size const & a, Size const & b); + extern std::string make_uuid (); extern std::string make_digest (std::string filename); extern std::string content_kind_to_string (ContentKind kind); diff --git a/src/wscript b/src/wscript index 04656976..d243ae46 100644 --- a/src/wscript +++ b/src/wscript @@ -49,6 +49,7 @@ def build(bld): subtitle_asset.h test_mode.h types.h + util.h version.h xml.h """ -- cgit v1.2.3 From 2489080f9a5d2891da0fc313b2c0ac1450a630ad Mon Sep 17 00:00:00 2001 From: Carl Hetherington Date: Fri, 18 Jan 2013 20:25:02 +0000 Subject: Allow incremental writing of picture MXFs. --- asdcplib/src/AS_DCP.h | 2 + asdcplib/src/JP2K_Codestream_Parser.cpp | 29 ++++++++++++ src/asset.h | 5 +-- src/mxf_asset.cc | 4 +- src/mxf_asset.h | 13 +++++- src/picture_asset.cc | 78 +++++++++++++++++++++++++++++---- src/picture_asset.h | 37 +++++++++++++++- src/sound_asset.cc | 2 +- 8 files changed, 153 insertions(+), 17 deletions(-) diff --git a/asdcplib/src/AS_DCP.h b/asdcplib/src/AS_DCP.h index b227c063..3d679413 100755 --- a/asdcplib/src/AS_DCP.h +++ b/asdcplib/src/AS_DCP.h @@ -1090,6 +1090,8 @@ namespace ASDCP { // encrypted headers. Result_t OpenReadFrame(const char* filename, FrameBuffer&) const; + Result_t OpenReadFrame(const unsigned char * data, unsigned int size, FrameBuffer&) const; + // Fill a PictureDescriptor struct with the values from the file's codestream. // Returns RESULT_INIT if the file is not open. Result_t FillPictureDescriptor(PictureDescriptor&) const; diff --git a/asdcplib/src/JP2K_Codestream_Parser.cpp b/asdcplib/src/JP2K_Codestream_Parser.cpp index c7891231..5ab7a322 100755 --- a/asdcplib/src/JP2K_Codestream_Parser.cpp +++ b/asdcplib/src/JP2K_Codestream_Parser.cpp @@ -91,6 +91,26 @@ public: return result; } + + Result_t OpenReadFrame(const unsigned char * data, unsigned int size, FrameBuffer& FB) + { + if ( FB.Capacity() < size ) + { + DefaultLogSink().Error("FrameBuf.Capacity: %u frame length: %u\n", FB.Capacity(), (ui32_t) size); + return RESULT_SMALLBUF; + } + + memcpy (FB.Data(), data, size); + FB.Size(size); + + byte_t start_of_data = 0; // out param + const Result_t result = ParseMetadataIntoDesc(FB, m_PDesc, &start_of_data); + + if ( ASDCP_SUCCESS(result) ) + FB.PlaintextOffset(start_of_data); + + return result; + } }; ASDCP::Result_t @@ -224,6 +244,15 @@ ASDCP::JP2K::CodestreamParser::OpenReadFrame(const char* filename, FrameBuffer& return m_Parser->OpenReadFrame(filename, FB); } +// Opens the stream for reading, parses enough data to provide a complete +// set of stream metadata for the MXFWriter below. +ASDCP::Result_t +ASDCP::JP2K::CodestreamParser::OpenReadFrame(const unsigned char* data, unsigned int size, FrameBuffer& FB) const +{ + const_cast(this)->m_Parser = new h__CodestreamParser; + return m_Parser->OpenReadFrame(data, size, FB); +} + // ASDCP::Result_t ASDCP::JP2K::CodestreamParser::FillPictureDescriptor(PictureDescriptor& PDesc) const diff --git a/src/asset.h b/src/asset.h index cc6fbcb7..3ba0a0cf 100644 --- a/src/asset.h +++ b/src/asset.h @@ -70,14 +70,13 @@ public: return _uuid; } + boost::filesystem::path path () const; + virtual bool equals (boost::shared_ptr other, EqualityOptions opt, std::list& notes) const = 0; protected: - friend class PictureAsset; - friend class SoundAsset; std::string digest () const; - boost::filesystem::path path () const; /** Directory that our MXF or XML file is in */ std::string _directory; diff --git a/src/mxf_asset.cc b/src/mxf_asset.cc index 77e4b098..af3c74dc 100644 --- a/src/mxf_asset.cc +++ b/src/mxf_asset.cc @@ -60,7 +60,7 @@ MXFAsset::set_duration (int d) } void -MXFAsset::fill_writer_info (ASDCP::WriterInfo* writer_info) const +MXFAsset::fill_writer_info (ASDCP::WriterInfo* writer_info, string uuid) { writer_info->ProductVersion = Metadata::instance()->product_version; writer_info->CompanyName = Metadata::instance()->company_name; @@ -68,7 +68,7 @@ MXFAsset::fill_writer_info (ASDCP::WriterInfo* writer_info) const writer_info->LabelSetType = ASDCP::LS_MXF_SMPTE; unsigned int c; - Kumu::hex2bin (_uuid.c_str(), writer_info->AssetUUID, Kumu::UUID_Length, &c); + Kumu::hex2bin (uuid.c_str(), writer_info->AssetUUID, Kumu::UUID_Length, &c); assert (c == Kumu::UUID_Length); } diff --git a/src/mxf_asset.h b/src/mxf_asset.h index 95261353..fd786cc6 100644 --- a/src/mxf_asset.h +++ b/src/mxf_asset.h @@ -45,12 +45,21 @@ public: virtual bool equals (boost::shared_ptr other, EqualityOptions opt, std::list& notes) const; int intrinsic_duration () const; + int frames_per_second () const { + return _fps; + } + + void set_intrinsic_duration (int d) { + _intrinsic_duration = d; + } -protected: /** Fill in a ADSCP::WriteInfo struct. * @param w struct to fill in. + * @param uuid uuid to use. */ - void fill_writer_info (ASDCP::WriterInfo* w) const; + static void fill_writer_info (ASDCP::WriterInfo* w, std::string uuid); + +protected: /** Signal to emit to report progress */ boost::signals2::signal* _progress; diff --git a/src/picture_asset.cc b/src/picture_asset.cc index 3058c13d..f3d52396 100644 --- a/src/picture_asset.cc +++ b/src/picture_asset.cc @@ -46,8 +46,9 @@ using boost::dynamic_pointer_cast; using boost::lexical_cast; using namespace libdcp; -PictureAsset::PictureAsset (string directory, string mxf_name, boost::signals2::signal* progress, int fps, int intrinsic_duration) +PictureAsset::PictureAsset (string directory, string mxf_name, boost::signals2::signal* progress, int fps, int intrinsic_duration, Size size) : MXFAsset (directory, mxf_name, progress, fps, intrinsic_duration) + , _size (size) { } @@ -136,9 +137,8 @@ MonoPictureAsset::MonoPictureAsset ( int fps, int intrinsic_duration, Size size) - : PictureAsset (directory, mxf_name, progress, fps, intrinsic_duration) + : PictureAsset (directory, mxf_name, progress, fps, intrinsic_duration, size) { - _size = size; construct (get_path); } @@ -150,14 +150,19 @@ MonoPictureAsset::MonoPictureAsset ( int fps, int intrinsic_duration, Size size) - : PictureAsset (directory, mxf_name, progress, fps, intrinsic_duration) + : PictureAsset (directory, mxf_name, progress, fps, intrinsic_duration, size) { - _size = size; construct (boost::bind (&MonoPictureAsset::path_from_list, this, _1, files)); } +MonoPictureAsset::MonoPictureAsset (string directory, string mxf_name, int fps, Size size) + : PictureAsset (directory, mxf_name, 0, fps, 0, size) +{ + +} + MonoPictureAsset::MonoPictureAsset (string directory, string mxf_name, int fps, int intrinsic_duration) - : PictureAsset (directory, mxf_name, 0, fps, intrinsic_duration) + : PictureAsset (directory, mxf_name, 0, fps, intrinsic_duration, Size (0, 0)) { ASDCP::JP2K::MXFReader reader; if (ASDCP_FAILURE (reader.OpenRead (path().string().c_str()))) { @@ -187,7 +192,7 @@ MonoPictureAsset::construct (boost::function get_path) picture_desc.EditRate = ASDCP::Rational (_fps, 1); ASDCP::WriterInfo writer_info; - fill_writer_info (&writer_info); + fill_writer_info (&writer_info, _uuid); ASDCP::JP2K::MXFWriter mxf_writer; if (ASDCP_FAILURE (mxf_writer.OpenWrite (path().string().c_str(), writer_info, picture_desc))) { @@ -357,7 +362,7 @@ PictureAsset::frame_buffer_equals ( StereoPictureAsset::StereoPictureAsset (string directory, string mxf_name, int fps, int intrinsic_duration) - : PictureAsset (directory, mxf_name, 0, fps, intrinsic_duration) + : PictureAsset (directory, mxf_name, 0, fps, intrinsic_duration, Size (0, 0)) { ASDCP::JP2K::MXFSReader reader; if (ASDCP_FAILURE (reader.OpenRead (path().string().c_str()))) { @@ -378,3 +383,60 @@ StereoPictureAsset::get_frame (int n) const { return shared_ptr (new StereoPictureFrame (path().string(), n + _entry_point)); } + +shared_ptr +MonoPictureAsset::start_write () +{ + /* XXX: can't we use a shared_ptr here? */ + return shared_ptr (new MonoPictureAssetWriter (this)); +} + +MonoPictureAssetWriter::MonoPictureAssetWriter (MonoPictureAsset* a) + : _frame_buffer (4 * Kumu::Megabyte) + , _asset (a) + , _frames_written (0) + , _finalized (false) +{ + +} + +void +MonoPictureAssetWriter::write (uint8_t* data, int size) +{ + if (ASDCP_FAILURE (_j2k_parser.OpenReadFrame (data, size, _frame_buffer))) { + throw MiscError ("could not parse J2K frame"); + } + + if (_frames_written == 0) { + _j2k_parser.FillPictureDescriptor (_picture_descriptor); + _picture_descriptor.EditRate = ASDCP::Rational (_asset->frames_per_second(), 1); + + MXFAsset::fill_writer_info (&_writer_info, _asset->uuid()); + + if (ASDCP_FAILURE (_mxf_writer.OpenWrite (_asset->path().c_str(), _writer_info, _picture_descriptor))) { + throw MXFFileError ("could not open MXF file for writing", _asset->path().string()); + } + } + + if (ASDCP_FAILURE (_mxf_writer.WriteFrame (_frame_buffer, 0, 0))) { + throw MiscError ("error in writing video MXF"); + } + + _frames_written++; +} + +void +MonoPictureAssetWriter::finalize () +{ + if (ASDCP_FAILURE (_mxf_writer.Finalize())) { + throw MiscError ("error in finalizing video MXF"); + } + + _finalized = true; + _asset->set_intrinsic_duration (_frames_written); +} + +MonoPictureAssetWriter::~MonoPictureAssetWriter () +{ + assert (_finalized); +} diff --git a/src/picture_asset.h b/src/picture_asset.h index d2c6f656..059e5926 100644 --- a/src/picture_asset.h +++ b/src/picture_asset.h @@ -22,6 +22,7 @@ */ #include +#include "AS_DCP.h" #include "mxf_asset.h" #include "util.h" @@ -35,7 +36,7 @@ class StereoPictureFrame; class PictureAsset : public MXFAsset { public: - PictureAsset (std::string directory, std::string mxf_name, boost::signals2::signal* progress, int fps, int intrinsic_duration); + PictureAsset (std::string directory, std::string mxf_name, boost::signals2::signal* progress, int fps, int intrinsic_duration, Size size); /** Write details of this asset to a CPL stream. * @param s Stream. @@ -59,6 +60,31 @@ protected: Size _size; }; +class MonoPictureAsset; + +class MonoPictureAssetWriter +{ +public: + ~MonoPictureAssetWriter (); + + void write (uint8_t* data, int size); + void finalize (); + +private: + friend class MonoPictureAsset; + + MonoPictureAssetWriter (MonoPictureAsset *); + + ASDCP::JP2K::CodestreamParser _j2k_parser; + ASDCP::JP2K::FrameBuffer _frame_buffer; + ASDCP::JP2K::MXFWriter _mxf_writer; + ASDCP::WriterInfo _writer_info; + ASDCP::JP2K::PictureDescriptor _picture_descriptor; + MonoPictureAsset* _asset; + int _frames_written; + bool _finalized; +}; + /** A 2D (monoscopic) picture asset */ class MonoPictureAsset : public PictureAsset { @@ -103,6 +129,15 @@ public: Size size ); + MonoPictureAsset ( + std::string directory, + std::string mxf_name, + int fps, + Size size + ); + + boost::shared_ptr start_write (); + MonoPictureAsset (std::string directory, std::string mxf_name, int fps, int intrinsic_duration); boost::shared_ptr get_frame (int n) const; diff --git a/src/sound_asset.cc b/src/sound_asset.cc index be77739a..04ca88da 100644 --- a/src/sound_asset.cc +++ b/src/sound_asset.cc @@ -157,7 +157,7 @@ SoundAsset::construct (boost::function get_path) frame_buffer.Size (ASDCP::PCM::CalcFrameBufferSize (audio_desc)); ASDCP::WriterInfo writer_info; - fill_writer_info (&writer_info); + fill_writer_info (&writer_info, _uuid); ASDCP::PCM::MXFWriter mxf_writer; if (ASDCP_FAILURE (mxf_writer.OpenWrite (path().string().c_str(), writer_info, audio_desc))) { -- cgit v1.2.3 From 6a5bb039b3bfd508cc87b6b15102b9eb60c62f8d Mon Sep 17 00:00:00 2001 From: Carl Hetherington Date: Fri, 18 Jan 2013 21:46:20 +0000 Subject: Add basics for progressive sound asset writing. --- src/dcp.cc | 8 +--- src/mxf_asset.cc | 11 +++++ src/mxf_asset.h | 2 + src/picture_asset.cc | 14 ++++++- src/picture_asset.h | 12 ++---- src/sound_asset.cc | 112 +++++++++++++++++++++++++++++++++++++++++++++++++-- src/sound_asset.h | 39 +++++++++++++++++- 7 files changed, 176 insertions(+), 22 deletions(-) diff --git a/src/dcp.cc b/src/dcp.cc index e148c772..4f1732da 100644 --- a/src/dcp.cc +++ b/src/dcp.cc @@ -361,9 +361,7 @@ CPL::CPL (string directory, string file, shared_ptr asset_map, b try { picture.reset (new MonoPictureAsset ( _directory, - asset_map->asset_from_id (p->id)->chunks.front()->path, - _fps, - (*i)->asset_list->main_picture->duration + asset_map->asset_from_id (p->id)->chunks.front()->path ) ); @@ -400,9 +398,7 @@ CPL::CPL (string directory, string file, shared_ptr asset_map, b try { sound.reset (new SoundAsset ( _directory, - asset_map->asset_from_id ((*i)->asset_list->main_sound->id)->chunks.front()->path, - _fps, - (*i)->asset_list->main_sound->duration + asset_map->asset_from_id ((*i)->asset_list->main_sound->id)->chunks.front()->path ) ); diff --git a/src/mxf_asset.cc b/src/mxf_asset.cc index af3c74dc..7c75cb27 100644 --- a/src/mxf_asset.cc +++ b/src/mxf_asset.cc @@ -36,6 +36,17 @@ using boost::shared_ptr; using boost::dynamic_pointer_cast; using namespace libdcp; +MXFAsset::MXFAsset (string directory, string file_name) + : Asset (directory, file_name) + , _progress (0) + , _fps (0) + , _entry_point (0) + , _intrinsic_duration (0) + , _duration (0) +{ + +} + MXFAsset::MXFAsset (string directory, string file_name, boost::signals2::signal* progress, int fps, int intrinsic_duration) : Asset (directory, file_name) , _progress (progress) diff --git a/src/mxf_asset.h b/src/mxf_asset.h index fd786cc6..ff43fecb 100644 --- a/src/mxf_asset.h +++ b/src/mxf_asset.h @@ -30,6 +30,8 @@ namespace libdcp class MXFAsset : public Asset { public: + MXFAsset (std::string directory, std::string file_name); + /** Construct an MXFAsset. * @param directory Directory where MXF file is. * @param file_name Name of MXF file. diff --git a/src/picture_asset.cc b/src/picture_asset.cc index f3d52396..a7d5243a 100644 --- a/src/picture_asset.cc +++ b/src/picture_asset.cc @@ -53,6 +53,12 @@ PictureAsset::PictureAsset (string directory, string mxf_name, boost::signals2:: } +PictureAsset::PictureAsset (string directory, string mxf_name) + : MXFAsset (directory, mxf_name) +{ + +} + void PictureAsset::write_to_cpl (ostream& s) const { @@ -161,8 +167,8 @@ MonoPictureAsset::MonoPictureAsset (string directory, string mxf_name, int fps, } -MonoPictureAsset::MonoPictureAsset (string directory, string mxf_name, int fps, int intrinsic_duration) - : PictureAsset (directory, mxf_name, 0, fps, intrinsic_duration, Size (0, 0)) +MonoPictureAsset::MonoPictureAsset (string directory, string mxf_name) + : PictureAsset (directory, mxf_name) { ASDCP::JP2K::MXFReader reader; if (ASDCP_FAILURE (reader.OpenRead (path().string().c_str()))) { @@ -176,6 +182,9 @@ MonoPictureAsset::MonoPictureAsset (string directory, string mxf_name, int fps, _size.width = desc.StoredWidth; _size.height = desc.StoredHeight; + _fps = desc.EditRate.Numerator; + assert (desc.EditRate.Denominator == 1); + _intrinsic_duration = desc.ContainerDuration; } void @@ -434,6 +443,7 @@ MonoPictureAssetWriter::finalize () _finalized = true; _asset->set_intrinsic_duration (_frames_written); + _asset->set_duration (_frames_written); } MonoPictureAssetWriter::~MonoPictureAssetWriter () diff --git a/src/picture_asset.h b/src/picture_asset.h index 059e5926..dd69e352 100644 --- a/src/picture_asset.h +++ b/src/picture_asset.h @@ -36,6 +36,7 @@ class StereoPictureFrame; class PictureAsset : public MXFAsset { public: + PictureAsset (std::string directory, std::string mxf_name); PictureAsset (std::string directory, std::string mxf_name, boost::signals2::signal* progress, int fps, int intrinsic_duration, Size size); /** Write details of this asset to a CPL stream. @@ -129,17 +130,12 @@ public: Size size ); - MonoPictureAsset ( - std::string directory, - std::string mxf_name, - int fps, - Size size - ); + MonoPictureAsset (std::string directory, std::string mxf_name); + + MonoPictureAsset (std::string directory, std::string mxf_name, int fps, Size size); boost::shared_ptr start_write (); - MonoPictureAsset (std::string directory, std::string mxf_name, int fps, int intrinsic_duration); - boost::shared_ptr get_frame (int n) const; bool equals (boost::shared_ptr other, EqualityOptions opt, std::list& notes) const; diff --git a/src/sound_asset.cc b/src/sound_asset.cc index 04ca88da..89132f26 100644 --- a/src/sound_asset.cc +++ b/src/sound_asset.cc @@ -75,8 +75,8 @@ SoundAsset::SoundAsset ( construct (get_path); } -SoundAsset::SoundAsset (string directory, string mxf_name, int fps, int intrinsic_duration) - : MXFAsset (directory, mxf_name, 0, fps, intrinsic_duration) +SoundAsset::SoundAsset (string directory, string mxf_name) + : MXFAsset (directory, mxf_name) , _channels (0) , _start_frame (0) { @@ -85,7 +85,6 @@ SoundAsset::SoundAsset (string directory, string mxf_name, int fps, int intrinsi throw MXFFileError ("could not open MXF file for reading", path().string()); } - ASDCP::PCM::AudioDescriptor desc; if (ASDCP_FAILURE (reader.FillAudioDescriptor (desc))) { throw DCPReadError ("could not read audio MXF information"); @@ -93,6 +92,18 @@ SoundAsset::SoundAsset (string directory, string mxf_name, int fps, int intrinsi _sampling_rate = desc.AudioSamplingRate.Numerator / desc.AudioSamplingRate.Denominator; _channels = desc.ChannelCount; + _fps = desc.EditRate.Numerator; + assert (desc.EditRate.Denominator == 1); + _intrinsic_duration = desc.ContainerDuration; +} + +SoundAsset::SoundAsset (string directory, string mxf_name, int fps, int channels, int sampling_rate) + : MXFAsset (directory, mxf_name, 0, fps, 0) + , _channels (channels) + , _sampling_rate (sampling_rate) + , _start_frame (0) +{ + } string @@ -157,7 +168,7 @@ SoundAsset::construct (boost::function get_path) frame_buffer.Size (ASDCP::PCM::CalcFrameBufferSize (audio_desc)); ASDCP::WriterInfo writer_info; - fill_writer_info (&writer_info, _uuid); + MXFAsset::fill_writer_info (&writer_info, _uuid); ASDCP::PCM::MXFWriter mxf_writer; if (ASDCP_FAILURE (mxf_writer.OpenWrite (path().string().c_str(), writer_info, audio_desc))) { @@ -302,3 +313,96 @@ SoundAsset::get_frame (int n) const { return shared_ptr (new SoundFrame (path().string(), n + _entry_point)); } + +shared_ptr +SoundAsset::start_write () +{ + /* XXX: can't we use a shared_ptr here? */ + return shared_ptr (new SoundAssetWriter (this)); +} + +SoundAssetWriter::SoundAssetWriter (SoundAsset* a) + : _asset (a) + , _finalized (false) + , _frames_written (0) + , _frame_buffer_offset (0) +{ + /* Derived from ASDCP::Wav::SimpleWaveHeader::FillADesc */ + _audio_desc.EditRate = ASDCP::Rational (_asset->frames_per_second(), 1); + _audio_desc.AudioSamplingRate = ASDCP::Rational (_asset->sampling_rate(), 0); + _audio_desc.Locked = 0; + _audio_desc.ChannelCount = _asset->channels (); + _audio_desc.QuantizationBits = 24; + _audio_desc.BlockAlign = 3 * _asset->channels(); + _audio_desc.AvgBps = _asset->sampling_rate() * _audio_desc.BlockAlign; + _audio_desc.LinkedTrackID = 0; + _audio_desc.ChannelFormat = ASDCP::PCM::CF_NONE; + + _frame_buffer.Capacity (ASDCP::PCM::CalcFrameBufferSize (_audio_desc)); + _frame_buffer.Size (ASDCP::PCM::CalcFrameBufferSize (_audio_desc)); + memset (_frame_buffer.Data(), 0, _frame_buffer.Capacity()); + + MXFAsset::fill_writer_info (&_writer_info, _asset->uuid ()); + + if (ASDCP_FAILURE (_mxf_writer.OpenWrite (_asset->path().c_str(), _writer_info, _audio_desc))) { + throw FileError ("could not open audio MXF for writing", _asset->path().string()); + } +} + +void +SoundAssetWriter::write (float const * const * data, int frames) +{ + for (int i = 0; i < frames; ++i) { + + byte_t* out = _frame_buffer.Data() + _frame_buffer_offset; + + /* Write one sample per channel */ + for (int j = 0; j < _asset->channels(); ++j) { + int32_t const s = data[j][i] * (1 << 23); + *out++ = (s & 0xff); + *out++ = (s & 0xff00) >> 8; + *out++ = (s & 0xff0000) >> 16; + } + _frame_buffer_offset += 3 * _asset->channels(); + + assert (_frame_buffer_offset <= int (_frame_buffer.Capacity())); + + /* Finish the MXF frame if required */ + if (_frame_buffer_offset == int (_frame_buffer.Capacity())) { + write_current_frame (); + _frame_buffer_offset = 0; + memset (_frame_buffer.Data(), 0, _frame_buffer.Capacity()); + } + } +} + +void +SoundAssetWriter::write_current_frame () +{ + if (ASDCP_FAILURE (_mxf_writer.WriteFrame (_frame_buffer, 0, 0))) { + throw MiscError ("could not write audio MXF frame"); + } + + ++_frames_written; +} + +void +SoundAssetWriter::finalize () +{ + if (_frame_buffer_offset > 0) { + write_current_frame (); + } + + if (ASDCP_FAILURE (_mxf_writer.Finalize())) { + throw MiscError ("could not finalise audio MXF"); + } + + _finalized = true; + _asset->set_intrinsic_duration (_frames_written); + _asset->set_duration (_frames_written); +} + +SoundAssetWriter::~SoundAssetWriter () +{ + assert (_finalized); +} diff --git a/src/sound_asset.h b/src/sound_asset.h index 569bb305..17767b3a 100644 --- a/src/sound_asset.h +++ b/src/sound_asset.h @@ -24,13 +24,40 @@ * @brief An asset made up of PCM audio data files */ +#include "AS_DCP.h" #include "mxf_asset.h" #include "types.h" namespace libdcp { -class SoundFrame; +class SoundFrame; + +class SoundAsset; + +class SoundAssetWriter +{ +public: + ~SoundAssetWriter (); + + void write (float const * const *, int); + void finalize (); + +private: + friend class SoundAsset; + + SoundAssetWriter (SoundAsset *); + void write_current_frame (); + + SoundAsset* _asset; + bool _finalized; + int _frames_written; + int _frame_buffer_offset; + ASDCP::PCM::MXFWriter _mxf_writer; + ASDCP::PCM::FrameBuffer _frame_buffer; + ASDCP::WriterInfo _writer_info; + ASDCP::PCM::AudioDescriptor _audio_desc; +}; /** @brief An asset made up of WAV files */ class SoundAsset : public MXFAsset @@ -80,12 +107,20 @@ public: int channels ); + SoundAsset ( + std::string directory, + std::string mxf_name + ); + SoundAsset ( std::string directory, std::string mxf_name, int fps, - int intrinsic_duration + int channels, + int sampling_rate ); + + boost::shared_ptr start_write (); /** Write details of this asset to a CPL stream. * @param s Stream. -- cgit v1.2.3 From e1c8accb4b1324f09e1565d14d4785e8bbef7dcf Mon Sep 17 00:00:00 2001 From: Carl Hetherington Date: Fri, 18 Jan 2013 22:15:51 +0000 Subject: Tidying up; comments; fps in assets -> edit rate. --- src/mxf_asset.cc | 29 +++++----------------------- src/mxf_asset.h | 42 +++++++++++++++++++++++++++------------- src/picture_asset.cc | 17 ++++++++++++----- src/picture_asset.h | 54 +++++++++++++++++++++++++++++++++++++++++++++++----- src/sound_asset.cc | 14 +++++++------- 5 files changed, 102 insertions(+), 54 deletions(-) diff --git a/src/mxf_asset.cc b/src/mxf_asset.cc index 7c75cb27..9b4cbf74 100644 --- a/src/mxf_asset.cc +++ b/src/mxf_asset.cc @@ -39,7 +39,7 @@ using namespace libdcp; MXFAsset::MXFAsset (string directory, string file_name) : Asset (directory, file_name) , _progress (0) - , _fps (0) + , _edit_rate (0) , _entry_point (0) , _intrinsic_duration (0) , _duration (0) @@ -47,29 +47,16 @@ MXFAsset::MXFAsset (string directory, string file_name) } -MXFAsset::MXFAsset (string directory, string file_name, boost::signals2::signal* progress, int fps, int intrinsic_duration) +MXFAsset::MXFAsset (string directory, string file_name, boost::signals2::signal* progress, int edit_rate, int intrinsic_duration) : Asset (directory, file_name) , _progress (progress) - , _fps (fps) + , _edit_rate (edit_rate) , _entry_point (0) , _intrinsic_duration (intrinsic_duration) , _duration (intrinsic_duration) { } - -void -MXFAsset::set_entry_point (int e) -{ - _entry_point = e; -} - -void -MXFAsset::set_duration (int d) -{ - _duration = d; -} - void MXFAsset::fill_writer_info (ASDCP::WriterInfo* writer_info, string uuid) { @@ -97,8 +84,8 @@ MXFAsset::equals (shared_ptr other, EqualityOptions, list& return false; } - if (_fps != other_mxf->_fps) { - notes.push_back ("MXF frames per second differ"); + if (_edit_rate != other_mxf->_edit_rate) { + notes.push_back ("MXF edit rates differ"); return false; } @@ -114,9 +101,3 @@ MXFAsset::equals (shared_ptr other, EqualityOptions, list& return true; } - -int -MXFAsset::intrinsic_duration () const -{ - return _intrinsic_duration; -} diff --git a/src/mxf_asset.h b/src/mxf_asset.h index ff43fecb..430e9157 100644 --- a/src/mxf_asset.h +++ b/src/mxf_asset.h @@ -30,31 +30,47 @@ namespace libdcp class MXFAsset : public Asset { public: + /** Construct an MXFAsset. + * This class will not write anything to disk in this constructor, but subclasses may. + * + * @param directory Directory where MXF file is. + * @param file_name Name of MXF file. + */ MXFAsset (std::string directory, std::string file_name); /** Construct an MXFAsset. + * This class will not write anything to disk in this constructor, but subclasses may. + * * @param directory Directory where MXF file is. * @param file_name Name of MXF file. - * @param progress Signal to inform of progress. - * @param fps Frames per second. + * @param progress Signal to use to inform of progress, or 0. + * @param edit_rate Edit rate in frames per second (usually equal to the video frame rate). * @param intrinsic_duration Duration of the whole asset in frames. */ - MXFAsset (std::string directory, std::string file_name, boost::signals2::signal* progress, int fps, int intrinsic_duration); + MXFAsset (std::string directory, std::string file_name, boost::signals2::signal* progress, int edit_rate, int intrinsic_duration); - void set_entry_point (int e); - void set_duration (int d); - - virtual bool equals (boost::shared_ptr other, EqualityOptions opt, std::list& notes) const; + void set_entry_point (int e) { + _entry_point = e; + } - int intrinsic_duration () const; - int frames_per_second () const { - return _fps; + void set_duration (int d) { + _duration = d; } void set_intrinsic_duration (int d) { _intrinsic_duration = d; } + virtual bool equals (boost::shared_ptr other, EqualityOptions opt, std::list& notes) const; + + int intrinsic_duration () const { + return _intrinsic_duration; + } + + int edit_rate () const { + return _edit_rate; + } + /** Fill in a ADSCP::WriteInfo struct. * @param w struct to fill in. * @param uuid uuid to use. @@ -63,10 +79,10 @@ public: protected: - /** Signal to emit to report progress */ + /** Signal to emit to report progress, or 0 */ boost::signals2::signal* _progress; - /** Frames per second */ - int _fps; + /** The edit rate; this is normally equal to the number of video frames per second */ + int _edit_rate; /** Start point to present in frames */ int _entry_point; /** Total length in frames */ diff --git a/src/picture_asset.cc b/src/picture_asset.cc index a7d5243a..a2f6b584 100644 --- a/src/picture_asset.cc +++ b/src/picture_asset.cc @@ -65,11 +65,11 @@ PictureAsset::write_to_cpl (ostream& s) const s << " \n" << " urn:uuid:" << _uuid << "\n" << " " << _file_name << "\n" - << " " << _fps << " 1\n" + << " " << _edit_rate << " 1\n" << " " << _intrinsic_duration << "\n" << " " << _entry_point << "\n" << " " << _duration << "\n" - << " " << _fps << " 1\n" + << " " << _edit_rate << " 1\n" << " " << _size.width << " " << _size.height << "\n" << " \n"; } @@ -182,7 +182,7 @@ MonoPictureAsset::MonoPictureAsset (string directory, string mxf_name) _size.width = desc.StoredWidth; _size.height = desc.StoredHeight; - _fps = desc.EditRate.Numerator; + _edit_rate = desc.EditRate.Numerator; assert (desc.EditRate.Denominator == 1); _intrinsic_duration = desc.ContainerDuration; } @@ -198,7 +198,7 @@ MonoPictureAsset::construct (boost::function get_path) ASDCP::JP2K::PictureDescriptor picture_desc; j2k_parser.FillPictureDescriptor (picture_desc); - picture_desc.EditRate = ASDCP::Rational (_fps, 1); + picture_desc.EditRate = ASDCP::Rational (_edit_rate, 1); ASDCP::WriterInfo writer_info; fill_writer_info (&writer_info, _uuid); @@ -400,6 +400,9 @@ MonoPictureAsset::start_write () return shared_ptr (new MonoPictureAssetWriter (this)); } +/** @param a Asset to write to. `a' must not be deleted while + * this writer class still exists, or bad things will happen. + */ MonoPictureAssetWriter::MonoPictureAssetWriter (MonoPictureAsset* a) : _frame_buffer (4 * Kumu::Megabyte) , _asset (a) @@ -412,13 +415,17 @@ MonoPictureAssetWriter::MonoPictureAssetWriter (MonoPictureAsset* a) void MonoPictureAssetWriter::write (uint8_t* data, int size) { + assert (!_finalized); + if (ASDCP_FAILURE (_j2k_parser.OpenReadFrame (data, size, _frame_buffer))) { throw MiscError ("could not parse J2K frame"); } if (_frames_written == 0) { + /* This is our first frame; set up the writer */ + _j2k_parser.FillPictureDescriptor (_picture_descriptor); - _picture_descriptor.EditRate = ASDCP::Rational (_asset->frames_per_second(), 1); + _picture_descriptor.EditRate = ASDCP::Rational (_asset->edit_rate(), 1); MXFAsset::fill_writer_info (&_writer_info, _asset->uuid()); diff --git a/src/picture_asset.h b/src/picture_asset.h index dd69e352..ea558e7d 100644 --- a/src/picture_asset.h +++ b/src/picture_asset.h @@ -36,7 +36,24 @@ class StereoPictureFrame; class PictureAsset : public MXFAsset { public: + /** Construct a PictureAsset. + * This class will not write anything to disk in this constructor, but subclasses may. + * + * @param directory Directory where MXF file is. + * @param mxf_name Name of MXF file. + */ PictureAsset (std::string directory, std::string mxf_name); + + /** Construct a PictureAsset. + * This class will not write anything to disk in this constructor, but subclasses may. + * + * @param directory Directory where MXF file is. + * @param mxf_name Name of MXF file. + * @param progress Signal to use to inform of progres, or 0. + * @param fps Video Frames per second. + * @param intrinsic_duration Duration of all the frames in the asset. + * @param size Size of video frame images in pixels. + */ PictureAsset (std::string directory, std::string mxf_name, boost::signals2::signal* progress, int fps, int intrinsic_duration, Size size); /** Write details of this asset to a CPL stream. @@ -63,6 +80,16 @@ protected: class MonoPictureAsset; +/** A helper class for writing to MonoPictureAssets progressively (i.e. writing frame-by-frame, + * rather than giving libdcp all the frames in one go). + * + * Objects of this class can only be created with MonoPictureAsset::start_write(). + * + * Frames can be written to the MonoPictureAsset by calling write() with a JPEG2000 image + * (a verbatim .j2 file). finalize() must be called after the last frame has been written. + * The action of finalize() can't be done in MonoPictureAssetWriter's destructor as it may + * throw an exception. + */ class MonoPictureAssetWriter { public: @@ -82,7 +109,9 @@ private: ASDCP::WriterInfo _writer_info; ASDCP::JP2K::PictureDescriptor _picture_descriptor; MonoPictureAsset* _asset; + /** Number of picture frames written to the asset so far */ int _frames_written; + /** true if finalize() has been called */ bool _finalized; }; @@ -90,13 +119,14 @@ private: class MonoPictureAsset : public PictureAsset { public: - /** Construct a PictureAsset, generating the MXF from the JPEG2000 files. + /** Construct a MonoPictureAsset, generating the MXF from the JPEG2000 files. * This may take some time; progress is indicated by emission of the Progress signal. + * * @param files Pathnames of JPEG2000 files, in frame order. * @param directory Directory in which to create MXF file. * @param mxf_name Name of MXF file to create. * @param progress Signal to inform of progress. - * @param fps Frames per second. + * @param fps Video frames per second. * @param intrinsic_duration Length of the whole asset in frames. * @param size Size of images in pixels. */ @@ -110,13 +140,14 @@ public: Size size ); - /** Construct a PictureAsset, generating the MXF from the JPEG2000 files. + /** Construct a MonoPictureAsset, generating the MXF from the JPEG2000 files. * This may take some time; progress is indicated by emission of the Progress signal. + * * @param get_path Functor which returns a JPEG2000 file path for a given frame (frames counted from 0). * @param directory Directory in which to create MXF file. * @param mxf_name Name of MXF file to create. * @param progress Signal to inform of progress. - * @param fps Frames per second. + * @param fps Video frames per second. * @param intrinsic_duration Length of the whole asset in frames. * @param size Size of images in pixels. */ @@ -130,10 +161,23 @@ public: Size size ); + /** Construct a MonoPictureAsset, reading the MXF from disk. + * @param directory Directory that the MXF is in. + * @param mxf_name The filename of the MXF within `directory'. + */ MonoPictureAsset (std::string directory, std::string mxf_name); - + + /** Construct a MonoPictureAsset for progressive writing using + * start_write() and a MonoPictureAssetWriter. + * + * @param directory Directory to put the MXF in. + * @param mxf_name Filename of the MXF within this directory. + * @param fps Video frames per second. + * @param size Size in pixels that the picture frames will be. + */ MonoPictureAsset (std::string directory, std::string mxf_name, int fps, Size size); + /** Start a progressive write to a MonoPictureAsset */ boost::shared_ptr start_write (); boost::shared_ptr get_frame (int n) const; diff --git a/src/sound_asset.cc b/src/sound_asset.cc index 89132f26..499f4112 100644 --- a/src/sound_asset.cc +++ b/src/sound_asset.cc @@ -92,7 +92,7 @@ SoundAsset::SoundAsset (string directory, string mxf_name) _sampling_rate = desc.AudioSamplingRate.Numerator / desc.AudioSamplingRate.Denominator; _channels = desc.ChannelCount; - _fps = desc.EditRate.Numerator; + _edit_rate = desc.EditRate.Numerator; assert (desc.EditRate.Denominator == 1); _intrinsic_duration = desc.ContainerDuration; } @@ -117,10 +117,10 @@ SoundAsset::path_from_channel (Channel channel, vector const & files) void SoundAsset::construct (boost::function get_path) { - ASDCP::Rational asdcp_fps (_fps, 1); + ASDCP::Rational asdcp_edit_rate (_edit_rate, 1); ASDCP::PCM::WAVParser pcm_parser_channel[_channels]; - if (pcm_parser_channel[0].OpenRead (get_path(LEFT).c_str(), asdcp_fps)) { + if (pcm_parser_channel[0].OpenRead (get_path(LEFT).c_str(), asdcp_edit_rate)) { throw FileError ("could not open WAV file for reading", get_path(LEFT)); } @@ -128,7 +128,7 @@ SoundAsset::construct (boost::function get_path) pcm_parser_channel[0].FillAudioDescriptor (audio_desc); audio_desc.ChannelCount = 0; audio_desc.BlockAlign = 0; - audio_desc.EditRate = asdcp_fps; + audio_desc.EditRate = asdcp_edit_rate; audio_desc.AvgBps = audio_desc.AvgBps * _channels; Channel channels[] = { @@ -152,7 +152,7 @@ SoundAsset::construct (boost::function get_path) string const path = get_path (channels[i]); - if (ASDCP_FAILURE (pcm_parser_channel[i].OpenRead (path.c_str(), asdcp_fps))) { + if (ASDCP_FAILURE (pcm_parser_channel[i].OpenRead (path.c_str(), asdcp_edit_rate))) { throw FileError ("could not open WAV file for reading", path); } @@ -227,7 +227,7 @@ SoundAsset::write_to_cpl (ostream& s) const s << " \n" << " urn:uuid:" << _uuid << "\n" << " " << _file_name << "\n" - << " " << _fps << " 1\n" + << " " << _edit_rate << " 1\n" << " " << _intrinsic_duration << "\n" << " " << _entry_point << "\n" << " " << _duration << "\n" @@ -328,7 +328,7 @@ SoundAssetWriter::SoundAssetWriter (SoundAsset* a) , _frame_buffer_offset (0) { /* Derived from ASDCP::Wav::SimpleWaveHeader::FillADesc */ - _audio_desc.EditRate = ASDCP::Rational (_asset->frames_per_second(), 1); + _audio_desc.EditRate = ASDCP::Rational (_asset->edit_rate(), 1); _audio_desc.AudioSamplingRate = ASDCP::Rational (_asset->sampling_rate(), 0); _audio_desc.Locked = 0; _audio_desc.ChannelCount = _asset->channels (); -- cgit v1.2.3 From a2c5f0ee3dca60fa3c593a55f9bf7f42f3aa88d4 Mon Sep 17 00:00:00 2001 From: Carl Hetherington Date: Sun, 20 Jan 2013 23:54:13 +0000 Subject: Fix typo in audio sampling rate setup. --- src/sound_asset.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/sound_asset.cc b/src/sound_asset.cc index 499f4112..2ed18312 100644 --- a/src/sound_asset.cc +++ b/src/sound_asset.cc @@ -329,7 +329,7 @@ SoundAssetWriter::SoundAssetWriter (SoundAsset* a) { /* Derived from ASDCP::Wav::SimpleWaveHeader::FillADesc */ _audio_desc.EditRate = ASDCP::Rational (_asset->edit_rate(), 1); - _audio_desc.AudioSamplingRate = ASDCP::Rational (_asset->sampling_rate(), 0); + _audio_desc.AudioSamplingRate = ASDCP::Rational (_asset->sampling_rate(), 1); _audio_desc.Locked = 0; _audio_desc.ChannelCount = _asset->channels (); _audio_desc.QuantizationBits = 24; -- cgit v1.2.3 From 102c567af0eaa478f062971ae8dd5f6891e1457d Mon Sep 17 00:00:00 2001 From: Carl Hetherington Date: Mon, 21 Jan 2013 20:45:00 +0000 Subject: Fix compile with old boost. --- src/picture_asset.cc | 2 +- src/sound_asset.cc | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/picture_asset.cc b/src/picture_asset.cc index a2f6b584..8f1fe0cc 100644 --- a/src/picture_asset.cc +++ b/src/picture_asset.cc @@ -429,7 +429,7 @@ MonoPictureAssetWriter::write (uint8_t* data, int size) MXFAsset::fill_writer_info (&_writer_info, _asset->uuid()); - if (ASDCP_FAILURE (_mxf_writer.OpenWrite (_asset->path().c_str(), _writer_info, _picture_descriptor))) { + if (ASDCP_FAILURE (_mxf_writer.OpenWrite (_asset->path().string().c_str(), _writer_info, _picture_descriptor))) { throw MXFFileError ("could not open MXF file for writing", _asset->path().string()); } } diff --git a/src/sound_asset.cc b/src/sound_asset.cc index 2ed18312..c6b6ac93 100644 --- a/src/sound_asset.cc +++ b/src/sound_asset.cc @@ -344,7 +344,7 @@ SoundAssetWriter::SoundAssetWriter (SoundAsset* a) MXFAsset::fill_writer_info (&_writer_info, _asset->uuid ()); - if (ASDCP_FAILURE (_mxf_writer.OpenWrite (_asset->path().c_str(), _writer_info, _audio_desc))) { + if (ASDCP_FAILURE (_mxf_writer.OpenWrite (_asset->path().string().c_str(), _writer_info, _audio_desc))) { throw FileError ("could not open audio MXF for writing", _asset->path().string()); } } -- cgit v1.2.3 From c21da9cdd8284e8d36a08bc7976744a3cd74bede Mon Sep 17 00:00:00 2001 From: Carl Hetherington Date: Mon, 21 Jan 2013 21:01:59 +0000 Subject: Try to remove need for asdcplib includes in libdcp headers. --- src/picture_asset.cc | 30 ++++++++++++++++++++++-------- src/picture_asset.h | 19 ++++++++++++------- src/sound_asset.cc | 51 ++++++++++++++++++++++++++++++--------------------- src/sound_asset.h | 17 ++++++++++++----- 4 files changed, 76 insertions(+), 41 deletions(-) diff --git a/src/picture_asset.cc b/src/picture_asset.cc index a2f6b584..564ada79 100644 --- a/src/picture_asset.cc +++ b/src/picture_asset.cc @@ -400,11 +400,25 @@ MonoPictureAsset::start_write () return shared_ptr (new MonoPictureAssetWriter (this)); } +struct MonoPictureAssetWriter::ASDCPState +{ + ASDCPState() + : frame_buffer (4 * Kumu::Megabyte) + {} + + ASDCP::JP2K::CodestreamParser j2k_parser; + ASDCP::JP2K::FrameBuffer frame_buffer; + ASDCP::JP2K::MXFWriter mxf_writer; + ASDCP::WriterInfo writer_info; + ASDCP::JP2K::PictureDescriptor picture_descriptor; +}; + + /** @param a Asset to write to. `a' must not be deleted while * this writer class still exists, or bad things will happen. */ MonoPictureAssetWriter::MonoPictureAssetWriter (MonoPictureAsset* a) - : _frame_buffer (4 * Kumu::Megabyte) + : _state (new MonoPictureAssetWriter::ASDCPState) , _asset (a) , _frames_written (0) , _finalized (false) @@ -417,24 +431,24 @@ MonoPictureAssetWriter::write (uint8_t* data, int size) { assert (!_finalized); - if (ASDCP_FAILURE (_j2k_parser.OpenReadFrame (data, size, _frame_buffer))) { + if (ASDCP_FAILURE (_state->j2k_parser.OpenReadFrame (data, size, _state->frame_buffer))) { throw MiscError ("could not parse J2K frame"); } if (_frames_written == 0) { /* This is our first frame; set up the writer */ - _j2k_parser.FillPictureDescriptor (_picture_descriptor); - _picture_descriptor.EditRate = ASDCP::Rational (_asset->edit_rate(), 1); + _state->j2k_parser.FillPictureDescriptor (_state->picture_descriptor); + _state->picture_descriptor.EditRate = ASDCP::Rational (_asset->edit_rate(), 1); - MXFAsset::fill_writer_info (&_writer_info, _asset->uuid()); + MXFAsset::fill_writer_info (&_state->writer_info, _asset->uuid()); - if (ASDCP_FAILURE (_mxf_writer.OpenWrite (_asset->path().c_str(), _writer_info, _picture_descriptor))) { + if (ASDCP_FAILURE (_state->mxf_writer.OpenWrite (_asset->path().c_str(), _state->writer_info, _state->picture_descriptor))) { throw MXFFileError ("could not open MXF file for writing", _asset->path().string()); } } - if (ASDCP_FAILURE (_mxf_writer.WriteFrame (_frame_buffer, 0, 0))) { + if (ASDCP_FAILURE (_state->mxf_writer.WriteFrame (_state->frame_buffer, 0, 0))) { throw MiscError ("error in writing video MXF"); } @@ -444,7 +458,7 @@ MonoPictureAssetWriter::write (uint8_t* data, int size) void MonoPictureAssetWriter::finalize () { - if (ASDCP_FAILURE (_mxf_writer.Finalize())) { + if (ASDCP_FAILURE (_state->mxf_writer.Finalize())) { throw MiscError ("error in finalizing video MXF"); } diff --git a/src/picture_asset.h b/src/picture_asset.h index ea558e7d..71900200 100644 --- a/src/picture_asset.h +++ b/src/picture_asset.h @@ -22,7 +22,6 @@ */ #include -#include "AS_DCP.h" #include "mxf_asset.h" #include "util.h" @@ -100,14 +99,20 @@ public: private: friend class MonoPictureAsset; - + MonoPictureAssetWriter (MonoPictureAsset *); - ASDCP::JP2K::CodestreamParser _j2k_parser; - ASDCP::JP2K::FrameBuffer _frame_buffer; - ASDCP::JP2K::MXFWriter _mxf_writer; - ASDCP::WriterInfo _writer_info; - ASDCP::JP2K::PictureDescriptor _picture_descriptor; + /* no copy construction */ + MonoPictureAssetWriter (MonoPictureAssetWriter const &); + MonoPictureAssetWriter& operator= (MonoPictureAssetWriter const &); + + /* do this with an opaque pointer so we don't have to include + ASDCP headers + */ + + struct ASDCPState; + boost::shared_ptr _state; + MonoPictureAsset* _asset; /** Number of picture frames written to the asset so far */ int _frames_written; diff --git a/src/sound_asset.cc b/src/sound_asset.cc index 2ed18312..08ca71e5 100644 --- a/src/sound_asset.cc +++ b/src/sound_asset.cc @@ -321,30 +321,39 @@ SoundAsset::start_write () return shared_ptr (new SoundAssetWriter (this)); } +struct SoundAssetWriter::ASDCPState +{ + ASDCP::PCM::MXFWriter mxf_writer; + ASDCP::PCM::FrameBuffer frame_buffer; + ASDCP::WriterInfo writer_info; + ASDCP::PCM::AudioDescriptor audio_desc; +}; + SoundAssetWriter::SoundAssetWriter (SoundAsset* a) - : _asset (a) + : _state (new SoundAssetWriter::ASDCPState) + , _asset (a) , _finalized (false) , _frames_written (0) , _frame_buffer_offset (0) { /* Derived from ASDCP::Wav::SimpleWaveHeader::FillADesc */ - _audio_desc.EditRate = ASDCP::Rational (_asset->edit_rate(), 1); - _audio_desc.AudioSamplingRate = ASDCP::Rational (_asset->sampling_rate(), 1); - _audio_desc.Locked = 0; - _audio_desc.ChannelCount = _asset->channels (); - _audio_desc.QuantizationBits = 24; - _audio_desc.BlockAlign = 3 * _asset->channels(); - _audio_desc.AvgBps = _asset->sampling_rate() * _audio_desc.BlockAlign; - _audio_desc.LinkedTrackID = 0; - _audio_desc.ChannelFormat = ASDCP::PCM::CF_NONE; + _state->audio_desc.EditRate = ASDCP::Rational (_asset->edit_rate(), 1); + _state->audio_desc.AudioSamplingRate = ASDCP::Rational (_asset->sampling_rate(), 1); + _state->audio_desc.Locked = 0; + _state->audio_desc.ChannelCount = _asset->channels (); + _state->audio_desc.QuantizationBits = 24; + _state->audio_desc.BlockAlign = 3 * _asset->channels(); + _state->audio_desc.AvgBps = _asset->sampling_rate() * _state->audio_desc.BlockAlign; + _state->audio_desc.LinkedTrackID = 0; + _state->audio_desc.ChannelFormat = ASDCP::PCM::CF_NONE; - _frame_buffer.Capacity (ASDCP::PCM::CalcFrameBufferSize (_audio_desc)); - _frame_buffer.Size (ASDCP::PCM::CalcFrameBufferSize (_audio_desc)); - memset (_frame_buffer.Data(), 0, _frame_buffer.Capacity()); + _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()); - MXFAsset::fill_writer_info (&_writer_info, _asset->uuid ()); + MXFAsset::fill_writer_info (&_state->writer_info, _asset->uuid ()); - if (ASDCP_FAILURE (_mxf_writer.OpenWrite (_asset->path().c_str(), _writer_info, _audio_desc))) { + if (ASDCP_FAILURE (_state->mxf_writer.OpenWrite (_asset->path().c_str(), _state->writer_info, _state->audio_desc))) { throw FileError ("could not open audio MXF for writing", _asset->path().string()); } } @@ -354,7 +363,7 @@ SoundAssetWriter::write (float const * const * data, int frames) { for (int i = 0; i < frames; ++i) { - byte_t* out = _frame_buffer.Data() + _frame_buffer_offset; + byte_t* out = _state->frame_buffer.Data() + _frame_buffer_offset; /* Write one sample per channel */ for (int j = 0; j < _asset->channels(); ++j) { @@ -365,13 +374,13 @@ SoundAssetWriter::write (float const * const * data, int frames) } _frame_buffer_offset += 3 * _asset->channels(); - assert (_frame_buffer_offset <= int (_frame_buffer.Capacity())); + assert (_frame_buffer_offset <= int (_state->frame_buffer.Capacity())); /* Finish the MXF frame if required */ - if (_frame_buffer_offset == int (_frame_buffer.Capacity())) { + if (_frame_buffer_offset == int (_state->frame_buffer.Capacity())) { write_current_frame (); _frame_buffer_offset = 0; - memset (_frame_buffer.Data(), 0, _frame_buffer.Capacity()); + memset (_state->frame_buffer.Data(), 0, _state->frame_buffer.Capacity()); } } } @@ -379,7 +388,7 @@ SoundAssetWriter::write (float const * const * data, int frames) void SoundAssetWriter::write_current_frame () { - if (ASDCP_FAILURE (_mxf_writer.WriteFrame (_frame_buffer, 0, 0))) { + if (ASDCP_FAILURE (_state->mxf_writer.WriteFrame (_state->frame_buffer, 0, 0))) { throw MiscError ("could not write audio MXF frame"); } @@ -393,7 +402,7 @@ SoundAssetWriter::finalize () write_current_frame (); } - if (ASDCP_FAILURE (_mxf_writer.Finalize())) { + if (ASDCP_FAILURE (_state->mxf_writer.Finalize())) { throw MiscError ("could not finalise audio MXF"); } diff --git a/src/sound_asset.h b/src/sound_asset.h index 17767b3a..e13c5028 100644 --- a/src/sound_asset.h +++ b/src/sound_asset.h @@ -24,7 +24,6 @@ * @brief An asset made up of PCM audio data files */ -#include "AS_DCP.h" #include "mxf_asset.h" #include "types.h" @@ -47,16 +46,24 @@ private: friend class SoundAsset; SoundAssetWriter (SoundAsset *); + + /* 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 _state; + SoundAsset* _asset; bool _finalized; int _frames_written; int _frame_buffer_offset; - ASDCP::PCM::MXFWriter _mxf_writer; - ASDCP::PCM::FrameBuffer _frame_buffer; - ASDCP::WriterInfo _writer_info; - ASDCP::PCM::AudioDescriptor _audio_desc; }; /** @brief An asset made up of WAV files */ -- cgit v1.2.3 From d714233760a8f6a0541c279c3046984f2d199814 Mon Sep 17 00:00:00 2001 From: Carl Hetherington Date: Tue, 22 Jan 2013 23:22:27 +0000 Subject: Remove hacky start_frame stuff from SoundAsset for now. --- examples/make_dcp.cc | 2 +- src/sound_asset.cc | 17 ++--------------- src/sound_asset.h | 8 +------- test/tests.cc | 3 +-- 4 files changed, 5 insertions(+), 25 deletions(-) diff --git a/examples/make_dcp.cc b/examples/make_dcp.cc index 1f5c74a1..3891db3f 100644 --- a/examples/make_dcp.cc +++ b/examples/make_dcp.cc @@ -93,7 +93,7 @@ main () /* Now we can create the sound asset using these files */ boost::shared_ptr sound_asset ( - new libdcp::SoundAsset (sound_files, "My Film DCP", "audio.mxf", 0, 24, 48, 0) + new libdcp::SoundAsset (sound_files, "My Film DCP", "audio.mxf", 0, 24, 48) ); /* Now that we have the assets, we can create a Reel to put them in and add it to the CPL */ diff --git a/src/sound_asset.cc b/src/sound_asset.cc index b7253917..4d76a2fd 100644 --- a/src/sound_asset.cc +++ b/src/sound_asset.cc @@ -46,12 +46,11 @@ SoundAsset::SoundAsset ( string directory, string mxf_name, boost::signals2::signal* progress, - int fps, int intrinsic_duration, int start_frame + int fps, int intrinsic_duration ) : MXFAsset (directory, mxf_name, progress, fps, intrinsic_duration) , _channels (files.size ()) , _sampling_rate (0) - , _start_frame (start_frame) { assert (_channels); @@ -63,12 +62,11 @@ SoundAsset::SoundAsset ( string directory, string mxf_name, boost::signals2::signal* progress, - int fps, int intrinsic_duration, int start_frame, int channels + int fps, int intrinsic_duration, int channels ) : MXFAsset (directory, mxf_name, progress, fps, intrinsic_duration) , _channels (channels) , _sampling_rate (0) - , _start_frame (start_frame) { assert (_channels); @@ -78,7 +76,6 @@ SoundAsset::SoundAsset ( SoundAsset::SoundAsset (string directory, string mxf_name) : MXFAsset (directory, mxf_name) , _channels (0) - , _start_frame (0) { ASDCP::PCM::MXFReader reader; if (ASDCP_FAILURE (reader.OpenRead (path().string().c_str()))) { @@ -101,7 +98,6 @@ SoundAsset::SoundAsset (string directory, string mxf_name, int fps, int channels : MXFAsset (directory, mxf_name, 0, fps, 0) , _channels (channels) , _sampling_rate (sampling_rate) - , _start_frame (0) { } @@ -174,15 +170,6 @@ SoundAsset::construct (boost::function get_path) if (ASDCP_FAILURE (mxf_writer.OpenWrite (path().string().c_str(), writer_info, audio_desc))) { 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 < _intrinsic_duration; ++i) { diff --git a/src/sound_asset.h b/src/sound_asset.h index e13c5028..ad350ce5 100644 --- a/src/sound_asset.h +++ b/src/sound_asset.h @@ -78,7 +78,6 @@ public: * @param progress Signal to inform of progress. * @param fps Frames per second. * @param intrinsic_duration Length of the whole asset in frames. - * @param start_frame Frame in the source to start writing from. * Note that this is different to entry_point in that the asset will contain no data before start_frame. */ SoundAsset ( @@ -87,8 +86,7 @@ public: std::string mxf_name, boost::signals2::signal* progress, int fps, - int intrinsic_duration, - int start_frame + int intrinsic_duration ); /** Construct a SoundAsset, generating the MXF from some WAV files. @@ -99,8 +97,6 @@ public: * @param progress Signal to inform of progress. * @param fps Frames per second. * @param intrinsic_duration Length of the whole asset in frames. - * @param start_frame Frame in the source to start writing from. - * Note that this is different to entry_point in that the asset will contain no data before start_frame. * @param channels Number of audio channels. */ SoundAsset ( @@ -110,7 +106,6 @@ public: boost::signals2::signal* progress, int fps, int intrinsic_duration, - int start_frame, int channels ); @@ -153,7 +148,6 @@ private: /** Number of channels in the asset */ int _channels; int _sampling_rate; - int _start_frame; }; } diff --git a/test/tests.cc b/test/tests.cc index 3fb56a28..2d21ae86 100644 --- a/test/tests.cc +++ b/test/tests.cc @@ -85,7 +85,6 @@ BOOST_AUTO_TEST_CASE (dcp_test) &(d.Progress), 24, 24, - 0, 2 )); @@ -102,7 +101,7 @@ BOOST_AUTO_TEST_CASE (error_test) p.push_back ("frobozz"); BOOST_CHECK_THROW (new libdcp::MonoPictureAsset (p, "build/test/bar", "video.mxf", &d.Progress, 24, 24, libdcp::Size (32, 32)), libdcp::FileError); - BOOST_CHECK_THROW (new libdcp::SoundAsset (p, "build/test/bar", "audio.mxf", &d.Progress, 24, 24, 0), libdcp::FileError); + BOOST_CHECK_THROW (new libdcp::SoundAsset (p, "build/test/bar", "audio.mxf", &d.Progress, 24, 24), libdcp::FileError); } BOOST_AUTO_TEST_CASE (read_dcp) -- cgit v1.2.3 From dcdd532760f8970505b7fa5c83f86fbe39a73148 Mon Sep 17 00:00:00 2001 From: Carl Hetherington Date: Wed, 23 Jan 2013 16:37:13 +0000 Subject: Use pkg-config for libopenjpeg when it is being linked dynamically. --- wscript | 11 +---------- 1 file changed, 1 insertion(+), 10 deletions(-) diff --git a/wscript b/wscript index 7412271e..a0734d09 100644 --- a/wscript +++ b/wscript @@ -29,19 +29,10 @@ def configure(conf): conf.check_cfg(package = 'openssl', args = '--cflags --libs', uselib_store = 'OPENSSL', mandatory = True) conf.check_cfg(package = 'libxml++-2.6', args = '--cflags --libs', uselib_store = 'LIBXML++', mandatory = True) - - openjpeg_fragment = """ - #include \n - #include \n - int main () {\n - void* p = (void *) opj_image_create;\n - return 0;\n - } - """ if conf.options.static_openjpeg: conf.check_cc(fragment = openjpeg_fragment, msg = 'Checking for library openjpeg', stlib = 'openjpeg', uselib_store = 'OPENJPEG') else: - conf.check_cc(fragment = openjpeg_fragment, msg = 'Checking for library openjpeg', lib = 'openjpeg', uselib_store = 'OPENJPEG') + conf.check_cfg(package = 'libopenjpeg', args = '--cflags --libs', uselib_store = 'OPENJPEG', mandatory = True) if conf.options.target_windows: boost_lib_suffix = '-mt' -- cgit v1.2.3 From 103c20d48c22f0c604e402de41bce7336ef9b386 Mon Sep 17 00:00:00 2001 From: Carl Hetherington Date: Fri, 25 Jan 2013 01:21:51 +0000 Subject: Allow changing of MXF directory / filename; un-expose ASDCP frame buffer classes in the API. --- src/asset.h | 8 ++++++++ src/picture_asset.cc | 12 ++++++------ src/picture_frame.cc | 36 ++++++++++++++++++++++++++++++++++++ src/picture_frame.h | 12 ++++++------ 4 files changed, 56 insertions(+), 12 deletions(-) diff --git a/src/asset.h b/src/asset.h index 3ba0a0cf..436e8b41 100644 --- a/src/asset.h +++ b/src/asset.h @@ -71,6 +71,14 @@ public: } boost::filesystem::path path () const; + + void set_directory (std::string d) { + _directory = d; + } + + void set_file_name (std::string f) { + _file_name = f; + } virtual bool equals (boost::shared_ptr other, EqualityOptions opt, std::list& notes) const = 0; diff --git a/src/picture_asset.cc b/src/picture_asset.cc index c3b49668..cd6dd4dc 100644 --- a/src/picture_asset.cc +++ b/src/picture_asset.cc @@ -260,8 +260,8 @@ MonoPictureAsset::equals (shared_ptr other, EqualityOptions opt, li if (!frame_buffer_equals ( i, opt, notes, - frame_A->j2k_frame()->RoData(), frame_A->j2k_frame()->Size(), - frame_B->j2k_frame()->RoData(), frame_B->j2k_frame()->Size() + frame_A->j2k_data(), frame_A->j2k_size(), + frame_B->j2k_data(), frame_B->j2k_size() )) { return false; } @@ -286,16 +286,16 @@ StereoPictureAsset::equals (shared_ptr other, EqualityOptions opt, if (!frame_buffer_equals ( i, opt, notes, - frame_A->j2k_frame()->Left.RoData(), frame_A->j2k_frame()->Left.Size(), - frame_B->j2k_frame()->Left.RoData(), frame_B->j2k_frame()->Left.Size() + frame_A->left_j2k_data(), frame_A->left_j2k_size(), + frame_B->left_j2k_data(), frame_B->left_j2k_size() )) { return false; } if (!frame_buffer_equals ( i, opt, notes, - frame_A->j2k_frame()->Right.RoData(), frame_A->j2k_frame()->Right.Size(), - frame_B->j2k_frame()->Right.RoData(), frame_B->j2k_frame()->Right.Size() + frame_A->right_j2k_data(), frame_A->right_j2k_size(), + frame_B->right_j2k_data(), frame_B->right_j2k_size() )) { return false; } diff --git a/src/picture_frame.cc b/src/picture_frame.cc index a2b90a0b..907f70ab 100644 --- a/src/picture_frame.cc +++ b/src/picture_frame.cc @@ -54,6 +54,18 @@ MonoPictureFrame::~MonoPictureFrame () delete _buffer; } +uint8_t const * +MonoPictureFrame::j2k_data () const +{ + return _buffer->RoData (); +} + +int +MonoPictureFrame::j2k_size () const +{ + return _buffer->Size (); +} + /** @param reduce a factor by which to reduce the resolution * of the image, expressed as a power of two (pass 0 for no * reduction). @@ -127,3 +139,27 @@ StereoPictureFrame::argb_frame (Eye eye, int reduce) const opj_image_destroy (xyz_frame); return f; } + +uint8_t const * +StereoPictureFrame::left_j2k_data () const +{ + return _buffer->Left.RoData (); +} + +int +StereoPictureFrame::left_j2k_size () const +{ + return _buffer->Left.Size (); +} + +uint8_t const * +StereoPictureFrame::right_j2k_data () const +{ + return _buffer->Right.RoData (); +} + +int +StereoPictureFrame::right_j2k_size () const +{ + return _buffer->Right.Size (); +} diff --git a/src/picture_frame.h b/src/picture_frame.h index ad51abed..20ce069e 100644 --- a/src/picture_frame.h +++ b/src/picture_frame.h @@ -41,9 +41,8 @@ public: ~MonoPictureFrame (); boost::shared_ptr argb_frame (int reduce = 0) const; - ASDCP::JP2K::FrameBuffer* j2k_frame () const { - return _buffer; - } + uint8_t const * j2k_data () const; + int j2k_size () const; private: ASDCP::JP2K::FrameBuffer* _buffer; @@ -57,9 +56,10 @@ public: ~StereoPictureFrame (); boost::shared_ptr argb_frame (Eye eye, int reduce = 0) const; - ASDCP::JP2K::SFrameBuffer* j2k_frame () const { - return _buffer; - } + uint8_t const * left_j2k_data () const; + int left_j2k_size () const; + uint8_t const * right_j2k_data () const; + int right_j2k_size () const; private: ASDCP::JP2K::SFrameBuffer* _buffer; -- cgit v1.2.3 From a246eb45b34ebc6bf277694b295f693706be8c6a Mon Sep 17 00:00:00 2001 From: Carl Hetherington Date: Mon, 28 Jan 2013 00:11:30 +0000 Subject: Add support for hashing mono picture MXF writes on the way out. --- asdcplib/src/AS_DCP.h | 7 +++++- asdcplib/src/AS_DCP_JP2K.cpp | 16 +++++++++----- asdcplib/src/AS_DCP_internal.h | 2 +- asdcplib/src/KM_fileio.cpp | 49 +++++++++++++++++++++++++++++++++++++++--- asdcplib/src/KM_fileio.h | 7 ++++++ asdcplib/src/h__Writer.cpp | 8 ++++++- src/picture_asset.cc | 27 ++++++++++++++++++----- src/picture_asset.h | 24 ++++++++++++++++++++- 8 files changed, 123 insertions(+), 17 deletions(-) diff --git a/asdcplib/src/AS_DCP.h b/asdcplib/src/AS_DCP.h index 3d679413..d5675586 100755 --- a/asdcplib/src/AS_DCP.h +++ b/asdcplib/src/AS_DCP.h @@ -87,6 +87,7 @@ This project depends upon the following libraries: #define _AS_DCP_H_ #include +#include #include #include #include @@ -1172,12 +1173,16 @@ namespace ASDCP { // Writes a frame of essence to the MXF file. If the optional AESEncContext // argument is present, the essence is encrypted prior to writing. + // A MD5 hash of the data that we write is written to hash if it is not 0 // Fails if the file is not open, is finalized, or an operating system // error occurs. - Result_t WriteFrame(const FrameBuffer&, AESEncContext* = 0, HMACContext* = 0); + Result_t WriteFrame(const FrameBuffer&, AESEncContext* = 0, HMACContext* = 0, std::string* hash = 0); // Closes the MXF file, writing the index and revised header. Result_t Finalize(); + + // Return the current file offset in the MXF file that we are writing + ui64_t Tell() const; }; // diff --git a/asdcplib/src/AS_DCP_JP2K.cpp b/asdcplib/src/AS_DCP_JP2K.cpp index ca6d5270..359cd910 100755 --- a/asdcplib/src/AS_DCP_JP2K.cpp +++ b/asdcplib/src/AS_DCP_JP2K.cpp @@ -815,7 +815,7 @@ public: Result_t OpenWrite(const char*, EssenceType_t type, ui32_t HeaderSize); Result_t SetSourceStream(const PictureDescriptor&, const std::string& label, ASDCP::Rational LocalEditRate = ASDCP::Rational(0,0)); - Result_t WriteFrame(const JP2K::FrameBuffer&, bool add_index, AESEncContext*, HMACContext*); + Result_t WriteFrame(const JP2K::FrameBuffer&, bool add_index, AESEncContext*, HMACContext*, std::string* hash = 0); Result_t Finalize(); Result_t JP2K_PDesc_to_MD(JP2K::PictureDescriptor& PDesc); }; @@ -978,7 +978,7 @@ lh__Writer::SetSourceStream(const PictureDescriptor& PDesc, const std::string& l // ASDCP::Result_t lh__Writer::WriteFrame(const JP2K::FrameBuffer& FrameBuf, bool add_index, - AESEncContext* Ctx, HMACContext* HMAC) + AESEncContext* Ctx, HMACContext* HMAC, std::string* hash) { Result_t result = RESULT_OK; @@ -988,7 +988,7 @@ lh__Writer::WriteFrame(const JP2K::FrameBuffer& FrameBuf, bool add_index, ui64_t StreamOffset = m_StreamOffset; if ( ASDCP_SUCCESS(result) ) - result = WriteEKLVPacket(FrameBuf, m_EssenceUL, Ctx, HMAC); + result = WriteEKLVPacket(FrameBuf, m_EssenceUL, Ctx, HMAC, hash); if ( ASDCP_SUCCESS(result) && add_index ) { @@ -1099,12 +1099,12 @@ ASDCP::JP2K::MXFWriter::OpenWrite(const char* filename, const WriterInfo& Info, // Fails if the file is not open, is finalized, or an operating system // error occurs. ASDCP::Result_t -ASDCP::JP2K::MXFWriter::WriteFrame(const FrameBuffer& FrameBuf, AESEncContext* Ctx, HMACContext* HMAC) +ASDCP::JP2K::MXFWriter::WriteFrame(const FrameBuffer& FrameBuf, AESEncContext* Ctx, HMACContext* HMAC, std::string* hash) { if ( m_Writer.empty() ) return RESULT_INIT; - return m_Writer->WriteFrame(FrameBuf, true, Ctx, HMAC); + return m_Writer->WriteFrame(FrameBuf, true, Ctx, HMAC, hash); } // Closes the MXF file, writing the index and other closing information. @@ -1117,6 +1117,12 @@ ASDCP::JP2K::MXFWriter::Finalize() return m_Writer->Finalize(); } +ui64_t +ASDCP::JP2K::MXFWriter::Tell() const +{ + return m_Writer->m_File.Tell(); +} + //------------------------------------------------------------------------------------------ // diff --git a/asdcplib/src/AS_DCP_internal.h b/asdcplib/src/AS_DCP_internal.h index 4c1507c8..15b52822 100755 --- a/asdcplib/src/AS_DCP_internal.h +++ b/asdcplib/src/AS_DCP_internal.h @@ -237,7 +237,7 @@ namespace ASDCP ui32_t TCFrameRate, ui32_t BytesPerEditUnit = 0); Result_t WriteEKLVPacket(const ASDCP::FrameBuffer& FrameBuf, - const byte_t* EssenceUL, AESEncContext* Ctx, HMACContext* HMAC); + const byte_t* EssenceUL, AESEncContext* Ctx, HMACContext* HMAC, std::string* hash = 0); Result_t WriteMXFFooter(); diff --git a/asdcplib/src/KM_fileio.cpp b/asdcplib/src/KM_fileio.cpp index 2914f982..138bc3b4 100644 --- a/asdcplib/src/KM_fileio.cpp +++ b/asdcplib/src/KM_fileio.cpp @@ -32,6 +32,8 @@ THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #include #include #include +#include +#include #include @@ -49,7 +51,6 @@ using namespace Kumu; typedef struct _stati64 fstat_t; #define S_IFLNK 0 - // win32 has WriteFileGather() and ReadFileScatter() but they // demand page alignment and page sizing, making them unsuitable // for use with arbitrary buffer sizes. @@ -614,7 +615,10 @@ Kumu::FileReader::Size() const // these are declared here instead of in the header file // because we have a mem_ptr that is managing a hidden class -Kumu::FileWriter::FileWriter() {} +Kumu::FileWriter::FileWriter() + : m_Hashing (false) +{} + Kumu::FileWriter::~FileWriter() {} // @@ -639,6 +643,37 @@ Kumu::FileWriter::Writev(const byte_t* buf, ui32_t buf_len) return RESULT_OK; } +void +Kumu::FileWriter::StartHashing() +{ + m_Hashing = true; + MD5_Init (&m_MD5Context); +} + +void +Kumu::FileWriter::MaybeHash(void const * data, int size) +{ + if (m_Hashing) { + MD5_Update (&m_MD5Context, data, size); + } +} + +std::string +Kumu::FileWriter::StopHashing() +{ + m_Hashing = false; + + unsigned char digest[MD5_DIGEST_LENGTH]; + MD5_Final (digest, &m_MD5Context); + + std::stringstream s; + for (int i = 0; i < MD5_DIGEST_LENGTH; ++i) { + s << std::hex << std::setfill('0') << std::setw(2) << ((int) digest[i]); + } + + return s.str (); +} + #ifdef KM_WIN32 //------------------------------------------------------------------------------------------ @@ -830,6 +865,7 @@ Kumu::FileWriter::Writev(ui32_t* bytes_written) break; } + MaybeHash (iov->m_iovec[i].iov_base, iov->m_iovec[i].iov_len); *bytes_written += tmp_count; } @@ -860,6 +896,8 @@ Kumu::FileWriter::Write(const byte_t* buf, ui32_t buf_len, ui32_t* bytes_written if ( result == 0 || *bytes_written != buf_len ) return Kumu::RESULT_WRITEFAIL; + MaybeHash (buf, buf_len); + return Kumu::RESULT_OK; } @@ -1006,6 +1044,10 @@ Kumu::FileWriter::Writev(ui32_t* bytes_written) if ( write_size == -1L || write_size != total_size ) return RESULT_WRITEFAIL; + for (int i = 0; i < iov->m_Count; ++i) { + MaybeHash (iov->m_iovec[i].iov_base, iov->m_iovec[i].iov_len); + } + iov->m_Count = 0; *bytes_written = write_size; return RESULT_OK; @@ -1025,6 +1067,7 @@ Kumu::FileWriter::Write(const byte_t* buf, ui32_t buf_len, ui32_t* bytes_written return RESULT_STATE; int write_size = write(m_Handle, buf, buf_len); + MaybeHash (buf, buf_len); if ( write_size == -1L || (ui32_t)write_size != buf_len ) return RESULT_WRITEFAIL; @@ -1034,7 +1077,7 @@ Kumu::FileWriter::Write(const byte_t* buf, ui32_t buf_len, ui32_t* bytes_written } -#endif // KM_WIN32 +#endif //------------------------------------------------------------------------------------------ diff --git a/asdcplib/src/KM_fileio.h b/asdcplib/src/KM_fileio.h index b078e32b..cb00acc8 100755 --- a/asdcplib/src/KM_fileio.h +++ b/asdcplib/src/KM_fileio.h @@ -35,6 +35,7 @@ THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #include #include #include +#include #ifdef KM_WIN32 # include @@ -298,6 +299,8 @@ namespace Kumu class h__iovec; mem_ptr m_IOVec; KM_NO_COPY_CONSTRUCT(FileWriter); + bool m_Hashing; + MD5_CTX m_MD5Context; public: FileWriter(); @@ -317,6 +320,10 @@ namespace Kumu // the iovec list will be written to disk before the given buffer,as though // you had called Writev() first. Result_t Write(const byte_t*, ui32_t, ui32_t* = 0); // write buffer to disk + + void StartHashing(); + void MaybeHash(void const *, int); + std::string StopHashing(); }; Result_t CreateDirectoriesInPath(const std::string& Path); diff --git a/asdcplib/src/h__Writer.cpp b/asdcplib/src/h__Writer.cpp index 5d3a1d5a..662e0f82 100755 --- a/asdcplib/src/h__Writer.cpp +++ b/asdcplib/src/h__Writer.cpp @@ -499,11 +499,13 @@ ASDCP::h__Writer::WriteMXFHeader(const std::string& PackageLabel, const UL& Wrap // standard method of writing a plaintext or encrypted frame Result_t ASDCP::h__Writer::WriteEKLVPacket(const ASDCP::FrameBuffer& FrameBuf, const byte_t* EssenceUL, - AESEncContext* Ctx, HMACContext* HMAC) + AESEncContext* Ctx, HMACContext* HMAC, std::string* hash) { Result_t result = RESULT_OK; IntegrityPack IntPack; + m_File.StartHashing(); + byte_t overhead[128]; Kumu::MemIOWriter Overhead(overhead, 128); assert(m_Dict); @@ -635,6 +637,10 @@ ASDCP::h__Writer::WriteEKLVPacket(const ASDCP::FrameBuffer& FrameBuf, const byte if ( ASDCP_SUCCESS(result) ) result = m_File.Writev(); + if (hash) { + *hash = m_File.StopHashing(); + } + return result; } diff --git a/src/picture_asset.cc b/src/picture_asset.cc index cd6dd4dc..d242777c 100644 --- a/src/picture_asset.cc +++ b/src/picture_asset.cc @@ -41,6 +41,9 @@ using std::ostream; using std::list; using std::vector; using std::max; +using std::pair; +using std::make_pair; +using std::istream; using boost::shared_ptr; using boost::dynamic_pointer_cast; using boost::lexical_cast; @@ -216,7 +219,6 @@ MonoPictureAsset::construct (boost::function get_path) throw FileError ("could not open JPEG2000 file for reading", path); } - /* XXX: passing 0 to WriteFrame ok? */ if (ASDCP_FAILURE (mxf_writer.WriteFrame (frame_buffer, 0, 0))) { throw MiscError ("error in writing video MXF"); } @@ -240,7 +242,7 @@ MonoPictureAsset::path_from_list (int f, vector const & files) const shared_ptr MonoPictureAsset::get_frame (int n) const { - return shared_ptr (new MonoPictureFrame (path().string(), n + _entry_point)); + return shared_ptr (new MonoPictureFrame (path().string(), n)); } @@ -390,7 +392,7 @@ StereoPictureAsset::StereoPictureAsset (string directory, string mxf_name, int f shared_ptr StereoPictureAsset::get_frame (int n) const { - return shared_ptr (new StereoPictureFrame (path().string(), n + _entry_point)); + return shared_ptr (new StereoPictureFrame (path().string(), n)); } shared_ptr @@ -400,6 +402,17 @@ MonoPictureAsset::start_write () return shared_ptr (new MonoPictureAssetWriter (this)); } +FrameInfo::FrameInfo (istream& s) +{ + s >> offset >> length >> hash; +} + +void +FrameInfo::write (ostream& s) +{ + s << offset << " " << length << " " << hash; +} + struct MonoPictureAssetWriter::ASDCPState { ASDCPState() @@ -426,7 +439,7 @@ MonoPictureAssetWriter::MonoPictureAssetWriter (MonoPictureAsset* a) } -void +FrameInfo MonoPictureAssetWriter::write (uint8_t* data, int size) { assert (!_finalized); @@ -448,11 +461,15 @@ MonoPictureAssetWriter::write (uint8_t* data, int size) } } - if (ASDCP_FAILURE (_state->mxf_writer.WriteFrame (_state->frame_buffer, 0, 0))) { + uint64_t const before_offset = _state->mxf_writer.Tell (); + + string hash; + if (ASDCP_FAILURE (_state->mxf_writer.WriteFrame (_state->frame_buffer, 0, 0, &hash))) { throw MiscError ("error in writing video MXF"); } _frames_written++; + return FrameInfo (before_offset, _state->mxf_writer.Tell() - before_offset, hash); } void diff --git a/src/picture_asset.h b/src/picture_asset.h index 71900200..4e9e1dd7 100644 --- a/src/picture_asset.h +++ b/src/picture_asset.h @@ -17,6 +17,9 @@ */ +#ifndef LIBDCP_PICTURE_ASSET_H +#define LIBDCP_PICTURE_ASSET_H + /** @file src/picture_asset.h * @brief An asset made up of JPEG2000 files */ @@ -79,6 +82,23 @@ protected: class MonoPictureAsset; +struct FrameInfo +{ + FrameInfo (uint64_t o, uint64_t l, std::string h) + : offset (o) + , length (l) + , hash (h) + {} + + FrameInfo (std::istream& s); + + void write (std::ostream& s); + + uint64_t offset; + uint64_t length; + std::string hash; +}; + /** A helper class for writing to MonoPictureAssets progressively (i.e. writing frame-by-frame, * rather than giving libdcp all the frames in one go). * @@ -94,7 +114,7 @@ class MonoPictureAssetWriter public: ~MonoPictureAssetWriter (); - void write (uint8_t* data, int size); + FrameInfo write (uint8_t* data, int size); void finalize (); private: @@ -205,3 +225,5 @@ public: } + +#endif -- cgit v1.2.3 From 5724ce48e44192ae0f303ea93cbecf7936700193 Mon Sep 17 00:00:00 2001 From: Carl Hetherington Date: Mon, 28 Jan 2013 00:15:35 +0000 Subject: Add GNU global stuff. --- .gitignore | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/.gitignore b/.gitignore index d2f33477..d845eee5 100644 --- a/.gitignore +++ b/.gitignore @@ -10,3 +10,7 @@ src/lut.cc src/lut.h *.pyc __pycache__ +GPATH +GRTAGS +GSYMS +GTAGS -- cgit v1.2.3 From fe4c98bdc865290d10e70ebab7e48247d390f4c4 Mon Sep 17 00:00:00 2001 From: Carl Hetherington Date: Fri, 1 Feb 2013 21:12:06 +0000 Subject: Unfinished attempt to overwrite existing; tricky because you need to delay writes of the MXF header until you know lots of stuff about the JP2K file (to fill in the picture descriptor). --- asdcplib/src/AS_DCP.h | 6 ++-- asdcplib/src/AS_DCP_JP2K.cpp | 63 +++++++++++++++++++++++++++++++++++------ asdcplib/src/AS_DCP_internal.h | 2 ++ asdcplib/src/KM_prng.cpp | 21 +++++++++++++- asdcplib/src/KM_prng.h | 3 ++ asdcplib/src/KM_util.cpp | 9 ++++++ asdcplib/src/KM_util.h | 3 ++ asdcplib/src/h__Writer.cpp | 12 ++++++++ run-tests.sh | 6 ++++ src/picture_asset.cc | 42 +++++++++++++++++++++++---- src/picture_asset.h | 5 +++- test/tests.cc | 64 ++++++++++++++++++++++++++++++++++++++++++ 12 files changed, 219 insertions(+), 17 deletions(-) diff --git a/asdcplib/src/AS_DCP.h b/asdcplib/src/AS_DCP.h index d5675586..2681bf14 100755 --- a/asdcplib/src/AS_DCP.h +++ b/asdcplib/src/AS_DCP.h @@ -1165,11 +1165,11 @@ namespace ASDCP { virtual MXF::OPAtomHeader& OPAtomHeader(); virtual MXF::OPAtomIndexFooter& OPAtomIndexFooter(); - // Open the file for writing. The file must not exist. Returns error if + // Open the file for writing. The file must not exist unless overwrite is true. Returns error if // the operation cannot be completed or if nonsensical data is discovered // in the essence descriptor. Result_t OpenWrite(const char* filename, const WriterInfo&, - const PictureDescriptor&, ui32_t HeaderSize = 16384); + const PictureDescriptor&, ui32_t HeaderSize, bool overwrite); // Writes a frame of essence to the MXF file. If the optional AESEncContext // argument is present, the essence is encrypted prior to writing. @@ -1178,6 +1178,8 @@ namespace ASDCP { // error occurs. Result_t WriteFrame(const FrameBuffer&, AESEncContext* = 0, HMACContext* = 0, std::string* hash = 0); + Result_t FakeWriteFrame(int size); + // Closes the MXF file, writing the index and revised header. Result_t Finalize(); diff --git a/asdcplib/src/AS_DCP_JP2K.cpp b/asdcplib/src/AS_DCP_JP2K.cpp index 359cd910..05f5e005 100755 --- a/asdcplib/src/AS_DCP_JP2K.cpp +++ b/asdcplib/src/AS_DCP_JP2K.cpp @@ -1,3 +1,5 @@ +/* -*- c-basic-offset: 2; -*- */ + /* Copyright (c) 2004-2012, John Hurst All rights reserved. @@ -33,6 +35,7 @@ THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #include #include +using std::cout; using namespace ASDCP::JP2K; using Kumu::GenRandomValue; @@ -812,10 +815,11 @@ public: ~lh__Writer(){} - Result_t OpenWrite(const char*, EssenceType_t type, ui32_t HeaderSize); + Result_t OpenWrite(const char*, EssenceType_t type, ui32_t HeaderSize, bool); Result_t SetSourceStream(const PictureDescriptor&, const std::string& label, ASDCP::Rational LocalEditRate = ASDCP::Rational(0,0)); Result_t WriteFrame(const JP2K::FrameBuffer&, bool add_index, AESEncContext*, HMACContext*, std::string* hash = 0); + Result_t FakeWriteFrame(int size, bool add_index); Result_t Finalize(); Result_t JP2K_PDesc_to_MD(JP2K::PictureDescriptor& PDesc); }; @@ -900,15 +904,21 @@ lh__Writer::JP2K_PDesc_to_MD(JP2K::PictureDescriptor& PDesc) } -// Open the file for writing. The file must not exist. Returns error if +// Open the file for writing. The file must not exist unless overwrite is true. Returns error if // the operation cannot be completed. ASDCP::Result_t -lh__Writer::OpenWrite(const char* filename, EssenceType_t type, ui32_t HeaderSize) +lh__Writer::OpenWrite(const char* filename, EssenceType_t type, ui32_t HeaderSize, bool overwrite) { if ( ! m_State.Test_BEGIN() ) return RESULT_STATE; - Result_t result = m_File.OpenWrite(filename); + Result_t result = RESULT_OK; + if (overwrite) { + result = m_File.OpenModify(filename); + m_File.Seek(0); + } else { + result = m_File.OpenWrite(filename); + } if ( ASDCP_SUCCESS(result) ) { @@ -986,6 +996,8 @@ lh__Writer::WriteFrame(const JP2K::FrameBuffer& FrameBuf, bool add_index, result = m_State.Goto_RUNNING(); // first time through ui64_t StreamOffset = m_StreamOffset; + cout << "Real write @ " << StreamOffset << " (header is " << m_HeaderSize << ")\n"; + cout << "\tfile @ " << m_File.Tell() << "\n"; if ( ASDCP_SUCCESS(result) ) result = WriteEKLVPacket(FrameBuf, m_EssenceUL, Ctx, HMAC, hash); @@ -1001,6 +1013,32 @@ lh__Writer::WriteFrame(const JP2K::FrameBuffer& FrameBuf, bool add_index, return result; } +Result_t +lh__Writer::FakeWriteFrame(int size, bool add_index) +{ + Result_t result = RESULT_OK; + + if ( m_State.Test_READY() ) + result = m_State.Goto_RUNNING(); + + ui64_t StreamOffset = m_StreamOffset; + cout << "Fake write @ " << StreamOffset << " (header is " << m_HeaderSize << ")\n"; + cout << "\tfile @ " << m_File.Tell() << "\n"; + + if ( ASDCP_SUCCESS(result) ) + result = FakeWriteEKLVPacket(size); + + if ( ASDCP_SUCCESS(result) && add_index ) + { + IndexTableSegment::IndexEntry Entry; + Entry.StreamOffset = StreamOffset; + m_FooterPart.PushIndexEntry(Entry); + } + + m_FramesWritten++; + return result; +} + // Closes the MXF file, writing the index and other closing information. // @@ -1069,11 +1107,11 @@ ASDCP::JP2K::MXFWriter::OPAtomIndexFooter() return m_Writer->m_FooterPart; } -// Open the file for writing. The file must not exist. Returns error if +// Open the file for writing. The file must not exist unless overwrite is true. Returns error if // the operation cannot be completed. ASDCP::Result_t ASDCP::JP2K::MXFWriter::OpenWrite(const char* filename, const WriterInfo& Info, - const PictureDescriptor& PDesc, ui32_t HeaderSize) + const PictureDescriptor& PDesc, ui32_t HeaderSize, bool overwrite) { if ( Info.LabelSetType == LS_MXF_SMPTE ) m_Writer = new h__Writer(DefaultSMPTEDict()); @@ -1082,7 +1120,7 @@ ASDCP::JP2K::MXFWriter::OpenWrite(const char* filename, const WriterInfo& Info, m_Writer->m_Info = Info; - Result_t result = m_Writer->OpenWrite(filename, ASDCP::ESS_JPEG_2000, HeaderSize); + Result_t result = m_Writer->OpenWrite(filename, ASDCP::ESS_JPEG_2000, HeaderSize, overwrite); if ( ASDCP_SUCCESS(result) ) result = m_Writer->SetSourceStream(PDesc, JP2K_PACKAGE_LABEL); @@ -1107,6 +1145,15 @@ ASDCP::JP2K::MXFWriter::WriteFrame(const FrameBuffer& FrameBuf, AESEncContext* C return m_Writer->WriteFrame(FrameBuf, true, Ctx, HMAC, hash); } +ASDCP::Result_t +ASDCP::JP2K::MXFWriter::FakeWriteFrame(int size) +{ + if ( m_Writer.empty() ) + return RESULT_INIT; + + return m_Writer->FakeWriteFrame(size, true); +} + // Closes the MXF file, writing the index and other closing information. ASDCP::Result_t ASDCP::JP2K::MXFWriter::Finalize() @@ -1233,7 +1280,7 @@ ASDCP::JP2K::MXFSWriter::OpenWrite(const char* filename, const WriterInfo& Info, m_Writer->m_Info = Info; - Result_t result = m_Writer->OpenWrite(filename, ASDCP::ESS_JPEG_2000_S, HeaderSize); + Result_t result = m_Writer->OpenWrite(filename, ASDCP::ESS_JPEG_2000_S, HeaderSize, false); if ( ASDCP_SUCCESS(result) ) { diff --git a/asdcplib/src/AS_DCP_internal.h b/asdcplib/src/AS_DCP_internal.h index 15b52822..73106a26 100755 --- a/asdcplib/src/AS_DCP_internal.h +++ b/asdcplib/src/AS_DCP_internal.h @@ -239,6 +239,8 @@ namespace ASDCP Result_t WriteEKLVPacket(const ASDCP::FrameBuffer& FrameBuf, const byte_t* EssenceUL, AESEncContext* Ctx, HMACContext* HMAC, std::string* hash = 0); + Result_t FakeWriteEKLVPacket(int size); + Result_t WriteMXFFooter(); }; diff --git a/asdcplib/src/KM_prng.cpp b/asdcplib/src/KM_prng.cpp index 06b22d91..463ae157 100755 --- a/asdcplib/src/KM_prng.cpp +++ b/asdcplib/src/KM_prng.cpp @@ -1,3 +1,5 @@ +/* -*- c-basic-offset: 2; -*- */ + /* Copyright (c) 2006-2009, John Hurst All rights reserved. @@ -98,7 +100,9 @@ public: set_key(rng_key); - m_libdcp_test_rng_state = 1; +#ifdef LIBDCP_POSIX + reset(); +#endif } // @@ -153,6 +157,13 @@ public: /* XXX */ #endif } + +#ifdef LIBDCP_POSIX + void reset () + { + m_libdcp_test_rng_state = 1; + } +#endif }; @@ -206,6 +217,14 @@ Kumu::FortunaRNG::FillRandom(Kumu::ByteString& Buffer) return Buffer.Data(); } +#ifdef LIBDCP_POSIX +void +Kumu::FortunaRNG::Reset() +{ + s_RNG->reset(); +} +#endif + //------------------------------------------------------------------------------------------ // diff --git a/asdcplib/src/KM_prng.h b/asdcplib/src/KM_prng.h index 4d7ab2b7..0b941f3b 100755 --- a/asdcplib/src/KM_prng.h +++ b/asdcplib/src/KM_prng.h @@ -45,6 +45,9 @@ namespace Kumu ~FortunaRNG(); const byte_t* FillRandom(byte_t* buf, ui32_t len); const byte_t* FillRandom(ByteString&); +#ifdef LIBDCP_POSIX + void Reset(); +#endif }; diff --git a/asdcplib/src/KM_util.cpp b/asdcplib/src/KM_util.cpp index 23e8a1a6..b1814840 100755 --- a/asdcplib/src/KM_util.cpp +++ b/asdcplib/src/KM_util.cpp @@ -534,6 +534,15 @@ Kumu::GenRandomValue(UUID& ID) ID.Set(tmp_buf); } +#ifdef LIBDCP_POSIX +void +Kumu::ResetTestRNG() +{ + FortunaRNG RNG; + RNG.Reset(); +} +#endif + // void Kumu::GenRandomUUID(byte_t* buf) diff --git a/asdcplib/src/KM_util.h b/asdcplib/src/KM_util.h index 892670e6..a9793ba0 100755 --- a/asdcplib/src/KM_util.h +++ b/asdcplib/src/KM_util.h @@ -381,6 +381,9 @@ namespace Kumu void GenRandomUUID(byte_t* buf); // buf must be UUID_Length or longer void GenRandomValue(UUID&); +#ifdef LIBDCP_POSIX + void ResetTestRNG(); +#endif typedef ArchivableList UUIDList; diff --git a/asdcplib/src/h__Writer.cpp b/asdcplib/src/h__Writer.cpp index 662e0f82..d743e300 100755 --- a/asdcplib/src/h__Writer.cpp +++ b/asdcplib/src/h__Writer.cpp @@ -32,6 +32,7 @@ THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #include "AS_DCP_internal.h" #include "KLV.h" +using std::cout; using namespace ASDCP; using namespace ASDCP::MXF; @@ -644,6 +645,17 @@ ASDCP::h__Writer::WriteEKLVPacket(const ASDCP::FrameBuffer& FrameBuf, const byte return result; } +Result_t +ASDCP::h__Writer::FakeWriteEKLVPacket(int size) +{ + Result_t result = RESULT_OK; + + m_StreamOffset += size; + m_File.Seek(size, Kumu::SP_POS); + + return result; +} + // standard method of writing the header and footer of a completed MXF file // diff --git a/run-tests.sh b/run-tests.sh index 7e464329..888968ad 100755 --- a/run-tests.sh +++ b/run-tests.sh @@ -63,5 +63,11 @@ if [ "$?" != "0" ]; then echo "FAIL: dcpinfo output from rewrite incorrect" exit 1 fi + +diff build/test/baz/video1.mxf build/test/baz/video2.mxf +if [ "$?" != "0" ]; then + echo "FAIL: MXFs from recovery incorrect" + exit 1 +fi echo "PASS" diff --git a/src/picture_asset.cc b/src/picture_asset.cc index d242777c..11815761 100644 --- a/src/picture_asset.cc +++ b/src/picture_asset.cc @@ -207,7 +207,7 @@ MonoPictureAsset::construct (boost::function get_path) fill_writer_info (&writer_info, _uuid); ASDCP::JP2K::MXFWriter mxf_writer; - if (ASDCP_FAILURE (mxf_writer.OpenWrite (path().string().c_str(), writer_info, picture_desc))) { + if (ASDCP_FAILURE (mxf_writer.OpenWrite (path().string().c_str(), writer_info, picture_desc, 16384, false))) { throw MXFFileError ("could not open MXF file for writing", path().string()); } @@ -399,7 +399,14 @@ shared_ptr MonoPictureAsset::start_write () { /* XXX: can't we use a shared_ptr here? */ - return shared_ptr (new MonoPictureAssetWriter (this)); + return shared_ptr (new MonoPictureAssetWriter (this, false)); +} + +shared_ptr +MonoPictureAsset::start_overwrite () +{ + /* XXX: can't we use a shared_ptr here? */ + return shared_ptr (new MonoPictureAssetWriter (this, true)); } FrameInfo::FrameInfo (istream& s) @@ -455,8 +462,8 @@ MonoPictureAssetWriter::write (uint8_t* data, int size) _state->picture_descriptor.EditRate = ASDCP::Rational (_asset->edit_rate(), 1); MXFAsset::fill_writer_info (&_state->writer_info, _asset->uuid()); - - if (ASDCP_FAILURE (_state->mxf_writer.OpenWrite (_asset->path().string().c_str(), _state->writer_info, _state->picture_descriptor))) { + + if (ASDCP_FAILURE (_state->mxf_writer.OpenWrite (_asset->path().string().c_str(), _state->writer_info, _state->picture_descriptor, 16384, false))) { throw MXFFileError ("could not open MXF file for writing", _asset->path().string()); } } @@ -468,10 +475,35 @@ MonoPictureAssetWriter::write (uint8_t* data, int size) throw MiscError ("error in writing video MXF"); } - _frames_written++; + ++_frames_written; return FrameInfo (before_offset, _state->mxf_writer.Tell() - before_offset, hash); } +void +MonoPictureAssetWriter::fake_write (int size) +{ + assert (!_finalized); + + if (_frames_written == 0) { + /* This is our first frame; set up the writer */ + + _state->j2k_parser.FillPictureDescriptor (_state->picture_descriptor); + _state->picture_descriptor.EditRate = ASDCP::Rational (_asset->edit_rate(), 1); + + MXFAsset::fill_writer_info (&_state->writer_info, _asset->uuid()); + + if (ASDCP_FAILURE (_state->mxf_writer.OpenWrite (_asset->path().string().c_str(), _state->writer_info, _state->picture_descriptor, 16384, true))) { + throw MXFFileError ("could not open MXF file for writing", _asset->path().string()); + } + } + + if (ASDCP_FAILURE (_state->mxf_writer.FakeWriteFrame (size))) { + throw MiscError ("error in writing video MXF"); + } + + ++_frames_written; +} + void MonoPictureAssetWriter::finalize () { diff --git a/src/picture_asset.h b/src/picture_asset.h index 4e9e1dd7..9df85bad 100644 --- a/src/picture_asset.h +++ b/src/picture_asset.h @@ -115,12 +115,13 @@ public: ~MonoPictureAssetWriter (); FrameInfo write (uint8_t* data, int size); + void fake_write (int size); void finalize (); private: friend class MonoPictureAsset; - MonoPictureAssetWriter (MonoPictureAsset *); + MonoPictureAssetWriter (MonoPictureAsset *, bool); /* no copy construction */ MonoPictureAssetWriter (MonoPictureAssetWriter const &); @@ -205,6 +206,8 @@ public: /** Start a progressive write to a MonoPictureAsset */ boost::shared_ptr start_write (); + boost::shared_ptr start_overwrite (); + boost::shared_ptr get_frame (int n) const; bool equals (boost::shared_ptr other, EqualityOptions opt, std::list& notes) const; diff --git a/test/tests.cc b/test/tests.cc index 2d21ae86..c9243b88 100644 --- a/test/tests.cc +++ b/test/tests.cc @@ -35,6 +35,7 @@ #include using std::string; +using std::cout; using std::vector; using std::list; using boost::shared_ptr; @@ -578,3 +579,66 @@ BOOST_AUTO_TEST_CASE (color) BOOST_CHECK_EQUAL (c.to_argb_string(), "FF0000FF"); } + +BOOST_AUTO_TEST_CASE (recovery) +{ + Kumu::libdcp_test = true; + + cout << "=== recovery.\n"; + + string const picture = "test/data/32x32_red_square.j2c"; + int const length = boost::filesystem::file_size (picture); + uint8_t* data = new uint8_t[length]; + { + FILE* f = fopen (picture.c_str(), "rb"); + BOOST_CHECK (f); + fread (data, 1, length, f); + fclose (f); + } + + Kumu::ResetTestRNG (); + + boost::filesystem::remove_all ("build/test/baz"); + boost::filesystem::create_directories ("build/test/baz"); + shared_ptr mp (new libdcp::MonoPictureAsset ("build/test/baz", "video1.mxf", 24, libdcp::Size (32, 32))); + shared_ptr writer = mp->start_write (); + + int written_length = 0; + for (int i = 0; i < 24; ++i) { + libdcp::FrameInfo info = writer->write (data, length); + written_length = info.length; + cout << "- written length " << written_length << "\n"; + } + + writer->finalize (); + writer.reset (); + + cout << "=== recovery part 2.\n"; + + boost::filesystem::copy_file ("build/test/baz/video1.mxf", "build/test/baz/video2.mxf"); + boost::filesystem::resize_file ("build/test/baz/video2.mxf", 16384 + 353 * 11); + + { + FILE* f = fopen ("build/test/baz/video2.mxf", "wa"); + rewind (f); + char zeros[256]; + memset (zeros, 0, 256); + fwrite (zeros, 1, 256, f); + fclose (f); + } + + Kumu::ResetTestRNG (); + + mp.reset (new libdcp::MonoPictureAsset ("build/test/baz", "video2.mxf", 24, libdcp::Size (32, 32))); + writer = mp->start_overwrite (); + + for (int i = 0; i < 4; ++i) { + writer->fake_write (written_length); + } + + for (int i = 0; i < 20; ++i) { + writer->write (data, length); + } + + writer->finalize (); +} -- cgit v1.2.3 From bb41c81485834a31c178cf2b2f4b5345aa00e5b4 Mon Sep 17 00:00:00 2001 From: Carl Hetherington Date: Sat, 2 Feb 2013 12:04:23 +0000 Subject: Basics of fake write seem to work. --- asdcplib/src/AS_DCP_JP2K.cpp | 4 --- src/picture_asset.cc | 70 ++++++++++++++++++-------------------------- src/picture_asset.h | 12 ++++---- test/tests.cc | 29 ++++++++---------- 4 files changed, 46 insertions(+), 69 deletions(-) diff --git a/asdcplib/src/AS_DCP_JP2K.cpp b/asdcplib/src/AS_DCP_JP2K.cpp index 05f5e005..e67bd8df 100755 --- a/asdcplib/src/AS_DCP_JP2K.cpp +++ b/asdcplib/src/AS_DCP_JP2K.cpp @@ -996,8 +996,6 @@ lh__Writer::WriteFrame(const JP2K::FrameBuffer& FrameBuf, bool add_index, result = m_State.Goto_RUNNING(); // first time through ui64_t StreamOffset = m_StreamOffset; - cout << "Real write @ " << StreamOffset << " (header is " << m_HeaderSize << ")\n"; - cout << "\tfile @ " << m_File.Tell() << "\n"; if ( ASDCP_SUCCESS(result) ) result = WriteEKLVPacket(FrameBuf, m_EssenceUL, Ctx, HMAC, hash); @@ -1022,8 +1020,6 @@ lh__Writer::FakeWriteFrame(int size, bool add_index) result = m_State.Goto_RUNNING(); ui64_t StreamOffset = m_StreamOffset; - cout << "Fake write @ " << StreamOffset << " (header is " << m_HeaderSize << ")\n"; - cout << "\tfile @ " << m_File.Tell() << "\n"; if ( ASDCP_SUCCESS(result) ) result = FakeWriteEKLVPacket(size); diff --git a/src/picture_asset.cc b/src/picture_asset.cc index 11815761..b6120171 100644 --- a/src/picture_asset.cc +++ b/src/picture_asset.cc @@ -44,6 +44,7 @@ using std::max; using std::pair; using std::make_pair; using std::istream; +using std::cout; using boost::shared_ptr; using boost::dynamic_pointer_cast; using boost::lexical_cast; @@ -396,28 +397,21 @@ StereoPictureAsset::get_frame (int n) const } shared_ptr -MonoPictureAsset::start_write () +MonoPictureAsset::start_write (uint8_t* data, int size, bool overwrite) { /* XXX: can't we use a shared_ptr here? */ - return shared_ptr (new MonoPictureAssetWriter (this, false)); -} - -shared_ptr -MonoPictureAsset::start_overwrite () -{ - /* XXX: can't we use a shared_ptr here? */ - return shared_ptr (new MonoPictureAssetWriter (this, true)); + return shared_ptr (new MonoPictureAssetWriter (this, data, size, overwrite)); } FrameInfo::FrameInfo (istream& s) { - s >> offset >> length >> hash; + s >> offset >> size >> hash; } void FrameInfo::write (ostream& s) { - s << offset << " " << length << " " << hash; + s << offset << " " << size << " " << hash; } struct MonoPictureAssetWriter::ASDCPState @@ -437,36 +431,41 @@ struct MonoPictureAssetWriter::ASDCPState /** @param a Asset to write to. `a' must not be deleted while * this writer class still exists, or bad things will happen. */ -MonoPictureAssetWriter::MonoPictureAssetWriter (MonoPictureAsset* a) +MonoPictureAssetWriter::MonoPictureAssetWriter (MonoPictureAsset* a, uint8_t* data, int size, bool overwrite) : _state (new MonoPictureAssetWriter::ASDCPState) , _asset (a) , _frames_written (0) , _finalized (false) { + if (ASDCP_FAILURE (_state->j2k_parser.OpenReadFrame (data, size, _state->frame_buffer))) { + throw MiscError ("could not parse J2K frame"); + } + _state->j2k_parser.FillPictureDescriptor (_state->picture_descriptor); + _state->picture_descriptor.EditRate = ASDCP::Rational (_asset->edit_rate(), 1); + + MXFAsset::fill_writer_info (&_state->writer_info, _asset->uuid()); + + if (ASDCP_FAILURE (_state->mxf_writer.OpenWrite ( + _asset->path().string().c_str(), + _state->writer_info, + _state->picture_descriptor, + 16384, + overwrite) + )) { + + throw MXFFileError ("could not open MXF file for writing", _asset->path().string()); + } } FrameInfo MonoPictureAssetWriter::write (uint8_t* data, int size) { assert (!_finalized); - - if (ASDCP_FAILURE (_state->j2k_parser.OpenReadFrame (data, size, _state->frame_buffer))) { - throw MiscError ("could not parse J2K frame"); - } - if (_frames_written == 0) { - /* This is our first frame; set up the writer */ - - _state->j2k_parser.FillPictureDescriptor (_state->picture_descriptor); - _state->picture_descriptor.EditRate = ASDCP::Rational (_asset->edit_rate(), 1); - - MXFAsset::fill_writer_info (&_state->writer_info, _asset->uuid()); - - if (ASDCP_FAILURE (_state->mxf_writer.OpenWrite (_asset->path().string().c_str(), _state->writer_info, _state->picture_descriptor, 16384, false))) { - throw MXFFileError ("could not open MXF file for writing", _asset->path().string()); - } - } + if (ASDCP_FAILURE (_state->j2k_parser.OpenReadFrame (data, size, _state->frame_buffer))) { + throw MiscError ("could not parse J2K frame"); + } uint64_t const before_offset = _state->mxf_writer.Tell (); @@ -484,19 +483,6 @@ MonoPictureAssetWriter::fake_write (int size) { assert (!_finalized); - if (_frames_written == 0) { - /* This is our first frame; set up the writer */ - - _state->j2k_parser.FillPictureDescriptor (_state->picture_descriptor); - _state->picture_descriptor.EditRate = ASDCP::Rational (_asset->edit_rate(), 1); - - MXFAsset::fill_writer_info (&_state->writer_info, _asset->uuid()); - - if (ASDCP_FAILURE (_state->mxf_writer.OpenWrite (_asset->path().string().c_str(), _state->writer_info, _state->picture_descriptor, 16384, true))) { - throw MXFFileError ("could not open MXF file for writing", _asset->path().string()); - } - } - if (ASDCP_FAILURE (_state->mxf_writer.FakeWriteFrame (size))) { throw MiscError ("error in writing video MXF"); } @@ -507,6 +493,8 @@ MonoPictureAssetWriter::fake_write (int size) void MonoPictureAssetWriter::finalize () { + assert (!_finalized); + if (ASDCP_FAILURE (_state->mxf_writer.Finalize())) { throw MiscError ("error in finalizing video MXF"); } diff --git a/src/picture_asset.h b/src/picture_asset.h index 9df85bad..2ec17235 100644 --- a/src/picture_asset.h +++ b/src/picture_asset.h @@ -84,9 +84,9 @@ class MonoPictureAsset; struct FrameInfo { - FrameInfo (uint64_t o, uint64_t l, std::string h) + FrameInfo (uint64_t o, uint64_t s, std::string h) : offset (o) - , length (l) + , size (s) , hash (h) {} @@ -95,7 +95,7 @@ struct FrameInfo void write (std::ostream& s); uint64_t offset; - uint64_t length; + uint64_t size; std::string hash; }; @@ -121,7 +121,7 @@ public: private: friend class MonoPictureAsset; - MonoPictureAssetWriter (MonoPictureAsset *, bool); + MonoPictureAssetWriter (MonoPictureAsset *, uint8_t *, int, bool); /* no copy construction */ MonoPictureAssetWriter (MonoPictureAssetWriter const &); @@ -204,9 +204,7 @@ public: MonoPictureAsset (std::string directory, std::string mxf_name, int fps, Size size); /** Start a progressive write to a MonoPictureAsset */ - boost::shared_ptr start_write (); - - boost::shared_ptr start_overwrite (); + boost::shared_ptr start_write (uint8_t *, int, bool); boost::shared_ptr get_frame (int n) const; bool equals (boost::shared_ptr other, EqualityOptions opt, std::list& notes) const; diff --git a/test/tests.cc b/test/tests.cc index c9243b88..fb0e0430 100644 --- a/test/tests.cc +++ b/test/tests.cc @@ -584,15 +584,13 @@ BOOST_AUTO_TEST_CASE (recovery) { Kumu::libdcp_test = true; - cout << "=== recovery.\n"; - string const picture = "test/data/32x32_red_square.j2c"; - int const length = boost::filesystem::file_size (picture); - uint8_t* data = new uint8_t[length]; + int const size = boost::filesystem::file_size (picture); + uint8_t* data = new uint8_t[size]; { FILE* f = fopen (picture.c_str(), "rb"); BOOST_CHECK (f); - fread (data, 1, length, f); + fread (data, 1, size, f); fclose (f); } @@ -601,25 +599,22 @@ BOOST_AUTO_TEST_CASE (recovery) boost::filesystem::remove_all ("build/test/baz"); boost::filesystem::create_directories ("build/test/baz"); shared_ptr mp (new libdcp::MonoPictureAsset ("build/test/baz", "video1.mxf", 24, libdcp::Size (32, 32))); - shared_ptr writer = mp->start_write (); + shared_ptr writer = mp->start_write (data, size, false); - int written_length = 0; + int written_size = 0; for (int i = 0; i < 24; ++i) { - libdcp::FrameInfo info = writer->write (data, length); - written_length = info.length; - cout << "- written length " << written_length << "\n"; + libdcp::FrameInfo info = writer->write (data, size); + written_size = info.size; } writer->finalize (); writer.reset (); - cout << "=== recovery part 2.\n"; - boost::filesystem::copy_file ("build/test/baz/video1.mxf", "build/test/baz/video2.mxf"); boost::filesystem::resize_file ("build/test/baz/video2.mxf", 16384 + 353 * 11); { - FILE* f = fopen ("build/test/baz/video2.mxf", "wa"); + FILE* f = fopen ("build/test/baz/video2.mxf", "r+"); rewind (f); char zeros[256]; memset (zeros, 0, 256); @@ -630,14 +625,14 @@ BOOST_AUTO_TEST_CASE (recovery) Kumu::ResetTestRNG (); mp.reset (new libdcp::MonoPictureAsset ("build/test/baz", "video2.mxf", 24, libdcp::Size (32, 32))); - writer = mp->start_overwrite (); + writer = mp->start_write (data, size, true); for (int i = 0; i < 4; ++i) { - writer->fake_write (written_length); + writer->fake_write (written_size); } - for (int i = 0; i < 20; ++i) { - writer->write (data, length); + for (int i = 4; i < 24; ++i) { + writer->write (data, size); } writer->finalize (); -- cgit v1.2.3 From fad33631d56d1cf92aff6463cd3ceea8eb494149 Mon Sep 17 00:00:00 2001 From: Carl Hetherington Date: Sat, 2 Feb 2013 12:47:49 +0000 Subject: Tweak API a little. --- src/picture_asset.cc | 24 ++++++++++++++++++++---- src/picture_asset.h | 7 +++++-- test/tests.cc | 8 +++++--- 3 files changed, 30 insertions(+), 9 deletions(-) diff --git a/src/picture_asset.cc b/src/picture_asset.cc index b6120171..d63cdee0 100644 --- a/src/picture_asset.cc +++ b/src/picture_asset.cc @@ -397,10 +397,10 @@ StereoPictureAsset::get_frame (int n) const } shared_ptr -MonoPictureAsset::start_write (uint8_t* data, int size, bool overwrite) +MonoPictureAsset::start_write (bool overwrite) { /* XXX: can't we use a shared_ptr here? */ - return shared_ptr (new MonoPictureAssetWriter (this, data, size, overwrite)); + return shared_ptr (new MonoPictureAssetWriter (this, overwrite)); } FrameInfo::FrameInfo (istream& s) @@ -431,11 +431,20 @@ struct MonoPictureAssetWriter::ASDCPState /** @param a Asset to write to. `a' must not be deleted while * this writer class still exists, or bad things will happen. */ -MonoPictureAssetWriter::MonoPictureAssetWriter (MonoPictureAsset* a, uint8_t* data, int size, bool overwrite) +MonoPictureAssetWriter::MonoPictureAssetWriter (MonoPictureAsset* a, bool overwrite) : _state (new MonoPictureAssetWriter::ASDCPState) , _asset (a) , _frames_written (0) + , _started (false) , _finalized (false) + , _overwrite (overwrite) +{ + +} + + +void +MonoPictureAssetWriter::start (uint8_t* data, int size) { if (ASDCP_FAILURE (_state->j2k_parser.OpenReadFrame (data, size, _state->frame_buffer))) { throw MiscError ("could not parse J2K frame"); @@ -451,11 +460,13 @@ MonoPictureAssetWriter::MonoPictureAssetWriter (MonoPictureAsset* a, uint8_t* da _state->writer_info, _state->picture_descriptor, 16384, - overwrite) + _overwrite) )) { throw MXFFileError ("could not open MXF file for writing", _asset->path().string()); } + + _started = true; } FrameInfo @@ -463,6 +474,10 @@ MonoPictureAssetWriter::write (uint8_t* data, int size) { assert (!_finalized); + if (!_started) { + start (data, size); + } + if (ASDCP_FAILURE (_state->j2k_parser.OpenReadFrame (data, size, _state->frame_buffer))) { throw MiscError ("could not parse J2K frame"); } @@ -481,6 +496,7 @@ MonoPictureAssetWriter::write (uint8_t* data, int size) void MonoPictureAssetWriter::fake_write (int size) { + assert (_started); assert (!_finalized); if (ASDCP_FAILURE (_state->mxf_writer.FakeWriteFrame (size))) { diff --git a/src/picture_asset.h b/src/picture_asset.h index 2ec17235..d3fabbbd 100644 --- a/src/picture_asset.h +++ b/src/picture_asset.h @@ -121,7 +121,8 @@ public: private: friend class MonoPictureAsset; - MonoPictureAssetWriter (MonoPictureAsset *, uint8_t *, int, bool); + MonoPictureAssetWriter (MonoPictureAsset *, bool); + void start (uint8_t *, int); /* no copy construction */ MonoPictureAssetWriter (MonoPictureAssetWriter const &); @@ -137,8 +138,10 @@ private: MonoPictureAsset* _asset; /** Number of picture frames written to the asset so far */ int _frames_written; + bool _started; /** true if finalize() has been called */ bool _finalized; + bool _overwrite; }; /** A 2D (monoscopic) picture asset */ @@ -204,7 +207,7 @@ public: MonoPictureAsset (std::string directory, std::string mxf_name, int fps, Size size); /** Start a progressive write to a MonoPictureAsset */ - boost::shared_ptr start_write (uint8_t *, int, bool); + boost::shared_ptr start_write (bool); boost::shared_ptr get_frame (int n) const; bool equals (boost::shared_ptr other, EqualityOptions opt, std::list& notes) const; diff --git a/test/tests.cc b/test/tests.cc index fb0e0430..eb5d0991 100644 --- a/test/tests.cc +++ b/test/tests.cc @@ -599,7 +599,7 @@ BOOST_AUTO_TEST_CASE (recovery) boost::filesystem::remove_all ("build/test/baz"); boost::filesystem::create_directories ("build/test/baz"); shared_ptr mp (new libdcp::MonoPictureAsset ("build/test/baz", "video1.mxf", 24, libdcp::Size (32, 32))); - shared_ptr writer = mp->start_write (data, size, false); + shared_ptr writer = mp->start_write (false); int written_size = 0; for (int i = 0; i < 24; ++i) { @@ -625,9 +625,11 @@ BOOST_AUTO_TEST_CASE (recovery) Kumu::ResetTestRNG (); mp.reset (new libdcp::MonoPictureAsset ("build/test/baz", "video2.mxf", 24, libdcp::Size (32, 32))); - writer = mp->start_write (data, size, true); + writer = mp->start_write (true); - for (int i = 0; i < 4; ++i) { + writer->write (data, size); + + for (int i = 1; i < 4; ++i) { writer->fake_write (written_size); } -- cgit v1.2.3 From c94582da47f390ce6d9e4064f7a7ddc3cd3be07b Mon Sep 17 00:00:00 2001 From: Carl Hetherington Date: Sat, 2 Feb 2013 15:17:16 +0000 Subject: Try to check for boost 1.45 for filesystem::resize_file(). --- wscript | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/wscript b/wscript index a0734d09..76e08ef5 100644 --- a/wscript +++ b/wscript @@ -46,6 +46,18 @@ def configure(conf): # Windows builds are any more reliable conf.env.append_value('CXXFLAGS', '-O2') + conf.check_cxx(fragment = """ + #include \n + #if BOOST_VERSION < 104500\n + #error boost too old\n + #endif\n + int main(void) { return 0; }\n + """, + mandatory = True, + msg = 'Checking for boost library >= 1.45', + okmsg = 'ok', + errmsg = 'too old\nPlease install boost version 1.45 or higher.') + conf.check_cxx(fragment = """ #include \n int main() { boost::filesystem::copy_file ("a", "b"); }\n -- cgit v1.2.3 From 53d348a8025f493db3b0434ce8dd88aa71269b63 Mon Sep 17 00:00:00 2001 From: Carl Hetherington Date: Sat, 2 Feb 2013 15:17:28 +0000 Subject: Tweak message. --- wscript | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/wscript b/wscript index 76e08ef5..c3cc6a1d 100644 --- a/wscript +++ b/wscript @@ -55,7 +55,7 @@ def configure(conf): """, mandatory = True, msg = 'Checking for boost library >= 1.45', - okmsg = 'ok', + okmsg = 'yes', errmsg = 'too old\nPlease install boost version 1.45 or higher.') conf.check_cxx(fragment = """ -- cgit v1.2.3 From b4209d6fe71f2d3e354dc60ec975fb6cf4407e93 Mon Sep 17 00:00:00 2001 From: Carl Hetherington Date: Tue, 5 Feb 2013 18:45:28 +0000 Subject: Bump version --- wscript | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/wscript b/wscript index c3cc6a1d..1e902cf3 100644 --- a/wscript +++ b/wscript @@ -3,7 +3,7 @@ import os import lut APPNAME = 'libdcp' -VERSION = '0.37pre' +VERSION = '0.37' def options(opt): opt.load('compiler_cxx') -- cgit v1.2.3 From b3ca04718ea6205afc1a3177018e10469fb552a2 Mon Sep 17 00:00:00 2001 From: Carl Hetherington Date: Tue, 5 Feb 2013 18:47:32 +0000 Subject: Bump version --- wscript | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/wscript b/wscript index 1e902cf3..b7cceb5b 100644 --- a/wscript +++ b/wscript @@ -3,7 +3,7 @@ import os import lut APPNAME = 'libdcp' -VERSION = '0.37' +VERSION = '0.38pre' def options(opt): opt.load('compiler_cxx') -- cgit v1.2.3 From 0365080bf27206473ff57c32cde9f44ea2099a4f Mon Sep 17 00:00:00 2001 From: Carl Hetherington Date: Tue, 5 Feb 2013 19:35:30 +0000 Subject: Fix build on Windows. --- test/tests.cc | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/test/tests.cc b/test/tests.cc index eb5d0991..62cab54c 100644 --- a/test/tests.cc +++ b/test/tests.cc @@ -594,7 +594,10 @@ BOOST_AUTO_TEST_CASE (recovery) fclose (f); } +#ifdef LIBDCP_POSIX + /* XXX: fix this posix-only stuff */ Kumu::ResetTestRNG (); +#endif boost::filesystem::remove_all ("build/test/baz"); boost::filesystem::create_directories ("build/test/baz"); @@ -622,7 +625,9 @@ BOOST_AUTO_TEST_CASE (recovery) fclose (f); } +#ifdef LIBDCP_POSIX Kumu::ResetTestRNG (); +#endif mp.reset (new libdcp::MonoPictureAsset ("build/test/baz", "video2.mxf", 24, libdcp::Size (32, 32))); writer = mp->start_write (true); -- cgit v1.2.3 From 2b279e0e9e5f7f3a5712defaeb6d6866fd77c490 Mon Sep 17 00:00:00 2001 From: Carl Hetherington Date: Tue, 5 Feb 2013 19:36:33 +0000 Subject: Bump version --- wscript | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/wscript b/wscript index b7cceb5b..f6069550 100644 --- a/wscript +++ b/wscript @@ -3,7 +3,7 @@ import os import lut APPNAME = 'libdcp' -VERSION = '0.38pre' +VERSION = '0.38' def options(opt): opt.load('compiler_cxx') -- cgit v1.2.3 From 5187d24af1657bedc99d7c06be2c4c7824f3993b Mon Sep 17 00:00:00 2001 From: Carl Hetherington Date: Tue, 5 Feb 2013 19:38:26 +0000 Subject: Bump version --- wscript | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/wscript b/wscript index f6069550..4210c35b 100644 --- a/wscript +++ b/wscript @@ -3,7 +3,7 @@ import os import lut APPNAME = 'libdcp' -VERSION = '0.38' +VERSION = '0.39pre' def options(opt): opt.load('compiler_cxx') -- cgit v1.2.3 From 47d48da4bae33a3fb5f9942bc2d5afeb09e714eb Mon Sep 17 00:00:00 2001 From: Carl Hetherington Date: Tue, 5 Feb 2013 19:53:30 +0000 Subject: Try to implement FileWriter::OpenModify on Windows. --- asdcplib/src/KM_fileio.cpp | 28 ++++++++++++++++++++++++++++ 1 file changed, 28 insertions(+) diff --git a/asdcplib/src/KM_fileio.cpp b/asdcplib/src/KM_fileio.cpp index 138bc3b4..d48e7554 100644 --- a/asdcplib/src/KM_fileio.cpp +++ b/asdcplib/src/KM_fileio.cpp @@ -831,6 +831,34 @@ Kumu::FileWriter::OpenWrite(const char* filename) return Kumu::RESULT_OK; } +// +Kumu::Result_t +Kumu::FileWriter::OpenModify(const char* filename) +{ + KM_TEST_NULL_STR_L(filename); + m_Filename = filename; + + // suppress popup window on error + UINT prev = ::SetErrorMode(SEM_FAILCRITICALERRORS|SEM_NOOPENFILEERRORBOX); + + m_Handle = ::CreateFileA(filename, + (GENERIC_WRITE|GENERIC_READ), // open for reading + FILE_SHARE_READ, // share for reading + NULL, // no security + OPEN_ALWAYS, // don't truncate existing + FILE_ATTRIBUTE_NORMAL, // normal file + NULL // no template file + ); + + ::SetErrorMode(prev); + + if ( m_Handle == INVALID_HANDLE_VALUE ) + return Kumu::RESULT_FILEOPEN; + + m_IOVec = new h__iovec; + return Kumu::RESULT_OK; +} + // Kumu::Result_t Kumu::FileWriter::Writev(ui32_t* bytes_written) -- cgit v1.2.3 From 761bf8c5dfc8a7c01eca9f33ff39e7753d0c8c8a Mon Sep 17 00:00:00 2001 From: Carl Hetherington Date: Tue, 5 Feb 2013 19:53:43 +0000 Subject: Bump version --- wscript | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/wscript b/wscript index 4210c35b..f99c357d 100644 --- a/wscript +++ b/wscript @@ -3,7 +3,7 @@ import os import lut APPNAME = 'libdcp' -VERSION = '0.39pre' +VERSION = '0.39' def options(opt): opt.load('compiler_cxx') -- cgit v1.2.3 From 3d75f8a9bd53f555a0ba3bd912dff157ec0d3cb1 Mon Sep 17 00:00:00 2001 From: Carl Hetherington Date: Tue, 5 Feb 2013 19:56:13 +0000 Subject: Bump version --- wscript | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/wscript b/wscript index f99c357d..2995c442 100644 --- a/wscript +++ b/wscript @@ -3,7 +3,7 @@ import os import lut APPNAME = 'libdcp' -VERSION = '0.39' +VERSION = '0.40pre' def options(opt): opt.load('compiler_cxx') -- cgit v1.2.3 From 6e5411a943ef9b3f23cfb8dd9dcc1a756b55bfbe Mon Sep 17 00:00:00 2001 From: Carl Hetherington Date: Wed, 6 Feb 2013 23:51:06 +0000 Subject: Fix static build. --- wscript | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/wscript b/wscript index 2995c442..27483bac 100644 --- a/wscript +++ b/wscript @@ -30,7 +30,16 @@ def configure(conf): conf.check_cfg(package = 'openssl', args = '--cflags --libs', uselib_store = 'OPENSSL', mandatory = True) conf.check_cfg(package = 'libxml++-2.6', args = '--cflags --libs', uselib_store = 'LIBXML++', mandatory = True) if conf.options.static_openjpeg: - conf.check_cc(fragment = openjpeg_fragment, msg = 'Checking for library openjpeg', stlib = 'openjpeg', uselib_store = 'OPENJPEG') + + conf.check_cc(fragment = """ + #include \n + #include \n + int main () {\n + void* p = (void *) opj_image_create;\n + return 0;\n + } + """, + msg = 'Checking for library openjpeg', stlib = 'openjpeg', uselib_store = 'OPENJPEG', mandatory = True) else: conf.check_cfg(package = 'libopenjpeg', args = '--cflags --libs', uselib_store = 'OPENJPEG', mandatory = True) -- cgit v1.2.3 From 53fb1df6ca3848f9835b745b8ce13b0ad2196137 Mon Sep 17 00:00:00 2001 From: Carl Hetherington Date: Sun, 10 Feb 2013 20:04:20 +0000 Subject: Throw some more specific exceptions on MXF file errors. --- src/picture_asset.cc | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/picture_asset.cc b/src/picture_asset.cc index d63cdee0..e0e55979 100644 --- a/src/picture_asset.cc +++ b/src/picture_asset.cc @@ -221,7 +221,7 @@ MonoPictureAsset::construct (boost::function get_path) } if (ASDCP_FAILURE (mxf_writer.WriteFrame (frame_buffer, 0, 0))) { - throw MiscError ("error in writing video MXF"); + throw MXFFileError ("error in writing video MXF", this->path().string()); } if (_progress) { @@ -230,7 +230,7 @@ MonoPictureAsset::construct (boost::function get_path) } if (ASDCP_FAILURE (mxf_writer.Finalize())) { - throw MiscError ("error in finalising video MXF"); + throw MXFFileError ("error in finalising video MXF", path().string()); } } @@ -486,7 +486,7 @@ MonoPictureAssetWriter::write (uint8_t* data, int size) string hash; if (ASDCP_FAILURE (_state->mxf_writer.WriteFrame (_state->frame_buffer, 0, 0, &hash))) { - throw MiscError ("error in writing video MXF"); + throw MXFFileError ("error in writing video MXF", _asset->path().string()); } ++_frames_written; @@ -500,7 +500,7 @@ MonoPictureAssetWriter::fake_write (int size) assert (!_finalized); if (ASDCP_FAILURE (_state->mxf_writer.FakeWriteFrame (size))) { - throw MiscError ("error in writing video MXF"); + throw MXFFileError ("error in writing video MXF", _asset->path().string()); } ++_frames_written; @@ -512,7 +512,7 @@ MonoPictureAssetWriter::finalize () assert (!_finalized); if (ASDCP_FAILURE (_state->mxf_writer.Finalize())) { - throw MiscError ("error in finalizing video MXF"); + throw MXFFileError ("error in finalizing video MXF", _asset->path().string()); } _finalized = true; -- cgit v1.2.3 From 4a557a8b6631f132e851b1bb362cde4270ca6057 Mon Sep 17 00:00:00 2001 From: Carl Hetherington Date: Sun, 10 Feb 2013 21:32:30 +0000 Subject: Derive exceptions from boost::exception and use boost::throw_exception to enable thread-safe exception handling by callers. --- src/dcp.cc | 16 ++++++++-------- src/dcp_time.cc | 2 +- src/picture_asset.cc | 38 +++++++++++++++++++------------------- src/picture_frame.cc | 8 ++++---- src/sound_asset.cc | 34 +++++++++++++++++----------------- src/sound_frame.cc | 4 ++-- src/subtitle_asset.cc | 2 +- src/types.cc | 12 ++++++------ src/util.cc | 6 +++--- src/xml.cc | 20 ++++++++++---------- 10 files changed, 71 insertions(+), 71 deletions(-) diff --git a/src/dcp.cc b/src/dcp.cc index 4f1732da..d446b205 100644 --- a/src/dcp.cc +++ b/src/dcp.cc @@ -182,17 +182,17 @@ DCP::read (bool require_mxfs) if (boost::filesystem::exists (p)) { asset_map.reset (new AssetMap (p.string ())); } else { - throw DCPReadError ("could not find AssetMap file"); + boost::throw_exception (DCPReadError ("could not find AssetMap file")); } } } catch (FileError& e) { - throw FileError ("could not load AssetMap file", files.asset_map); + boost::throw_exception (FileError ("could not load AssetMap file", files.asset_map)); } for (list >::const_iterator i = asset_map->assets.begin(); i != asset_map->assets.end(); ++i) { if ((*i)->chunks.size() != 1) { - throw XMLError ("unsupported asset chunk count"); + boost::throw_exception (XMLError ("unsupported asset chunk count")); } boost::filesystem::path t = _directory; @@ -219,24 +219,24 @@ DCP::read (bool require_mxfs) if (files.pkl.empty ()) { files.pkl = t.string(); } else { - throw DCPReadError ("duplicate PKLs found"); + boost::throw_exception (DCPReadError ("duplicate PKLs found")); } } } if (files.cpls.empty ()) { - throw FileError ("no CPL files found", ""); + boost::throw_exception (FileError ("no CPL files found", "")); } if (files.pkl.empty ()) { - throw FileError ("no PKL file found", ""); + boost::throw_exception (FileError ("no PKL file found", "")); } shared_ptr pkl; try { pkl.reset (new PKLFile (files.pkl)); } catch (FileError& e) { - throw FileError ("could not load PKL file", files.pkl); + boost::throw_exception (FileError ("could not load PKL file", files.pkl)); } /* Cross-check */ @@ -325,7 +325,7 @@ CPL::CPL (string directory, string file, shared_ptr asset_map, b try { cpl.reset (new CPLFile (file)); } catch (FileError& e) { - throw FileError ("could not load CPL file", file); + boost::throw_exception (FileError ("could not load CPL file", file)); } /* Now cherry-pick the required bits into our own data structure */ diff --git a/src/dcp_time.cc b/src/dcp_time.cc index 15ad05d4..bdf55f93 100644 --- a/src/dcp_time.cc +++ b/src/dcp_time.cc @@ -59,7 +59,7 @@ Time::Time (string time) vector b; split (b, time, is_any_of (":")); if (b.size() != 4) { - throw DCPReadError ("unrecognised time specification"); + boost::throw_exception (DCPReadError ("unrecognised time specification")); } h = lexical_cast (b[0]); diff --git a/src/picture_asset.cc b/src/picture_asset.cc index e0e55979..13253242 100644 --- a/src/picture_asset.cc +++ b/src/picture_asset.cc @@ -87,21 +87,21 @@ PictureAsset::equals (shared_ptr other, EqualityOptions opt, listpath().string().c_str()))) { - throw MXFFileError ("could not open MXF file for reading", path().string()); + boost::throw_exception (MXFFileError ("could not open MXF file for reading", path().string())); } ASDCP::JP2K::PictureDescriptor desc_A; if (ASDCP_FAILURE (reader_A.FillPictureDescriptor (desc_A))) { - throw DCPReadError ("could not read video MXF information"); + boost::throw_exception (DCPReadError ("could not read video MXF information")); } ASDCP::JP2K::PictureDescriptor desc_B; if (ASDCP_FAILURE (reader_B.FillPictureDescriptor (desc_B))) { - throw DCPReadError ("could not read video MXF information"); + boost::throw_exception (DCPReadError ("could not read video MXF information")); } if ( @@ -176,12 +176,12 @@ MonoPictureAsset::MonoPictureAsset (string directory, string mxf_name) { ASDCP::JP2K::MXFReader reader; if (ASDCP_FAILURE (reader.OpenRead (path().string().c_str()))) { - throw MXFFileError ("could not open MXF file for reading", path().string()); + boost::throw_exception (MXFFileError ("could not open MXF file for reading", path().string())); } ASDCP::JP2K::PictureDescriptor desc; if (ASDCP_FAILURE (reader.FillPictureDescriptor (desc))) { - throw DCPReadError ("could not read video MXF information"); + boost::throw_exception (DCPReadError ("could not read video MXF information")); } _size.width = desc.StoredWidth; @@ -197,7 +197,7 @@ MonoPictureAsset::construct (boost::function get_path) ASDCP::JP2K::CodestreamParser j2k_parser; ASDCP::JP2K::FrameBuffer frame_buffer (4 * Kumu::Megabyte); if (ASDCP_FAILURE (j2k_parser.OpenReadFrame (get_path(0).c_str(), frame_buffer))) { - throw FileError ("could not open JPEG2000 file for reading", get_path (0)); + boost::throw_exception (FileError ("could not open JPEG2000 file for reading", get_path (0))); } ASDCP::JP2K::PictureDescriptor picture_desc; @@ -209,7 +209,7 @@ MonoPictureAsset::construct (boost::function get_path) ASDCP::JP2K::MXFWriter mxf_writer; if (ASDCP_FAILURE (mxf_writer.OpenWrite (path().string().c_str(), writer_info, picture_desc, 16384, false))) { - throw MXFFileError ("could not open MXF file for writing", path().string()); + boost::throw_exception (MXFFileError ("could not open MXF file for writing", path().string())); } for (int i = 0; i < _intrinsic_duration; ++i) { @@ -217,11 +217,11 @@ MonoPictureAsset::construct (boost::function get_path) string const path = get_path (i); if (ASDCP_FAILURE (j2k_parser.OpenReadFrame (path.c_str(), frame_buffer))) { - throw FileError ("could not open JPEG2000 file for reading", path); + boost::throw_exception (FileError ("could not open JPEG2000 file for reading", path)); } if (ASDCP_FAILURE (mxf_writer.WriteFrame (frame_buffer, 0, 0))) { - throw MXFFileError ("error in writing video MXF", this->path().string()); + boost::throw_exception (MXFFileError ("error in writing video MXF", this->path().string())); } if (_progress) { @@ -230,7 +230,7 @@ MonoPictureAsset::construct (boost::function get_path) } if (ASDCP_FAILURE (mxf_writer.Finalize())) { - throw MXFFileError ("error in finalising video MXF", path().string()); + boost::throw_exception (MXFFileError ("error in finalising video MXF", path().string())); } } @@ -378,12 +378,12 @@ StereoPictureAsset::StereoPictureAsset (string directory, string mxf_name, int f { ASDCP::JP2K::MXFSReader reader; if (ASDCP_FAILURE (reader.OpenRead (path().string().c_str()))) { - throw MXFFileError ("could not open MXF file for reading", path().string()); + boost::throw_exception (MXFFileError ("could not open MXF file for reading", path().string())); } ASDCP::JP2K::PictureDescriptor desc; if (ASDCP_FAILURE (reader.FillPictureDescriptor (desc))) { - throw DCPReadError ("could not read video MXF information"); + boost::throw_exception (DCPReadError ("could not read video MXF information")); } _size.width = desc.StoredWidth; @@ -447,7 +447,7 @@ void MonoPictureAssetWriter::start (uint8_t* data, int size) { if (ASDCP_FAILURE (_state->j2k_parser.OpenReadFrame (data, size, _state->frame_buffer))) { - throw MiscError ("could not parse J2K frame"); + boost::throw_exception (MiscError ("could not parse J2K frame")); } _state->j2k_parser.FillPictureDescriptor (_state->picture_descriptor); @@ -463,7 +463,7 @@ MonoPictureAssetWriter::start (uint8_t* data, int size) _overwrite) )) { - throw MXFFileError ("could not open MXF file for writing", _asset->path().string()); + boost::throw_exception (MXFFileError ("could not open MXF file for writing", _asset->path().string())); } _started = true; @@ -479,14 +479,14 @@ MonoPictureAssetWriter::write (uint8_t* data, int size) } if (ASDCP_FAILURE (_state->j2k_parser.OpenReadFrame (data, size, _state->frame_buffer))) { - throw MiscError ("could not parse J2K frame"); + boost::throw_exception (MiscError ("could not parse J2K frame")); } uint64_t const before_offset = _state->mxf_writer.Tell (); string hash; if (ASDCP_FAILURE (_state->mxf_writer.WriteFrame (_state->frame_buffer, 0, 0, &hash))) { - throw MXFFileError ("error in writing video MXF", _asset->path().string()); + boost::throw_exception (MXFFileError ("error in writing video MXF", _asset->path().string())); } ++_frames_written; @@ -500,7 +500,7 @@ MonoPictureAssetWriter::fake_write (int size) assert (!_finalized); if (ASDCP_FAILURE (_state->mxf_writer.FakeWriteFrame (size))) { - throw MXFFileError ("error in writing video MXF", _asset->path().string()); + boost::throw_exception (MXFFileError ("error in writing video MXF", _asset->path().string())); } ++_frames_written; @@ -512,7 +512,7 @@ MonoPictureAssetWriter::finalize () assert (!_finalized); if (ASDCP_FAILURE (_state->mxf_writer.Finalize())) { - throw MXFFileError ("error in finalizing video MXF", _asset->path().string()); + boost::throw_exception (MXFFileError ("error in finalizing video MXF", _asset->path().string())); } _finalized = true; diff --git a/src/picture_frame.cc b/src/picture_frame.cc index 907f70ab..5898d0ea 100644 --- a/src/picture_frame.cc +++ b/src/picture_frame.cc @@ -38,14 +38,14 @@ MonoPictureFrame::MonoPictureFrame (string mxf_path, int n) { ASDCP::JP2K::MXFReader reader; if (ASDCP_FAILURE (reader.OpenRead (mxf_path.c_str()))) { - throw FileError ("could not open MXF file for reading", mxf_path); + boost::throw_exception (FileError ("could not open MXF file for reading", mxf_path)); } /* XXX: unfortunate guesswork on this buffer size */ _buffer = new ASDCP::JP2K::FrameBuffer (4 * Kumu::Megabyte); if (ASDCP_FAILURE (reader.ReadFrame (n, *_buffer))) { - throw DCPReadError ("could not read video frame"); + boost::throw_exception (DCPReadError ("could not read video frame")); } } @@ -93,14 +93,14 @@ StereoPictureFrame::StereoPictureFrame (string mxf_path, int n) { ASDCP::JP2K::MXFSReader reader; if (ASDCP_FAILURE (reader.OpenRead (mxf_path.c_str()))) { - throw FileError ("could not open MXF file for reading", mxf_path); + boost::throw_exception (FileError ("could not open MXF file for reading", mxf_path)); } /* XXX: unfortunate guesswork on this buffer size */ _buffer = new ASDCP::JP2K::SFrameBuffer (4 * Kumu::Megabyte); if (ASDCP_FAILURE (reader.ReadFrame (n, *_buffer))) { - throw DCPReadError ("could not read video frame"); + boost::throw_exception (DCPReadError ("could not read video frame")); } } diff --git a/src/sound_asset.cc b/src/sound_asset.cc index 4d76a2fd..014b95a2 100644 --- a/src/sound_asset.cc +++ b/src/sound_asset.cc @@ -79,12 +79,12 @@ SoundAsset::SoundAsset (string directory, string mxf_name) { ASDCP::PCM::MXFReader reader; if (ASDCP_FAILURE (reader.OpenRead (path().string().c_str()))) { - throw MXFFileError ("could not open MXF file for reading", path().string()); + boost::throw_exception (MXFFileError ("could not open MXF file for reading", path().string())); } ASDCP::PCM::AudioDescriptor desc; if (ASDCP_FAILURE (reader.FillAudioDescriptor (desc))) { - throw DCPReadError ("could not read audio MXF information"); + boost::throw_exception (DCPReadError ("could not read audio MXF information")); } _sampling_rate = desc.AudioSamplingRate.Numerator / desc.AudioSamplingRate.Denominator; @@ -117,7 +117,7 @@ SoundAsset::construct (boost::function get_path) ASDCP::PCM::WAVParser pcm_parser_channel[_channels]; if (pcm_parser_channel[0].OpenRead (get_path(LEFT).c_str(), asdcp_edit_rate)) { - throw FileError ("could not open WAV file for reading", get_path(LEFT)); + boost::throw_exception (FileError ("could not open WAV file for reading", get_path(LEFT))); } ASDCP::PCM::AudioDescriptor audio_desc; @@ -149,7 +149,7 @@ SoundAsset::construct (boost::function get_path) string const path = get_path (channels[i]); if (ASDCP_FAILURE (pcm_parser_channel[i].OpenRead (path.c_str(), asdcp_edit_rate))) { - throw FileError ("could not open WAV file for reading", path); + boost::throw_exception (FileError ("could not open WAV file for reading", path)); } pcm_parser_channel[i].FillAudioDescriptor (audio_desc_channel[i]); @@ -168,7 +168,7 @@ SoundAsset::construct (boost::function get_path) ASDCP::PCM::MXFWriter mxf_writer; if (ASDCP_FAILURE (mxf_writer.OpenWrite (path().string().c_str(), writer_info, audio_desc))) { - throw FileError ("could not open audio MXF for writing", path().string()); + boost::throw_exception (FileError ("could not open audio MXF for writing", path().string())); } for (int i = 0; i < _intrinsic_duration; ++i) { @@ -176,7 +176,7 @@ SoundAsset::construct (boost::function get_path) for (int j = 0; j < _channels; ++j) { memset (frame_buffer_channel[j].Data(), 0, frame_buffer_channel[j].Capacity()); if (ASDCP_FAILURE (pcm_parser_channel[j].ReadFrame (frame_buffer_channel[j]))) { - throw MiscError ("could not read audio frame"); + boost::throw_exception (MiscError ("could not read audio frame")); } } @@ -195,7 +195,7 @@ SoundAsset::construct (boost::function get_path) } if (ASDCP_FAILURE (mxf_writer.WriteFrame (frame_buffer, 0, 0))) { - throw MiscError ("could not write audio MXF frame"); + boost::throw_exception (MiscError ("could not write audio MXF frame")); } if (_progress) { @@ -204,7 +204,7 @@ SoundAsset::construct (boost::function get_path) } if (ASDCP_FAILURE (mxf_writer.Finalize())) { - throw MiscError ("could not finalise audio MXF"); + boost::throw_exception (MiscError ("could not finalise audio MXF")); } } @@ -230,21 +230,21 @@ SoundAsset::equals (shared_ptr other, EqualityOptions opt, listpath().string().c_str()))) { - throw MXFFileError ("could not open MXF file for reading", path().string()); + boost::throw_exception (MXFFileError ("could not open MXF file for reading", path().string())); } ASDCP::PCM::AudioDescriptor desc_A; if (ASDCP_FAILURE (reader_A.FillAudioDescriptor (desc_A))) { - throw DCPReadError ("could not read audio MXF information"); + boost::throw_exception (DCPReadError ("could not read audio MXF information")); } ASDCP::PCM::AudioDescriptor desc_B; if (ASDCP_FAILURE (reader_B.FillAudioDescriptor (desc_B))) { - throw DCPReadError ("could not read audio MXF information"); + boost::throw_exception (DCPReadError ("could not read audio MXF information")); } if ( @@ -269,11 +269,11 @@ SoundAsset::equals (shared_ptr other, EqualityOptions opt, listwriter_info, _asset->uuid ()); if (ASDCP_FAILURE (_state->mxf_writer.OpenWrite (_asset->path().string().c_str(), _state->writer_info, _state->audio_desc))) { - throw FileError ("could not open audio MXF for writing", _asset->path().string()); + boost::throw_exception (FileError ("could not open audio MXF for writing", _asset->path().string())); } } @@ -376,7 +376,7 @@ void SoundAssetWriter::write_current_frame () { if (ASDCP_FAILURE (_state->mxf_writer.WriteFrame (_state->frame_buffer, 0, 0))) { - throw MiscError ("could not write audio MXF frame"); + boost::throw_exception (MiscError ("could not write audio MXF frame")); } ++_frames_written; @@ -390,7 +390,7 @@ SoundAssetWriter::finalize () } if (ASDCP_FAILURE (_state->mxf_writer.Finalize())) { - throw MiscError ("could not finalise audio MXF"); + boost::throw_exception (MiscError ("could not finalise audio MXF")); } _finalized = true; diff --git a/src/sound_frame.cc b/src/sound_frame.cc index ed626f5e..c2a10564 100644 --- a/src/sound_frame.cc +++ b/src/sound_frame.cc @@ -29,14 +29,14 @@ SoundFrame::SoundFrame (string mxf_path, int n) { ASDCP::PCM::MXFReader reader; if (ASDCP_FAILURE (reader.OpenRead (mxf_path.c_str()))) { - throw FileError ("could not open MXF file for reading", mxf_path); + boost::throw_exception (FileError ("could not open MXF file for reading", mxf_path)); } /* XXX: unfortunate guesswork on this buffer size */ _buffer = new ASDCP::PCM::FrameBuffer (1 * Kumu::Megabyte); if (ASDCP_FAILURE (reader.ReadFrame (n, *_buffer))) { - throw DCPReadError ("could not read audio frame"); + boost::throw_exception (DCPReadError ("could not read audio frame")); } } diff --git a/src/subtitle_asset.cc b/src/subtitle_asset.cc index c7051eae..ba91cf90 100644 --- a/src/subtitle_asset.cc +++ b/src/subtitle_asset.cc @@ -413,7 +413,7 @@ SubtitleAsset::write_xml (ostream& s) const << " " << _language << "\n"; if (_load_font_nodes.size() > 1) { - throw MiscError ("multiple LoadFont nodes not supported"); + boost::throw_exception (MiscError ("multiple LoadFont nodes not supported")); } if (!_load_font_nodes.empty ()) { diff --git a/src/types.cc b/src/types.cc index ac01ae45..693b9ab2 100644 --- a/src/types.cc +++ b/src/types.cc @@ -15,7 +15,7 @@ Fraction::Fraction (string s) vector b; split (b, s, is_any_of (" ")); if (b.size() != 2) { - throw XMLError ("malformed fraction " + s + " in XML node"); + boost::throw_exception (XMLError ("malformed fraction " + s + " in XML node")); } numerator = lexical_cast (b[0]); denominator = lexical_cast (b[1]); @@ -57,7 +57,7 @@ Color::Color (string argb_hex) { int alpha; if (sscanf (argb_hex.c_str(), "%2x%2x%2x%2x", &alpha, &r, &g, &b) < 4) { - throw XMLError ("could not parse colour string"); + boost::throw_exception (XMLError ("could not parse colour string")); } } @@ -118,7 +118,7 @@ libdcp::effect_to_string (Effect e) return "shadow"; } - throw MiscError ("unknown effect type"); + boost::throw_exception (MiscError ("unknown effect type")); } Effect @@ -132,7 +132,7 @@ libdcp::string_to_effect (string s) return SHADOW; } - throw DCPReadError ("unknown subtitle effect type"); + boost::throw_exception (DCPReadError ("unknown subtitle effect type")); } string @@ -147,7 +147,7 @@ libdcp::valign_to_string (VAlign v) return "bottom"; } - throw MiscError ("unknown valign type"); + boost::throw_exception (MiscError ("unknown valign type")); } VAlign @@ -161,7 +161,7 @@ libdcp::string_to_valign (string s) return BOTTOM; } - throw DCPReadError ("unknown subtitle valign type"); + boost::throw_exception (DCPReadError ("unknown subtitle valign type")); } diff --git a/src/util.cc b/src/util.cc index 1cbec719..b1556e33 100644 --- a/src/util.cc +++ b/src/util.cc @@ -66,7 +66,7 @@ libdcp::make_digest (string filename) { Kumu::FileReader reader; if (ASDCP_FAILURE (reader.OpenRead (filename.c_str ()))) { - throw FileError ("could not open file to compute digest", filename); + boost::throw_exception (FileError ("could not open file to compute digest", filename)); } SHA_CTX sha; @@ -81,7 +81,7 @@ libdcp::make_digest (string filename) if (r == Kumu::RESULT_ENDOFFILE) { break; } else if (ASDCP_FAILURE (r)) { - throw FileError ("could not read file to compute digest", filename); + boost::throw_exception (FileError ("could not read file to compute digest", filename)); } SHA1_Update (&sha, read_buffer.Data(), read); @@ -187,7 +187,7 @@ libdcp::decompress_j2k (uint8_t* data, int64_t size, int reduce) if (!image) { opj_destroy_decompress (decoder); opj_cio_close (cio); - throw DCPReadError ("could not decode JPEG2000 codestream"); + boost::throw_exception (DCPReadError ("could not decode JPEG2000 codestream")); } opj_cio_close (cio); diff --git a/src/xml.cc b/src/xml.cc index 22e91ac0..508790ab 100644 --- a/src/xml.cc +++ b/src/xml.cc @@ -29,9 +29,9 @@ XMLNode::node_child (string name) { list n = node_children (name); if (n.size() > 1) { - throw XMLError ("duplicate XML tag " + name); + boost::throw_exception (XMLError ("duplicate XML tag " + name)); } else if (n.empty ()) { - throw XMLError ("missing XML tag " + name + " in " + _node->get_name()); + boost::throw_exception (XMLError ("missing XML tag " + name + " in " + _node->get_name())); } return n.front (); @@ -68,7 +68,7 @@ XMLNode::optional_string_child (string name) { list nodes = node_children (name); if (nodes.size() > 2) { - throw XMLError ("duplicate XML tag " + name); + boost::throw_exception (XMLError ("duplicate XML tag " + name)); } if (nodes.empty ()) { @@ -103,7 +103,7 @@ XMLNode::optional_int64_child (string name) { list nodes = node_children (name); if (nodes.size() > 2) { - throw XMLError ("duplicate XML tag " + name); + boost::throw_exception (XMLError ("duplicate XML tag " + name)); } if (nodes.empty ()) { @@ -136,12 +136,12 @@ XMLNode::string_attribute (string name) { xmlpp::Element const * e = dynamic_cast (_node); if (!e) { - throw XMLError ("missing attribute"); + boost::throw_exception (XMLError ("missing attribute")); } xmlpp::Attribute* a = e->get_attribute (name); if (!a) { - throw XMLError ("missing attribute"); + boost::throw_exception (XMLError ("missing attribute")); } return a->get_value (); @@ -218,7 +218,7 @@ XMLNode::done () xmlpp::Node::NodeList c = _node->get_children (); for (xmlpp::Node::NodeList::iterator i = c.begin(); i != c.end(); ++i) { if (dynamic_cast (*i) && find (_taken.begin(), _taken.end(), (*i)->get_name()) == _taken.end ()) { - throw XMLError ("unexpected XML node " + (*i)->get_name()); + boost::throw_exception (XMLError ("unexpected XML node " + (*i)->get_name())); } } } @@ -242,18 +242,18 @@ XMLNode::content () XMLFile::XMLFile (string file, string root_name) { if (!filesystem::exists (file)) { - throw FileError ("XML file does not exist", file); + boost::throw_exception (FileError ("XML file does not exist", file)); } _parser = new xmlpp::DomParser; _parser->parse_file (file); if (!_parser) { - throw XMLError ("could not parse XML"); + boost::throw_exception (XMLError ("could not parse XML")); } _node = _parser->get_document()->get_root_node (); if (_node->get_name() != root_name) { - throw XMLError ("unrecognised root node"); + boost::throw_exception (XMLError ("unrecognised root node")); } } -- cgit v1.2.3 From 38e26b05c0ea7498b9e728d0e3ea85e7479f3096 Mon Sep 17 00:00:00 2001 From: Carl Hetherington Date: Mon, 11 Feb 2013 08:12:46 +0000 Subject: Bump version --- wscript | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/wscript b/wscript index 27483bac..42538c32 100644 --- a/wscript +++ b/wscript @@ -3,7 +3,7 @@ import os import lut APPNAME = 'libdcp' -VERSION = '0.40pre' +VERSION = '0.40' def options(opt): opt.load('compiler_cxx') -- cgit v1.2.3 From f4848302d0d62284e318bcd4ebff991f4cb2c225 Mon Sep 17 00:00:00 2001 From: Carl Hetherington Date: Mon, 11 Feb 2013 08:14:11 +0000 Subject: Bump version --- wscript | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/wscript b/wscript index 42538c32..ddc333fa 100644 --- a/wscript +++ b/wscript @@ -3,7 +3,7 @@ import os import lut APPNAME = 'libdcp' -VERSION = '0.40' +VERSION = '0.41pre' def options(opt): opt.load('compiler_cxx') -- cgit v1.2.3 From 7d431bf964b377f1402174f8c2d1ac8731f0ed9f Mon Sep 17 00:00:00 2001 From: Carl Hetherington Date: Sat, 16 Feb 2013 16:10:27 +0000 Subject: Ignore global tags files on dist. --- wscript | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/wscript b/wscript index ddc333fa..07519f75 100644 --- a/wscript +++ b/wscript @@ -111,7 +111,7 @@ def build(bld): bld.add_post_fun(post) def dist(ctx): - ctx.excl = 'TODO core *~ .git build .waf* .lock* doc/*~ src/*~ test/ref/*~ __pycache__' + ctx.excl = 'TODO core *~ .git build .waf* .lock* doc/*~ src/*~ test/ref/*~ __pycache__ GPATH GRTAGS GSYMS GTAGS' def create_version_cc(bld, version): if os.path.exists('.git'): -- cgit v1.2.3 From 45625f3116a09d3c8415a54bf8d19fdbb3a3aa9b Mon Sep 17 00:00:00 2001 From: Carl Hetherington Date: Wed, 13 Mar 2013 16:46:50 +0000 Subject: Compute LUTs at run-time. --- .gitignore | 2 - lut.py | 127 --------------------------------------------------- src/gamma_lut.cc | 16 +++++++ src/gamma_lut.h | 13 ++++++ src/lut.h | 63 +++++++++++++++++++++++++ src/lut_cache.h | 28 ++++++++++++ src/picture_frame.cc | 12 +++-- src/picture_frame.h | 4 +- src/util.cc | 40 ++++++++++------ src/util.h | 4 +- src/wscript | 3 +- src/xyz_srgb_lut.cc | 24 ++++++++++ src/xyz_srgb_lut.h | 13 ++++++ test/tests.cc | 1 + wscript | 3 -- 15 files changed, 199 insertions(+), 154 deletions(-) delete mode 100644 lut.py create mode 100644 src/gamma_lut.cc create mode 100644 src/gamma_lut.h create mode 100644 src/lut.h create mode 100644 src/lut_cache.h create mode 100644 src/xyz_srgb_lut.cc create mode 100644 src/xyz_srgb_lut.h diff --git a/.gitignore b/.gitignore index d845eee5..2170048b 100644 --- a/.gitignore +++ b/.gitignore @@ -6,8 +6,6 @@ build doc/html doc/latex src/version.cc -src/lut.cc -src/lut.h *.pyc __pycache__ GPATH diff --git a/lut.py b/lut.py deleted file mode 100644 index 9dd4ff20..00000000 --- a/lut.py +++ /dev/null @@ -1,127 +0,0 @@ -from __future__ import print_function -import math - -BIT_DEPTH = 12 -DCI_GAMMA = 2.6 -SRGB_GAMMA = 2.4; -BIT_LENGTH = int(math.pow(2, BIT_DEPTH)) -COLOR_DEPTH = BIT_LENGTH - 1 - -def boilerplate(f): - print("""/* - Copyright (C) 2012 Carl Hetherington - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. - -*/ - - -/* This file is auto-generated by the build scripts; edits will be lost - on ./waf configure. -*/ -""", file=f) - -def make_luts(): - cc = open('src/lut.cc', 'w') - - boilerplate(cc) - - print("#include \"lut.h\"", file=cc) - - print(""" -/* sRGB color matrix for XYZ -> RGB */ -float color_matrix[3][3] = { - { 3.240454836, -1.537138850, -0.498531547}, - {-0.969266390, 1.876010929, 0.041556082}, - { 0.055643420, -0.204025854, 1.057225162} -};\n\n -""", file=cc) - - print(""" -float lut_in[COLOR_DEPTH + 1] = {\n -\t/* Bit depth: %d -\t * Reference white: DCI -\t * Gamma: %f -\t */ -""" % (BIT_DEPTH, DCI_GAMMA), file=cc) - - c = 0 - for i in range(0, BIT_LENGTH): - v = math.pow (i / (BIT_LENGTH - 1.0), DCI_GAMMA); - - if (c == 0): - print(" ", end='', file=cc) - - if i < BIT_LENGTH - 1: - print("%06f, " % v, end="", file=cc) - if c == 12: - c = 0; - print("", file=cc) - else: - c += 1 - else: - print("%06f" % v, file=cc) - - print("};", file=cc) - - print(""" -int lut_out[COLOR_DEPTH + 1] = { -\t/* Bit depth: %d -\t * Reference white: sRGB -\t * Gamma: %f -\t */ -""", file=cc) - - c = 0 - for i in range (0, BIT_LENGTH): - v = i / (BIT_LENGTH - 1.0) - - if (v < (0.04045 / 12.92)): - v *= 12.92 - else: - v = (1.055 * pow (v, (1 / SRGB_GAMMA))) - 0.055 - - v *= 255 - - if c == 0: - print(" ", end="", file=cc) - - if i < BIT_LENGTH - 1: - print("%d, " % v, end="", file=cc) - if c == 12: - c = 0; - print("", file=cc) - else: - c += 1 - else: - print("%d" % v, file=cc) - - print("};", file=cc) - - h = open('src/lut.h', 'w') - - boilerplate(h) - - print(""" -#define COLOR_DEPTH (%d) -#define DCI_COEFFICIENT (48.0/52.37) - -extern float color_matrix[3][3]; -extern int lut_out[COLOR_DEPTH + 1]; -extern float lut_in[COLOR_DEPTH + 1]; -""" % COLOR_DEPTH, file=h) - -if __name__ == "__main__": - make_luts() diff --git a/src/gamma_lut.cc b/src/gamma_lut.cc new file mode 100644 index 00000000..acc80af0 --- /dev/null +++ b/src/gamma_lut.cc @@ -0,0 +1,16 @@ +#include +#include "gamma_lut.h" +#include "lut_cache.h" + +using namespace libdcp; + +LUTCache GammaLUT::cache; + +GammaLUT::GammaLUT(int bits, float gamma) + : LUT (bits, gamma) +{ + int const bit_length = pow(2, bits); + for (int i = 0; i < bit_length; ++i) { + _lut[i] = pow(float(i) / (bit_length - 1), gamma); + } +} diff --git a/src/gamma_lut.h b/src/gamma_lut.h new file mode 100644 index 00000000..e41cd21f --- /dev/null +++ b/src/gamma_lut.h @@ -0,0 +1,13 @@ +#include "lut.h" +#include "lut_cache.h" + +namespace libdcp { + +class GammaLUT : public LUT +{ +public: + GammaLUT (int bit_length, float gamma); + static LUTCache cache; +}; + +} diff --git a/src/lut.h b/src/lut.h new file mode 100644 index 00000000..8363e6a4 --- /dev/null +++ b/src/lut.h @@ -0,0 +1,63 @@ +/* + Copyright (C) 2012 Carl Hetherington + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + +*/ + +#ifndef LIBDCP_LUT_H +#define LIBDCP_LUT_H + +#include + +namespace libdcp { + +template +class LUT +{ +public: + LUT(int bit_depth, float gamma) + : _lut(0) + , _bit_depth (bit_depth) + , _gamma (gamma) + { + _lut = new T[int(std::pow(2, _bit_depth))]; + } + + virtual ~LUT() { + delete[] _lut; + } + + T const * lut() const { + return _lut; + } + + int bit_depth () const { + return _bit_depth; + } + + float gamma () const { + return _gamma; + } + +protected: + T* _lut; + int _bit_depth; + float _gamma; +}; + +} + +#endif diff --git a/src/lut_cache.h b/src/lut_cache.h new file mode 100644 index 00000000..b60ee109 --- /dev/null +++ b/src/lut_cache.h @@ -0,0 +1,28 @@ +#ifndef LIBDCP_LUT_CACHE_H +#define LIBDCP_LUT_CACHE_H + +#include +#include + +template +class LUTCache +{ +public: + boost::shared_ptr get (int bit_depth, float gamma) + { + for (typename std::list >::iterator i = _cache.begin(); i != _cache.end(); ++i) { + if ((*i)->bit_depth() == bit_depth && (*i)->gamma() == gamma) { + return *i; + } + } + + boost::shared_ptr lut (new T (bit_depth, gamma)); + _cache.push_back (lut); + return lut; + } + +private: + std::list > _cache; +}; + +#endif diff --git a/src/picture_frame.cc b/src/picture_frame.cc index 907f70ab..5d5f12c2 100644 --- a/src/picture_frame.cc +++ b/src/picture_frame.cc @@ -25,6 +25,10 @@ #include "argb_frame.h" #include "lut.h" #include "util.h" +#include "gamma_lut.h" +#include "xyz_srgb_lut.h" + +#define DCI_GAMMA 2.6 using std::string; using boost::shared_ptr; @@ -76,11 +80,11 @@ MonoPictureFrame::j2k_size () const * */ shared_ptr -MonoPictureFrame::argb_frame (int reduce) const +MonoPictureFrame::argb_frame (int reduce, float srgb_gamma) const { opj_image_t* xyz_frame = decompress_j2k (const_cast (_buffer->RoData()), _buffer->Size(), reduce); assert (xyz_frame->numcomps == 3); - shared_ptr f = xyz_to_rgb (xyz_frame); + shared_ptr f = xyz_to_rgb (xyz_frame, GammaLUT::cache.get (12, DCI_GAMMA), XYZsRGBLUT::cache.get (12, srgb_gamma)); opj_image_destroy (xyz_frame); return f; } @@ -122,7 +126,7 @@ StereoPictureFrame::~StereoPictureFrame () * */ shared_ptr -StereoPictureFrame::argb_frame (Eye eye, int reduce) const +StereoPictureFrame::argb_frame (Eye eye, int reduce, float srgb_gamma) const { opj_image_t* xyz_frame = 0; switch (eye) { @@ -135,7 +139,7 @@ StereoPictureFrame::argb_frame (Eye eye, int reduce) const } assert (xyz_frame->numcomps == 3); - shared_ptr f = xyz_to_rgb (xyz_frame); + shared_ptr f = xyz_to_rgb (xyz_frame, GammaLUT::cache.get (12, DCI_GAMMA), XYZsRGBLUT::cache.get (12, srgb_gamma)); opj_image_destroy (xyz_frame); return f; } diff --git a/src/picture_frame.h b/src/picture_frame.h index 20ce069e..42c5d629 100644 --- a/src/picture_frame.h +++ b/src/picture_frame.h @@ -40,7 +40,7 @@ public: MonoPictureFrame (std::string mxf_path, int n); ~MonoPictureFrame (); - boost::shared_ptr argb_frame (int reduce = 0) const; + boost::shared_ptr argb_frame (int reduce = 0, float srgb_gamma = 2.4) const; uint8_t const * j2k_data () const; int j2k_size () const; @@ -55,7 +55,7 @@ public: StereoPictureFrame (std::string mxf_path, int n); ~StereoPictureFrame (); - boost::shared_ptr argb_frame (Eye eye, int reduce = 0) const; + boost::shared_ptr argb_frame (Eye eye, int reduce = 0, float srgb_gamma = 2.4) const; uint8_t const * left_j2k_data () const; int left_j2k_size () const; uint8_t const * right_j2k_data () const; diff --git a/src/util.cc b/src/util.cc index 1cbec719..bd5f32ed 100644 --- a/src/util.cc +++ b/src/util.cc @@ -34,7 +34,8 @@ #include "exceptions.h" #include "types.h" #include "argb_frame.h" -#include "lut.h" +#include "gamma_lut.h" +#include "xyz_srgb_lut.h" using std::string; using std::stringstream; @@ -202,8 +203,19 @@ libdcp::decompress_j2k (uint8_t* data, int64_t size, int reduce) * @return RGB image. */ shared_ptr -libdcp::xyz_to_rgb (opj_image_t* xyz_frame) +libdcp::xyz_to_rgb (opj_image_t* xyz_frame, shared_ptr lut_in, shared_ptr lut_out) { + float const dci_coefficient = 48.0 / 52.37; + + /* sRGB color matrix for XYZ -> RGB */ + float const colour_matrix[3][3] = { + { 3.240454836, -1.537138850, -0.498531547}, + {-0.969266390, 1.876010929, 0.041556082}, + { 0.055643420, -0.204025854, 1.057225162} + }; + + int const max_colour = pow (2, lut_out->bit_depth()) - 1; + struct { double x, y, z; } s; @@ -227,19 +239,19 @@ libdcp::xyz_to_rgb (opj_image_t* xyz_frame) assert (*xyz_x >= 0 && *xyz_y >= 0 && *xyz_z >= 0 && *xyz_x < 4096 && *xyz_x < 4096 && *xyz_z < 4096); /* In gamma LUT */ - s.x = lut_in[*xyz_x++]; - s.y = lut_in[*xyz_y++]; - s.z = lut_in[*xyz_z++]; + s.x = lut_in->lut()[*xyz_x++]; + s.y = lut_in->lut()[*xyz_y++]; + s.z = lut_in->lut()[*xyz_z++]; /* DCI companding */ - s.x /= DCI_COEFFICIENT; - s.y /= DCI_COEFFICIENT; - s.z /= DCI_COEFFICIENT; + s.x /= dci_coefficient; + s.y /= dci_coefficient; + s.z /= dci_coefficient; /* XYZ to RGB */ - d.r = ((s.x * color_matrix[0][0]) + (s.y * color_matrix[0][1]) + (s.z * color_matrix[0][2])); - d.g = ((s.x * color_matrix[1][0]) + (s.y * color_matrix[1][1]) + (s.z * color_matrix[1][2])); - d.b = ((s.x * color_matrix[2][0]) + (s.y * color_matrix[2][1]) + (s.z * color_matrix[2][2])); + d.r = ((s.x * colour_matrix[0][0]) + (s.y * colour_matrix[0][1]) + (s.z * colour_matrix[0][2])); + d.g = ((s.x * colour_matrix[1][0]) + (s.y * colour_matrix[1][1]) + (s.z * colour_matrix[1][2])); + d.b = ((s.x * colour_matrix[2][0]) + (s.y * colour_matrix[2][1]) + (s.z * colour_matrix[2][2])); d.r = min (d.r, 1.0); d.r = max (d.r, 0.0); @@ -251,9 +263,9 @@ libdcp::xyz_to_rgb (opj_image_t* xyz_frame) d.b = max (d.b, 0.0); /* Out gamma LUT */ - *argb_line++ = lut_out[(int) (d.b * COLOR_DEPTH)]; - *argb_line++ = lut_out[(int) (d.g * COLOR_DEPTH)]; - *argb_line++ = lut_out[(int) (d.r * COLOR_DEPTH)]; + *argb_line++ = lut_out->lut()[(int) (d.b * max_colour)]; + *argb_line++ = lut_out->lut()[(int) (d.g * max_colour)]; + *argb_line++ = lut_out->lut()[(int) (d.r * max_colour)]; *argb_line++ = 0xff; } diff --git a/src/util.h b/src/util.h index f5685970..2036a7ce 100644 --- a/src/util.h +++ b/src/util.h @@ -33,6 +33,8 @@ namespace libdcp { class ARGBFrame; +class GammaLUT; +class XYZsRGBLUT; struct Size { Size () @@ -58,7 +60,7 @@ extern std::string content_kind_to_string (ContentKind kind); extern ContentKind content_kind_from_string (std::string kind); 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 xyz_to_rgb (opj_image_t* xyz_frame); +extern boost::shared_ptr xyz_to_rgb (opj_image_t* xyz_frame, boost::shared_ptr, boost::shared_ptr); } diff --git a/src/wscript b/src/wscript index d243ae46..efba2502 100644 --- a/src/wscript +++ b/src/wscript @@ -15,7 +15,7 @@ def build(bld): cpl_file.cc dcp.cc dcp_time.cc - lut.cc + gamma_lut.cc metadata.cc mxf_asset.cc picture_asset.cc @@ -31,6 +31,7 @@ def build(bld): util.cc version.cc xml.cc + xyz_srgb_lut.cc """ headers = """ diff --git a/src/xyz_srgb_lut.cc b/src/xyz_srgb_lut.cc new file mode 100644 index 00000000..3d207195 --- /dev/null +++ b/src/xyz_srgb_lut.cc @@ -0,0 +1,24 @@ +#include +#include +#include "xyz_srgb_lut.h" + +using namespace libdcp; + +LUTCache XYZsRGBLUT::cache; + +XYZsRGBLUT::XYZsRGBLUT(int bits, float gamma) + : LUT (bits, gamma) +{ + int const bit_length = pow(2, bits); + + for (int i = 0; i < bit_length; ++i) { + float v = float(i) / (bit_length - 1); + if (v < (0.04045 / 12.92)) { + v *= 12.92; + } else { + v = (1.055 * pow (v, (1 / gamma))) - 0.055; + } + + _lut[i] = int(v * 255); + } +} diff --git a/src/xyz_srgb_lut.h b/src/xyz_srgb_lut.h new file mode 100644 index 00000000..63f89178 --- /dev/null +++ b/src/xyz_srgb_lut.h @@ -0,0 +1,13 @@ +#include "lut.h" +#include "lut_cache.h" + +namespace libdcp { + +class XYZsRGBLUT : public LUT +{ +public: + XYZsRGBLUT(int colour_depth, float gamma); + static LUTCache cache; +}; + +} diff --git a/test/tests.cc b/test/tests.cc index 62cab54c..30c9f406 100644 --- a/test/tests.cc +++ b/test/tests.cc @@ -29,6 +29,7 @@ #include "picture_asset.h" #include "sound_asset.h" #include "reel.h" +#include "gamma_lut.h" #define BOOST_TEST_DYN_LINK #define BOOST_TEST_MODULE libdcp_test diff --git a/wscript b/wscript index 27483bac..8829ccd8 100644 --- a/wscript +++ b/wscript @@ -1,6 +1,5 @@ import subprocess import os -import lut APPNAME = 'libdcp' VERSION = '0.40pre' @@ -83,8 +82,6 @@ def configure(conf): msg = 'Checking for boost signals2 library', uselib_store = 'BOOST_SIGNALS2') - lut.make_luts() - conf.recurse('test') conf.recurse('asdcplib') -- cgit v1.2.3 From 6bad5e41a3bf9293138e846a2234abebfef3be4c Mon Sep 17 00:00:00 2001 From: Carl Hetherington Date: Wed, 13 Mar 2013 16:47:46 +0000 Subject: Bump version --- wscript | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/wscript b/wscript index 6bf75fd4..3b73f7b1 100644 --- a/wscript +++ b/wscript @@ -2,7 +2,7 @@ import subprocess import os APPNAME = 'libdcp' -VERSION = '0.41pre' +VERSION = '0.41' def options(opt): opt.load('compiler_cxx') -- cgit v1.2.3 From 5790a7e1ddda02afbca611b2978a4390e7ee9595 Mon Sep 17 00:00:00 2001 From: Carl Hetherington Date: Wed, 13 Mar 2013 16:50:32 +0000 Subject: Bump version --- wscript | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/wscript b/wscript index 3b73f7b1..39d99b18 100644 --- a/wscript +++ b/wscript @@ -2,7 +2,7 @@ import subprocess import os APPNAME = 'libdcp' -VERSION = '0.41' +VERSION = '0.42pre' def options(opt): opt.load('compiler_cxx') -- cgit v1.2.3 From 847b0c0f95ddb9ee0bcb7f70e6ee50007828d6d2 Mon Sep 17 00:00:00 2001 From: Carl Hetherington Date: Sun, 24 Mar 2013 20:09:32 +0000 Subject: Revert use of _entry_point when getting sound frames from existing MXFs; seems to cause problems. --- src/sound_asset.cc | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/sound_asset.cc b/src/sound_asset.cc index 014b95a2..e18441c6 100644 --- a/src/sound_asset.cc +++ b/src/sound_asset.cc @@ -298,7 +298,8 @@ SoundAsset::equals (shared_ptr other, EqualityOptions opt, list SoundAsset::get_frame (int n) const { - return shared_ptr (new SoundFrame (path().string(), n + _entry_point)); + /* XXX: should add on entry point here? */ + return shared_ptr (new SoundFrame (path().string(), n)); } shared_ptr -- cgit v1.2.3 From 2effb3dcb769838f5cc44c749bff8fdbcd90d218 Mon Sep 17 00:00:00 2001 From: Carl Hetherington Date: Sun, 24 Mar 2013 20:12:36 +0000 Subject: Bump version --- wscript | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/wscript b/wscript index 39d99b18..19287187 100644 --- a/wscript +++ b/wscript @@ -2,7 +2,7 @@ import subprocess import os APPNAME = 'libdcp' -VERSION = '0.42pre' +VERSION = '0.42' def options(opt): opt.load('compiler_cxx') -- cgit v1.2.3 From 1c4257eacfe62f30f3e08edfe049a954cd7b43a3 Mon Sep 17 00:00:00 2001 From: Carl Hetherington Date: Sun, 24 Mar 2013 20:24:10 +0000 Subject: Try removing the DCI companding from the xyz->rgb conversion. --- src/util.cc | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/util.cc b/src/util.cc index a6d65374..d5565245 100644 --- a/src/util.cc +++ b/src/util.cc @@ -242,11 +242,13 @@ libdcp::xyz_to_rgb (opj_image_t* xyz_frame, shared_ptr lut_in, s s.x = lut_in->lut()[*xyz_x++]; s.y = lut_in->lut()[*xyz_y++]; s.z = lut_in->lut()[*xyz_z++]; - + +#if 0 /* DCI companding */ s.x /= dci_coefficient; s.y /= dci_coefficient; s.z /= dci_coefficient; +#endif /* XYZ to RGB */ d.r = ((s.x * colour_matrix[0][0]) + (s.y * colour_matrix[0][1]) + (s.z * colour_matrix[0][2])); -- cgit v1.2.3 From 10655124e560b28418a765bebaa760dfc9885b0a Mon Sep 17 00:00:00 2001 From: Carl Hetherington Date: Sun, 24 Mar 2013 21:04:49 +0000 Subject: Re-enable DCI companding; modify RGB matrix to that given on http://www.digitall.net.au/products/dcp-player/64.html --- src/util.cc | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/src/util.cc b/src/util.cc index d5565245..7543f8ba 100644 --- a/src/util.cc +++ b/src/util.cc @@ -208,11 +208,19 @@ libdcp::xyz_to_rgb (opj_image_t* xyz_frame, shared_ptr lut_in, s float const dci_coefficient = 48.0 / 52.37; /* sRGB color matrix for XYZ -> RGB */ +#if 0 float const colour_matrix[3][3] = { { 3.240454836, -1.537138850, -0.498531547}, {-0.969266390, 1.876010929, 0.041556082}, { 0.055643420, -0.204025854, 1.057225162} }; +#endif + + float const colour_matrix[3][3] = { + { 3.1338561, -1.6168667, -0.4906146 }, + { -0.9787684, 1.9161415, 0.0334540 }, + { 0.0719453, -0.2289914, 1.4052427 } + }; int const max_colour = pow (2, lut_out->bit_depth()) - 1; @@ -243,12 +251,10 @@ libdcp::xyz_to_rgb (opj_image_t* xyz_frame, shared_ptr lut_in, s s.y = lut_in->lut()[*xyz_y++]; s.z = lut_in->lut()[*xyz_z++]; -#if 0 /* DCI companding */ s.x /= dci_coefficient; s.y /= dci_coefficient; s.z /= dci_coefficient; -#endif /* XYZ to RGB */ d.r = ((s.x * colour_matrix[0][0]) + (s.y * colour_matrix[0][1]) + (s.z * colour_matrix[0][2])); -- cgit v1.2.3 From 1cb397e4cb51ba31b6e19b20d97a1b7553f36617 Mon Sep 17 00:00:00 2001 From: Carl Hetherington Date: Sun, 24 Mar 2013 21:06:48 +0000 Subject: Bump version --- wscript | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/wscript b/wscript index 19287187..5fcdb64c 100644 --- a/wscript +++ b/wscript @@ -2,7 +2,7 @@ import subprocess import os APPNAME = 'libdcp' -VERSION = '0.42' +VERSION = '0.43pre' def options(opt): opt.load('compiler_cxx') -- cgit v1.2.3 From 135c084653b225727a5ccf12e0bc2dab89ce702b Mon Sep 17 00:00:00 2001 From: Carl Hetherington Date: Sun, 24 Mar 2013 21:08:16 +0000 Subject: Bump version --- wscript | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/wscript b/wscript index 5fcdb64c..ae56c77c 100644 --- a/wscript +++ b/wscript @@ -2,7 +2,7 @@ import subprocess import os APPNAME = 'libdcp' -VERSION = '0.43pre' +VERSION = '0.43' def options(opt): opt.load('compiler_cxx') -- cgit v1.2.3 From 80aff70f10576946c71690f3f71bdba0beeb5b07 Mon Sep 17 00:00:00 2001 From: Carl Hetherington Date: Sun, 24 Mar 2013 21:09:23 +0000 Subject: Bump version --- wscript | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/wscript b/wscript index ae56c77c..3f643950 100644 --- a/wscript +++ b/wscript @@ -2,7 +2,7 @@ import subprocess import os APPNAME = 'libdcp' -VERSION = '0.43' +VERSION = '0.44pre' def options(opt): opt.load('compiler_cxx') -- cgit v1.2.3 From 7508e009c6b9232379789d8f9bf9342430801734 Mon Sep 17 00:00:00 2001 From: Carl Hetherington Date: Sun, 24 Mar 2013 21:19:07 +0000 Subject: Remove linearisation from low-valued pixels in XYZ to sRGB LUT. --- src/xyz_srgb_lut.cc | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/xyz_srgb_lut.cc b/src/xyz_srgb_lut.cc index 3d207195..eb443a59 100644 --- a/src/xyz_srgb_lut.cc +++ b/src/xyz_srgb_lut.cc @@ -13,11 +13,15 @@ XYZsRGBLUT::XYZsRGBLUT(int bits, float gamma) for (int i = 0; i < bit_length; ++i) { float v = float(i) / (bit_length - 1); +#if 0 if (v < (0.04045 / 12.92)) { v *= 12.92; } else { +#endif v = (1.055 * pow (v, (1 / gamma))) - 0.055; +#if 0 } +#endif _lut[i] = int(v * 255); } -- cgit v1.2.3 From d3ca129cf385a23db3ad0e80b6cc5c8bf986021f Mon Sep 17 00:00:00 2001 From: Carl Hetherington Date: Sun, 24 Mar 2013 21:19:24 +0000 Subject: Bump version --- wscript | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/wscript b/wscript index 3f643950..f9e2c648 100644 --- a/wscript +++ b/wscript @@ -2,7 +2,7 @@ import subprocess import os APPNAME = 'libdcp' -VERSION = '0.44pre' +VERSION = '0.44' def options(opt): opt.load('compiler_cxx') -- cgit v1.2.3 From d7bad6c854f8e27f099ddb44a9c14e1e1e51ca1a Mon Sep 17 00:00:00 2001 From: Carl Hetherington Date: Sun, 24 Mar 2013 21:20:40 +0000 Subject: Bump version --- wscript | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/wscript b/wscript index f9e2c648..de31ce1f 100644 --- a/wscript +++ b/wscript @@ -2,7 +2,7 @@ import subprocess import os APPNAME = 'libdcp' -VERSION = '0.44' +VERSION = '0.45pre' def options(opt): opt.load('compiler_cxx') -- cgit v1.2.3 From ab3163255b9713fc40a73fcfc3753b62ee084b8d Mon Sep 17 00:00:00 2001 From: Carl Hetherington Date: Tue, 26 Mar 2013 20:22:05 +0000 Subject: Set RGB colour matrix from Thomas' email re FH. --- src/util.cc | 13 +++---------- 1 file changed, 3 insertions(+), 10 deletions(-) diff --git a/src/util.cc b/src/util.cc index 7543f8ba..2fae8561 100644 --- a/src/util.cc +++ b/src/util.cc @@ -208,18 +208,11 @@ libdcp::xyz_to_rgb (opj_image_t* xyz_frame, shared_ptr lut_in, s float const dci_coefficient = 48.0 / 52.37; /* sRGB color matrix for XYZ -> RGB */ -#if 0 - float const colour_matrix[3][3] = { - { 3.240454836, -1.537138850, -0.498531547}, - {-0.969266390, 1.876010929, 0.041556082}, - { 0.055643420, -0.204025854, 1.057225162} - }; -#endif float const colour_matrix[3][3] = { - { 3.1338561, -1.6168667, -0.4906146 }, - { -0.9787684, 1.9161415, 0.0334540 }, - { 0.0719453, -0.2289914, 1.4052427 } + { 3.24096989631653, -1.5373831987381, -0.498610764741898 }, + { -0.96924364566803, 1.87596750259399, 0.0415550582110882 }, + { 0.0556300804018974, -0.203976958990097, 1.05697154998779 } }; int const max_colour = pow (2, lut_out->bit_depth()) - 1; -- cgit v1.2.3 From 6407924747622d6785ecfed24c35db355ca38032 Mon Sep 17 00:00:00 2001 From: Carl Hetherington Date: Tue, 26 Mar 2013 21:29:30 +0000 Subject: Reinstate linearisation of low-end of XYZ->RGB transform. --- src/xyz_srgb_lut.cc | 4 ---- 1 file changed, 4 deletions(-) diff --git a/src/xyz_srgb_lut.cc b/src/xyz_srgb_lut.cc index eb443a59..3d207195 100644 --- a/src/xyz_srgb_lut.cc +++ b/src/xyz_srgb_lut.cc @@ -13,15 +13,11 @@ XYZsRGBLUT::XYZsRGBLUT(int bits, float gamma) for (int i = 0; i < bit_length; ++i) { float v = float(i) / (bit_length - 1); -#if 0 if (v < (0.04045 / 12.92)) { v *= 12.92; } else { -#endif v = (1.055 * pow (v, (1 / gamma))) - 0.055; -#if 0 } -#endif _lut[i] = int(v * 255); } -- cgit v1.2.3 From a015aebf5b641c62c6c69c0f2667d8fd9a87ade4 Mon Sep 17 00:00:00 2001 From: Carl Hetherington Date: Mon, 1 Apr 2013 23:25:32 +0100 Subject: Missing include. --- src/types.h | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/types.h b/src/types.h index f1b5f640..ebcfb838 100644 --- a/src/types.h +++ b/src/types.h @@ -24,6 +24,8 @@ #ifndef LIBDCP_TYPES_H #define LIBDCP_TYPES_H +#include + namespace libdcp { -- cgit v1.2.3 From 6322c72a13d7be2e991a8e0421414c0af8187b88 Mon Sep 17 00:00:00 2001 From: Carl Hetherington Date: Mon, 15 Apr 2013 13:38:14 +0100 Subject: Use boost::function for making notes during equals operations. --- src/asset.cc | 1 + src/asset.h | 3 ++- src/dcp.cc | 20 ++++++++++---------- src/dcp.h | 7 +++---- src/mxf_asset.cc | 12 ++++++------ src/mxf_asset.h | 2 +- src/picture_asset.cc | 29 +++++++++++++++-------------- src/picture_asset.h | 8 ++++---- src/reel.cc | 14 +++++++------- src/reel.h | 3 ++- src/sound_asset.cc | 10 +++++----- src/sound_asset.h | 2 +- src/subtitle_asset.h | 4 ++-- tools/dcpdiff.cc | 13 +++++++------ 14 files changed, 66 insertions(+), 62 deletions(-) diff --git a/src/asset.cc b/src/asset.cc index 3d2a0e03..305fc9a7 100644 --- a/src/asset.cc +++ b/src/asset.cc @@ -24,6 +24,7 @@ #include #include #include +#include #include "AS_DCP.h" #include "KM_util.h" #include "asset.h" diff --git a/src/asset.h b/src/asset.h index 436e8b41..527dea7a 100644 --- a/src/asset.h +++ b/src/asset.h @@ -27,6 +27,7 @@ #include #include #include +#include #include "types.h" namespace ASDCP { @@ -80,7 +81,7 @@ public: _file_name = f; } - virtual bool equals (boost::shared_ptr other, EqualityOptions opt, std::list& notes) const = 0; + virtual bool equals (boost::shared_ptr other, EqualityOptions opt, boost::function) const = 0; protected: diff --git a/src/dcp.cc b/src/dcp.cc index d446b205..49d41c70 100644 --- a/src/dcp.cc +++ b/src/dcp.cc @@ -248,10 +248,10 @@ DCP::read (bool require_mxfs) } bool -DCP::equals (DCP const & other, EqualityOptions opt, list& notes) const +DCP::equals (DCP const & other, EqualityOptions opt, boost::function note) const { if (_cpls.size() != other._cpls.size()) { - notes.push_back ("CPL counts differ"); + note ("CPL counts differ"); return false; } @@ -259,7 +259,7 @@ DCP::equals (DCP const & other, EqualityOptions opt, list& notes) const list >::const_iterator b = other._cpls.begin (); while (a != _cpls.end ()) { - if (!(*a)->equals (*b->get(), opt, notes)) { + if (!(*a)->equals (*b->get(), opt, note)) { return false; } ++a; @@ -516,30 +516,30 @@ CPL::write_to_assetmap (ostream& s) const bool -CPL::equals (CPL const & other, EqualityOptions opt, list& notes) const +CPL::equals (CPL const & other, EqualityOptions opt, boost::function note) const { if (_name != other._name) { - notes.push_back ("names differ"); + note ("names differ"); return false; } if (_content_kind != other._content_kind) { - notes.push_back ("content kinds differ"); + note ("content kinds differ"); return false; } if (_fps != other._fps) { - notes.push_back ("frames per second differ"); + note ("frames per second differ"); return false; } if (_length != other._length) { - notes.push_back ("lengths differ"); + note ("lengths differ"); return false; } if (_reels.size() != other._reels.size()) { - notes.push_back ("reel counts differ"); + note ("reel counts differ"); return false; } @@ -547,7 +547,7 @@ CPL::equals (CPL const & other, EqualityOptions opt, list& notes) const list >::const_iterator b = other._reels.begin (); while (a != _reels.end ()) { - if (!(*a)->equals (*b, opt, notes)) { + if (!(*a)->equals (*b, opt, note)) { return false; } ++a; diff --git a/src/dcp.h b/src/dcp.h index c5734542..7e9b4edc 100644 --- a/src/dcp.h +++ b/src/dcp.h @@ -84,7 +84,7 @@ public: std::list > assets () const; - bool equals (CPL const & other, EqualityOptions options, std::list& notes) const; + bool equals (CPL const & other, EqualityOptions options, boost::function note) const; void write_xml () const; void write_to_assetmap (std::ostream& s) const; @@ -141,11 +141,10 @@ public: /** Compare this DCP with another, according to various options. * @param other DCP to compare this one to. - * @param options Options to define just what "equality" means. - * @param notes Filled in with notes about differences. + * @param options Options to define what "equality" means. * @return true if the DCPs are equal according to EqualityOptions, otherwise false. */ - bool equals (DCP const & other, EqualityOptions options, std::list& notes) const; + bool equals (DCP const & other, EqualityOptions options, boost::function note) const; /** Add a CPL to this DCP. * @param cpl CPL to add. diff --git a/src/mxf_asset.cc b/src/mxf_asset.cc index 9b4cbf74..cf265712 100644 --- a/src/mxf_asset.cc +++ b/src/mxf_asset.cc @@ -71,31 +71,31 @@ MXFAsset::fill_writer_info (ASDCP::WriterInfo* writer_info, string uuid) } bool -MXFAsset::equals (shared_ptr other, EqualityOptions, list& notes) const +MXFAsset::equals (shared_ptr other, EqualityOptions, boost::function note) const { shared_ptr other_mxf = dynamic_pointer_cast (other); if (!other_mxf) { - notes.push_back ("comparing an MXF asset with a non-MXF asset"); + note ("comparing an MXF asset with a non-MXF asset"); return false; } if (_file_name != other_mxf->_file_name) { - notes.push_back ("MXF names differ"); + note ("MXF names differ"); return false; } if (_edit_rate != other_mxf->_edit_rate) { - notes.push_back ("MXF edit rates differ"); + note ("MXF edit rates differ"); return false; } if (_intrinsic_duration != other_mxf->_intrinsic_duration) { - notes.push_back ("MXF intrinsic durations differ"); + note ("MXF intrinsic durations differ"); return false; } if (_duration != other_mxf->_duration) { - notes.push_back ("MXF durations differ"); + note ("MXF durations differ"); return false; } diff --git a/src/mxf_asset.h b/src/mxf_asset.h index 430e9157..0c98f3c6 100644 --- a/src/mxf_asset.h +++ b/src/mxf_asset.h @@ -61,7 +61,7 @@ public: _intrinsic_duration = d; } - virtual bool equals (boost::shared_ptr other, EqualityOptions opt, std::list& notes) const; + virtual bool equals (boost::shared_ptr other, EqualityOptions opt, boost::function note) const; int intrinsic_duration () const { return _intrinsic_duration; diff --git a/src/picture_asset.cc b/src/picture_asset.cc index 13253242..807564c5 100644 --- a/src/picture_asset.cc +++ b/src/picture_asset.cc @@ -79,9 +79,9 @@ PictureAsset::write_to_cpl (ostream& s) const } bool -PictureAsset::equals (shared_ptr other, EqualityOptions opt, list& notes) const +PictureAsset::equals (shared_ptr other, EqualityOptions opt, boost::function note) const { - if (!MXFAsset::equals (other, opt, notes)) { + if (!MXFAsset::equals (other, opt, note)) { return false; } @@ -125,7 +125,7 @@ PictureAsset::equals (shared_ptr other, EqualityOptions opt, list other, EqualityOptions opt, list& notes) const +MonoPictureAsset::equals (shared_ptr other, EqualityOptions opt, boost::function note) const { - if (!PictureAsset::equals (other, opt, notes)) { + if (!PictureAsset::equals (other, opt, note)) { return false; } @@ -262,7 +262,7 @@ MonoPictureAsset::equals (shared_ptr other, EqualityOptions opt, li shared_ptr frame_B = other_picture->get_frame (i); if (!frame_buffer_equals ( - i, opt, notes, + i, opt, note, frame_A->j2k_data(), frame_A->j2k_size(), frame_B->j2k_data(), frame_B->j2k_size() )) { @@ -274,9 +274,9 @@ MonoPictureAsset::equals (shared_ptr other, EqualityOptions opt, li } bool -StereoPictureAsset::equals (shared_ptr other, EqualityOptions opt, list& notes) const +StereoPictureAsset::equals (shared_ptr other, EqualityOptions opt, boost::function note) const { - if (!PictureAsset::equals (other, opt, notes)) { + if (!PictureAsset::equals (other, opt, note)) { return false; } @@ -288,7 +288,7 @@ StereoPictureAsset::equals (shared_ptr other, EqualityOptions opt, shared_ptr frame_B = other_picture->get_frame (i); if (!frame_buffer_equals ( - i, opt, notes, + i, opt, note, frame_A->left_j2k_data(), frame_A->left_j2k_size(), frame_B->left_j2k_data(), frame_B->left_j2k_size() )) { @@ -296,7 +296,7 @@ StereoPictureAsset::equals (shared_ptr other, EqualityOptions opt, } if (!frame_buffer_equals ( - i, opt, notes, + i, opt, note, frame_A->right_j2k_data(), frame_A->right_j2k_size(), frame_B->right_j2k_data(), frame_B->right_j2k_size() )) { @@ -309,7 +309,8 @@ StereoPictureAsset::equals (shared_ptr other, EqualityOptions opt, bool PictureAsset::frame_buffer_equals ( - int frame, EqualityOptions opt, list& notes, uint8_t const * data_A, unsigned int size_A, uint8_t const * data_B, unsigned int size_B + int frame, EqualityOptions opt, boost::function note, + uint8_t const * data_A, unsigned int size_A, uint8_t const * data_B, unsigned int size_B ) const { if (size_A == size_B && memcmp (data_A, data_B, size_A) == 0) { @@ -324,7 +325,7 @@ PictureAsset::frame_buffer_equals ( /* Compare them */ if (image_A->numcomps != image_B->numcomps) { - notes.push_back ("image component counts for frame " + lexical_cast(frame) + " differ"); + note ("image component counts for frame " + lexical_cast(frame) + " differ"); return false; } @@ -335,7 +336,7 @@ PictureAsset::frame_buffer_equals ( for (int c = 0; c < image_A->numcomps; ++c) { if (image_A->comps[c].w != image_B->comps[c].w || image_A->comps[c].h != image_B->comps[c].h) { - notes.push_back ("image sizes for frame " + lexical_cast(frame) + " differ"); + note ("image sizes for frame " + lexical_cast(frame) + " differ"); return false; } @@ -362,7 +363,7 @@ PictureAsset::frame_buffer_equals ( double const std_dev = sqrt (double (total_squared_deviation) / abs_diffs.size()); if (mean > opt.max_mean_pixel_error || std_dev > opt.max_std_dev_pixel_error) { - notes.push_back ("mean or standard deviation out of range for " + lexical_cast(frame)); + note ("mean or standard deviation out of range for " + lexical_cast(frame)); return false; } diff --git a/src/picture_asset.h b/src/picture_asset.h index d3fabbbd..f4d4d7a4 100644 --- a/src/picture_asset.h +++ b/src/picture_asset.h @@ -63,7 +63,7 @@ public: */ void write_to_cpl (std::ostream& s) const; - bool equals (boost::shared_ptr other, EqualityOptions opt, std::list& notes) const; + bool equals (boost::shared_ptr other, EqualityOptions opt, boost::function note) const; Size size () const { return _size; @@ -72,7 +72,7 @@ public: protected: bool frame_buffer_equals ( - int frame, EqualityOptions opt, std::list& notes, + int frame, EqualityOptions opt, boost::function note, uint8_t const * data_A, unsigned int size_A, uint8_t const * data_B, unsigned int size_B ) const; @@ -210,7 +210,7 @@ public: boost::shared_ptr start_write (bool); boost::shared_ptr get_frame (int n) const; - bool equals (boost::shared_ptr other, EqualityOptions opt, std::list& notes) const; + bool equals (boost::shared_ptr other, EqualityOptions opt, boost::function note) const; private: std::string path_from_list (int f, std::vector const & files) const; @@ -224,7 +224,7 @@ public: StereoPictureAsset (std::string directory, std::string mxf_name, int fps, int intrinsic_duration); boost::shared_ptr get_frame (int n) const; - bool equals (boost::shared_ptr other, EqualityOptions opt, std::list& notes) const; + bool equals (boost::shared_ptr other, EqualityOptions opt, boost::function note) const; }; diff --git a/src/reel.cc b/src/reel.cc index 8995f874..096acf19 100644 --- a/src/reel.cc +++ b/src/reel.cc @@ -50,32 +50,32 @@ Reel::write_to_cpl (ostream& s) const } bool -Reel::equals (boost::shared_ptr other, EqualityOptions opt, list& notes) const +Reel::equals (boost::shared_ptr other, EqualityOptions opt, boost::function note) const { if ((_main_picture && !other->_main_picture) || (!_main_picture && other->_main_picture)) { - notes.push_back ("reel has different assets"); + note ("reel has different assets"); return false; } - if (_main_picture && !_main_picture->equals (other->_main_picture, opt, notes)) { + if (_main_picture && !_main_picture->equals (other->_main_picture, opt, note)) { return false; } if ((_main_sound && !other->_main_sound) || (!_main_sound && other->_main_sound)) { - notes.push_back ("reel has different assets"); + note ("reel has different assets"); return false; } - if (_main_sound && !_main_sound->equals (other->_main_sound, opt, notes)) { + if (_main_sound && !_main_sound->equals (other->_main_sound, opt, note)) { return false; } if ((_main_subtitle && !other->_main_subtitle) || (!_main_subtitle && other->_main_subtitle)) { - notes.push_back ("reel has different assets"); + note ("reel has different assets"); return false; } - if (_main_subtitle && !_main_subtitle->equals (other->_main_subtitle, opt, notes)) { + if (_main_subtitle && !_main_subtitle->equals (other->_main_subtitle, opt, note)) { return false; } diff --git a/src/reel.h b/src/reel.h index c7d3b164..b0dfc84d 100644 --- a/src/reel.h +++ b/src/reel.h @@ -19,6 +19,7 @@ #include #include +#include #include "types.h" namespace libdcp { @@ -55,7 +56,7 @@ public: void write_to_cpl (std::ostream & s) const; - bool equals (boost::shared_ptr other, EqualityOptions opt, std::list& notes) const; + bool equals (boost::shared_ptr other, EqualityOptions opt, boost::function notes) const; private: boost::shared_ptr _main_picture; diff --git a/src/sound_asset.cc b/src/sound_asset.cc index e18441c6..da6e72bc 100644 --- a/src/sound_asset.cc +++ b/src/sound_asset.cc @@ -222,9 +222,9 @@ SoundAsset::write_to_cpl (ostream& s) const } bool -SoundAsset::equals (shared_ptr other, EqualityOptions opt, list& notes) const +SoundAsset::equals (shared_ptr other, EqualityOptions opt, boost::function note) const { - if (!MXFAsset::equals (other, opt, notes)) { + if (!MXFAsset::equals (other, opt, note)) { return false; } @@ -260,7 +260,7 @@ SoundAsset::equals (shared_ptr other, EqualityOptions opt, list other, EqualityOptions opt, list(i) + " differ"); + note ("sizes of audio data for frame " + lexical_cast(i) + " differ"); return false; } @@ -285,7 +285,7 @@ SoundAsset::equals (shared_ptr other, EqualityOptions opt, list opt.max_audio_sample_error) { - notes.push_back ("PCM data difference of " + lexical_cast (d)); + note ("PCM data difference of " + lexical_cast (d)); return false; } } diff --git a/src/sound_asset.h b/src/sound_asset.h index ad350ce5..dedebac3 100644 --- a/src/sound_asset.h +++ b/src/sound_asset.h @@ -129,7 +129,7 @@ public: */ void write_to_cpl (std::ostream& s) const; - bool equals (boost::shared_ptr other, EqualityOptions opt, std::list& notes) const; + bool equals (boost::shared_ptr other, EqualityOptions opt, boost::function note) const; boost::shared_ptr get_frame (int n) const; diff --git a/src/subtitle_asset.h b/src/subtitle_asset.h index 71ae42fc..b3936dc2 100644 --- a/src/subtitle_asset.h +++ b/src/subtitle_asset.h @@ -184,9 +184,9 @@ public: SubtitleAsset (std::string directory, std::string movie_title, std::string language); void write_to_cpl (std::ostream&) const; - virtual bool equals (boost::shared_ptr, EqualityOptions, std::list& notes) const { + virtual bool equals (boost::shared_ptr, EqualityOptions, boost::function note) const { /* XXX */ - notes.push_back ("subtitle assets not compared yet"); + note ("subtitle assets not compared yet"); return true; } diff --git a/tools/dcpdiff.cc b/tools/dcpdiff.cc index 025308e6..6d55586d 100644 --- a/tools/dcpdiff.cc +++ b/tools/dcpdiff.cc @@ -20,6 +20,12 @@ help (string n) << "and differing UUIDs.\n"; } +void +note (string n) +{ + cout << " " << n << "\n"; +} + int main (int argc, char* argv[]) { @@ -87,12 +93,7 @@ main (int argc, char* argv[]) /* I think this is just below the LSB at 16-bits (ie the 8th most significant bit at 24-bit) */ options.max_audio_sample_error = 255; - list notes; - bool equals = a->equals (*b, options, notes); - - for (list::iterator i = notes.begin(); i != notes.end(); ++i) { - cout << " " << *i << "\n"; - } + bool const equals = a->equals (*b, options, boost::bind (note, _1)); if (equals) { exit (EXIT_SUCCESS); -- cgit v1.2.3 From 034abb6bb0f1d0382620bdcc43501ce0ba30b03a Mon Sep 17 00:00:00 2001 From: Carl Hetherington Date: Mon, 15 Apr 2013 13:48:22 +0100 Subject: Try to give basic progress indication on dcpdiff. --- src/asset.h | 2 +- src/dcp.cc | 16 ++++++++-------- src/dcp.h | 4 ++-- src/mxf_asset.cc | 12 ++++++------ src/mxf_asset.h | 2 +- src/picture_asset.cc | 17 +++++++++-------- src/picture_asset.h | 8 ++++---- src/reel.cc | 8 ++++---- src/reel.h | 2 +- src/sound_asset.cc | 8 ++++---- src/sound_asset.h | 2 +- src/subtitle_asset.h | 4 ++-- src/types.h | 5 +++++ tools/dcpdiff.cc | 23 ++++++++++++++++------- 14 files changed, 64 insertions(+), 49 deletions(-) diff --git a/src/asset.h b/src/asset.h index 527dea7a..1b1bf4c6 100644 --- a/src/asset.h +++ b/src/asset.h @@ -81,7 +81,7 @@ public: _file_name = f; } - virtual bool equals (boost::shared_ptr other, EqualityOptions opt, boost::function) const = 0; + virtual bool equals (boost::shared_ptr other, EqualityOptions opt, boost::function) const = 0; protected: diff --git a/src/dcp.cc b/src/dcp.cc index 49d41c70..bac266ab 100644 --- a/src/dcp.cc +++ b/src/dcp.cc @@ -248,10 +248,10 @@ DCP::read (bool require_mxfs) } bool -DCP::equals (DCP const & other, EqualityOptions opt, boost::function note) const +DCP::equals (DCP const & other, EqualityOptions opt, boost::function note) const { if (_cpls.size() != other._cpls.size()) { - note ("CPL counts differ"); + note (ERROR, "CPL counts differ"); return false; } @@ -516,30 +516,30 @@ CPL::write_to_assetmap (ostream& s) const bool -CPL::equals (CPL const & other, EqualityOptions opt, boost::function note) const +CPL::equals (CPL const & other, EqualityOptions opt, boost::function note) const { if (_name != other._name) { - note ("names differ"); + note (ERROR, "names differ"); return false; } if (_content_kind != other._content_kind) { - note ("content kinds differ"); + note (ERROR, "content kinds differ"); return false; } if (_fps != other._fps) { - note ("frames per second differ"); + note (ERROR, "frames per second differ"); return false; } if (_length != other._length) { - note ("lengths differ"); + note (ERROR, "lengths differ"); return false; } if (_reels.size() != other._reels.size()) { - note ("reel counts differ"); + note (ERROR, "reel counts differ"); return false; } diff --git a/src/dcp.h b/src/dcp.h index 7e9b4edc..9e2e8a02 100644 --- a/src/dcp.h +++ b/src/dcp.h @@ -84,7 +84,7 @@ public: std::list > assets () const; - bool equals (CPL const & other, EqualityOptions options, boost::function note) const; + bool equals (CPL const & other, EqualityOptions options, boost::function note) const; void write_xml () const; void write_to_assetmap (std::ostream& s) const; @@ -144,7 +144,7 @@ public: * @param options Options to define what "equality" means. * @return true if the DCPs are equal according to EqualityOptions, otherwise false. */ - bool equals (DCP const & other, EqualityOptions options, boost::function note) const; + bool equals (DCP const & other, EqualityOptions options, boost::function note) const; /** Add a CPL to this DCP. * @param cpl CPL to add. diff --git a/src/mxf_asset.cc b/src/mxf_asset.cc index cf265712..9b491dd7 100644 --- a/src/mxf_asset.cc +++ b/src/mxf_asset.cc @@ -71,31 +71,31 @@ MXFAsset::fill_writer_info (ASDCP::WriterInfo* writer_info, string uuid) } bool -MXFAsset::equals (shared_ptr other, EqualityOptions, boost::function note) const +MXFAsset::equals (shared_ptr other, EqualityOptions, boost::function note) const { shared_ptr other_mxf = dynamic_pointer_cast (other); if (!other_mxf) { - note ("comparing an MXF asset with a non-MXF asset"); + note (ERROR, "comparing an MXF asset with a non-MXF asset"); return false; } if (_file_name != other_mxf->_file_name) { - note ("MXF names differ"); + note (ERROR, "MXF names differ"); return false; } if (_edit_rate != other_mxf->_edit_rate) { - note ("MXF edit rates differ"); + note (ERROR, "MXF edit rates differ"); return false; } if (_intrinsic_duration != other_mxf->_intrinsic_duration) { - note ("MXF intrinsic durations differ"); + note (ERROR, "MXF intrinsic durations differ"); return false; } if (_duration != other_mxf->_duration) { - note ("MXF durations differ"); + note (ERROR, "MXF durations differ"); return false; } diff --git a/src/mxf_asset.h b/src/mxf_asset.h index 0c98f3c6..29b3c1b0 100644 --- a/src/mxf_asset.h +++ b/src/mxf_asset.h @@ -61,7 +61,7 @@ public: _intrinsic_duration = d; } - virtual bool equals (boost::shared_ptr other, EqualityOptions opt, boost::function note) const; + virtual bool equals (boost::shared_ptr other, EqualityOptions opt, boost::function note) const; int intrinsic_duration () const { return _intrinsic_duration; diff --git a/src/picture_asset.cc b/src/picture_asset.cc index 807564c5..4b775980 100644 --- a/src/picture_asset.cc +++ b/src/picture_asset.cc @@ -79,7 +79,7 @@ PictureAsset::write_to_cpl (ostream& s) const } bool -PictureAsset::equals (shared_ptr other, EqualityOptions opt, boost::function note) const +PictureAsset::equals (shared_ptr other, EqualityOptions opt, boost::function note) const { if (!MXFAsset::equals (other, opt, note)) { return false; @@ -125,7 +125,7 @@ PictureAsset::equals (shared_ptr other, EqualityOptions opt, boost: // desc_A.QuantizationDefault != desc_B.QuantizationDefault ) { - note ("video MXF picture descriptors differ"); + note (ERROR, "video MXF picture descriptors differ"); return false; } @@ -248,7 +248,7 @@ MonoPictureAsset::get_frame (int n) const bool -MonoPictureAsset::equals (shared_ptr other, EqualityOptions opt, boost::function note) const +MonoPictureAsset::equals (shared_ptr other, EqualityOptions opt, boost::function note) const { if (!PictureAsset::equals (other, opt, note)) { return false; @@ -258,6 +258,7 @@ MonoPictureAsset::equals (shared_ptr other, EqualityOptions opt, bo assert (other_picture); for (int i = 0; i < _intrinsic_duration; ++i) { + note (PROGRESS, "Comparing video frame " + lexical_cast (i) + " of " + lexical_cast (_intrinsic_duration)); shared_ptr frame_A = get_frame (i); shared_ptr frame_B = other_picture->get_frame (i); @@ -274,7 +275,7 @@ MonoPictureAsset::equals (shared_ptr other, EqualityOptions opt, bo } bool -StereoPictureAsset::equals (shared_ptr other, EqualityOptions opt, boost::function note) const +StereoPictureAsset::equals (shared_ptr other, EqualityOptions opt, boost::function note) const { if (!PictureAsset::equals (other, opt, note)) { return false; @@ -309,7 +310,7 @@ StereoPictureAsset::equals (shared_ptr other, EqualityOptions opt, bool PictureAsset::frame_buffer_equals ( - int frame, EqualityOptions opt, boost::function note, + int frame, EqualityOptions opt, boost::function note, uint8_t const * data_A, unsigned int size_A, uint8_t const * data_B, unsigned int size_B ) const { @@ -325,7 +326,7 @@ PictureAsset::frame_buffer_equals ( /* Compare them */ if (image_A->numcomps != image_B->numcomps) { - note ("image component counts for frame " + lexical_cast(frame) + " differ"); + note (ERROR, "image component counts for frame " + lexical_cast(frame) + " differ"); return false; } @@ -336,7 +337,7 @@ PictureAsset::frame_buffer_equals ( for (int c = 0; c < image_A->numcomps; ++c) { if (image_A->comps[c].w != image_B->comps[c].w || image_A->comps[c].h != image_B->comps[c].h) { - note ("image sizes for frame " + lexical_cast(frame) + " differ"); + note (ERROR, "image sizes for frame " + lexical_cast(frame) + " differ"); return false; } @@ -363,7 +364,7 @@ PictureAsset::frame_buffer_equals ( double const std_dev = sqrt (double (total_squared_deviation) / abs_diffs.size()); if (mean > opt.max_mean_pixel_error || std_dev > opt.max_std_dev_pixel_error) { - note ("mean or standard deviation out of range for " + lexical_cast(frame)); + note (ERROR, "mean or standard deviation out of range for " + lexical_cast(frame)); return false; } diff --git a/src/picture_asset.h b/src/picture_asset.h index f4d4d7a4..c9226b1f 100644 --- a/src/picture_asset.h +++ b/src/picture_asset.h @@ -63,7 +63,7 @@ public: */ void write_to_cpl (std::ostream& s) const; - bool equals (boost::shared_ptr other, EqualityOptions opt, boost::function note) const; + bool equals (boost::shared_ptr other, EqualityOptions opt, boost::function note) const; Size size () const { return _size; @@ -72,7 +72,7 @@ public: protected: bool frame_buffer_equals ( - int frame, EqualityOptions opt, boost::function note, + int frame, EqualityOptions opt, boost::function note, uint8_t const * data_A, unsigned int size_A, uint8_t const * data_B, unsigned int size_B ) const; @@ -210,7 +210,7 @@ public: boost::shared_ptr start_write (bool); boost::shared_ptr get_frame (int n) const; - bool equals (boost::shared_ptr other, EqualityOptions opt, boost::function note) const; + bool equals (boost::shared_ptr other, EqualityOptions opt, boost::function note) const; private: std::string path_from_list (int f, std::vector const & files) const; @@ -224,7 +224,7 @@ public: StereoPictureAsset (std::string directory, std::string mxf_name, int fps, int intrinsic_duration); boost::shared_ptr get_frame (int n) const; - bool equals (boost::shared_ptr other, EqualityOptions opt, boost::function note) const; + bool equals (boost::shared_ptr other, EqualityOptions opt, boost::function note) const; }; diff --git a/src/reel.cc b/src/reel.cc index 096acf19..86533ea2 100644 --- a/src/reel.cc +++ b/src/reel.cc @@ -50,10 +50,10 @@ Reel::write_to_cpl (ostream& s) const } bool -Reel::equals (boost::shared_ptr other, EqualityOptions opt, boost::function note) const +Reel::equals (boost::shared_ptr other, EqualityOptions opt, boost::function note) const { if ((_main_picture && !other->_main_picture) || (!_main_picture && other->_main_picture)) { - note ("reel has different assets"); + note (ERROR, "reel has different assets"); return false; } @@ -62,7 +62,7 @@ Reel::equals (boost::shared_ptr other, EqualityOptions opt, boost::f } if ((_main_sound && !other->_main_sound) || (!_main_sound && other->_main_sound)) { - note ("reel has different assets"); + note (ERROR, "reel has different assets"); return false; } @@ -71,7 +71,7 @@ Reel::equals (boost::shared_ptr other, EqualityOptions opt, boost::f } if ((_main_subtitle && !other->_main_subtitle) || (!_main_subtitle && other->_main_subtitle)) { - note ("reel has different assets"); + note (ERROR, "reel has different assets"); return false; } diff --git a/src/reel.h b/src/reel.h index b0dfc84d..93dc0920 100644 --- a/src/reel.h +++ b/src/reel.h @@ -56,7 +56,7 @@ public: void write_to_cpl (std::ostream & s) const; - bool equals (boost::shared_ptr other, EqualityOptions opt, boost::function notes) const; + bool equals (boost::shared_ptr other, EqualityOptions opt, boost::function notes) const; private: boost::shared_ptr _main_picture; diff --git a/src/sound_asset.cc b/src/sound_asset.cc index da6e72bc..6e29aadf 100644 --- a/src/sound_asset.cc +++ b/src/sound_asset.cc @@ -222,7 +222,7 @@ SoundAsset::write_to_cpl (ostream& s) const } bool -SoundAsset::equals (shared_ptr other, EqualityOptions opt, boost::function note) const +SoundAsset::equals (shared_ptr other, EqualityOptions opt, boost::function note) const { if (!MXFAsset::equals (other, opt, note)) { return false; @@ -260,7 +260,7 @@ SoundAsset::equals (shared_ptr other, EqualityOptions opt, boost::f // desc_A.ChannelFormat != desc_B.ChannelFormat || ) { - note ("audio MXF picture descriptors differ"); + note (ERROR, "audio MXF picture descriptors differ"); return false; } @@ -277,7 +277,7 @@ SoundAsset::equals (shared_ptr other, EqualityOptions opt, boost::f } if (buffer_A.Size() != buffer_B.Size()) { - note ("sizes of audio data for frame " + lexical_cast(i) + " differ"); + note (ERROR, "sizes of audio data for frame " + lexical_cast(i) + " differ"); return false; } @@ -285,7 +285,7 @@ SoundAsset::equals (shared_ptr other, EqualityOptions opt, boost::f 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 ("PCM data difference of " + lexical_cast (d)); + note (ERROR, "PCM data difference of " + lexical_cast (d)); return false; } } diff --git a/src/sound_asset.h b/src/sound_asset.h index dedebac3..9e6e75cf 100644 --- a/src/sound_asset.h +++ b/src/sound_asset.h @@ -129,7 +129,7 @@ public: */ void write_to_cpl (std::ostream& s) const; - bool equals (boost::shared_ptr other, EqualityOptions opt, boost::function note) const; + bool equals (boost::shared_ptr other, EqualityOptions opt, boost::function note) const; boost::shared_ptr get_frame (int n) const; diff --git a/src/subtitle_asset.h b/src/subtitle_asset.h index b3936dc2..1e31df2b 100644 --- a/src/subtitle_asset.h +++ b/src/subtitle_asset.h @@ -184,9 +184,9 @@ public: SubtitleAsset (std::string directory, std::string movie_title, std::string language); void write_to_cpl (std::ostream&) const; - virtual bool equals (boost::shared_ptr, EqualityOptions, boost::function note) const { + virtual bool equals (boost::shared_ptr, EqualityOptions, boost::function note) const { /* XXX */ - note ("subtitle assets not compared yet"); + note (ERROR, "subtitle assets not compared yet"); return true; } diff --git a/src/types.h b/src/types.h index ebcfb838..4c824080 100644 --- a/src/types.h +++ b/src/types.h @@ -107,6 +107,11 @@ struct EqualityOptions { int max_audio_sample_error; }; +enum NoteType { + PROGRESS, + ERROR +}; + /** @class Color * @brief An RGB color (aka colour). */ diff --git a/tools/dcpdiff.cc b/tools/dcpdiff.cc index 6d55586d..7913c533 100644 --- a/tools/dcpdiff.cc +++ b/tools/dcpdiff.cc @@ -8,12 +8,15 @@ using namespace std; using namespace boost; using namespace libdcp; +static bool verbose = false; + static void help (string n) { cerr << "Syntax: " << n << " [OPTION] \n" - << " -v, --version show libdcp version\n" + << " -V, --version show libdcp version\n" << " -h, --help show this help\n" + << " -v, --verbose be verbose\n" << "\n" << "The s are the DCP directories to compare.\n" << "Comparison is of metadata and content, ignoring timestamps\n" @@ -21,9 +24,11 @@ help (string n) } void -note (string n) +note (NoteType t, string n) { - cout << " " << n << "\n"; + if (t == ERROR || (t == PROGRESS && verbose)) { + cout << " " << n << "\n"; + } } int @@ -34,24 +39,28 @@ main (int argc, char* argv[]) int option_index = 0; while (1) { static struct option long_options[] = { - { "version", no_argument, 0, 'v'}, + { "version", no_argument, 0, 'V'}, { "help", no_argument, 0, 'h'}, + { "verbose", no_argument, 0, 'v'}, { 0, 0, 0, 0 } }; - int c = getopt_long (argc, argv, "vh", long_options, &option_index); + int c = getopt_long (argc, argv, "Vhv", long_options, &option_index); if (c == -1) { break; } switch (c) { - case 'v': + case 'V': cout << "dcpdiff version " << LIBDCP_VERSION << "\n"; exit (EXIT_SUCCESS); case 'h': help (argv[0]); exit (EXIT_SUCCESS); + case 'v': + verbose = true; + break; } } @@ -93,7 +102,7 @@ main (int argc, char* argv[]) /* I think this is just below the LSB at 16-bits (ie the 8th most significant bit at 24-bit) */ options.max_audio_sample_error = 255; - bool const equals = a->equals (*b, options, boost::bind (note, _1)); + bool const equals = a->equals (*b, options, boost::bind (note, _1, _2)); if (equals) { exit (EXIT_SUCCESS); -- cgit v1.2.3 From 2ad4929f4b3fec0413633c00364f4a6fda3e6c0c Mon Sep 17 00:00:00 2001 From: Carl Hetherington Date: Tue, 16 Apr 2013 09:54:23 +0100 Subject: Merge and add option to ignore differing MXF names. --- src/mxf_asset.cc | 6 ++++-- src/types.h | 2 ++ tools/dcpdiff.cc | 7 ++++++- 3 files changed, 12 insertions(+), 3 deletions(-) diff --git a/src/mxf_asset.cc b/src/mxf_asset.cc index 9b491dd7..144532f8 100644 --- a/src/mxf_asset.cc +++ b/src/mxf_asset.cc @@ -71,7 +71,7 @@ MXFAsset::fill_writer_info (ASDCP::WriterInfo* writer_info, string uuid) } bool -MXFAsset::equals (shared_ptr other, EqualityOptions, boost::function note) const +MXFAsset::equals (shared_ptr other, EqualityOptions opt, boost::function note) const { shared_ptr other_mxf = dynamic_pointer_cast (other); if (!other_mxf) { @@ -81,7 +81,9 @@ MXFAsset::equals (shared_ptr other, EqualityOptions, boost::functio if (_file_name != other_mxf->_file_name) { note (ERROR, "MXF names differ"); - return false; + if (!opt.mxf_names_can_differ) { + return false; + } } if (_edit_rate != other_mxf->_edit_rate) { diff --git a/src/types.h b/src/types.h index 4c824080..b6372e9a 100644 --- a/src/types.h +++ b/src/types.h @@ -100,11 +100,13 @@ struct EqualityOptions { : max_mean_pixel_error (0) , max_std_dev_pixel_error (0) , max_audio_sample_error (0) + , mxf_names_can_differ (false) {} double max_mean_pixel_error; double max_std_dev_pixel_error; int max_audio_sample_error; + bool mxf_names_can_differ; }; enum NoteType { diff --git a/tools/dcpdiff.cc b/tools/dcpdiff.cc index 7913c533..6db45a1b 100644 --- a/tools/dcpdiff.cc +++ b/tools/dcpdiff.cc @@ -17,6 +17,7 @@ help (string n) << " -V, --version show libdcp version\n" << " -h, --help show this help\n" << " -v, --verbose be verbose\n" + << " -n, --names allow differing MXF names\n" << "\n" << "The s are the DCP directories to compare.\n" << "Comparison is of metadata and content, ignoring timestamps\n" @@ -42,10 +43,11 @@ main (int argc, char* argv[]) { "version", no_argument, 0, 'V'}, { "help", no_argument, 0, 'h'}, { "verbose", no_argument, 0, 'v'}, + { "names", no_argument, 0, 'n'}, { 0, 0, 0, 0 } }; - int c = getopt_long (argc, argv, "Vhv", long_options, &option_index); + int c = getopt_long (argc, argv, "Vhvn", long_options, &option_index); if (c == -1) { break; @@ -61,6 +63,9 @@ main (int argc, char* argv[]) case 'v': verbose = true; break; + case 'n': + options.mxf_names_can_differ = true; + break; } } -- cgit v1.2.3 From 9ce517d0c789e0e1ef98f25e3449a75945fc62ab Mon Sep 17 00:00:00 2001 From: Carl Hetherington Date: Tue, 16 Apr 2013 13:36:20 +0100 Subject: Add a couple of notes. --- src/picture_asset.cc | 3 +++ src/types.h | 3 ++- tools/dcpdiff.cc | 2 +- 3 files changed, 6 insertions(+), 2 deletions(-) diff --git a/src/picture_asset.cc b/src/picture_asset.cc index 4b775980..f2982b47 100644 --- a/src/picture_asset.cc +++ b/src/picture_asset.cc @@ -315,6 +315,7 @@ PictureAsset::frame_buffer_equals ( ) const { if (size_A == size_B && memcmp (data_A, data_B, size_A) == 0) { + note (NOTE, "J2K identical"); /* Easy result; the J2K data is identical */ return true; } @@ -367,6 +368,8 @@ PictureAsset::frame_buffer_equals ( note (ERROR, "mean or standard deviation out of range for " + lexical_cast(frame)); return false; } + + note (NOTE, "mean difference " + lexical_cast (mean) + ", deviation " + lexical_cast (std_dev)); opj_image_destroy (image_A); opj_image_destroy (image_B); diff --git a/src/types.h b/src/types.h index 4c824080..928e6a30 100644 --- a/src/types.h +++ b/src/types.h @@ -109,7 +109,8 @@ struct EqualityOptions { enum NoteType { PROGRESS, - ERROR + ERROR, + NOTE }; /** @class Color diff --git a/tools/dcpdiff.cc b/tools/dcpdiff.cc index 7913c533..b4c58b36 100644 --- a/tools/dcpdiff.cc +++ b/tools/dcpdiff.cc @@ -26,7 +26,7 @@ help (string n) void note (NoteType t, string n) { - if (t == ERROR || (t == PROGRESS && verbose)) { + if (t == ERROR || verbose) { cout << " " << n << "\n"; } } -- cgit v1.2.3 From 68301a6fd61adac018b96f3616f07ca5f90698e1 Mon Sep 17 00:00:00 2001 From: Carl Hetherington Date: Tue, 16 Apr 2013 16:27:45 +0100 Subject: Add cscript. --- cscript | 2 ++ 1 file changed, 2 insertions(+) create mode 100644 cscript diff --git a/cscript b/cscript new file mode 100644 index 00000000..0a04589d --- /dev/null +++ b/cscript @@ -0,0 +1,2 @@ +builds = ['source'] + -- cgit v1.2.3 From 4e374e18ce142e3418a74d19cd78d3cf9e416fc8 Mon Sep 17 00:00:00 2001 From: Carl Hetherington Date: Wed, 17 Apr 2013 10:42:31 +0100 Subject: cscript tweak. --- cscript | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cscript b/cscript index 0a04589d..501d3548 100644 --- a/cscript +++ b/cscript @@ -1,2 +1,2 @@ -builds = ['source'] +release_targets = ['source'] -- cgit v1.2.3 From 77c46d57b694506e0834244dde1616c63771f0e6 Mon Sep 17 00:00:00 2001 From: Carl Hetherington Date: Wed, 17 Apr 2013 13:17:52 +0100 Subject: Add build() method to cscript. --- cscript | 3 +++ 1 file changed, 3 insertions(+) diff --git a/cscript b/cscript index 501d3548..18837ad8 100644 --- a/cscript +++ b/cscript @@ -1,2 +1,5 @@ release_targets = ['source'] +def build(prefix): + command('./waf configure --prefix=%s build install' % prefix) + -- cgit v1.2.3 From 3b1afd9479b20b0374d8fa370f82b806b4465a6d Mon Sep 17 00:00:00 2001 From: Carl Hetherington Date: Wed, 17 Apr 2013 13:23:53 +0100 Subject: Add paths. --- cscript | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/cscript b/cscript index 18837ad8..f5590c55 100644 --- a/cscript +++ b/cscript @@ -1,5 +1,6 @@ release_targets = ['source'] def build(prefix): - command('./waf configure --prefix=%s build install' % prefix) + command('CXXFLAGS=-I%s/include LINKFLAGS=-L%s/lib PKG_CONFIG_PATH=%s/lib/pkgconfig ./waf configure --prefix=%s build install' % (prefix, prefix, prefix, prefix)) + -- cgit v1.2.3 From 6da141cf4717903a979c80a5bc0a70ef354013b7 Mon Sep 17 00:00:00 2001 From: Carl Hetherington Date: Wed, 17 Apr 2013 20:39:50 +0100 Subject: cscript must build statically. --- cscript | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/cscript b/cscript index f5590c55..f0e28128 100644 --- a/cscript +++ b/cscript @@ -1,6 +1,7 @@ release_targets = ['source'] def build(prefix): - command('CXXFLAGS=-I%s/include LINKFLAGS=-L%s/lib PKG_CONFIG_PATH=%s/lib/pkgconfig ./waf configure --prefix=%s build install' % (prefix, prefix, prefix, prefix)) + command("""CXXFLAGS=-I%s/include LINKFLAGS=-L%s/lib PKG_CONFIG_PATH=%s/lib/pkgconfig + ./waf configure --static-openjpeg --static-libdcp --prefix=%s build install""" % (prefix, prefix, prefix, prefix)) -- cgit v1.2.3 From 3d88bdfd57f4f8a1a716ec0f7f7ab9438af9299d Mon Sep 17 00:00:00 2001 From: Carl Hetherington Date: Wed, 17 Apr 2013 20:42:20 +0100 Subject: Fix build method. --- cscript | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/cscript b/cscript index f0e28128..0457ebbf 100644 --- a/cscript +++ b/cscript @@ -1,7 +1,7 @@ release_targets = ['source'] -def build(prefix): +def build(dep_prefix, install_prefix): command("""CXXFLAGS=-I%s/include LINKFLAGS=-L%s/lib PKG_CONFIG_PATH=%s/lib/pkgconfig - ./waf configure --static-openjpeg --static-libdcp --prefix=%s build install""" % (prefix, prefix, prefix, prefix)) + ./waf configure --static-openjpeg --static-libdcp --prefix=%s build install""" % (dep_prefix, dep_prefix, dep_prefix, install_prefix)) -- cgit v1.2.3 From 178fadde4c7b4c0816f06ead30030fa29e7d13c7 Mon Sep 17 00:00:00 2001 From: Carl Hetherington Date: Thu, 18 Apr 2013 00:26:44 +0100 Subject: cdist tinkering. --- cbuild | 16 ++++++++++++++++ cscript | 13 ++++++++++--- 2 files changed, 26 insertions(+), 3 deletions(-) create mode 100755 cbuild diff --git a/cbuild b/cbuild new file mode 100755 index 00000000..59beeb13 --- /dev/null +++ b/cbuild @@ -0,0 +1,16 @@ +#!/usr/bin/python + +import argparse +import os + +parser = argparse.ArgumentParser() +parser.add_argument('command') +parser.add_argument('-p', '--prefix', help='prefix', required=True) +args = parser.parse_args() + +def command(c): + print c + os.system(c) + +if args.command == 'build': + command('./waf configure --prefix=%s build install' % args.prefix) diff --git a/cscript b/cscript index 0457ebbf..9e0eaaac 100644 --- a/cscript +++ b/cscript @@ -1,7 +1,14 @@ release_targets = ['source'] -def build(dep_prefix, install_prefix): - command("""CXXFLAGS=-I%s/include LINKFLAGS=-L%s/lib PKG_CONFIG_PATH=%s/lib/pkgconfig - ./waf configure --static-openjpeg --static-libdcp --prefix=%s build install""" % (dep_prefix, dep_prefix, dep_prefix, install_prefix)) +def build(dep_prefix, install_prefix, target, static, parallel): + configure = './waf configure --prefix=%s' % install_prefix + if static: + configure += ' --static-openjpeg --static-libdcp' + + var = "CXXFLAGS=-I%s/include LINKFLAGS=-L%s/lib PKG_CONFIG_PATH=%s/lib/pkgconfig" % (dep_prefix, dep_prefix, dep_prefix) + + command('%s %s' % (var, configure)) + command('./waf build install') + -- cgit v1.2.3 From 160d55ae1f3fe8d84ade777154c673d350e3c02c Mon Sep 17 00:00:00 2001 From: Carl Hetherington Date: Thu, 18 Apr 2013 21:40:15 +0100 Subject: cdist bits. --- cbuild | 7 ++++++- cscript | 21 ++++++++------------- 2 files changed, 14 insertions(+), 14 deletions(-) diff --git a/cbuild b/cbuild index 59beeb13..836dabaa 100755 --- a/cbuild +++ b/cbuild @@ -6,6 +6,7 @@ import os parser = argparse.ArgumentParser() parser.add_argument('command') parser.add_argument('-p', '--prefix', help='prefix', required=True) +parser.add_argument('-s', '--static', help='build statically', action='store_true') args = parser.parse_args() def command(c): @@ -13,4 +14,8 @@ def command(c): os.system(c) if args.command == 'build': - command('./waf configure --prefix=%s build install' % args.prefix) + cmd = './waf configure --prefix=%s' % args.prefix + if args.static: + cmd += ' --static-libdcp --static-openjpeg' + cmd += ' build install' + command(cmd) diff --git a/cscript b/cscript index 9e0eaaac..09bd76bb 100644 --- a/cscript +++ b/cscript @@ -1,14 +1,9 @@ -release_targets = ['source'] - -def build(dep_prefix, install_prefix, target, static, parallel): - configure = './waf configure --prefix=%s' % install_prefix - if static: - configure += ' --static-openjpeg --static-libdcp' - - var = "CXXFLAGS=-I%s/include LINKFLAGS=-L%s/lib PKG_CONFIG_PATH=%s/lib/pkgconfig" % (dep_prefix, dep_prefix, dep_prefix) - - command('%s %s' % (var, configure)) - command('./waf build install') - - +def build(env, target): + cmd = './waf configure --prefix=%s' % env.work_dir(True) + if target.platform == 'linux': + cmd += ' --static-libdcp --static-openjpeg' + elif target.platform == 'windows': + cmd += ' --target-windows' + env.command(cmd) + env.command('./waf build install') -- cgit v1.2.3 From ba39445dc02a21fd29562ba0693dd7e3d9f3308b Mon Sep 17 00:00:00 2001 From: Carl Hetherington Date: Thu, 18 Apr 2013 23:05:23 +0100 Subject: cscript. --- cscript | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cscript b/cscript index 09bd76bb..459ddc3a 100644 --- a/cscript +++ b/cscript @@ -1,6 +1,6 @@ def build(env, target): - cmd = './waf configure --prefix=%s' % env.work_dir(True) + cmd = './waf configure --prefix=%s' % env.work_dir_cscript() if target.platform == 'linux': cmd += ' --static-libdcp --static-openjpeg' elif target.platform == 'windows': -- cgit v1.2.3 From 305d5c4e32c005b3e481082cda0fb968e88e5a8b Mon Sep 17 00:00:00 2001 From: Carl Hetherington Date: Thu, 18 Apr 2013 23:22:44 +0100 Subject: Bump version --- wscript | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/wscript b/wscript index de31ce1f..dfb06278 100644 --- a/wscript +++ b/wscript @@ -2,7 +2,7 @@ import subprocess import os APPNAME = 'libdcp' -VERSION = '0.45pre' +VERSION = '0.45beta1' def options(opt): opt.load('compiler_cxx') -- cgit v1.2.3 From 45a9430c3601ce689819efc43dff9e2b1a1b404d Mon Sep 17 00:00:00 2001 From: Carl Hetherington Date: Thu, 18 Apr 2013 23:23:11 +0100 Subject: Bump version --- wscript | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/wscript b/wscript index dfb06278..9ed59bd6 100644 --- a/wscript +++ b/wscript @@ -2,7 +2,7 @@ import subprocess import os APPNAME = 'libdcp' -VERSION = '0.45beta1' +VERSION = '0.45' def options(opt): opt.load('compiler_cxx') -- cgit v1.2.3 From 959bf5088ad3144915f86e92a8d12183a3a3298d Mon Sep 17 00:00:00 2001 From: Carl Hetherington Date: Thu, 18 Apr 2013 23:23:11 +0100 Subject: Bump version --- wscript | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/wscript b/wscript index 9ed59bd6..01fd4a7b 100644 --- a/wscript +++ b/wscript @@ -2,7 +2,7 @@ import subprocess import os APPNAME = 'libdcp' -VERSION = '0.45' +VERSION = '0.46pre' def options(opt): opt.load('compiler_cxx') -- cgit v1.2.3 From 0619a2de893636c19d0e654532303893e96ab1a4 Mon Sep 17 00:00:00 2001 From: Carl Hetherington Date: Fri, 19 Apr 2013 08:05:58 +0100 Subject: Try to fix. --- src/types.h | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/types.h b/src/types.h index 3fcbd58f..b1de4a0f 100644 --- a/src/types.h +++ b/src/types.h @@ -109,6 +109,9 @@ struct EqualityOptions { bool mxf_names_can_differ; }; +/* Win32 defines this */ +#undef ERROR + enum NoteType { PROGRESS, ERROR, -- cgit v1.2.3 From 2728469db21a91ce114ffbe9b9212a96fa3e1f54 Mon Sep 17 00:00:00 2001 From: Carl Hetherington Date: Fri, 19 Apr 2013 08:27:26 +0100 Subject: Bump version --- wscript | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/wscript b/wscript index 01fd4a7b..f7520b48 100644 --- a/wscript +++ b/wscript @@ -2,7 +2,7 @@ import subprocess import os APPNAME = 'libdcp' -VERSION = '0.46pre' +VERSION = '0.46' def options(opt): opt.load('compiler_cxx') -- cgit v1.2.3 From 7836aa40bdde4354b2a816995faa09fa609917cf Mon Sep 17 00:00:00 2001 From: Carl Hetherington Date: Fri, 19 Apr 2013 08:27:26 +0100 Subject: Bump version --- wscript | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/wscript b/wscript index f7520b48..c5ceb102 100644 --- a/wscript +++ b/wscript @@ -2,7 +2,7 @@ import subprocess import os APPNAME = 'libdcp' -VERSION = '0.46' +VERSION = '0.47pre' def options(opt): opt.load('compiler_cxx') -- cgit v1.2.3 From f985e5e8cccaa44704d51dcfea3cc5042e22781f Mon Sep 17 00:00:00 2001 From: Carl Hetherington Date: Wed, 24 Apr 2013 13:48:04 +0100 Subject: Add make_doxygen to cscript. --- cscript | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/cscript b/cscript index 459ddc3a..9f50e689 100644 --- a/cscript +++ b/cscript @@ -7,3 +7,7 @@ def build(env, target): cmd += ' --target-windows' env.command(cmd) env.command('./waf build install') + +def make_doxygen(env): + env.command('doxygen') + return os.path.abspath('build/doc/html') -- cgit v1.2.3 From 8cb727dc875648b5a13b4209a771bffd3747b8ff Mon Sep 17 00:00:00 2001 From: Carl Hetherington Date: Wed, 24 Apr 2013 16:02:28 +0100 Subject: cscript tweak. --- cscript | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/cscript b/cscript index 9f50e689..3510f709 100644 --- a/cscript +++ b/cscript @@ -10,4 +10,8 @@ def build(env, target): def make_doxygen(env): env.command('doxygen') + try: + os.makedirs('build/doc') + except: + pass return os.path.abspath('build/doc/html') -- cgit v1.2.3 From 78957123f6e70e9460fd1707a047f221037e5d30 Mon Sep 17 00:00:00 2001 From: Carl Hetherington Date: Wed, 24 Apr 2013 16:04:38 +0100 Subject: cscript tweaks. --- cbuild | 21 --------------------- cscript | 2 +- 2 files changed, 1 insertion(+), 22 deletions(-) delete mode 100755 cbuild diff --git a/cbuild b/cbuild deleted file mode 100755 index 836dabaa..00000000 --- a/cbuild +++ /dev/null @@ -1,21 +0,0 @@ -#!/usr/bin/python - -import argparse -import os - -parser = argparse.ArgumentParser() -parser.add_argument('command') -parser.add_argument('-p', '--prefix', help='prefix', required=True) -parser.add_argument('-s', '--static', help='build statically', action='store_true') -args = parser.parse_args() - -def command(c): - print c - os.system(c) - -if args.command == 'build': - cmd = './waf configure --prefix=%s' % args.prefix - if args.static: - cmd += ' --static-libdcp --static-openjpeg' - cmd += ' build install' - command(cmd) diff --git a/cscript b/cscript index 3510f709..468b4b4d 100644 --- a/cscript +++ b/cscript @@ -9,9 +9,9 @@ def build(env, target): env.command('./waf build install') def make_doxygen(env): - env.command('doxygen') try: os.makedirs('build/doc') except: pass + env.command('doxygen') return os.path.abspath('build/doc/html') -- cgit v1.2.3 From 635fdc3e5ab744d064bf93cb164a738489971954 Mon Sep 17 00:00:00 2001 From: Carl Hetherington Date: Wed, 24 Apr 2013 16:05:19 +0100 Subject: cscript tweaks. --- cscript | 1 + 1 file changed, 1 insertion(+) diff --git a/cscript b/cscript index 468b4b4d..9cc47606 100644 --- a/cscript +++ b/cscript @@ -13,5 +13,6 @@ def make_doxygen(env): os.makedirs('build/doc') except: pass + env.command('pwd') env.command('doxygen') return os.path.abspath('build/doc/html') -- cgit v1.2.3 From 085f9fa7a4e389a5579742f20e142513c21bbd82 Mon Sep 17 00:00:00 2001 From: Carl Hetherington Date: Wed, 24 Apr 2013 16:06:09 +0100 Subject: cscript tweaks. --- cscript | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/cscript b/cscript index 9cc47606..18913fa1 100644 --- a/cscript +++ b/cscript @@ -1,3 +1,4 @@ +import os def build(env, target): cmd = './waf configure --prefix=%s' % env.work_dir_cscript() @@ -9,10 +10,6 @@ def build(env, target): env.command('./waf build install') def make_doxygen(env): - try: - os.makedirs('build/doc') - except: - pass - env.command('pwd') + os.makedirs('build/doc') env.command('doxygen') return os.path.abspath('build/doc/html') -- cgit v1.2.3 From 5b6d753439207fcb33b84690bcc22d142a7c3bfa Mon Sep 17 00:00:00 2001 From: Carl Hetherington Date: Mon, 29 Apr 2013 15:22:55 +0100 Subject: Change output gamma correction to be closer to EasyDCP behaviour. --- src/picture_frame.cc | 5 ++--- src/util.cc | 13 +++++++------ src/util.h | 2 +- src/wscript | 1 - src/xyz_srgb_lut.cc | 24 ------------------------ src/xyz_srgb_lut.h | 13 ------------- 6 files changed, 10 insertions(+), 48 deletions(-) delete mode 100644 src/xyz_srgb_lut.cc delete mode 100644 src/xyz_srgb_lut.h diff --git a/src/picture_frame.cc b/src/picture_frame.cc index 98802101..7e6bc1f8 100644 --- a/src/picture_frame.cc +++ b/src/picture_frame.cc @@ -26,7 +26,6 @@ #include "lut.h" #include "util.h" #include "gamma_lut.h" -#include "xyz_srgb_lut.h" #define DCI_GAMMA 2.6 @@ -84,7 +83,7 @@ MonoPictureFrame::argb_frame (int reduce, float srgb_gamma) const { opj_image_t* xyz_frame = decompress_j2k (const_cast (_buffer->RoData()), _buffer->Size(), reduce); assert (xyz_frame->numcomps == 3); - shared_ptr f = xyz_to_rgb (xyz_frame, GammaLUT::cache.get (12, DCI_GAMMA), XYZsRGBLUT::cache.get (12, srgb_gamma)); + shared_ptr f = xyz_to_rgb (xyz_frame, GammaLUT::cache.get (12, DCI_GAMMA), GammaLUT::cache.get (12, 1 / srgb_gamma)); opj_image_destroy (xyz_frame); return f; } @@ -139,7 +138,7 @@ StereoPictureFrame::argb_frame (Eye eye, int reduce, float srgb_gamma) const } assert (xyz_frame->numcomps == 3); - shared_ptr f = xyz_to_rgb (xyz_frame, GammaLUT::cache.get (12, DCI_GAMMA), XYZsRGBLUT::cache.get (12, srgb_gamma)); + shared_ptr f = xyz_to_rgb (xyz_frame, GammaLUT::cache.get (12, DCI_GAMMA), GammaLUT::cache.get (12, 1 / srgb_gamma)); opj_image_destroy (xyz_frame); return f; } diff --git a/src/util.cc b/src/util.cc index 2fae8561..c66e63f5 100644 --- a/src/util.cc +++ b/src/util.cc @@ -35,7 +35,6 @@ #include "types.h" #include "argb_frame.h" #include "gamma_lut.h" -#include "xyz_srgb_lut.h" using std::string; using std::stringstream; @@ -203,11 +202,13 @@ libdcp::decompress_j2k (uint8_t* data, int64_t size, int reduce) * @return RGB image. */ shared_ptr -libdcp::xyz_to_rgb (opj_image_t* xyz_frame, shared_ptr lut_in, shared_ptr lut_out) +libdcp::xyz_to_rgb (opj_image_t* xyz_frame, shared_ptr lut_in, shared_ptr lut_out) { float const dci_coefficient = 48.0 / 52.37; - /* sRGB color matrix for XYZ -> RGB */ + /* sRGB color matrix for XYZ -> RGB. This is the same as the one used by the Fraunhofer + EasyDCP player, I think. + */ float const colour_matrix[3][3] = { { 3.24096989631653, -1.5373831987381, -0.498610764741898 }, @@ -264,9 +265,9 @@ libdcp::xyz_to_rgb (opj_image_t* xyz_frame, shared_ptr lut_in, s d.b = max (d.b, 0.0); /* Out gamma LUT */ - *argb_line++ = lut_out->lut()[(int) (d.b * max_colour)]; - *argb_line++ = lut_out->lut()[(int) (d.g * max_colour)]; - *argb_line++ = lut_out->lut()[(int) (d.r * max_colour)]; + *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; } diff --git a/src/util.h b/src/util.h index 2036a7ce..6332ddc0 100644 --- a/src/util.h +++ b/src/util.h @@ -60,7 +60,7 @@ extern std::string content_kind_to_string (ContentKind kind); extern ContentKind content_kind_from_string (std::string kind); 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 xyz_to_rgb (opj_image_t* xyz_frame, boost::shared_ptr, boost::shared_ptr); +extern boost::shared_ptr xyz_to_rgb (opj_image_t* xyz_frame, boost::shared_ptr, boost::shared_ptr); } diff --git a/src/wscript b/src/wscript index efba2502..3960f2b0 100644 --- a/src/wscript +++ b/src/wscript @@ -31,7 +31,6 @@ def build(bld): util.cc version.cc xml.cc - xyz_srgb_lut.cc """ headers = """ diff --git a/src/xyz_srgb_lut.cc b/src/xyz_srgb_lut.cc deleted file mode 100644 index 3d207195..00000000 --- a/src/xyz_srgb_lut.cc +++ /dev/null @@ -1,24 +0,0 @@ -#include -#include -#include "xyz_srgb_lut.h" - -using namespace libdcp; - -LUTCache XYZsRGBLUT::cache; - -XYZsRGBLUT::XYZsRGBLUT(int bits, float gamma) - : LUT (bits, gamma) -{ - int const bit_length = pow(2, bits); - - for (int i = 0; i < bit_length; ++i) { - float v = float(i) / (bit_length - 1); - if (v < (0.04045 / 12.92)) { - v *= 12.92; - } else { - v = (1.055 * pow (v, (1 / gamma))) - 0.055; - } - - _lut[i] = int(v * 255); - } -} diff --git a/src/xyz_srgb_lut.h b/src/xyz_srgb_lut.h deleted file mode 100644 index 63f89178..00000000 --- a/src/xyz_srgb_lut.h +++ /dev/null @@ -1,13 +0,0 @@ -#include "lut.h" -#include "lut_cache.h" - -namespace libdcp { - -class XYZsRGBLUT : public LUT -{ -public: - XYZsRGBLUT(int colour_depth, float gamma); - static LUTCache cache; -}; - -} -- cgit v1.2.3 From 1a18b2d2552179ad9d8c550439043b23314fc750 Mon Sep 17 00:00:00 2001 From: Carl Hetherington Date: Mon, 29 Apr 2013 15:23:13 +0100 Subject: Bump version --- wscript | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/wscript b/wscript index c5ceb102..9fce01de 100644 --- a/wscript +++ b/wscript @@ -2,7 +2,7 @@ import subprocess import os APPNAME = 'libdcp' -VERSION = '0.47pre' +VERSION = '0.47' def options(opt): opt.load('compiler_cxx') -- cgit v1.2.3 From 49fb66ee26be51bee67ae552c9cf4f8d21495b79 Mon Sep 17 00:00:00 2001 From: Carl Hetherington Date: Mon, 29 Apr 2013 15:23:13 +0100 Subject: Bump version --- wscript | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/wscript b/wscript index 9fce01de..f7f7cb88 100644 --- a/wscript +++ b/wscript @@ -2,7 +2,7 @@ import subprocess import os APPNAME = 'libdcp' -VERSION = '0.47' +VERSION = '0.48pre' def options(opt): opt.load('compiler_cxx') -- cgit v1.2.3 From 568d433830710baa7b0c64a5b7491758beb95b1c Mon Sep 17 00:00:00 2001 From: Carl Hetherington Date: Thu, 2 May 2013 17:20:04 +0100 Subject: Move edit rate / durations / entry point etc. into Asset from MXFAsset. --- src/asset.cc | 28 +++++++++++++++++++++++++++- src/asset.h | 40 ++++++++++++++++++++++++++++++++++++++-- src/dcp.cc | 5 ++++- src/mxf_asset.cc | 29 +++++------------------------ src/mxf_asset.h | 28 ---------------------------- 5 files changed, 74 insertions(+), 56 deletions(-) diff --git a/src/asset.cc b/src/asset.cc index 305fc9a7..58c821a7 100644 --- a/src/asset.cc +++ b/src/asset.cc @@ -35,10 +35,14 @@ using namespace std; using namespace boost; using namespace libdcp; -Asset::Asset (string directory, string file_name) +Asset::Asset (string directory, string file_name, int edit_rate, int intrinsic_duration) : _directory (directory) , _file_name (file_name) , _uuid (make_uuid ()) + , _edit_rate (edit_rate) + , _entry_point (0) + , _intrinsic_duration (intrinsic_duration) + , _duration (intrinsic_duration) { if (_file_name.empty ()) { _file_name = _uuid + ".xml"; @@ -91,3 +95,25 @@ Asset::digest () const return _digest; } + + +bool +Asset::equals (shared_ptr other, EqualityOptions, boost::function note) const +{ + if (_edit_rate != other->_edit_rate) { + note (ERROR, "MXF edit rates differ"); + return false; + } + + if (_intrinsic_duration != other->_intrinsic_duration) { + note (ERROR, "MXF intrinsic durations differ"); + return false; + } + + if (_duration != other->_duration) { + note (ERROR, "MXF durations differ"); + return false; + } + + return true; +} diff --git a/src/asset.h b/src/asset.h index 1b1bf4c6..06c66356 100644 --- a/src/asset.h +++ b/src/asset.h @@ -48,7 +48,7 @@ public: * @param directory Directory where our XML or MXF file is. * @param file_name Name of our file within directory, or empty to make one up based on UUID. */ - Asset (std::string directory, std::string file_name = ""); + Asset (std::string directory, std::string file_name = "", int edit_rate = 0, int intrinsic_duration = 0); virtual ~Asset() {} @@ -80,8 +80,36 @@ public: void set_file_name (std::string f) { _file_name = f; } + + int entry_point () const { + return _entry_point; + } + + 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; + } - virtual bool equals (boost::shared_ptr other, EqualityOptions opt, boost::function) const = 0; + void set_duration (int d) { + _duration = d; + } + + void set_intrinsic_duration (int d) { + _intrinsic_duration = d; + } + + virtual bool equals (boost::shared_ptr other, EqualityOptions opt, boost::function) const; protected: @@ -93,6 +121,14 @@ protected: std::string _file_name; /** Our UUID */ std::string _uuid; + /** The edit rate; this is normally equal to the number of video frames per second */ + int _edit_rate; + /** Start point to present in frames */ + int _entry_point; + /** Total length in frames */ + int _intrinsic_duration; + /** Length to present in frames */ + int _duration; private: /** Digest of our MXF or XML file */ diff --git a/src/dcp.cc b/src/dcp.cc index bac266ab..3fe69e40 100644 --- a/src/dcp.cc +++ b/src/dcp.cc @@ -365,7 +365,8 @@ CPL::CPL (string directory, string file, shared_ptr asset_map, b ) ); - picture->set_entry_point ((*i)->asset_list->main_picture->entry_point); + picture->set_entry_point (p->entry_point); + picture->set_duration (p->duration); } catch (MXFFileError) { if (require_mxfs) { throw; @@ -384,6 +385,7 @@ CPL::CPL (string directory, string file, shared_ptr asset_map, b ); picture->set_entry_point (p->entry_point); + picture->set_duration (p->duration); } catch (MXFFileError) { if (require_mxfs) { @@ -403,6 +405,7 @@ CPL::CPL (string directory, string file, shared_ptr asset_map, b ); sound->set_entry_point ((*i)->asset_list->main_sound->entry_point); + sound->set_duration ((*i)->asset_list->main_sound->duration); } catch (MXFFileError) { if (require_mxfs) { throw; diff --git a/src/mxf_asset.cc b/src/mxf_asset.cc index 144532f8..229c332f 100644 --- a/src/mxf_asset.cc +++ b/src/mxf_asset.cc @@ -39,21 +39,13 @@ using namespace libdcp; MXFAsset::MXFAsset (string directory, string file_name) : Asset (directory, file_name) , _progress (0) - , _edit_rate (0) - , _entry_point (0) - , _intrinsic_duration (0) - , _duration (0) { } MXFAsset::MXFAsset (string directory, string file_name, boost::signals2::signal* progress, int edit_rate, int intrinsic_duration) - : Asset (directory, file_name) + : Asset (directory, file_name, edit_rate, intrinsic_duration) , _progress (progress) - , _edit_rate (edit_rate) - , _entry_point (0) - , _intrinsic_duration (intrinsic_duration) - , _duration (intrinsic_duration) { } @@ -73,6 +65,10 @@ MXFAsset::fill_writer_info (ASDCP::WriterInfo* writer_info, string uuid) bool MXFAsset::equals (shared_ptr other, EqualityOptions opt, boost::function note) const { + if (!Asset::equals (other, opt, note)) { + return false; + } + shared_ptr other_mxf = dynamic_pointer_cast (other); if (!other_mxf) { note (ERROR, "comparing an MXF asset with a non-MXF asset"); @@ -85,21 +81,6 @@ MXFAsset::equals (shared_ptr other, EqualityOptions opt, boost::fun return false; } } - - if (_edit_rate != other_mxf->_edit_rate) { - note (ERROR, "MXF edit rates differ"); - return false; - } - - if (_intrinsic_duration != other_mxf->_intrinsic_duration) { - note (ERROR, "MXF intrinsic durations differ"); - return false; - } - - if (_duration != other_mxf->_duration) { - note (ERROR, "MXF durations differ"); - return false; - } return true; } diff --git a/src/mxf_asset.h b/src/mxf_asset.h index 29b3c1b0..5815fd90 100644 --- a/src/mxf_asset.h +++ b/src/mxf_asset.h @@ -49,27 +49,7 @@ public: */ MXFAsset (std::string directory, std::string file_name, boost::signals2::signal* progress, int edit_rate, int intrinsic_duration); - void set_entry_point (int e) { - _entry_point = e; - } - - void set_duration (int d) { - _duration = d; - } - - void set_intrinsic_duration (int d) { - _intrinsic_duration = d; - } - virtual bool equals (boost::shared_ptr other, EqualityOptions opt, boost::function note) const; - - int intrinsic_duration () const { - return _intrinsic_duration; - } - - int edit_rate () const { - return _edit_rate; - } /** Fill in a ADSCP::WriteInfo struct. * @param w struct to fill in. @@ -81,14 +61,6 @@ protected: /** Signal to emit to report progress, or 0 */ boost::signals2::signal* _progress; - /** The edit rate; this is normally equal to the number of video frames per second */ - int _edit_rate; - /** Start point to present in frames */ - int _entry_point; - /** Total length in frames */ - int _intrinsic_duration; - /** Length to present in frames */ - int _duration; }; } -- cgit v1.2.3 From 4eff4595c012cfebf184cb249d4d8e2c1f32f5e4 Mon Sep 17 00:00:00 2001 From: Carl Hetherington Date: Thu, 2 May 2013 17:20:27 +0100 Subject: Bump version --- wscript | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/wscript b/wscript index f7f7cb88..5c811f3f 100644 --- a/wscript +++ b/wscript @@ -2,7 +2,7 @@ import subprocess import os APPNAME = 'libdcp' -VERSION = '0.48pre' +VERSION = '0.48' def options(opt): opt.load('compiler_cxx') -- cgit v1.2.3 From a65d775d08f4598a87d7100458a26e3921290333 Mon Sep 17 00:00:00 2001 From: Carl Hetherington Date: Thu, 2 May 2013 17:20:27 +0100 Subject: Bump version --- wscript | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/wscript b/wscript index 5c811f3f..e88f79bf 100644 --- a/wscript +++ b/wscript @@ -2,7 +2,7 @@ import subprocess import os APPNAME = 'libdcp' -VERSION = '0.48' +VERSION = '0.49pre' def options(opt): opt.load('compiler_cxx') -- cgit v1.2.3 From 8c7829cd20778082a7a5ea612639c313f3006faa Mon Sep 17 00:00:00 2001 From: Carl Hetherington Date: Fri, 3 May 2013 16:12:50 +0100 Subject: A few tweaks to dcpdiff. --- src/picture_asset.cc | 13 +++++++++---- tools/dcpdiff.cc | 24 +++++++++++++++++------- 2 files changed, 26 insertions(+), 11 deletions(-) diff --git a/src/picture_asset.cc b/src/picture_asset.cc index f2982b47..a505dc63 100644 --- a/src/picture_asset.cc +++ b/src/picture_asset.cc @@ -364,13 +364,18 @@ PictureAsset::frame_buffer_equals ( double const std_dev = sqrt (double (total_squared_deviation) / abs_diffs.size()); - if (mean > opt.max_mean_pixel_error || std_dev > opt.max_std_dev_pixel_error) { - note (ERROR, "mean or standard deviation out of range for " + lexical_cast(frame)); + note (NOTE, "mean difference " + lexical_cast (mean) + ", deviation " + lexical_cast (std_dev)); + + if (mean > opt.max_mean_pixel_error) { + note (ERROR, "mean " + lexical_cast(mean) + " out of range " + lexical_cast(opt.max_mean_pixel_error) + " in frame " + lexical_cast(frame)); + return false; + } + + if (std_dev > opt.max_std_dev_pixel_error) { + note (ERROR, "standard deviation " + lexical_cast(std_dev) + " out of range " + lexical_cast(opt.max_std_dev_pixel_error) + " in frame " + lexical_cast(frame)); return false; } - note (NOTE, "mean difference " + lexical_cast (mean) + ", deviation " + lexical_cast (std_dev)); - opj_image_destroy (image_A); opj_image_destroy (image_B); diff --git a/tools/dcpdiff.cc b/tools/dcpdiff.cc index 490059aa..b361b93a 100644 --- a/tools/dcpdiff.cc +++ b/tools/dcpdiff.cc @@ -14,10 +14,12 @@ static void help (string n) { cerr << "Syntax: " << n << " [OPTION] \n" - << " -V, --version show libdcp version\n" - << " -h, --help show this help\n" - << " -v, --verbose be verbose\n" - << " -n, --names allow differing MXF names\n" + << " -V, --version show libdcp version\n" + << " -h, --help show this help\n" + << " -v, --verbose be verbose\n" + << " -n, --names allow differing MXF names\n" + << " -m, --mean-pixel maximum allowed mean pixel error (default 5)\n" + << " -s, --std-dev-pixel maximum allowed standard deviation of pixel error (default 5)\n" << "\n" << "The s are the DCP directories to compare.\n" << "Comparison is of metadata and content, ignoring timestamps\n" @@ -36,6 +38,8 @@ int main (int argc, char* argv[]) { EqualityOptions options; + options.max_mean_pixel_error = 5; + options.max_std_dev_pixel_error = 5; int option_index = 0; while (1) { @@ -44,10 +48,12 @@ main (int argc, char* argv[]) { "help", no_argument, 0, 'h'}, { "verbose", no_argument, 0, 'v'}, { "names", no_argument, 0, 'n'}, + { "mean-pixel", required_argument, 0, 'm'}, + { "std-dev-pixel", required_argument, 0, 's'}, { 0, 0, 0, 0 } }; - int c = getopt_long (argc, argv, "Vhvn", long_options, &option_index); + int c = getopt_long (argc, argv, "Vhvnm:s:", long_options, &option_index); if (c == -1) { break; @@ -66,6 +72,12 @@ main (int argc, char* argv[]) case 'n': options.mxf_names_can_differ = true; break; + case 'm': + options.max_mean_pixel_error = atof (optarg); + break; + case 's': + options.max_std_dev_pixel_error = atof (optarg); + break; } } @@ -102,8 +114,6 @@ main (int argc, char* argv[]) exit (EXIT_FAILURE); } - options.max_mean_pixel_error = 5; - options.max_std_dev_pixel_error = 5; /* I think this is just below the LSB at 16-bits (ie the 8th most significant bit at 24-bit) */ options.max_audio_sample_error = 255; -- cgit v1.2.3 From 09ad2806848f5c3609b7915da504f94db099e3af Mon Sep 17 00:00:00 2001 From: Carl Hetherington Date: Sat, 4 May 2013 09:58:35 +0100 Subject: Split CPL up into its own files. --- examples/make_dcp.cc | 2 + src/cpl.cc | 296 +++++++++++++++++++++++++++++++++++++++++++++++++++ src/cpl.h | 95 +++++++++++++++++ src/dcp.cc | 259 +------------------------------------------- src/dcp.h | 67 +----------- src/wscript | 1 + test/rewrite_subs.cc | 1 + test/tests.cc | 1 + tools/dcpinfo.cc | 1 + 9 files changed, 400 insertions(+), 323 deletions(-) create mode 100644 src/cpl.cc create mode 100644 src/cpl.h diff --git a/examples/make_dcp.cc b/examples/make_dcp.cc index 3891db3f..06dd05ab 100644 --- a/examples/make_dcp.cc +++ b/examples/make_dcp.cc @@ -26,11 +26,13 @@ /* If you are using an installed libdcp, these #includes would need to be changed to #include +#include #include ... etc. ... */ #include "dcp.h" +#include "cpl.h" #include "picture_asset.h" #include "sound_asset.h" #include "reel.h" diff --git a/src/cpl.cc b/src/cpl.cc new file mode 100644 index 00000000..90c48ae9 --- /dev/null +++ b/src/cpl.cc @@ -0,0 +1,296 @@ +/* + Copyright (C) 2012 Carl Hetherington + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + +*/ + +#include +#include "cpl.h" +#include "cpl_file.h" +#include "util.h" +#include "picture_asset.h" +#include "sound_asset.h" +#include "subtitle_asset.h" +#include "asset_map.h" +#include "reel.h" +#include "metadata.h" + +using std::string; +using std::stringstream; +using std::ofstream; +using std::ostream; +using std::list; +using boost::shared_ptr; +using namespace libdcp; + +CPL::CPL (string directory, string name, ContentKind content_kind, int length, int frames_per_second) + : _directory (directory) + , _name (name) + , _content_kind (content_kind) + , _length (length) + , _fps (frames_per_second) +{ + _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 asset_map, bool require_mxfs) + : _directory (directory) + , _content_kind (FEATURE) + , _length (0) + , _fps (0) +{ + /* Read the XML */ + shared_ptr cpl; + try { + cpl.reset (new CPLFile (file)); + } catch (FileError& e) { + boost::throw_exception (FileError ("could not load CPL file", file)); + } + + /* Now cherry-pick the required bits into our own data structure */ + + _name = cpl->annotation_text; + _content_kind = cpl->content_kind; + + for (list >::iterator i = cpl->reels.begin(); i != cpl->reels.end(); ++i) { + + shared_ptr p; + + if ((*i)->asset_list->main_picture) { + p = (*i)->asset_list->main_picture; + } else { + p = (*i)->asset_list->main_stereoscopic_picture; + } + + _fps = p->edit_rate.numerator; + _length += p->duration; + + shared_ptr picture; + shared_ptr sound; + shared_ptr subtitle; + + /* Some rather twisted logic to decide if we are 3D or not; + some DCPs give a MainStereoscopicPicture to indicate 3D, others + just have a FrameRate twice the EditRate and apparently + expect you to divine the fact that they are hence 3D. + */ + + if (!(*i)->asset_list->main_stereoscopic_picture && p->edit_rate == p->frame_rate) { + + try { + picture.reset (new MonoPictureAsset ( + _directory, + asset_map->asset_from_id (p->id)->chunks.front()->path + ) + ); + + picture->set_entry_point ((*i)->asset_list->main_picture->entry_point); + } catch (MXFFileError) { + if (require_mxfs) { + throw; + } + } + + } else { + + try { + picture.reset (new StereoPictureAsset ( + _directory, + asset_map->asset_from_id (p->id)->chunks.front()->path, + _fps, + p->duration + ) + ); + + picture->set_entry_point (p->entry_point); + + } catch (MXFFileError) { + if (require_mxfs) { + throw; + } + } + + } + + if ((*i)->asset_list->main_sound) { + + try { + sound.reset (new SoundAsset ( + _directory, + asset_map->asset_from_id ((*i)->asset_list->main_sound->id)->chunks.front()->path + ) + ); + + sound->set_entry_point ((*i)->asset_list->main_sound->entry_point); + } catch (MXFFileError) { + if (require_mxfs) { + throw; + } + } + } + + if ((*i)->asset_list->main_subtitle) { + + subtitle.reset (new SubtitleAsset ( + _directory, + asset_map->asset_from_id ((*i)->asset_list->main_subtitle->id)->chunks.front()->path + ) + ); + } + + _reels.push_back (shared_ptr (new Reel (picture, sound, subtitle))); + } +} + +void +CPL::add_reel (shared_ptr reel) +{ + _reels.push_back (reel); +} + +void +CPL::write_xml () const +{ + boost::filesystem::path p; + p /= _directory; + stringstream s; + s << _uuid << "_cpl.xml"; + p /= s.str(); + ofstream os (p.string().c_str()); + + os << "\n" + << "\n" + << " urn:uuid:" << _uuid << "\n" + << " " << _name << "\n" + << " " << Metadata::instance()->issue_date << "\n" + << " " << Metadata::instance()->creator << "\n" + << " " << _name << "\n" + << " " << content_kind_to_string (_content_kind) << "\n" + << " \n" + << " urn:uri:" << _uuid << "_" << Metadata::instance()->issue_date << "\n" + << " " << _uuid << "_" << Metadata::instance()->issue_date << "\n" + << " \n" + << " \n" + << " \n"; + + for (list >::const_iterator i = _reels.begin(); i != _reels.end(); ++i) { + (*i)->write_to_cpl (os); + } + + os << " \n" + << "\n"; + + os.close (); + + _digest = make_digest (p.string ()); + _length = boost::filesystem::file_size (p.string ()); +} + +void +CPL::write_to_pkl (ostream& s) const +{ + s << " \n" + << " urn:uuid:" << _uuid << "\n" + << " " << _digest << "\n" + << " " << _length << "\n" + << " text/xml\n" + << " \n"; +} + +list > +CPL::assets () const +{ + list > a; + for (list >::const_iterator i = _reels.begin(); i != _reels.end(); ++i) { + if ((*i)->main_picture ()) { + a.push_back ((*i)->main_picture ()); + } + if ((*i)->main_sound ()) { + a.push_back ((*i)->main_sound ()); + } + if ((*i)->main_subtitle ()) { + a.push_back ((*i)->main_subtitle ()); + } + } + + return a; +} + +void +CPL::write_to_assetmap (ostream& s) const +{ + s << " \n" + << " urn:uuid:" << _uuid << "\n" + << " \n" + << " \n" + << " " << _uuid << "_cpl.xml\n" + << " 1\n" + << " 0\n" + << " " << _length << "\n" + << " \n" + << " \n" + << " \n"; +} + + + +bool +CPL::equals (CPL const & other, EqualityOptions opt, boost::function note) const +{ + if (_name != other._name) { + note (ERROR, "names differ"); + return false; + } + + if (_content_kind != other._content_kind) { + note (ERROR, "content kinds differ"); + return false; + } + + if (_fps != other._fps) { + note (ERROR, "frames per second differ"); + return false; + } + + if (_length != other._length) { + note (ERROR, "lengths differ"); + return false; + } + + if (_reels.size() != other._reels.size()) { + note (ERROR, "reel counts differ"); + return false; + } + + list >::const_iterator a = _reels.begin (); + list >::const_iterator b = other._reels.begin (); + + while (a != _reels.end ()) { + if (!(*a)->equals (*b, opt, note)) { + return false; + } + ++a; + ++b; + } + + return true; +} diff --git a/src/cpl.h b/src/cpl.h new file mode 100644 index 00000000..3be10894 --- /dev/null +++ b/src/cpl.h @@ -0,0 +1,95 @@ +/* + Copyright (C) 2012 Carl Hetherington + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + +*/ + +#include +#include +#include +#include "types.h" + +namespace libdcp { + +class AssetMap; +class Asset; +class Reel; + +/** @brief A CPL within a DCP */ +class CPL +{ +public: + CPL (std::string directory, std::string name, ContentKind content_kind, int length, int frames_per_second); + CPL (std::string directory, std::string file, boost::shared_ptr asset_map, bool require_mxfs = true); + + void add_reel (boost::shared_ptr reel); + + /** @return the length in frames */ + int length () const { + return _length; + } + + /** @return the type of the content, used by media servers + * to categorise things (e.g. feature, trailer, etc.) + */ + ContentKind content_kind () const { + return _content_kind; + } + + std::list > reels () const { + return _reels; + } + + /** @return the CPL's name, as will be presented on projector + * media servers and theatre management systems. + */ + std::string name () const { + return _name; + } + + /** @return the number of frames per second */ + int frames_per_second () const { + return _fps; + } + + std::list > assets () const; + + bool equals (CPL const & other, EqualityOptions options, boost::function note) const; + + void write_xml () const; + void write_to_assetmap (std::ostream& s) const; + void write_to_pkl (std::ostream& s) const; + +private: + std::string _directory; + /** the name of the DCP */ + std::string _name; + /** the content kind of the CPL */ + ContentKind _content_kind; + /** length in frames */ + mutable int _length; + /** frames per second */ + int _fps; + /** reels */ + std::list > _reels; + + /** our UUID */ + std::string _uuid; + /** a SHA1 digest of our XML */ + mutable std::string _digest; +}; + +} diff --git a/src/dcp.cc b/src/dcp.cc index bac266ab..e74e0d95 100644 --- a/src/dcp.cc +++ b/src/dcp.cc @@ -41,6 +41,7 @@ #include "pkl_file.h" #include "asset_map.h" #include "reel.h" +#include "cpl.h" using std::string; using std::list; @@ -298,261 +299,3 @@ DCP::assets () const return a; } -CPL::CPL (string directory, string name, ContentKind content_kind, int length, int frames_per_second) - : _directory (directory) - , _name (name) - , _content_kind (content_kind) - , _length (length) - , _fps (frames_per_second) -{ - _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 asset_map, bool require_mxfs) - : _directory (directory) - , _content_kind (FEATURE) - , _length (0) - , _fps (0) -{ - /* Read the XML */ - shared_ptr cpl; - try { - cpl.reset (new CPLFile (file)); - } catch (FileError& e) { - boost::throw_exception (FileError ("could not load CPL file", file)); - } - - /* Now cherry-pick the required bits into our own data structure */ - - _name = cpl->annotation_text; - _content_kind = cpl->content_kind; - - for (list >::iterator i = cpl->reels.begin(); i != cpl->reels.end(); ++i) { - - shared_ptr p; - - if ((*i)->asset_list->main_picture) { - p = (*i)->asset_list->main_picture; - } else { - p = (*i)->asset_list->main_stereoscopic_picture; - } - - _fps = p->edit_rate.numerator; - _length += p->duration; - - shared_ptr picture; - shared_ptr sound; - shared_ptr subtitle; - - /* Some rather twisted logic to decide if we are 3D or not; - some DCPs give a MainStereoscopicPicture to indicate 3D, others - just have a FrameRate twice the EditRate and apparently - expect you to divine the fact that they are hence 3D. - */ - - if (!(*i)->asset_list->main_stereoscopic_picture && p->edit_rate == p->frame_rate) { - - try { - picture.reset (new MonoPictureAsset ( - _directory, - asset_map->asset_from_id (p->id)->chunks.front()->path - ) - ); - - picture->set_entry_point ((*i)->asset_list->main_picture->entry_point); - } catch (MXFFileError) { - if (require_mxfs) { - throw; - } - } - - } else { - - try { - picture.reset (new StereoPictureAsset ( - _directory, - asset_map->asset_from_id (p->id)->chunks.front()->path, - _fps, - p->duration - ) - ); - - picture->set_entry_point (p->entry_point); - - } catch (MXFFileError) { - if (require_mxfs) { - throw; - } - } - - } - - if ((*i)->asset_list->main_sound) { - - try { - sound.reset (new SoundAsset ( - _directory, - asset_map->asset_from_id ((*i)->asset_list->main_sound->id)->chunks.front()->path - ) - ); - - sound->set_entry_point ((*i)->asset_list->main_sound->entry_point); - } catch (MXFFileError) { - if (require_mxfs) { - throw; - } - } - } - - if ((*i)->asset_list->main_subtitle) { - - subtitle.reset (new SubtitleAsset ( - _directory, - asset_map->asset_from_id ((*i)->asset_list->main_subtitle->id)->chunks.front()->path - ) - ); - } - - _reels.push_back (shared_ptr (new Reel (picture, sound, subtitle))); - } -} - -void -CPL::add_reel (shared_ptr reel) -{ - _reels.push_back (reel); -} - -void -CPL::write_xml () const -{ - boost::filesystem::path p; - p /= _directory; - stringstream s; - s << _uuid << "_cpl.xml"; - p /= s.str(); - ofstream os (p.string().c_str()); - - os << "\n" - << "\n" - << " urn:uuid:" << _uuid << "\n" - << " " << _name << "\n" - << " " << Metadata::instance()->issue_date << "\n" - << " " << Metadata::instance()->creator << "\n" - << " " << _name << "\n" - << " " << content_kind_to_string (_content_kind) << "\n" - << " \n" - << " urn:uri:" << _uuid << "_" << Metadata::instance()->issue_date << "\n" - << " " << _uuid << "_" << Metadata::instance()->issue_date << "\n" - << " \n" - << " \n" - << " \n"; - - for (list >::const_iterator i = _reels.begin(); i != _reels.end(); ++i) { - (*i)->write_to_cpl (os); - } - - os << " \n" - << "\n"; - - os.close (); - - _digest = make_digest (p.string ()); - _length = boost::filesystem::file_size (p.string ()); -} - -void -CPL::write_to_pkl (ostream& s) const -{ - s << " \n" - << " urn:uuid:" << _uuid << "\n" - << " " << _digest << "\n" - << " " << _length << "\n" - << " text/xml\n" - << " \n"; -} - -list > -CPL::assets () const -{ - list > a; - for (list >::const_iterator i = _reels.begin(); i != _reels.end(); ++i) { - if ((*i)->main_picture ()) { - a.push_back ((*i)->main_picture ()); - } - if ((*i)->main_sound ()) { - a.push_back ((*i)->main_sound ()); - } - if ((*i)->main_subtitle ()) { - a.push_back ((*i)->main_subtitle ()); - } - } - - return a; -} - -void -CPL::write_to_assetmap (ostream& s) const -{ - s << " \n" - << " urn:uuid:" << _uuid << "\n" - << " \n" - << " \n" - << " " << _uuid << "_cpl.xml\n" - << " 1\n" - << " 0\n" - << " " << _length << "\n" - << " \n" - << " \n" - << " \n"; -} - - - -bool -CPL::equals (CPL const & other, EqualityOptions opt, boost::function note) const -{ - if (_name != other._name) { - note (ERROR, "names differ"); - return false; - } - - if (_content_kind != other._content_kind) { - note (ERROR, "content kinds differ"); - return false; - } - - if (_fps != other._fps) { - note (ERROR, "frames per second differ"); - return false; - } - - if (_length != other._length) { - note (ERROR, "lengths differ"); - return false; - } - - if (_reels.size() != other._reels.size()) { - note (ERROR, "reel counts differ"); - return false; - } - - list >::const_iterator a = _reels.begin (); - list >::const_iterator b = other._reels.begin (); - - while (a != _reels.end ()) { - if (!(*a)->equals (*b, opt, note)) { - return false; - } - ++a; - ++b; - } - - return true; -} diff --git a/src/dcp.h b/src/dcp.h index 9e2e8a02..decac4f2 100644 --- a/src/dcp.h +++ b/src/dcp.h @@ -44,72 +44,9 @@ class SoundAsset; class SubtitleAsset; class Reel; class AssetMap; +class CPL; -/** @brief A CPL within a DCP */ -class CPL -{ -public: - CPL (std::string directory, std::string name, ContentKind content_kind, int length, int frames_per_second); - CPL (std::string directory, std::string file, boost::shared_ptr asset_map, bool require_mxfs = true); - - void add_reel (boost::shared_ptr reel); - - /** @return the length in frames */ - int length () const { - return _length; - } - - /** @return the type of the content, used by media servers - * to categorise things (e.g. feature, trailer, etc.) - */ - ContentKind content_kind () const { - return _content_kind; - } - - std::list > reels () const { - return _reels; - } - - /** @return the CPL's name, as will be presented on projector - * media servers and theatre management systems. - */ - std::string name () const { - return _name; - } - - /** @return the number of frames per second */ - int frames_per_second () const { - return _fps; - } - - std::list > assets () const; - - bool equals (CPL const & other, EqualityOptions options, boost::function note) const; - - void write_xml () const; - void write_to_assetmap (std::ostream& s) const; - void write_to_pkl (std::ostream& s) const; - -private: - std::string _directory; - /** the name of the DCP */ - std::string _name; - /** the content kind of the CPL */ - ContentKind _content_kind; - /** length in frames */ - mutable int _length; - /** frames per second */ - int _fps; - /** reels */ - std::list > _reels; - - /** our UUID */ - std::string _uuid; - /** a SHA1 digest of our XML */ - mutable std::string _digest; -}; - -/** @class DCP dcp.h libdcp/dcp.h +/** @class DCP * @brief A class to create or read a DCP. */ diff --git a/src/wscript b/src/wscript index 3960f2b0..95092173 100644 --- a/src/wscript +++ b/src/wscript @@ -14,6 +14,7 @@ def build(bld): asset_map.cc cpl_file.cc dcp.cc + cpl.cc dcp_time.cc gamma_lut.cc metadata.cc diff --git a/test/rewrite_subs.cc b/test/rewrite_subs.cc index 651b207a..adb9f6b4 100644 --- a/test/rewrite_subs.cc +++ b/test/rewrite_subs.cc @@ -1,5 +1,6 @@ #include #include "dcp.h" +#include "cpl.h" #include "reel.h" #include "subtitle_asset.h" diff --git a/test/tests.cc b/test/tests.cc index 30c9f406..d33890b6 100644 --- a/test/tests.cc +++ b/test/tests.cc @@ -30,6 +30,7 @@ #include "sound_asset.h" #include "reel.h" #include "gamma_lut.h" +#include "cpl.h" #define BOOST_TEST_DYN_LINK #define BOOST_TEST_MODULE libdcp_test diff --git a/tools/dcpinfo.cc b/tools/dcpinfo.cc index 40e2be99..04fec82f 100644 --- a/tools/dcpinfo.cc +++ b/tools/dcpinfo.cc @@ -8,6 +8,7 @@ #include "sound_asset.h" #include "picture_asset.h" #include "subtitle_asset.h" +#include "cpl.h" using std::string; using std::cerr; -- cgit v1.2.3 From af87bfc82beee0b0600558c84c3843dfd5a252f6 Mon Sep 17 00:00:00 2001 From: Carl Hetherington Date: Sat, 4 May 2013 11:13:04 +0100 Subject: Split metadata into XML and MXF bits; remove singleton. --- examples/make_dcp.cc | 3 ++- src/cpl.cc | 10 +++++----- src/cpl.h | 3 ++- src/dcp.cc | 24 ++++++++++++------------ src/dcp.h | 7 ++++--- src/metadata.cc | 30 ++++++++++++++---------------- src/metadata.h | 29 ++++++++++++++++------------- src/mxf_asset.cc | 8 ++++---- src/mxf_asset.h | 6 ++++-- src/picture_asset.cc | 27 ++++++++++++++++----------- src/picture_asset.h | 14 +++++++++----- src/sound_asset.cc | 23 +++++++++++++---------- src/sound_asset.h | 15 +++++++++------ src/test_mode.cc | 45 --------------------------------------------- src/test_mode.h | 29 ----------------------------- src/wscript | 3 +-- test/tests.cc | 23 +++++++++++++---------- 17 files changed, 124 insertions(+), 175 deletions(-) delete mode 100644 src/test_mode.cc delete mode 100644 src/test_mode.h diff --git a/examples/make_dcp.cc b/examples/make_dcp.cc index 06dd05ab..0d6a8215 100644 --- a/examples/make_dcp.cc +++ b/examples/make_dcp.cc @@ -108,7 +108,8 @@ main () /* Finally, we call this to write the XML description files to the DCP. After this, the DCP is ready to ingest and play. */ - dcp.write_xml (); + libdcp::XMLMetadata metadata; + dcp.write_xml (metadata); return 0; } diff --git a/src/cpl.cc b/src/cpl.cc index 90c48ae9..18526b24 100644 --- a/src/cpl.cc +++ b/src/cpl.cc @@ -168,7 +168,7 @@ CPL::add_reel (shared_ptr reel) } void -CPL::write_xml () const +CPL::write_xml (XMLMetadata const & metadata) const { boost::filesystem::path p; p /= _directory; @@ -181,13 +181,13 @@ CPL::write_xml () const << "\n" << " urn:uuid:" << _uuid << "\n" << " " << _name << "\n" - << " " << Metadata::instance()->issue_date << "\n" - << " " << Metadata::instance()->creator << "\n" + << " " << metadata.issue_date << "\n" + << " " << metadata.creator << "\n" << " " << _name << "\n" << " " << content_kind_to_string (_content_kind) << "\n" << " \n" - << " urn:uri:" << _uuid << "_" << Metadata::instance()->issue_date << "\n" - << " " << _uuid << "_" << Metadata::instance()->issue_date << "\n" + << " urn:uri:" << _uuid << "_" << metadata.issue_date << "\n" + << " " << _uuid << "_" << metadata.issue_date << "\n" << " \n" << " \n" << " \n"; diff --git a/src/cpl.h b/src/cpl.h index 3be10894..0abff749 100644 --- a/src/cpl.h +++ b/src/cpl.h @@ -27,6 +27,7 @@ namespace libdcp { class AssetMap; class Asset; class Reel; +class XMLMetadata; /** @brief A CPL within a DCP */ class CPL @@ -69,7 +70,7 @@ public: bool equals (CPL const & other, EqualityOptions options, boost::function note) const; - void write_xml () const; + void write_xml (XMLMetadata const &) const; void write_to_assetmap (std::ostream& s) const; void write_to_pkl (std::ostream& s) const; diff --git a/src/dcp.cc b/src/dcp.cc index e74e0d95..7af3f353 100644 --- a/src/dcp.cc +++ b/src/dcp.cc @@ -58,21 +58,21 @@ DCP::DCP (string directory) } void -DCP::write_xml () const +DCP::write_xml (XMLMetadata const & metadata) const { for (list >::const_iterator i = _cpls.begin(); i != _cpls.end(); ++i) { - (*i)->write_xml (); + (*i)->write_xml (metadata); } string pkl_uuid = make_uuid (); - string pkl_path = write_pkl (pkl_uuid); + string pkl_path = write_pkl (pkl_uuid, metadata); write_volindex (); - write_assetmap (pkl_uuid, boost::filesystem::file_size (pkl_path)); + write_assetmap (pkl_uuid, boost::filesystem::file_size (pkl_path), metadata); } std::string -DCP::write_pkl (string pkl_uuid) const +DCP::write_pkl (string pkl_uuid, XMLMetadata const & metadata) const { assert (!_cpls.empty ()); @@ -88,9 +88,9 @@ DCP::write_pkl (string pkl_uuid) const << " urn:uuid:" << pkl_uuid << "\n" /* XXX: this is a bit of a hack */ << " " << _cpls.front()->name() << "\n" - << " " << Metadata::instance()->issue_date << "\n" - << " " << Metadata::instance()->issuer << "\n" - << " " << Metadata::instance()->creator << "\n" + << " " << metadata.issue_date << "\n" + << " " << metadata.issuer << "\n" + << " " << metadata.creator << "\n" << " \n"; list > a = assets (); @@ -123,7 +123,7 @@ DCP::write_volindex () const } void -DCP::write_assetmap (string pkl_uuid, int pkl_length) const +DCP::write_assetmap (string pkl_uuid, int pkl_length, XMLMetadata const & metadata) const { boost::filesystem::path p; p /= _directory; @@ -133,10 +133,10 @@ DCP::write_assetmap (string pkl_uuid, int pkl_length) const am << "\n" << "\n" << " urn:uuid:" << make_uuid() << "\n" - << " " << Metadata::instance()->creator << "\n" + << " " << metadata.creator << "\n" << " 1\n" - << " " << Metadata::instance()->issue_date << "\n" - << " " << Metadata::instance()->issuer << "\n" + << " " << metadata.issue_date << "\n" + << " " << metadata.issuer << "\n" << " \n"; am << " \n" diff --git a/src/dcp.h b/src/dcp.h index decac4f2..42c0c6d9 100644 --- a/src/dcp.h +++ b/src/dcp.h @@ -45,6 +45,7 @@ class SubtitleAsset; class Reel; class AssetMap; class CPL; +class XMLMetadata; /** @class DCP * @brief A class to create or read a DCP. @@ -74,7 +75,7 @@ public: /** Write the required XML files to the directory that was * passed into the constructor. */ - void write_xml () const; + void write_xml (XMLMetadata const &) const; /** Compare this DCP with another, according to various options. * @param other DCP to compare this one to. @@ -103,7 +104,7 @@ private: /** Write the PKL file. * @param pkl_uuid UUID to use. */ - std::string write_pkl (std::string pkl_uuid) const; + std::string write_pkl (std::string pkl_uuid, XMLMetadata const &) const; /** Write the VOLINDEX file */ void write_volindex () const; @@ -112,7 +113,7 @@ private: * @param pkl_uuid UUID of our PKL. * @param pkl_length Length of our PKL in bytes. */ - void write_assetmap (std::string pkl_uuid, int pkl_length) const; + void write_assetmap (std::string pkl_uuid, int pkl_length, XMLMetadata const &) const; /** @return Assets in all this CPLs in this DCP */ std::list > assets () const; diff --git a/src/metadata.cc b/src/metadata.cc index 7e900e50..2967ac1d 100644 --- a/src/metadata.cc +++ b/src/metadata.cc @@ -27,15 +27,24 @@ using namespace std; using namespace libdcp; -Metadata* Metadata::_instance = 0; - -/** Construct a Metadata object with some default values */ -Metadata::Metadata () +MXFMetadata::MXFMetadata () : company_name ("libdcp") , product_name ("libdcp") , product_version (LIBDCP_VERSION) - , issuer ("libdcp" LIBDCP_VERSION) +{ + +} + + +XMLMetadata::XMLMetadata () + : issuer ("libdcp" LIBDCP_VERSION) , creator ("libdcp" LIBDCP_VERSION) +{ + set_issue_date_now (); +} + +void +XMLMetadata::set_issue_date_now () { char buffer[64]; time_t now; @@ -44,15 +53,4 @@ Metadata::Metadata () strftime (buffer, 64, "%Y-%m-%dT%I:%M:%S+00:00", tm); issue_date = string (buffer); } - -/** @return Singleton Metadata instance */ -Metadata * -Metadata::instance () -{ - if (_instance == 0) { - _instance = new Metadata; - } - - return _instance; -} diff --git a/src/metadata.h b/src/metadata.h index 1610491e..7336766d 100644 --- a/src/metadata.h +++ b/src/metadata.h @@ -17,6 +17,9 @@ */ +#ifndef LIBDCP_METADATA_H +#define LIBDCP_METADATA_H + /** @file src/metadata.h * @brief Metadata for writing to the DCP. */ @@ -26,28 +29,28 @@ namespace libdcp { -/** @brief A class to hold various metadata that will be written - * to the DCP. - * - * The values are initialised, and can be modified if desired. - */ -class Metadata +class MXFMetadata { public: - static Metadata* instance (); + MXFMetadata (); std::string company_name; std::string product_name; std::string product_version; +}; + +class XMLMetadata +{ +public: + XMLMetadata (); + + void set_issue_date_now (); + std::string issuer; std::string creator; std::string issue_date; - -private: - Metadata (); - - /** Singleton instance of Metadata */ - static Metadata* _instance; }; } + +#endif diff --git a/src/mxf_asset.cc b/src/mxf_asset.cc index 144532f8..eb323f59 100644 --- a/src/mxf_asset.cc +++ b/src/mxf_asset.cc @@ -58,11 +58,11 @@ MXFAsset::MXFAsset (string directory, string file_name, boost::signals2::signal< } void -MXFAsset::fill_writer_info (ASDCP::WriterInfo* writer_info, string uuid) +MXFAsset::fill_writer_info (ASDCP::WriterInfo* writer_info, string uuid, MXFMetadata const & metadata) { - writer_info->ProductVersion = Metadata::instance()->product_version; - writer_info->CompanyName = Metadata::instance()->company_name; - writer_info->ProductName = Metadata::instance()->product_name.c_str(); + writer_info->ProductVersion = metadata.product_version; + writer_info->CompanyName = metadata.company_name; + writer_info->ProductName = metadata.product_name.c_str(); writer_info->LabelSetType = ASDCP::LS_MXF_SMPTE; unsigned int c; diff --git a/src/mxf_asset.h b/src/mxf_asset.h index 29b3c1b0..f5cee5de 100644 --- a/src/mxf_asset.h +++ b/src/mxf_asset.h @@ -26,6 +26,8 @@ namespace libdcp { +class MXFMetadata; + /** @brief Parent class for assets which have MXF files */ class MXFAsset : public Asset { @@ -75,10 +77,10 @@ public: * @param w struct to fill in. * @param uuid uuid to use. */ - static void fill_writer_info (ASDCP::WriterInfo* w, std::string uuid); + static void fill_writer_info (ASDCP::WriterInfo* w, std::string uuid, MXFMetadata const & metadata); protected: - + /** Signal to emit to report progress, or 0 */ boost::signals2::signal* _progress; /** The edit rate; this is normally equal to the number of video frames per second */ diff --git a/src/picture_asset.cc b/src/picture_asset.cc index f2982b47..d98ef066 100644 --- a/src/picture_asset.cc +++ b/src/picture_asset.cc @@ -146,10 +146,12 @@ MonoPictureAsset::MonoPictureAsset ( boost::signals2::signal* progress, int fps, int intrinsic_duration, - Size size) + Size size, + MXFMetadata const & metadata + ) : PictureAsset (directory, mxf_name, progress, fps, intrinsic_duration, size) { - construct (get_path); + construct (get_path, metadata); } MonoPictureAsset::MonoPictureAsset ( @@ -159,10 +161,12 @@ MonoPictureAsset::MonoPictureAsset ( boost::signals2::signal* progress, int fps, int intrinsic_duration, - Size size) + Size size, + MXFMetadata const & metadata + ) : PictureAsset (directory, mxf_name, progress, fps, intrinsic_duration, size) { - construct (boost::bind (&MonoPictureAsset::path_from_list, this, _1, files)); + construct (boost::bind (&MonoPictureAsset::path_from_list, this, _1, files), metadata); } MonoPictureAsset::MonoPictureAsset (string directory, string mxf_name, int fps, Size size) @@ -192,7 +196,7 @@ MonoPictureAsset::MonoPictureAsset (string directory, string mxf_name) } void -MonoPictureAsset::construct (boost::function get_path) +MonoPictureAsset::construct (boost::function get_path, MXFMetadata const & metadata) { ASDCP::JP2K::CodestreamParser j2k_parser; ASDCP::JP2K::FrameBuffer frame_buffer (4 * Kumu::Megabyte); @@ -205,7 +209,7 @@ MonoPictureAsset::construct (boost::function get_path) picture_desc.EditRate = ASDCP::Rational (_edit_rate, 1); ASDCP::WriterInfo writer_info; - fill_writer_info (&writer_info, _uuid); + fill_writer_info (&writer_info, _uuid, metadata); ASDCP::JP2K::MXFWriter mxf_writer; if (ASDCP_FAILURE (mxf_writer.OpenWrite (path().string().c_str(), writer_info, picture_desc, 16384, false))) { @@ -402,10 +406,10 @@ StereoPictureAsset::get_frame (int n) const } shared_ptr -MonoPictureAsset::start_write (bool overwrite) +MonoPictureAsset::start_write (bool overwrite, MXFMetadata const & metadata) { - /* XXX: can't we use a shared_ptr here? */ - return shared_ptr (new MonoPictureAssetWriter (this, overwrite)); + /* XXX: can't we use shared_ptr here? */ + return shared_ptr (new MonoPictureAssetWriter (this, overwrite, metadata)); } FrameInfo::FrameInfo (istream& s) @@ -436,13 +440,14 @@ struct MonoPictureAssetWriter::ASDCPState /** @param a Asset to write to. `a' must not be deleted while * this writer class still exists, or bad things will happen. */ -MonoPictureAssetWriter::MonoPictureAssetWriter (MonoPictureAsset* a, bool overwrite) +MonoPictureAssetWriter::MonoPictureAssetWriter (MonoPictureAsset* a, bool overwrite, MXFMetadata const & m) : _state (new MonoPictureAssetWriter::ASDCPState) , _asset (a) , _frames_written (0) , _started (false) , _finalized (false) , _overwrite (overwrite) + , _metadata (m) { } @@ -458,7 +463,7 @@ MonoPictureAssetWriter::start (uint8_t* data, int size) _state->j2k_parser.FillPictureDescriptor (_state->picture_descriptor); _state->picture_descriptor.EditRate = ASDCP::Rational (_asset->edit_rate(), 1); - MXFAsset::fill_writer_info (&_state->writer_info, _asset->uuid()); + MXFAsset::fill_writer_info (&_state->writer_info, _asset->uuid(), _metadata); if (ASDCP_FAILURE (_state->mxf_writer.OpenWrite ( _asset->path().string().c_str(), diff --git a/src/picture_asset.h b/src/picture_asset.h index c9226b1f..59c4dc00 100644 --- a/src/picture_asset.h +++ b/src/picture_asset.h @@ -27,6 +27,7 @@ #include #include "mxf_asset.h" #include "util.h" +#include "metadata.h" namespace libdcp { @@ -121,7 +122,7 @@ public: private: friend class MonoPictureAsset; - MonoPictureAssetWriter (MonoPictureAsset *, bool); + MonoPictureAssetWriter (MonoPictureAsset *, bool, MXFMetadata const &); void start (uint8_t *, int); /* no copy construction */ @@ -142,6 +143,7 @@ private: /** true if finalize() has been called */ bool _finalized; bool _overwrite; + MXFMetadata _metadata; }; /** A 2D (monoscopic) picture asset */ @@ -166,7 +168,8 @@ public: boost::signals2::signal* progress, int fps, int intrinsic_duration, - Size size + Size size, + MXFMetadata const & metadata = MXFMetadata () ); /** Construct a MonoPictureAsset, generating the MXF from the JPEG2000 files. @@ -187,7 +190,8 @@ public: boost::signals2::signal* progress, int fps, int intrinsic_duration, - Size size + Size size, + MXFMetadata const & metadata = MXFMetadata () ); /** Construct a MonoPictureAsset, reading the MXF from disk. @@ -207,14 +211,14 @@ public: MonoPictureAsset (std::string directory, std::string mxf_name, int fps, Size size); /** Start a progressive write to a MonoPictureAsset */ - boost::shared_ptr start_write (bool); + boost::shared_ptr start_write (bool, MXFMetadata const & metadata = MXFMetadata ()); boost::shared_ptr get_frame (int n) const; bool equals (boost::shared_ptr other, EqualityOptions opt, boost::function note) const; private: std::string path_from_list (int f, std::vector const & files) const; - void construct (boost::function); + void construct (boost::function, MXFMetadata const &); }; /** A 3D (stereoscopic) picture asset */ diff --git a/src/sound_asset.cc b/src/sound_asset.cc index 6e29aadf..9b6b48aa 100644 --- a/src/sound_asset.cc +++ b/src/sound_asset.cc @@ -46,7 +46,8 @@ SoundAsset::SoundAsset ( string directory, string mxf_name, boost::signals2::signal* progress, - int fps, int intrinsic_duration + int fps, int intrinsic_duration, + MXFMetadata const & metadata ) : MXFAsset (directory, mxf_name, progress, fps, intrinsic_duration) , _channels (files.size ()) @@ -54,7 +55,7 @@ SoundAsset::SoundAsset ( { assert (_channels); - construct (boost::bind (&SoundAsset::path_from_channel, this, _1, files)); + construct (boost::bind (&SoundAsset::path_from_channel, this, _1, files), metadata); } SoundAsset::SoundAsset ( @@ -62,7 +63,8 @@ SoundAsset::SoundAsset ( string directory, string mxf_name, boost::signals2::signal* progress, - int fps, int intrinsic_duration, int channels + int fps, int intrinsic_duration, int channels, + MXFMetadata const & metadata ) : MXFAsset (directory, mxf_name, progress, fps, intrinsic_duration) , _channels (channels) @@ -70,7 +72,7 @@ SoundAsset::SoundAsset ( { assert (_channels); - construct (get_path); + construct (get_path, metadata); } SoundAsset::SoundAsset (string directory, string mxf_name) @@ -111,7 +113,7 @@ SoundAsset::path_from_channel (Channel channel, vector const & files) } void -SoundAsset::construct (boost::function get_path) +SoundAsset::construct (boost::function get_path, MXFMetadata const & metadata) { ASDCP::Rational asdcp_edit_rate (_edit_rate, 1); @@ -164,7 +166,7 @@ SoundAsset::construct (boost::function get_path) frame_buffer.Size (ASDCP::PCM::CalcFrameBufferSize (audio_desc)); ASDCP::WriterInfo writer_info; - MXFAsset::fill_writer_info (&writer_info, _uuid); + MXFAsset::fill_writer_info (&writer_info, _uuid, metadata); ASDCP::PCM::MXFWriter mxf_writer; if (ASDCP_FAILURE (mxf_writer.OpenWrite (path().string().c_str(), writer_info, audio_desc))) { @@ -303,10 +305,10 @@ SoundAsset::get_frame (int n) const } shared_ptr -SoundAsset::start_write () +SoundAsset::start_write (MXFMetadata const & metadata) { /* XXX: can't we use a shared_ptr here? */ - return shared_ptr (new SoundAssetWriter (this)); + return shared_ptr (new SoundAssetWriter (this, metadata)); } struct SoundAssetWriter::ASDCPState @@ -317,12 +319,13 @@ struct SoundAssetWriter::ASDCPState ASDCP::PCM::AudioDescriptor audio_desc; }; -SoundAssetWriter::SoundAssetWriter (SoundAsset* a) +SoundAssetWriter::SoundAssetWriter (SoundAsset* a, MXFMetadata const & m) : _state (new SoundAssetWriter::ASDCPState) , _asset (a) , _finalized (false) , _frames_written (0) , _frame_buffer_offset (0) + , _metadata (m) { /* Derived from ASDCP::Wav::SimpleWaveHeader::FillADesc */ _state->audio_desc.EditRate = ASDCP::Rational (_asset->edit_rate(), 1); @@ -339,7 +342,7 @@ SoundAssetWriter::SoundAssetWriter (SoundAsset* a) _state->frame_buffer.Size (ASDCP::PCM::CalcFrameBufferSize (_state->audio_desc)); memset (_state->frame_buffer.Data(), 0, _state->frame_buffer.Capacity()); - MXFAsset::fill_writer_info (&_state->writer_info, _asset->uuid ()); + MXFAsset::fill_writer_info (&_state->writer_info, _asset->uuid (), _metadata); if (ASDCP_FAILURE (_state->mxf_writer.OpenWrite (_asset->path().string().c_str(), _state->writer_info, _state->audio_desc))) { boost::throw_exception (FileError ("could not open audio MXF for writing", _asset->path().string())); diff --git a/src/sound_asset.h b/src/sound_asset.h index 9e6e75cf..5c230e06 100644 --- a/src/sound_asset.h +++ b/src/sound_asset.h @@ -26,12 +26,12 @@ #include "mxf_asset.h" #include "types.h" +#include "metadata.h" namespace libdcp { class SoundFrame; - class SoundAsset; class SoundAssetWriter @@ -45,7 +45,7 @@ public: private: friend class SoundAsset; - SoundAssetWriter (SoundAsset *); + SoundAssetWriter (SoundAsset *, MXFMetadata const &); /* no copy construction */ SoundAssetWriter (SoundAssetWriter const &); @@ -64,6 +64,7 @@ private: bool _finalized; int _frames_written; int _frame_buffer_offset; + MXFMetadata _metadata; }; /** @brief An asset made up of WAV files */ @@ -86,7 +87,8 @@ public: std::string mxf_name, boost::signals2::signal* progress, int fps, - int intrinsic_duration + int intrinsic_duration, + MXFMetadata const & metadata = MXFMetadata () ); /** Construct a SoundAsset, generating the MXF from some WAV files. @@ -106,7 +108,8 @@ public: boost::signals2::signal* progress, int fps, int intrinsic_duration, - int channels + int channels, + MXFMetadata const & metadata = MXFMetadata () ); SoundAsset ( @@ -122,7 +125,7 @@ public: int sampling_rate ); - boost::shared_ptr start_write (); + boost::shared_ptr start_write (MXFMetadata const & metadata = MXFMetadata ()); /** Write details of this asset to a CPL stream. * @param s Stream. @@ -142,7 +145,7 @@ public: } private: - void construct (boost::function get_path); + void construct (boost::function get_path, MXFMetadata const &); std::string path_from_channel (Channel channel, std::vector const & files); /** Number of channels in the asset */ diff --git a/src/test_mode.cc b/src/test_mode.cc deleted file mode 100644 index bfe10fee..00000000 --- a/src/test_mode.cc +++ /dev/null @@ -1,45 +0,0 @@ -/* - Copyright (C) 2012 Carl Hetherington - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. - -*/ - -/** @file src/test_mode.cc - * @brief A method to enable test mode for libdcp. - */ - -#include "KM_prng.h" -#include "test_mode.h" -#include "metadata.h" - -/** Calling this will seed the random number generator used to - * generate UUIDs with a known value, and set the DCP issue - * date to 1st January 2012 at midnight. This means that - * two runs of libdcp with the same inputs will produce - * the same output. - */ - -void -libdcp::enable_test_mode () -{ - Kumu::libdcp_test = true; - Metadata::instance()->issue_date = "2012-01-01T00:00:00+00:00"; - - /* Remove version strings */ - Metadata::instance()->issuer = "libdcp-test"; - Metadata::instance()->creator = "libdcp-test"; - Metadata::instance()->product_version = "test"; -} diff --git a/src/test_mode.h b/src/test_mode.h deleted file mode 100644 index b2e671d5..00000000 --- a/src/test_mode.h +++ /dev/null @@ -1,29 +0,0 @@ -/* - Copyright (C) 2012 Carl Hetherington - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. - -*/ - -/** @file src/test_mode.h - * @brief A method to enable test mode for libdcp. - */ - -namespace libdcp -{ - -extern void enable_test_mode (); - -} diff --git a/src/wscript b/src/wscript index 95092173..81c39926 100644 --- a/src/wscript +++ b/src/wscript @@ -27,7 +27,6 @@ def build(bld): sound_asset.cc sound_frame.cc subtitle_asset.cc - test_mode.cc types.cc util.cc version.cc @@ -36,6 +35,7 @@ def build(bld): headers = """ asset.h + cpl.h dcp.h dcp_time.h exceptions.h @@ -48,7 +48,6 @@ def build(bld): sound_asset.h sound_frame.h subtitle_asset.h - test_mode.h types.h util.h version.h diff --git a/test/tests.cc b/test/tests.cc index d33890b6..d8b7e5d4 100644 --- a/test/tests.cc +++ b/test/tests.cc @@ -59,13 +59,14 @@ BOOST_AUTO_TEST_CASE (dcp_test) { Kumu::libdcp_test = true; - libdcp::Metadata* t = libdcp::Metadata::instance (); - t->issuer = "OpenDCP 0.0.25"; - t->creator = "OpenDCP 0.0.25"; - t->company_name = "OpenDCP"; - t->product_name = "OpenDCP"; - t->product_version = "0.0.25"; - t->issue_date = "2012-07-17T04:45:18+00:00"; + libdcp::XMLMetadata xml_meta; + xml_meta.issuer = "OpenDCP 0.0.25"; + xml_meta.creator = "OpenDCP 0.0.25"; + xml_meta.issue_date = "2012-07-17T04:45:18+00:00"; + libdcp::MXFMetadata mxf_meta; + mxf_meta.company_name = "OpenDCP"; + mxf_meta.product_name = "OpenDCP"; + mxf_meta.product_version = "0.0.25"; boost::filesystem::remove_all ("build/test/foo"); boost::filesystem::create_directories ("build/test/foo"); libdcp::DCP d ("build/test/foo"); @@ -78,7 +79,8 @@ BOOST_AUTO_TEST_CASE (dcp_test) &d.Progress, 24, 24, - libdcp::Size (32, 32) + libdcp::Size (32, 32), + mxf_meta )); shared_ptr ms (new libdcp::SoundAsset ( @@ -88,13 +90,14 @@ BOOST_AUTO_TEST_CASE (dcp_test) &(d.Progress), 24, 24, - 2 + 2, + mxf_meta )); cpl->add_reel (shared_ptr (new libdcp::Reel (mp, ms, shared_ptr ()))); d.add_cpl (cpl); - d.write_xml (); + d.write_xml (xml_meta); } BOOST_AUTO_TEST_CASE (error_test) -- cgit v1.2.3 From 5f66118c2a3ece1cc6d109beae702fa384a86c4a Mon Sep 17 00:00:00 2001 From: Carl Hetherington Date: Sat, 4 May 2013 21:23:34 +0100 Subject: Bump version --- wscript | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/wscript b/wscript index e88f79bf..22e44b20 100644 --- a/wscript +++ b/wscript @@ -2,7 +2,7 @@ import subprocess import os APPNAME = 'libdcp' -VERSION = '0.49pre' +VERSION = '0.49' def options(opt): opt.load('compiler_cxx') -- cgit v1.2.3 From 34466763154ee900200e96b7d753c455a2c3414e Mon Sep 17 00:00:00 2001 From: Carl Hetherington Date: Sat, 4 May 2013 21:23:34 +0100 Subject: Bump version --- wscript | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/wscript b/wscript index 22e44b20..274408b6 100644 --- a/wscript +++ b/wscript @@ -2,7 +2,7 @@ import subprocess import os APPNAME = 'libdcp' -VERSION = '0.49' +VERSION = '0.50pre' def options(opt): opt.load('compiler_cxx') -- cgit v1.2.3 From 1368dfded40e5a774a73e2256e214bcaf4e74866 Mon Sep 17 00:00:00 2001 From: Carl Hetherington Date: Tue, 7 May 2013 15:53:38 +0100 Subject: AnnotationText is (I believe) optional. --- src/pkl_file.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/pkl_file.cc b/src/pkl_file.cc index 21763f27..6dfb627c 100644 --- a/src/pkl_file.cc +++ b/src/pkl_file.cc @@ -32,7 +32,7 @@ PKLFile::PKLFile (string file) : XMLFile (file, "PackingList") { id = string_child ("Id"); - annotation_text = string_child ("AnnotationText"); + annotation_text = optional_string_child ("AnnotationText"); issue_date = string_child ("IssueDate"); issuer = string_child ("Issuer"); creator = string_child ("Creator"); -- cgit v1.2.3 From acf47ae643e54c09e94f7fc904207d7ea6a24c22 Mon Sep 17 00:00:00 2001 From: Carl Hetherington Date: Tue, 7 May 2013 23:03:51 +0100 Subject: Better error on JPEG2000 decode failure. --- src/util.cc | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/util.cc b/src/util.cc index c66e63f5..6bee0dc7 100644 --- a/src/util.cc +++ b/src/util.cc @@ -26,6 +26,7 @@ #include #include #include +#include #include #include "KM_util.h" #include "KM_fileio.h" @@ -41,6 +42,7 @@ using std::stringstream; using std::min; using std::max; using boost::shared_ptr; +using boost::lexical_cast; using namespace libdcp; /** Create a UUID. @@ -187,7 +189,7 @@ libdcp::decompress_j2k (uint8_t* data, int64_t size, int reduce) if (!image) { opj_destroy_decompress (decoder); opj_cio_close (cio); - boost::throw_exception (DCPReadError ("could not decode JPEG2000 codestream")); + boost::throw_exception (DCPReadError ("could not decode JPEG2000 codestream of " + lexical_cast (size) + " bytes.")); } opj_cio_close (cio); -- cgit v1.2.3 From 25e46b967956a9467bbb054f7ac339288304526d Mon Sep 17 00:00:00 2001 From: Carl Hetherington Date: Wed, 8 May 2013 09:49:31 +0100 Subject: Bump version --- wscript | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/wscript b/wscript index 274408b6..3721ec85 100644 --- a/wscript +++ b/wscript @@ -2,7 +2,7 @@ import subprocess import os APPNAME = 'libdcp' -VERSION = '0.50pre' +VERSION = '0.50' def options(opt): opt.load('compiler_cxx') -- cgit v1.2.3 From d77d0d1bd972f6343752ca45a3d5e0a0924e2d50 Mon Sep 17 00:00:00 2001 From: Carl Hetherington Date: Wed, 8 May 2013 09:49:31 +0100 Subject: Bump version --- wscript | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/wscript b/wscript index 3721ec85..e8de8385 100644 --- a/wscript +++ b/wscript @@ -2,7 +2,7 @@ import subprocess import os APPNAME = 'libdcp' -VERSION = '0.50' +VERSION = '0.51pre' def options(opt): opt.load('compiler_cxx') -- cgit v1.2.3 From 797916ae28d976f3c5be62d37b45864219af6098 Mon Sep 17 00:00:00 2001 From: Carl Hetherington Date: Mon, 13 May 2013 14:20:36 +0100 Subject: Use libcxml. Lump all static configuration flags into one. --- asdcplib/src/wscript | 6 +- src/asset_map.cc | 36 +++---- src/asset_map.h | 12 +-- src/cpl_file.cc | 147 ++++++++++++++-------------- src/cpl_file.h | 35 +++---- src/pkl_file.cc | 30 +++--- src/pkl_file.h | 6 +- src/subtitle_asset.cc | 88 +++++++++-------- src/subtitle_asset.h | 22 ++--- src/wscript | 8 +- src/xml.cc | 263 -------------------------------------------------- src/xml.h | 156 ++++++++++++++---------------- wscript | 13 +-- 13 files changed, 275 insertions(+), 547 deletions(-) delete mode 100644 src/xml.cc diff --git a/asdcplib/src/wscript b/asdcplib/src/wscript index 6f9e1f44..661971ac 100644 --- a/asdcplib/src/wscript +++ b/asdcplib/src/wscript @@ -8,7 +8,7 @@ def configure(conf): conf.env.append_value('CXXFLAGS', '-DASDCP_PLATFORM="linux"') def build(bld): - if bld.env.STATIC_LIBDCP: + if bld.env.STATIC: obj = bld(features = 'cxx cxxstlib') else: obj = bld(features = 'cxx cxxshlib') @@ -27,7 +27,7 @@ def build(bld): KM_prng.cpp """ - if bld.env.STATIC_LIBDCP: + if bld.env.STATIC: obj = bld(features = 'cxx cxxstlib') else: obj = bld(features = 'cxx cxxshlib') @@ -66,6 +66,6 @@ def build(bld): MDD.cpp """ - if bld.env.STATIC_LIBDCP: + if bld.env.STATIC: bld.install_files('${PREFIX}/lib', 'libkumu-libdcp.a') bld.install_files('${PREFIX}/lib', 'libasdcp-libdcp.a') diff --git a/src/asset_map.cc b/src/asset_map.cc index 8fcc515f..fb42f363 100644 --- a/src/asset_map.cc +++ b/src/asset_map.cc @@ -24,6 +24,7 @@ #include #include "asset_map.h" #include "util.h" +#include "xml.h" using std::string; using std::list; @@ -31,28 +32,27 @@ using boost::shared_ptr; using namespace libdcp; AssetMap::AssetMap (string file) - : XMLFile (file, "AssetMap") { - id = string_child ("Id"); - creator = string_child ("Creator"); - volume_count = int64_child ("VolumeCount"); - issue_date = string_child ("IssueDate"); - issuer = string_child ("Issuer"); - assets = type_grand_children ("AssetList", "Asset"); + cxml::File f (file, "AssetMap"); + + id = f.string_child ("Id"); + creator = f.string_child ("Creator"); + volume_count = f.number_child ("VolumeCount"); + issue_date = f.string_child ("IssueDate"); + issuer = f.string_child ("Issuer"); + assets = type_grand_children (f, "AssetList", "Asset"); } -AssetMapAsset::AssetMapAsset (xmlpp::Node const * node) - : XMLNode (node) +AssetMapAsset::AssetMapAsset (shared_ptr node) { - id = string_child ("Id"); - packing_list = optional_string_child ("PackingList"); - chunks = type_grand_children ("ChunkList", "Chunk"); + id = node->string_child ("Id"); + packing_list = node->optional_string_child ("PackingList").get_value_or (""); + chunks = type_grand_children (node, "ChunkList", "Chunk"); } -Chunk::Chunk (xmlpp::Node const * node) - : XMLNode (node) +Chunk::Chunk (shared_ptr node) { - path = string_child ("Path"); + path = node->string_child ("Path"); string const prefix = "file://"; @@ -60,9 +60,9 @@ Chunk::Chunk (xmlpp::Node const * node) path = path.substr (prefix.length()); } - volume_index = optional_int64_child ("VolumeIndex"); - offset = optional_int64_child ("Offset"); - length = optional_int64_child ("Length"); + volume_index = node->optional_number_child ("VolumeIndex").get_value_or (0); + offset = node->optional_number_child ("Offset").get_value_or (0); + length = node->optional_number_child ("Length").get_value_or (0); } shared_ptr diff --git a/src/asset_map.h b/src/asset_map.h index 8cf89b4b..e7ba6978 100644 --- a/src/asset_map.h +++ b/src/asset_map.h @@ -23,18 +23,18 @@ #include #include -#include "xml.h" +#include namespace libdcp { /** @class Chunk * @brief A simple parser for and representation of a \ node within an asset map. */ -class Chunk : public XMLNode +class Chunk { public: Chunk (); - Chunk (xmlpp::Node const * node); + Chunk (boost::shared_ptr node); std::string path; int64_t volume_index; @@ -45,11 +45,11 @@ public: /** @class AssetMapAsset * @brief A simple parser for and representation of an \ node within an asset map. */ -class AssetMapAsset : public XMLNode +class AssetMapAsset { public: AssetMapAsset (); - AssetMapAsset (xmlpp::Node const * node); + AssetMapAsset (boost::shared_ptr node); std::string id; std::string packing_list; @@ -59,7 +59,7 @@ public: /** @class AssetMap * @brief A simple parser for and representation of an asset map file. */ -class AssetMap : public XMLFile +class AssetMap { public: AssetMap (std::string file); diff --git a/src/cpl_file.cc b/src/cpl_file.cc index 6a17d721..3126b99c 100644 --- a/src/cpl_file.cc +++ b/src/cpl_file.cc @@ -23,126 +23,125 @@ #include #include "cpl_file.h" +#include "xml.h" +#include "util.h" -using namespace std; +using std::string; +using std::bad_cast; +using boost::shared_ptr; using namespace libdcp; CPLFile::CPLFile (string file) - : XMLFile (file, "CompositionPlaylist") { - id = string_child ("Id"); - annotation_text = optional_string_child ("AnnotationText"); - issue_date = string_child ("IssueDate"); - creator = optional_string_child ("Creator"); - content_title_text = string_child ("ContentTitleText"); - content_kind = kind_child ("ContentKind"); - content_version = optional_type_child ("ContentVersion"); - ignore_child ("RatingList"); - reels = type_grand_children ("ReelList", "Reel"); - - ignore_child ("Issuer"); - ignore_child ("Signer"); - ignore_child ("Signature"); - - done (); + cxml::File f (file, "CompositionPlaylist"); + + id = f.string_child ("Id"); + 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")); + content_version = optional_type_child (f, "ContentVersion"); + f.ignore_child ("RatingList"); + reels = type_grand_children (f, "ReelList", "Reel"); + + f.ignore_child ("Issuer"); + f.ignore_child ("Signer"); + f.ignore_child ("Signature"); + + f.done (); } -ContentVersion::ContentVersion (xmlpp::Node const * node) - : XMLNode (node) +ContentVersion::ContentVersion (shared_ptr node) { - id = optional_string_child ("Id"); - label_text = string_child ("LabelText"); - done (); + id = node->optional_string_child ("Id").get_value_or (""); + label_text = node->string_child ("LabelText"); + node->done (); } -CPLReel::CPLReel (xmlpp::Node const * node) - : XMLNode (node) +CPLReel::CPLReel (shared_ptr node) { - id = string_child ("Id"); - asset_list = type_child ("AssetList"); + id = node->string_child ("Id"); + asset_list = type_child (node, "AssetList"); - ignore_child ("AnnotationText"); - done (); + node->ignore_child ("AnnotationText"); + node->done (); } -CPLAssetList::CPLAssetList (xmlpp::Node const * node) - : XMLNode (node) +CPLAssetList::CPLAssetList (shared_ptr node) { - main_picture = optional_type_child ("MainPicture"); - main_stereoscopic_picture = optional_type_child ("MainStereoscopicPicture"); - main_sound = optional_type_child ("MainSound"); - main_subtitle = optional_type_child ("MainSubtitle"); + main_picture = optional_type_child (node, "MainPicture"); + main_stereoscopic_picture = optional_type_child (node, "MainStereoscopicPicture"); + main_sound = optional_type_child (node, "MainSound"); + main_subtitle = optional_type_child (node, "MainSubtitle"); - done (); + node->done (); } -MainPicture::MainPicture (xmlpp::Node const * node) +MainPicture::MainPicture (shared_ptr node) : Picture (node) { } -MainStereoscopicPicture::MainStereoscopicPicture (xmlpp::Node const * node) +MainStereoscopicPicture::MainStereoscopicPicture (shared_ptr node) : Picture (node) { } -Picture::Picture (xmlpp::Node const * node) - : XMLNode (node) +Picture::Picture (shared_ptr node) { - id = string_child ("Id"); - annotation_text = optional_string_child ("AnnotationText"); - edit_rate = fraction_child ("EditRate"); - intrinsic_duration = int64_child ("IntrinsicDuration"); - entry_point = int64_child ("EntryPoint"); - duration = int64_child ("Duration"); - frame_rate = fraction_child ("FrameRate"); + id = node->string_child ("Id"); + annotation_text = node->optional_string_child ("AnnotationText").get_value_or (""); + edit_rate = Fraction (node->string_child ("EditRate")); + intrinsic_duration = node->number_child ("IntrinsicDuration"); + entry_point = node->number_child ("EntryPoint"); + duration = node->number_child ("Duration"); + frame_rate = Fraction (node->string_child ("FrameRate")); try { - screen_aspect_ratio = fraction_child ("ScreenAspectRatio"); + screen_aspect_ratio = Fraction (node->string_child ("ScreenAspectRatio")); } catch (XMLError& e) { /* Maybe it's not a fraction */ } try { - float f = float_child ("ScreenAspectRatio"); + float f = node->number_child ("ScreenAspectRatio"); screen_aspect_ratio = Fraction (f * 1000, 1000); } catch (bad_cast& e) { } - ignore_child ("Hash"); + node->ignore_child ("Hash"); - done (); + node->done (); } -MainSound::MainSound (xmlpp::Node const * node) - : XMLNode (node) +MainSound::MainSound (shared_ptr node) { - id = string_child ("Id"); - annotation_text = optional_string_child ("AnnotationText"); - edit_rate = fraction_child ("EditRate"); - intrinsic_duration = int64_child ("IntrinsicDuration"); - entry_point = int64_child ("EntryPoint"); - duration = int64_child ("Duration"); - - ignore_child ("Hash"); - ignore_child ("Language"); + id = node->string_child ("Id"); + annotation_text = node->optional_string_child ("AnnotationText").get_value_or (""); + edit_rate = Fraction (node->string_child ("EditRate")); + intrinsic_duration = node->number_child ("IntrinsicDuration"); + entry_point = node->number_child ("EntryPoint"); + duration = node->number_child ("Duration"); + + node->ignore_child ("Hash"); + node->ignore_child ("Language"); - done (); + node->done (); } -MainSubtitle::MainSubtitle (xmlpp::Node const * node) - : XMLNode (node) +MainSubtitle::MainSubtitle (shared_ptr node) { - id = string_child ("Id"); - annotation_text = optional_string_child ("AnnotationText"); - edit_rate = fraction_child ("EditRate"); - intrinsic_duration = int64_child ("IntrinsicDuration"); - entry_point = int64_child ("EntryPoint"); - duration = int64_child ("Duration"); - - ignore_child ("Hash"); - ignore_child ("Language"); + id = node->string_child ("Id"); + annotation_text = node->optional_string_child ("AnnotationText").get_value_or (""); + edit_rate = Fraction (node->string_child ("EditRate")); + intrinsic_duration = node->number_child ("IntrinsicDuration"); + entry_point = node->number_child ("EntryPoint"); + duration = node->number_child ("Duration"); + + node->ignore_child ("Hash"); + node->ignore_child ("Language"); - done (); + node->done (); } diff --git a/src/cpl_file.h b/src/cpl_file.h index 44115401..b17f47cd 100644 --- a/src/cpl_file.h +++ b/src/cpl_file.h @@ -23,16 +23,17 @@ #include #include -#include "xml.h" +#include +#include "types.h" namespace libdcp { -/** @brief A simple parser for and representation of a CPL \ node */ -class Picture : public XMLNode +/** @brief A simple representation of a CPL \ node */ +class Picture { public: Picture () {} - Picture (xmlpp::Node const * node); + Picture (boost::shared_ptr node); std::string id; std::string annotation_text; @@ -53,7 +54,7 @@ class MainPicture : public Picture { public: MainPicture () {} - MainPicture (xmlpp::Node const * node); + MainPicture (boost::shared_ptr node); }; /** @brief A simple parser for and representation of a CPL \ node */ @@ -61,15 +62,15 @@ class MainStereoscopicPicture : public Picture { public: MainStereoscopicPicture () {} - MainStereoscopicPicture (xmlpp::Node const * node); + MainStereoscopicPicture (boost::shared_ptr node); }; /** @brief A simple parser for and representation of a CPL \ node */ -class MainSound : public XMLNode +class MainSound { public: MainSound () {} - MainSound (xmlpp::Node const * node); + MainSound (boost::shared_ptr node); std::string id; std::string annotation_text; @@ -80,11 +81,11 @@ public: }; /** @brief A simple parser for and representation of a CPL \ node */ -class MainSubtitle : public XMLNode +class MainSubtitle { public: MainSubtitle () {} - MainSubtitle (xmlpp::Node const * node); + MainSubtitle (boost::shared_ptr node); std::string id; std::string annotation_text; @@ -95,11 +96,11 @@ public: }; /** @brief A simple parser for and representation of a CPL \ node */ -class CPLAssetList : public XMLNode +class CPLAssetList { public: CPLAssetList () {} - CPLAssetList (xmlpp::Node const * node); + CPLAssetList (boost::shared_ptr node); boost::shared_ptr main_picture; boost::shared_ptr main_stereoscopic_picture; @@ -108,11 +109,11 @@ public: }; /** @brief A simple parser for and representation of a CPL \ node */ -class CPLReel : public XMLNode +class CPLReel { public: CPLReel () {} - CPLReel (xmlpp::Node const * node); + CPLReel (boost::shared_ptr node); std::string id; boost::shared_ptr asset_list; @@ -120,11 +121,11 @@ public: /** @brief A simple parser for and representation of a CPL \ node */ -class ContentVersion : public XMLNode +class ContentVersion { public: ContentVersion () {} - ContentVersion (xmlpp::Node const * node); + ContentVersion (boost::shared_ptr node); std::string id; std::string label_text; @@ -136,7 +137,7 @@ public: * This class is used to parse XML CPL files. It is rarely necessary * for the caller to use it outside libdcp. */ -class CPLFile : public XMLFile +class CPLFile { public: /** Parse a CPL XML file into our member variables */ diff --git a/src/pkl_file.cc b/src/pkl_file.cc index 6dfb627c..9119d883 100644 --- a/src/pkl_file.cc +++ b/src/pkl_file.cc @@ -29,23 +29,23 @@ using namespace boost; using namespace libdcp; PKLFile::PKLFile (string file) - : XMLFile (file, "PackingList") { - id = string_child ("Id"); - annotation_text = optional_string_child ("AnnotationText"); - issue_date = string_child ("IssueDate"); - issuer = string_child ("Issuer"); - creator = string_child ("Creator"); - assets = type_grand_children ("AssetList", "Asset"); + cxml::File f (file, "PackingList"); + + id = f.string_child ("Id"); + annotation_text = f.optional_string_child ("AnnotationText").get_value_or (""); + issue_date = f.string_child ("IssueDate"); + issuer = f.string_child ("Issuer"); + creator = f.string_child ("Creator"); + assets = type_grand_children (f, "AssetList", "Asset"); } -PKLAsset::PKLAsset (xmlpp::Node const * node) - : XMLNode (node) +PKLAsset::PKLAsset (boost::shared_ptr node) { - id = string_child ("Id"); - annotation_text = optional_string_child ("AnnotationText"); - hash = string_child ("Hash"); - size = int64_child ("Size"); - type = string_child ("Type"); - original_file_name = optional_string_child ("OriginalFileName"); + id = node->string_child ("Id"); + annotation_text = node->optional_string_child ("AnnotationText").get_value_or (""); + hash = node->string_child ("Hash"); + size = node->number_child ("Size"); + type = node->string_child ("Type"); + original_file_name = node->optional_string_child ("OriginalFileName").get_value_or (""); } diff --git a/src/pkl_file.h b/src/pkl_file.h index b64da5da..77b83fca 100644 --- a/src/pkl_file.h +++ b/src/pkl_file.h @@ -26,11 +26,11 @@ namespace libdcp { -class PKLAsset : public XMLNode +class PKLAsset { public: PKLAsset () {} - PKLAsset (xmlpp::Node const * node); + PKLAsset (boost::shared_ptr); std::string id; std::string annotation_text; @@ -40,7 +40,7 @@ public: std::string original_file_name; }; -class PKLFile : public XMLFile +class PKLFile { public: PKLFile (std::string file); diff --git a/src/subtitle_asset.cc b/src/subtitle_asset.cc index ba91cf90..1eae1fcc 100644 --- a/src/subtitle_asset.cc +++ b/src/subtitle_asset.cc @@ -22,6 +22,7 @@ #include #include "subtitle_asset.h" #include "util.h" +#include "xml.h" using std::string; using std::list; @@ -30,6 +31,7 @@ using std::ofstream; using std::stringstream; using boost::shared_ptr; using boost::lexical_cast; +using boost::optional; using namespace libdcp; SubtitleAsset::SubtitleAsset (string directory, string xml_file) @@ -52,7 +54,7 @@ SubtitleAsset::SubtitleAsset (string directory, string movie_title, string langu void SubtitleAsset::read_xml (string xml_file) { - shared_ptr xml (new XMLFile (xml_file, "DCSubtitle")); + shared_ptr xml (new cxml::File (xml_file, "DCSubtitle")); _uuid = xml->string_child ("SubtitleID"); _movie_title = xml->string_child ("MovieTitle"); @@ -61,8 +63,8 @@ SubtitleAsset::read_xml (string xml_file) xml->ignore_child ("LoadFont"); - list > font_nodes = xml->type_children ("Font"); - _load_font_nodes = xml->type_children ("LoadFont"); + list > font_nodes = type_children (xml, "Font"); + _load_font_nodes = type_children (xml, "LoadFont"); /* Now make Subtitle objects to represent the raw XML nodes in a sane way. @@ -74,7 +76,7 @@ SubtitleAsset::read_xml (string xml_file) void SubtitleAsset::examine_font_nodes ( - shared_ptr xml, + shared_ptr xml, list > const & font_nodes, ParseState& parse_state ) @@ -100,7 +102,7 @@ SubtitleAsset::examine_font_nodes ( void SubtitleAsset::examine_text_nodes ( - shared_ptr xml, + shared_ptr xml, list > const & text_nodes, ParseState& parse_state ) @@ -152,23 +154,28 @@ SubtitleAsset::maybe_add_subtitle (string text, ParseState const & parse_state) ); } -FontNode::FontNode (xmlpp::Node const * node) - : XMLNode (node) +FontNode::FontNode (shared_ptr node) { - text = content (); + text = node->content (); - id = optional_string_attribute ("Id"); - size = optional_int64_attribute ("Size"); - italic = optional_bool_attribute ("Italic"); - color = optional_color_attribute ("Color"); - string const e = optional_string_attribute ("Effect"); - if (!e.empty ()) { - effect = string_to_effect (e); + id = node->optional_string_attribute ("Id").get_value_or (""); + size = node->optional_number_attribute ("Size").get_value_or (0); + italic = node->optional_bool_attribute ("Italic").get_value_or (false); + optional c = node->optional_string_attribute ("Color"); + if (c) { + color = Color (c.get ()); } - effect_color = optional_color_attribute ("EffectColor"); - subtitle_nodes = type_children ("Subtitle"); - font_nodes = type_children ("Font"); - text_nodes = type_children ("Text"); + optional const e = node->optional_string_attribute ("Effect"); + if (e) { + effect = string_to_effect (e.get ()); + } + c = node->optional_string_attribute ( "EffectColor"); + if (c) { + effect_color = Color (c.get ()); + } + subtitle_nodes = type_children (node, "Subtitle"); + font_nodes = type_children (node, "Font"); + text_nodes = type_children (node, "Text"); } FontNode::FontNode (list > const & font_nodes) @@ -199,29 +206,27 @@ FontNode::FontNode (list > const & font_nodes) } } -LoadFontNode::LoadFontNode (xmlpp::Node const * node) - : XMLNode (node) +LoadFontNode::LoadFontNode (shared_ptr node) { - id = string_attribute ("Id"); - uri = string_attribute ("URI"); + id = node->string_attribute ("Id"); + uri = node->string_attribute ("URI"); } -SubtitleNode::SubtitleNode (xmlpp::Node const * node) - : XMLNode (node) +SubtitleNode::SubtitleNode (shared_ptr node) { - in = time_attribute ("TimeIn"); - out = time_attribute ("TimeOut"); - font_nodes = type_children ("Font"); - text_nodes = type_children ("Text"); - fade_up_time = fade_time ("FadeUpTime"); - fade_down_time = fade_time ("FadeDownTime"); + in = Time (node->string_attribute ("TimeIn")); + out = Time (node->string_attribute ("TimeOut")); + font_nodes = type_children (node, "Font"); + text_nodes = type_children (node, "Text"); + fade_up_time = fade_time (node, "FadeUpTime"); + fade_down_time = fade_time (node, "FadeDownTime"); } Time -SubtitleNode::fade_time (string name) +SubtitleNode::fade_time (shared_ptr node, string name) { - string const u = optional_string_attribute (name); + string const u = node->optional_string_attribute (name).get_value_or (""); Time t; if (u.empty ()) { @@ -239,18 +244,17 @@ SubtitleNode::fade_time (string name) return t; } -TextNode::TextNode (xmlpp::Node const * node) - : XMLNode (node) - , v_align (CENTER) +TextNode::TextNode (shared_ptr node) + : v_align (CENTER) { - text = content (); - v_position = float_attribute ("VPosition"); - string const v = optional_string_attribute ("VAlign"); - if (!v.empty ()) { - v_align = string_to_valign (v); + text = node->content (); + v_position = node->number_attribute ("VPosition"); + optional v = node->optional_string_attribute ("VAlign"); + if (v) { + v_align = string_to_valign (v.get ()); } - font_nodes = type_children ("Font"); + font_nodes = type_children (node, "Font"); } list > diff --git a/src/subtitle_asset.h b/src/subtitle_asset.h index 1e31df2b..591985d1 100644 --- a/src/subtitle_asset.h +++ b/src/subtitle_asset.h @@ -26,11 +26,11 @@ namespace libdcp class FontNode; -class TextNode : public XMLNode +class TextNode { public: TextNode () {} - TextNode (xmlpp::Node const * node); + TextNode (boost::shared_ptr node); float v_position; VAlign v_align; @@ -38,11 +38,11 @@ public: std::list > font_nodes; }; -class SubtitleNode : public XMLNode +class SubtitleNode { public: SubtitleNode () {} - SubtitleNode (xmlpp::Node const * node); + SubtitleNode (boost::shared_ptr node); Time in; Time out; @@ -52,14 +52,14 @@ public: std::list > text_nodes; private: - Time fade_time (std::string name); + Time fade_time (boost::shared_ptr, std::string name); }; -class FontNode : public XMLNode +class FontNode { public: FontNode () {} - FontNode (xmlpp::Node const * node); + FontNode (boost::shared_ptr node); FontNode (std::list > const & font_nodes); std::string text; @@ -75,11 +75,11 @@ public: std::list > text_nodes; }; -class LoadFontNode : public XMLNode +class LoadFontNode { public: LoadFontNode () {} - LoadFontNode (xmlpp::Node const * node); + LoadFontNode (boost::shared_ptr node); std::string id; std::string uri; @@ -218,13 +218,13 @@ private: void maybe_add_subtitle (std::string text, ParseState const & parse_state); void examine_font_nodes ( - boost::shared_ptr xml, + boost::shared_ptr xml, std::list > const & font_nodes, ParseState& parse_state ); void examine_text_nodes ( - boost::shared_ptr xml, + boost::shared_ptr xml, std::list > const & text_nodes, ParseState& parse_state ); diff --git a/src/wscript b/src/wscript index 81c39926..fb8f688e 100644 --- a/src/wscript +++ b/src/wscript @@ -1,5 +1,5 @@ def build(bld): - if bld.env.STATIC_LIBDCP: + if bld.env.STATIC: obj = bld(features = 'cxx cxxstlib') else: obj = bld(features = 'cxx cxxshlib') @@ -7,7 +7,7 @@ def build(bld): obj.name = 'libdcp' obj.target = 'dcp' obj.export_includes = ['.'] - obj.uselib = 'BOOST_FILESYSTEM BOOST_SIGNALS2 OPENSSL SIGC++ LIBXML++ OPENJPEG' + obj.uselib = 'BOOST_FILESYSTEM BOOST_SIGNALS2 OPENSSL SIGC++ LIBXML++ OPENJPEG CXML' obj.use = 'libkumu-libdcp libasdcp-libdcp' obj.source = """ asset.cc @@ -30,7 +30,6 @@ def build(bld): types.cc util.cc version.cc - xml.cc """ headers = """ @@ -51,9 +50,8 @@ def build(bld): types.h util.h version.h - xml.h """ bld.install_files('${PREFIX}/include/libdcp', headers) - if bld.env.STATIC_LIBDCP: + if bld.env.STATIC: bld.install_files('${PREFIX}/lib', 'libdcp.a') diff --git a/src/xml.cc b/src/xml.cc deleted file mode 100644 index 508790ab..00000000 --- a/src/xml.cc +++ /dev/null @@ -1,263 +0,0 @@ -#include -#include -#include -#include -#include -#include -#include "xml.h" -#include "exceptions.h" -#include "util.h" - -using namespace std; -using namespace boost; -using namespace libdcp; - -XMLNode::XMLNode () - : _node (0) -{ - -} - -XMLNode::XMLNode (xmlpp::Node const * node) - : _node (node) -{ - -} - -xmlpp::Node * -XMLNode::node_child (string name) -{ - list n = node_children (name); - if (n.size() > 1) { - boost::throw_exception (XMLError ("duplicate XML tag " + name)); - } else if (n.empty ()) { - boost::throw_exception (XMLError ("missing XML tag " + name + " in " + _node->get_name())); - } - - return n.front (); -} - -list -XMLNode::node_children (string name) -{ - /* XXX: using find / get_path should work here, but I can't follow - how get_path works. - */ - - xmlpp::Node::NodeList c = _node->get_children (); - - list n; - for (xmlpp::Node::NodeList::iterator i = c.begin (); i != c.end(); ++i) { - if ((*i)->get_name() == name) { - n.push_back (*i); - } - } - - _taken.push_back (name); - return n; -} - -string -XMLNode::string_child (string name) -{ - return XMLNode (node_child (name)).content (); -} - -string -XMLNode::optional_string_child (string name) -{ - list nodes = node_children (name); - if (nodes.size() > 2) { - boost::throw_exception (XMLError ("duplicate XML tag " + name)); - } - - if (nodes.empty ()) { - return ""; - } - - return string_child (name); -} - -ContentKind -XMLNode::kind_child (string name) -{ - return content_kind_from_string (string_child (name)); -} - -Fraction -XMLNode::fraction_child (string name) -{ - return Fraction (string_child (name)); -} - -int64_t -XMLNode::int64_child (string name) -{ - string s = string_child (name); - erase_all (s, " "); - return lexical_cast (s); -} - -int64_t -XMLNode::optional_int64_child (string name) -{ - list nodes = node_children (name); - if (nodes.size() > 2) { - boost::throw_exception (XMLError ("duplicate XML tag " + name)); - } - - if (nodes.empty ()) { - return 0; - } - - return int64_child (name); -} - -float -XMLNode::float_child (string name) -{ - return lexical_cast (string_child (name)); -} - -void -XMLNode::ignore_child (string name) -{ - _taken.push_back (name); -} - -Time -XMLNode::time_attribute (string name) -{ - return Time (string_attribute (name)); -} - -string -XMLNode::string_attribute (string name) -{ - xmlpp::Element const * e = dynamic_cast (_node); - if (!e) { - boost::throw_exception (XMLError ("missing attribute")); - } - - xmlpp::Attribute* a = e->get_attribute (name); - if (!a) { - boost::throw_exception (XMLError ("missing attribute")); - } - - return a->get_value (); -} - -string -XMLNode::optional_string_attribute (string name) -{ - xmlpp::Element const * e = dynamic_cast (_node); - if (!e) { - return ""; - } - - xmlpp::Attribute* a = e->get_attribute (name); - if (!a) { - return ""; - } - - return a->get_value (); -} - -float -XMLNode::float_attribute (string name) -{ - return lexical_cast (string_attribute (name)); -} - -int64_t -XMLNode::int64_attribute (string name) -{ - return lexical_cast (string_attribute (name)); -} - -int64_t -XMLNode::optional_int64_attribute (string name) -{ - string const s = optional_string_attribute (name); - if (s.empty ()) { - return 0; - } - - return lexical_cast (s); -} - -optional -XMLNode::optional_bool_attribute (string name) -{ - string const s = optional_string_attribute (name); - if (s.empty ()) { - return optional (); - } - - if (s == "1" || s == "yes") { - return optional (true); - } - - return optional (false); -} - -optional -XMLNode::optional_color_attribute (string name) -{ - string const s = optional_string_attribute (name); - if (s.empty ()) { - return optional (); - } - - return optional (Color (s)); -} - -void -XMLNode::done () -{ - xmlpp::Node::NodeList c = _node->get_children (); - for (xmlpp::Node::NodeList::iterator i = c.begin(); i != c.end(); ++i) { - if (dynamic_cast (*i) && find (_taken.begin(), _taken.end(), (*i)->get_name()) == _taken.end ()) { - boost::throw_exception (XMLError ("unexpected XML node " + (*i)->get_name())); - } - } -} - -string -XMLNode::content () -{ - string content; - - xmlpp::Node::NodeList c = _node->get_children (); - for (xmlpp::Node::NodeList::const_iterator i = c.begin(); i != c.end(); ++i) { - xmlpp::ContentNode const * v = dynamic_cast (*i); - if (v) { - content += v->get_content (); - } - } - - return content; -} - -XMLFile::XMLFile (string file, string root_name) -{ - if (!filesystem::exists (file)) { - boost::throw_exception (FileError ("XML file does not exist", file)); - } - - _parser = new xmlpp::DomParser; - _parser->parse_file (file); - if (!_parser) { - boost::throw_exception (XMLError ("could not parse XML")); - } - - _node = _parser->get_document()->get_root_node (); - if (_node->get_name() != root_name) { - boost::throw_exception (XMLError ("unrecognised root node")); - } -} - -XMLFile::~XMLFile () -{ - delete _parser; -} diff --git a/src/xml.h b/src/xml.h index 6fc0d0fa..5978ff7e 100644 --- a/src/xml.h +++ b/src/xml.h @@ -1,103 +1,91 @@ -#ifndef LIBDCP_XML_H -#define LIBDCP_XML_H +/* + Copyright (C) 2013 Carl Hetherington -#include -#include -#include -#include -#include -#include -#include "types.h" -#include "exceptions.h" -#include "dcp_time.h" + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. -namespace xmlpp { - class Node; - class DomParser; -} + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. -namespace libdcp { + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. -/** @brief A helper class for XML nodes */ -class XMLNode -{ -public: - XMLNode (); - XMLNode (xmlpp::Node const * node); +*/ - std::string string_child (std::string); - std::string optional_string_child (std::string); - ContentKind kind_child (std::string); - Fraction fraction_child (std::string); - int64_t int64_child (std::string); - int64_t optional_int64_child (std::string); - float float_child (std::string); - void ignore_child (std::string); - void done (); +#ifndef LIBDCP_XML_H +#define LIBDCP_XML_H - Time time_attribute (std::string); - float float_attribute (std::string); - std::string string_attribute (std::string); - std::string optional_string_attribute (std::string); - int64_t int64_attribute (std::string); - int64_t optional_int64_attribute (std::string); - boost::optional optional_bool_attribute (std::string); - boost::optional optional_color_attribute (std::string); +#include +#include "exceptions.h" - std::string content (); +namespace libdcp +{ - template - boost::shared_ptr type_child (std::string name) { - return boost::shared_ptr (new T (node_child (name))); +template +boost::shared_ptr +optional_type_child (cxml::Node const & node, std::string name) +{ + std::list > n = node.node_children (name); + if (n.size() > 1) { + throw XMLError ("duplicate XML tag"); + } else if (n.empty ()) { + return boost::shared_ptr (); } - template - boost::shared_ptr optional_type_child (std::string name) { - std::list n = node_children (name); - if (n.size() > 1) { - throw XMLError ("duplicate XML tag"); - } else if (n.empty ()) { - return boost::shared_ptr (); - } - - return boost::shared_ptr (new T (n.front ())); - } + return boost::shared_ptr (new T (n.front ())); +} + +template +boost::shared_ptr type_child (boost::shared_ptr node, std::string name) { + return boost::shared_ptr (new T (node->node_child (name))); +} - template - std::list > type_children (std::string name) { - std::list n = node_children (name); - std::list > r; - for (typename std::list::iterator i = n.begin(); i != n.end(); ++i) { - r.push_back (boost::shared_ptr (new T (*i))); - } - return r; - } +template +boost::shared_ptr +optional_type_child (boost::shared_ptr node, std::string name) +{ + return optional_type_child (*node.get(), name); +} - template - std::list > type_grand_children (std::string name, std::string sub) { - XMLNode p (node_child (name)); - return p.type_children (sub); +template +std::list > +type_children (cxml::Node const & node, std::string name) +{ + std::list > n = node.node_children (name); + std::list > r; + for (typename std::list >::iterator i = n.begin(); i != n.end(); ++i) { + r.push_back (boost::shared_ptr (new T (*i))); } + return r; +} - xmlpp::Node const * _node; - -private: - xmlpp::Node* node_child (std::string); - std::list node_children (std::string); - std::list _taken; -}; - -/** @brief A helper class for XML files */ -class XMLFile : public XMLNode +template +std::list > +type_children (boost::shared_ptr node, std::string name) { -public: - XMLFile (std::string file, std::string root_name); - virtual ~XMLFile (); - -private: - xmlpp::DomParser* _parser; -}; + return type_children (*node.get(), name); +} + +template +std::list > +type_grand_children (cxml::Node const & node, std::string name, std::string sub) +{ + boost::shared_ptr p = node.node_child (name); + return type_children (p, sub); +} +template +std::list > +type_grand_children (boost::shared_ptr node, std::string name, std::string sub) +{ + return type_grand_children (*node.get(), name, sub); +} + } #endif diff --git a/wscript b/wscript index e8de8385..5414f13d 100644 --- a/wscript +++ b/wscript @@ -8,8 +8,7 @@ def options(opt): opt.load('compiler_cxx') opt.add_option('--target-windows', action='store_true', default = False, help = 'set up to do a cross-compile to Windows') opt.add_option('--enable-debug', action='store_true', default = False, help = 'build with debugging information and without optimisation') - opt.add_option('--static-openjpeg', action='store_true', default = False, help = 'link statically to openjpeg') - opt.add_option('--static-libdcp', action='store_true', default = False, help = 'build libdcp and in-tree dependencies statically') + opt.add_option('--static', action='store_true', default = False, help = 'build libdcp and in-tree dependencies statically, and link statically to openjpeg and cxml') def configure(conf): conf.load('compiler_cxx') @@ -17,8 +16,7 @@ def configure(conf): conf.env.append_value('CXXFLAGS', ['-DLIBDCP_VERSION="%s"' % VERSION]) conf.env.TARGET_WINDOWS = conf.options.target_windows - conf.env.STATIC_OPENJPEG = conf.options.static_openjpeg - conf.env.STATIC_LIBDCP = conf.options.static_libdcp + conf.env.STATIC = conf.options.static conf.env.ENABLE_DEBUG = conf.options.enable_debug if conf.options.target_windows: @@ -28,8 +26,7 @@ def configure(conf): conf.check_cfg(package = 'openssl', args = '--cflags --libs', uselib_store = 'OPENSSL', mandatory = True) conf.check_cfg(package = 'libxml++-2.6', args = '--cflags --libs', uselib_store = 'LIBXML++', mandatory = True) - if conf.options.static_openjpeg: - + if conf.options.static: conf.check_cc(fragment = """ #include \n #include \n @@ -39,8 +36,12 @@ def configure(conf): } """, msg = 'Checking for library openjpeg', stlib = 'openjpeg', uselib_store = 'OPENJPEG', mandatory = True) + + conf.env.HAVE_CXML = 1 + conf.env.STLIB_CXML = ['cxml'] else: conf.check_cfg(package = 'libopenjpeg', args = '--cflags --libs', uselib_store = 'OPENJPEG', mandatory = True) + conf.check_cfg(package = 'libcxml', args = '--cflags --libs', uselib_store = 'CXML', mandatory = True) if conf.options.target_windows: boost_lib_suffix = '-mt' -- cgit v1.2.3 From 7394f50d8b5334a17cac37c8956b1b7e8e5e49c8 Mon Sep 17 00:00:00 2001 From: Carl Hetherington Date: Mon, 13 May 2013 14:45:16 +0100 Subject: Try to move XML bits out into parse/ subdir. --- src/asset_map.cc | 78 ------------------------ src/asset_map.h | 77 ----------------------- src/cpl.cc | 14 ++--- src/cpl.h | 7 ++- src/cpl_file.cc | 147 -------------------------------------------- src/cpl_file.h | 157 ----------------------------------------------- src/dcp.cc | 17 +++--- src/dcp.h | 1 - src/parse/asset_map.cc | 78 ++++++++++++++++++++++++ src/parse/asset_map.h | 81 +++++++++++++++++++++++++ src/parse/cpl.cc | 147 ++++++++++++++++++++++++++++++++++++++++++++ src/parse/cpl.h | 161 +++++++++++++++++++++++++++++++++++++++++++++++++ src/parse/pkl.cc | 51 ++++++++++++++++ src/parse/pkl.h | 60 ++++++++++++++++++ src/parse/subtitle.cc | 135 +++++++++++++++++++++++++++++++++++++++++ src/parse/subtitle.h | 93 ++++++++++++++++++++++++++++ src/pkl_file.cc | 51 ---------------- src/pkl_file.h | 56 ----------------- src/subtitle_asset.cc | 125 ++++---------------------------------- src/subtitle_asset.h | 74 +++-------------------- src/wscript | 8 ++- 21 files changed, 849 insertions(+), 769 deletions(-) delete mode 100644 src/asset_map.cc delete mode 100644 src/asset_map.h delete mode 100644 src/cpl_file.cc delete mode 100644 src/cpl_file.h create mode 100644 src/parse/asset_map.cc create mode 100644 src/parse/asset_map.h create mode 100644 src/parse/cpl.cc create mode 100644 src/parse/cpl.h create mode 100644 src/parse/pkl.cc create mode 100644 src/parse/pkl.h create mode 100644 src/parse/subtitle.cc create mode 100644 src/parse/subtitle.h delete mode 100644 src/pkl_file.cc delete mode 100644 src/pkl_file.h diff --git a/src/asset_map.cc b/src/asset_map.cc deleted file mode 100644 index fb42f363..00000000 --- a/src/asset_map.cc +++ /dev/null @@ -1,78 +0,0 @@ -/* - Copyright (C) 2012 Carl Hetherington - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. - -*/ - -/** @file src/asset_map.cc - * @brief Classes used to parse a AssetMap. - */ - -#include -#include "asset_map.h" -#include "util.h" -#include "xml.h" - -using std::string; -using std::list; -using boost::shared_ptr; -using namespace libdcp; - -AssetMap::AssetMap (string file) -{ - cxml::File f (file, "AssetMap"); - - id = f.string_child ("Id"); - creator = f.string_child ("Creator"); - volume_count = f.number_child ("VolumeCount"); - issue_date = f.string_child ("IssueDate"); - issuer = f.string_child ("Issuer"); - assets = type_grand_children (f, "AssetList", "Asset"); -} - -AssetMapAsset::AssetMapAsset (shared_ptr node) -{ - id = node->string_child ("Id"); - packing_list = node->optional_string_child ("PackingList").get_value_or (""); - chunks = type_grand_children (node, "ChunkList", "Chunk"); -} - -Chunk::Chunk (shared_ptr node) -{ - path = node->string_child ("Path"); - - string const prefix = "file://"; - - if (boost::algorithm::starts_with (path, prefix)) { - path = path.substr (prefix.length()); - } - - volume_index = node->optional_number_child ("VolumeIndex").get_value_or (0); - offset = node->optional_number_child ("Offset").get_value_or (0); - length = node->optional_number_child ("Length").get_value_or (0); -} - -shared_ptr -AssetMap::asset_from_id (string id) const -{ - for (list >::const_iterator i = assets.begin (); i != assets.end(); ++i) { - if ((*i)->id == id) { - return *i; - } - } - - return shared_ptr (); -} diff --git a/src/asset_map.h b/src/asset_map.h deleted file mode 100644 index e7ba6978..00000000 --- a/src/asset_map.h +++ /dev/null @@ -1,77 +0,0 @@ -/* - Copyright (C) 2012 Carl Hetherington - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. - -*/ - -/** @file src/asset_map.h - * @brief Classes used to parse a AssetMap. - */ - -#include -#include -#include - -namespace libdcp { - -/** @class Chunk - * @brief A simple parser for and representation of a \ node within an asset map. - */ -class Chunk -{ -public: - Chunk (); - Chunk (boost::shared_ptr node); - - std::string path; - int64_t volume_index; - int64_t offset; - int64_t length; -}; - -/** @class AssetMapAsset - * @brief A simple parser for and representation of an \ node within an asset map. - */ -class AssetMapAsset -{ -public: - AssetMapAsset (); - AssetMapAsset (boost::shared_ptr node); - - std::string id; - std::string packing_list; - std::list > chunks; -}; - -/** @class AssetMap - * @brief A simple parser for and representation of an asset map file. - */ -class AssetMap -{ -public: - AssetMap (std::string file); - - boost::shared_ptr asset_from_id (std::string id) const; - - std::string id; - std::string creator; - int64_t volume_count; - std::string issue_date; - std::string issuer; - std::list > assets; -}; - -} diff --git a/src/cpl.cc b/src/cpl.cc index 10a83078..3a2ad0b3 100644 --- a/src/cpl.cc +++ b/src/cpl.cc @@ -19,12 +19,12 @@ #include #include "cpl.h" -#include "cpl_file.h" +#include "parse/cpl.h" #include "util.h" #include "picture_asset.h" #include "sound_asset.h" #include "subtitle_asset.h" -#include "asset_map.h" +#include "parse/asset_map.h" #include "reel.h" #include "metadata.h" @@ -52,16 +52,16 @@ CPL::CPL (string directory, string name, ContentKind content_kind, int length, i * @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 asset_map, bool require_mxfs) +CPL::CPL (string directory, string file, shared_ptr asset_map, bool require_mxfs) : _directory (directory) , _content_kind (FEATURE) , _length (0) , _fps (0) { /* Read the XML */ - shared_ptr cpl; + shared_ptr cpl; try { - cpl.reset (new CPLFile (file)); + cpl.reset (new parse::CPL (file)); } catch (FileError& e) { boost::throw_exception (FileError ("could not load CPL file", file)); } @@ -71,9 +71,9 @@ CPL::CPL (string directory, string file, shared_ptr asset_map, b _name = cpl->annotation_text; _content_kind = cpl->content_kind; - for (list >::iterator i = cpl->reels.begin(); i != cpl->reels.end(); ++i) { + for (list >::iterator i = cpl->reels.begin(); i != cpl->reels.end(); ++i) { - shared_ptr p; + shared_ptr p; if ((*i)->asset_list->main_picture) { p = (*i)->asset_list->main_picture; diff --git a/src/cpl.h b/src/cpl.h index 0abff749..c04fd6ad 100644 --- a/src/cpl.h +++ b/src/cpl.h @@ -24,7 +24,10 @@ namespace libdcp { -class AssetMap; +namespace parse { + class AssetMap; +} + class Asset; class Reel; class XMLMetadata; @@ -34,7 +37,7 @@ class CPL { public: CPL (std::string directory, std::string name, ContentKind content_kind, int length, int frames_per_second); - CPL (std::string directory, std::string file, boost::shared_ptr asset_map, bool require_mxfs = true); + CPL (std::string directory, std::string file, boost::shared_ptr asset_map, bool require_mxfs = true); void add_reel (boost::shared_ptr reel); diff --git a/src/cpl_file.cc b/src/cpl_file.cc deleted file mode 100644 index 3126b99c..00000000 --- a/src/cpl_file.cc +++ /dev/null @@ -1,147 +0,0 @@ -/* - Copyright (C) 2012 Carl Hetherington - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. - -*/ - -/** @file src/cpl_file.cc - * @brief Classes used to parse a CPL. - */ - -#include -#include "cpl_file.h" -#include "xml.h" -#include "util.h" - -using std::string; -using std::bad_cast; -using boost::shared_ptr; -using namespace libdcp; - -CPLFile::CPLFile (string file) -{ - cxml::File f (file, "CompositionPlaylist"); - - id = f.string_child ("Id"); - 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")); - content_version = optional_type_child (f, "ContentVersion"); - f.ignore_child ("RatingList"); - reels = type_grand_children (f, "ReelList", "Reel"); - - f.ignore_child ("Issuer"); - f.ignore_child ("Signer"); - f.ignore_child ("Signature"); - - f.done (); -} - -ContentVersion::ContentVersion (shared_ptr node) -{ - id = node->optional_string_child ("Id").get_value_or (""); - label_text = node->string_child ("LabelText"); - node->done (); -} - -CPLReel::CPLReel (shared_ptr node) -{ - id = node->string_child ("Id"); - asset_list = type_child (node, "AssetList"); - - node->ignore_child ("AnnotationText"); - node->done (); -} - -CPLAssetList::CPLAssetList (shared_ptr node) -{ - main_picture = optional_type_child (node, "MainPicture"); - main_stereoscopic_picture = optional_type_child (node, "MainStereoscopicPicture"); - main_sound = optional_type_child (node, "MainSound"); - main_subtitle = optional_type_child (node, "MainSubtitle"); - - node->done (); -} - -MainPicture::MainPicture (shared_ptr node) - : Picture (node) -{ - -} - -MainStereoscopicPicture::MainStereoscopicPicture (shared_ptr node) - : Picture (node) -{ - -} - -Picture::Picture (shared_ptr node) -{ - id = node->string_child ("Id"); - annotation_text = node->optional_string_child ("AnnotationText").get_value_or (""); - edit_rate = Fraction (node->string_child ("EditRate")); - intrinsic_duration = node->number_child ("IntrinsicDuration"); - entry_point = node->number_child ("EntryPoint"); - duration = node->number_child ("Duration"); - frame_rate = Fraction (node->string_child ("FrameRate")); - try { - screen_aspect_ratio = Fraction (node->string_child ("ScreenAspectRatio")); - } catch (XMLError& e) { - /* Maybe it's not a fraction */ - } - try { - float f = node->number_child ("ScreenAspectRatio"); - screen_aspect_ratio = Fraction (f * 1000, 1000); - } catch (bad_cast& e) { - - } - - node->ignore_child ("Hash"); - - node->done (); -} - -MainSound::MainSound (shared_ptr node) -{ - id = node->string_child ("Id"); - annotation_text = node->optional_string_child ("AnnotationText").get_value_or (""); - edit_rate = Fraction (node->string_child ("EditRate")); - intrinsic_duration = node->number_child ("IntrinsicDuration"); - entry_point = node->number_child ("EntryPoint"); - duration = node->number_child ("Duration"); - - node->ignore_child ("Hash"); - node->ignore_child ("Language"); - - node->done (); -} - -MainSubtitle::MainSubtitle (shared_ptr node) -{ - id = node->string_child ("Id"); - annotation_text = node->optional_string_child ("AnnotationText").get_value_or (""); - edit_rate = Fraction (node->string_child ("EditRate")); - intrinsic_duration = node->number_child ("IntrinsicDuration"); - entry_point = node->number_child ("EntryPoint"); - duration = node->number_child ("Duration"); - - node->ignore_child ("Hash"); - node->ignore_child ("Language"); - - node->done (); -} diff --git a/src/cpl_file.h b/src/cpl_file.h deleted file mode 100644 index b17f47cd..00000000 --- a/src/cpl_file.h +++ /dev/null @@ -1,157 +0,0 @@ -/* - Copyright (C) 2012 Carl Hetherington - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. - -*/ - -/** @file src/cpl_file.h - * @brief Classes used to parse a CPL. - */ - -#include -#include -#include -#include "types.h" - -namespace libdcp { - -/** @brief A simple representation of a CPL \ node */ -class Picture -{ -public: - Picture () {} - Picture (boost::shared_ptr node); - - std::string id; - std::string annotation_text; - Fraction edit_rate; - /** Duration of the whole thing */ - int64_t intrinsic_duration; - /** Start point in frames */ - int64_t entry_point; - /** Duration that will actually play */ - int64_t duration; - Fraction frame_rate; - Fraction screen_aspect_ratio; -}; - - -/** @brief A simple parser for and representation of a CPL \ node */ -class MainPicture : public Picture -{ -public: - MainPicture () {} - MainPicture (boost::shared_ptr node); -}; - -/** @brief A simple parser for and representation of a CPL \ node */ -class MainStereoscopicPicture : public Picture -{ -public: - MainStereoscopicPicture () {} - MainStereoscopicPicture (boost::shared_ptr node); -}; - -/** @brief A simple parser for and representation of a CPL \ node */ -class MainSound -{ -public: - MainSound () {} - MainSound (boost::shared_ptr node); - - std::string id; - std::string annotation_text; - Fraction edit_rate; - int64_t intrinsic_duration; - int64_t entry_point; - int64_t duration; -}; - -/** @brief A simple parser for and representation of a CPL \ node */ -class MainSubtitle -{ -public: - MainSubtitle () {} - MainSubtitle (boost::shared_ptr node); - - std::string id; - std::string annotation_text; - Fraction edit_rate; - int64_t intrinsic_duration; - int64_t entry_point; - int64_t duration; -}; - -/** @brief A simple parser for and representation of a CPL \ node */ -class CPLAssetList -{ -public: - CPLAssetList () {} - CPLAssetList (boost::shared_ptr node); - - boost::shared_ptr main_picture; - boost::shared_ptr main_stereoscopic_picture; - boost::shared_ptr main_sound; - boost::shared_ptr main_subtitle; -}; - -/** @brief A simple parser for and representation of a CPL \ node */ -class CPLReel -{ -public: - CPLReel () {} - CPLReel (boost::shared_ptr node); - - std::string id; - boost::shared_ptr asset_list; -}; - - -/** @brief A simple parser for and representation of a CPL \ node */ -class ContentVersion -{ -public: - ContentVersion () {} - ContentVersion (boost::shared_ptr node); - - std::string id; - std::string label_text; -}; - -/** @class CPLFile - * @brief Class to parse a CPL - * - * This class is used to parse XML CPL files. It is rarely necessary - * for the caller to use it outside libdcp. - */ -class CPLFile -{ -public: - /** Parse a CPL XML file into our member variables */ - CPLFile (std::string file); - - std::string id; - std::string annotation_text; - std::string issue_date; - std::string creator; - std::string content_title_text; - ContentKind content_kind; - boost::shared_ptr content_version; - std::list > reels; -}; - -} - diff --git a/src/dcp.cc b/src/dcp.cc index 7af3f353..7a43e9b2 100644 --- a/src/dcp.cc +++ b/src/dcp.cc @@ -37,9 +37,8 @@ #include "util.h" #include "metadata.h" #include "exceptions.h" -#include "cpl_file.h" -#include "pkl_file.h" -#include "asset_map.h" +#include "parse/pkl.h" +#include "parse/asset_map.h" #include "reel.h" #include "cpl.h" @@ -171,17 +170,17 @@ DCP::read (bool require_mxfs) { Files files; - shared_ptr asset_map; + shared_ptr asset_map; try { boost::filesystem::path p = _directory; p /= "ASSETMAP"; if (boost::filesystem::exists (p)) { - asset_map.reset (new AssetMap (p.string ())); + asset_map.reset (new libdcp::parse::AssetMap (p.string ())); } else { p = _directory; p /= "ASSETMAP.xml"; if (boost::filesystem::exists (p)) { - asset_map.reset (new AssetMap (p.string ())); + asset_map.reset (new libdcp::parse::AssetMap (p.string ())); } else { boost::throw_exception (DCPReadError ("could not find AssetMap file")); } @@ -191,7 +190,7 @@ DCP::read (bool require_mxfs) boost::throw_exception (FileError ("could not load AssetMap file", files.asset_map)); } - for (list >::const_iterator i = asset_map->assets.begin(); i != asset_map->assets.end(); ++i) { + for (list >::const_iterator i = asset_map->assets.begin(); i != asset_map->assets.end(); ++i) { if ((*i)->chunks.size() != 1) { boost::throw_exception (XMLError ("unsupported asset chunk count")); } @@ -233,9 +232,9 @@ DCP::read (bool require_mxfs) boost::throw_exception (FileError ("no PKL file found", "")); } - shared_ptr pkl; + shared_ptr pkl; try { - pkl.reset (new PKLFile (files.pkl)); + pkl.reset (new parse::PKL (files.pkl)); } catch (FileError& e) { boost::throw_exception (FileError ("could not load PKL file", files.pkl)); } diff --git a/src/dcp.h b/src/dcp.h index 42c0c6d9..eea043dd 100644 --- a/src/dcp.h +++ b/src/dcp.h @@ -43,7 +43,6 @@ class PictureAsset; class SoundAsset; class SubtitleAsset; class Reel; -class AssetMap; class CPL; class XMLMetadata; diff --git a/src/parse/asset_map.cc b/src/parse/asset_map.cc new file mode 100644 index 00000000..aedc931e --- /dev/null +++ b/src/parse/asset_map.cc @@ -0,0 +1,78 @@ +/* + Copyright (C) 2012 Carl Hetherington + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + +*/ + +/** @file src/asset_map.cc + * @brief Classes used to parse a AssetMap. + */ + +#include +#include "asset_map.h" +#include "../util.h" +#include "../xml.h" + +using std::string; +using std::list; +using boost::shared_ptr; +using namespace libdcp::parse; + +AssetMap::AssetMap (string file) +{ + cxml::File f (file, "AssetMap"); + + id = f.string_child ("Id"); + creator = f.string_child ("Creator"); + volume_count = f.number_child ("VolumeCount"); + issue_date = f.string_child ("IssueDate"); + issuer = f.string_child ("Issuer"); + assets = type_grand_children (f, "AssetList", "Asset"); +} + +AssetMapAsset::AssetMapAsset (shared_ptr node) +{ + id = node->string_child ("Id"); + packing_list = node->optional_string_child ("PackingList").get_value_or (""); + chunks = type_grand_children (node, "ChunkList", "Chunk"); +} + +Chunk::Chunk (shared_ptr node) +{ + path = node->string_child ("Path"); + + string const prefix = "file://"; + + if (boost::algorithm::starts_with (path, prefix)) { + path = path.substr (prefix.length()); + } + + volume_index = node->optional_number_child ("VolumeIndex").get_value_or (0); + offset = node->optional_number_child ("Offset").get_value_or (0); + length = node->optional_number_child ("Length").get_value_or (0); +} + +shared_ptr +AssetMap::asset_from_id (string id) const +{ + for (list >::const_iterator i = assets.begin (); i != assets.end(); ++i) { + if ((*i)->id == id) { + return *i; + } + } + + return shared_ptr (); +} diff --git a/src/parse/asset_map.h b/src/parse/asset_map.h new file mode 100644 index 00000000..af3e8918 --- /dev/null +++ b/src/parse/asset_map.h @@ -0,0 +1,81 @@ +/* + Copyright (C) 2012 Carl Hetherington + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + +*/ + +/** @file src/asset_map.h + * @brief Classes used to parse a AssetMap. + */ + +#include +#include +#include + +namespace libdcp { + +namespace parse { + +/** @class Chunk + * @brief A simple parser for and representation of a \ node within an asset map. + */ +class Chunk +{ +public: + Chunk (); + Chunk (boost::shared_ptr node); + + std::string path; + int64_t volume_index; + int64_t offset; + int64_t length; +}; + +/** @class AssetMapAsset + * @brief A simple parser for and representation of an \ node within an asset map. + */ +class AssetMapAsset +{ +public: + AssetMapAsset (); + AssetMapAsset (boost::shared_ptr node); + + std::string id; + std::string packing_list; + std::list > chunks; +}; + +/** @class AssetMap + * @brief A simple parser for and representation of an asset map file. + */ +class AssetMap +{ +public: + AssetMap (std::string file); + + boost::shared_ptr asset_from_id (std::string id) const; + + std::string id; + std::string creator; + int64_t volume_count; + std::string issue_date; + std::string issuer; + std::list > assets; +}; + +} + +} diff --git a/src/parse/cpl.cc b/src/parse/cpl.cc new file mode 100644 index 00000000..c4cf4374 --- /dev/null +++ b/src/parse/cpl.cc @@ -0,0 +1,147 @@ +/* + Copyright (C) 2012 Carl Hetherington + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + +*/ + +/** @file src/cpl_file.cc + * @brief Classes used to parse a CPL. + */ + +#include +#include "cpl.h" +#include "../xml.h" +#include "../util.h" + +using std::string; +using std::bad_cast; +using boost::shared_ptr; +using namespace libdcp::parse; + +CPL::CPL (string file) +{ + cxml::File f (file, "CompositionPlaylist"); + + id = f.string_child ("Id"); + 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")); + content_version = optional_type_child (f, "ContentVersion"); + f.ignore_child ("RatingList"); + reels = type_grand_children (f, "ReelList", "Reel"); + + f.ignore_child ("Issuer"); + f.ignore_child ("Signer"); + f.ignore_child ("Signature"); + + f.done (); +} + +ContentVersion::ContentVersion (shared_ptr node) +{ + id = node->optional_string_child ("Id").get_value_or (""); + label_text = node->string_child ("LabelText"); + node->done (); +} + +Reel::Reel (shared_ptr node) +{ + id = node->string_child ("Id"); + asset_list = type_child (node, "AssetList"); + + node->ignore_child ("AnnotationText"); + node->done (); +} + +CPLAssetList::CPLAssetList (shared_ptr node) +{ + main_picture = optional_type_child (node, "MainPicture"); + main_stereoscopic_picture = optional_type_child (node, "MainStereoscopicPicture"); + main_sound = optional_type_child (node, "MainSound"); + main_subtitle = optional_type_child (node, "MainSubtitle"); + + node->done (); +} + +MainPicture::MainPicture (shared_ptr node) + : Picture (node) +{ + +} + +MainStereoscopicPicture::MainStereoscopicPicture (shared_ptr node) + : Picture (node) +{ + +} + +Picture::Picture (shared_ptr node) +{ + id = node->string_child ("Id"); + annotation_text = node->optional_string_child ("AnnotationText").get_value_or (""); + edit_rate = Fraction (node->string_child ("EditRate")); + intrinsic_duration = node->number_child ("IntrinsicDuration"); + entry_point = node->number_child ("EntryPoint"); + duration = node->number_child ("Duration"); + frame_rate = Fraction (node->string_child ("FrameRate")); + try { + screen_aspect_ratio = Fraction (node->string_child ("ScreenAspectRatio")); + } catch (XMLError& e) { + /* Maybe it's not a fraction */ + } + try { + float f = node->number_child ("ScreenAspectRatio"); + screen_aspect_ratio = Fraction (f * 1000, 1000); + } catch (bad_cast& e) { + + } + + node->ignore_child ("Hash"); + + node->done (); +} + +MainSound::MainSound (shared_ptr node) +{ + id = node->string_child ("Id"); + annotation_text = node->optional_string_child ("AnnotationText").get_value_or (""); + edit_rate = Fraction (node->string_child ("EditRate")); + intrinsic_duration = node->number_child ("IntrinsicDuration"); + entry_point = node->number_child ("EntryPoint"); + duration = node->number_child ("Duration"); + + node->ignore_child ("Hash"); + node->ignore_child ("Language"); + + node->done (); +} + +MainSubtitle::MainSubtitle (shared_ptr node) +{ + id = node->string_child ("Id"); + annotation_text = node->optional_string_child ("AnnotationText").get_value_or (""); + edit_rate = Fraction (node->string_child ("EditRate")); + intrinsic_duration = node->number_child ("IntrinsicDuration"); + entry_point = node->number_child ("EntryPoint"); + duration = node->number_child ("Duration"); + + node->ignore_child ("Hash"); + node->ignore_child ("Language"); + + node->done (); +} diff --git a/src/parse/cpl.h b/src/parse/cpl.h new file mode 100644 index 00000000..434a244b --- /dev/null +++ b/src/parse/cpl.h @@ -0,0 +1,161 @@ +/* + Copyright (C) 2012 Carl Hetherington + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + +*/ + +/** @file src/parse/cpl.h + * @brief Classes used to parse a CPL. + */ + +#include +#include +#include +#include "../types.h" + +namespace libdcp { + +namespace parse { + +/** @brief A simple representation of a CPL \ node */ +class Picture +{ +public: + Picture () {} + Picture (boost::shared_ptr node); + + std::string id; + std::string annotation_text; + Fraction edit_rate; + /** Duration of the whole thing */ + int64_t intrinsic_duration; + /** Start point in frames */ + int64_t entry_point; + /** Duration that will actually play */ + int64_t duration; + Fraction frame_rate; + Fraction screen_aspect_ratio; +}; + + +/** @brief A simple parser for and representation of a CPL \ node */ +class MainPicture : public Picture +{ +public: + MainPicture () {} + MainPicture (boost::shared_ptr node); +}; + +/** @brief A simple parser for and representation of a CPL \ node */ +class MainStereoscopicPicture : public Picture +{ +public: + MainStereoscopicPicture () {} + MainStereoscopicPicture (boost::shared_ptr node); +}; + +/** @brief A simple parser for and representation of a CPL \ node */ +class MainSound +{ +public: + MainSound () {} + MainSound (boost::shared_ptr node); + + std::string id; + std::string annotation_text; + Fraction edit_rate; + int64_t intrinsic_duration; + int64_t entry_point; + int64_t duration; +}; + +/** @brief A simple parser for and representation of a CPL \ node */ +class MainSubtitle +{ +public: + MainSubtitle () {} + MainSubtitle (boost::shared_ptr node); + + std::string id; + std::string annotation_text; + Fraction edit_rate; + int64_t intrinsic_duration; + int64_t entry_point; + int64_t duration; +}; + +/** @brief A simple parser for and representation of a CPL \ node */ +class CPLAssetList +{ +public: + CPLAssetList () {} + CPLAssetList (boost::shared_ptr node); + + boost::shared_ptr main_picture; + boost::shared_ptr main_stereoscopic_picture; + boost::shared_ptr main_sound; + boost::shared_ptr main_subtitle; +}; + +/** @brief A simple parser for and representation of a CPL \ node */ +class Reel +{ +public: + Reel () {} + Reel (boost::shared_ptr node); + + std::string id; + boost::shared_ptr asset_list; +}; + + +/** @brief A simple parser for and representation of a CPL \ node */ +class ContentVersion +{ +public: + ContentVersion () {} + ContentVersion (boost::shared_ptr node); + + std::string id; + std::string label_text; +}; + +/** @class CPL + * @brief Class to parse a CPL + * + * This class is used to parse XML CPL files. It is rarely necessary + * for the caller to use it outside libdcp. + */ +class CPL +{ +public: + /** Parse a CPL XML file into our member variables */ + CPL (std::string file); + + std::string id; + std::string annotation_text; + std::string issue_date; + std::string creator; + std::string content_title_text; + ContentKind content_kind; + boost::shared_ptr content_version; + std::list > reels; +}; + +} + +} + diff --git a/src/parse/pkl.cc b/src/parse/pkl.cc new file mode 100644 index 00000000..d790cfe4 --- /dev/null +++ b/src/parse/pkl.cc @@ -0,0 +1,51 @@ +/* + Copyright (C) 2012 Carl Hetherington + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + +*/ + +/** @file src/pkl_file.cc + * @brief Classes used to parse a PKL. + */ + +#include +#include "pkl.h" + +using namespace std; +using namespace boost; +using namespace libdcp::parse; + +PKL::PKL (string file) +{ + cxml::File f (file, "PackingList"); + + id = f.string_child ("Id"); + annotation_text = f.optional_string_child ("AnnotationText").get_value_or (""); + issue_date = f.string_child ("IssueDate"); + issuer = f.string_child ("Issuer"); + creator = f.string_child ("Creator"); + assets = type_grand_children (f, "AssetList", "Asset"); +} + +PKLAsset::PKLAsset (boost::shared_ptr node) +{ + id = node->string_child ("Id"); + annotation_text = node->optional_string_child ("AnnotationText").get_value_or (""); + hash = node->string_child ("Hash"); + size = node->number_child ("Size"); + type = node->string_child ("Type"); + original_file_name = node->optional_string_child ("OriginalFileName").get_value_or (""); +} diff --git a/src/parse/pkl.h b/src/parse/pkl.h new file mode 100644 index 00000000..13d87fa1 --- /dev/null +++ b/src/parse/pkl.h @@ -0,0 +1,60 @@ +/* + Copyright (C) 2012 Carl Hetherington + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + +*/ + +/** @file src/parse/pkl.h + * @brief Classes used to parse a PKL + */ + +#include +#include "../xml.h" + +namespace libdcp { + +namespace parse { + +class PKLAsset +{ +public: + PKLAsset () {} + PKLAsset (boost::shared_ptr); + + std::string id; + std::string annotation_text; + std::string hash; + int64_t size; + std::string type; + std::string original_file_name; +}; + +class PKL +{ +public: + PKL (std::string file); + + std::string id; + std::string annotation_text; + std::string issue_date; + std::string issuer; + std::string creator; + std::list > assets; +}; + +} + +} diff --git a/src/parse/subtitle.cc b/src/parse/subtitle.cc new file mode 100644 index 00000000..471d62b7 --- /dev/null +++ b/src/parse/subtitle.cc @@ -0,0 +1,135 @@ +/* + Copyright (C) 2012-2013 Carl Hetherington + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + +*/ + +#include +#include +#include "subtitle.h" +#include "../types.h" + +using std::string; +using std::list; +using boost::shared_ptr; +using boost::optional; +using boost::lexical_cast; +using namespace libdcp; +using namespace libdcp::parse; + +Font::Font (shared_ptr node) +{ + text = node->content (); + + id = node->optional_string_attribute ("Id").get_value_or (""); + size = node->optional_number_attribute ("Size").get_value_or (0); + italic = node->optional_bool_attribute ("Italic").get_value_or (false); + optional c = node->optional_string_attribute ("Color"); + if (c) { + color = Color (c.get ()); + } + optional const e = node->optional_string_attribute ("Effect"); + if (e) { + effect = string_to_effect (e.get ()); + } + c = node->optional_string_attribute ( "EffectColor"); + if (c) { + effect_color = Color (c.get ()); + } + subtitle_nodes = type_children (node, "Subtitle"); + font_nodes = type_children (node, "Font"); + text_nodes = type_children (node, "Text"); +} + +Font::Font (list > const & font_nodes) + : size (0) + , italic (false) + , color ("FFFFFFFF") + , effect_color ("FFFFFFFF") +{ + for (list >::const_iterator i = font_nodes.begin(); i != font_nodes.end(); ++i) { + if (!(*i)->id.empty ()) { + id = (*i)->id; + } + if ((*i)->size != 0) { + size = (*i)->size; + } + if ((*i)->italic) { + italic = (*i)->italic.get (); + } + if ((*i)->color) { + color = (*i)->color.get (); + } + if ((*i)->effect) { + effect = (*i)->effect.get (); + } + if ((*i)->effect_color) { + effect_color = (*i)->effect_color.get (); + } + } +} + +LoadFont::LoadFont (shared_ptr node) +{ + id = node->string_attribute ("Id"); + uri = node->string_attribute ("URI"); +} + + +Subtitle::Subtitle (shared_ptr node) +{ + in = Time (node->string_attribute ("TimeIn")); + out = Time (node->string_attribute ("TimeOut")); + font_nodes = type_children (node, "Font"); + text_nodes = type_children (node, "Text"); + fade_up_time = fade_time (node, "FadeUpTime"); + fade_down_time = fade_time (node, "FadeDownTime"); +} + +Time +Subtitle::fade_time (shared_ptr node, string name) +{ + string const u = node->optional_string_attribute (name).get_value_or (""); + Time t; + + if (u.empty ()) { + t = Time (0, 0, 0, 20); + } else if (u.find (":") != string::npos) { + t = Time (u); + } else { + t = Time (0, 0, 0, lexical_cast (u)); + } + + if (t > Time (0, 0, 8, 0)) { + t = Time (0, 0, 8, 0); + } + + return t; +} + +Text::Text (shared_ptr node) + : v_align (CENTER) +{ + text = node->content (); + v_position = node->number_attribute ("VPosition"); + optional v = node->optional_string_attribute ("VAlign"); + if (v) { + v_align = string_to_valign (v.get ()); + } + + font_nodes = type_children (node, "Font"); +} + diff --git a/src/parse/subtitle.h b/src/parse/subtitle.h new file mode 100644 index 00000000..34321545 --- /dev/null +++ b/src/parse/subtitle.h @@ -0,0 +1,93 @@ +/* + Copyright (C) 2012 Carl Hetherington + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + +*/ + +#include "../xml.h" +#include "../dcp_time.h" +#include "../types.h" + +namespace libdcp +{ + +namespace parse +{ + +class Font; + +class Text +{ +public: + Text () {} + Text (boost::shared_ptr node); + + float v_position; + VAlign v_align; + std::string text; + std::list > font_nodes; +}; + +class Subtitle +{ +public: + Subtitle () {} + Subtitle (boost::shared_ptr node); + + Time in; + Time out; + Time fade_up_time; + Time fade_down_time; + std::list > font_nodes; + std::list > text_nodes; + +private: + Time fade_time (boost::shared_ptr, std::string name); +}; + +class Font +{ +public: + Font () {} + Font (boost::shared_ptr node); + Font (std::list > const & font_nodes); + + std::string text; + std::string id; + int size; + boost::optional italic; + boost::optional color; + boost::optional effect; + boost::optional effect_color; + + std::list > subtitle_nodes; + std::list > font_nodes; + std::list > text_nodes; +}; + +class LoadFont +{ +public: + LoadFont () {} + LoadFont (boost::shared_ptr node); + + std::string id; + std::string uri; +}; + +} + +} diff --git a/src/pkl_file.cc b/src/pkl_file.cc deleted file mode 100644 index 9119d883..00000000 --- a/src/pkl_file.cc +++ /dev/null @@ -1,51 +0,0 @@ -/* - Copyright (C) 2012 Carl Hetherington - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. - -*/ - -/** @file src/pkl_file.cc - * @brief Classes used to parse a PKL. - */ - -#include -#include "pkl_file.h" - -using namespace std; -using namespace boost; -using namespace libdcp; - -PKLFile::PKLFile (string file) -{ - cxml::File f (file, "PackingList"); - - id = f.string_child ("Id"); - annotation_text = f.optional_string_child ("AnnotationText").get_value_or (""); - issue_date = f.string_child ("IssueDate"); - issuer = f.string_child ("Issuer"); - creator = f.string_child ("Creator"); - assets = type_grand_children (f, "AssetList", "Asset"); -} - -PKLAsset::PKLAsset (boost::shared_ptr node) -{ - id = node->string_child ("Id"); - annotation_text = node->optional_string_child ("AnnotationText").get_value_or (""); - hash = node->string_child ("Hash"); - size = node->number_child ("Size"); - type = node->string_child ("Type"); - original_file_name = node->optional_string_child ("OriginalFileName").get_value_or (""); -} diff --git a/src/pkl_file.h b/src/pkl_file.h deleted file mode 100644 index 77b83fca..00000000 --- a/src/pkl_file.h +++ /dev/null @@ -1,56 +0,0 @@ -/* - Copyright (C) 2012 Carl Hetherington - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. - -*/ - -/** @file src/pkl_file.h - * @brief Classes used to parse a PKL - */ - -#include -#include "xml.h" - -namespace libdcp { - -class PKLAsset -{ -public: - PKLAsset () {} - PKLAsset (boost::shared_ptr); - - std::string id; - std::string annotation_text; - std::string hash; - int64_t size; - std::string type; - std::string original_file_name; -}; - -class PKLFile -{ -public: - PKLFile (std::string file); - - std::string id; - std::string annotation_text; - std::string issue_date; - std::string issuer; - std::string creator; - std::list > assets; -}; - -} diff --git a/src/subtitle_asset.cc b/src/subtitle_asset.cc index 1eae1fcc..d89d52de 100644 --- a/src/subtitle_asset.cc +++ b/src/subtitle_asset.cc @@ -63,8 +63,8 @@ SubtitleAsset::read_xml (string xml_file) xml->ignore_child ("LoadFont"); - list > font_nodes = type_children (xml, "Font"); - _load_font_nodes = type_children (xml, "LoadFont"); + list > font_nodes = type_children (xml, "Font"); + _load_font_nodes = type_children (xml, "LoadFont"); /* Now make Subtitle objects to represent the raw XML nodes in a sane way. @@ -77,16 +77,16 @@ SubtitleAsset::read_xml (string xml_file) void SubtitleAsset::examine_font_nodes ( shared_ptr xml, - list > const & font_nodes, + list > const & font_nodes, ParseState& parse_state ) { - for (list >::const_iterator i = font_nodes.begin(); i != font_nodes.end(); ++i) { + for (list >::const_iterator i = font_nodes.begin(); i != font_nodes.end(); ++i) { parse_state.font_nodes.push_back (*i); maybe_add_subtitle ((*i)->text, parse_state); - for (list >::iterator j = (*i)->subtitle_nodes.begin(); j != (*i)->subtitle_nodes.end(); ++j) { + for (list >::iterator j = (*i)->subtitle_nodes.begin(); j != (*i)->subtitle_nodes.end(); ++j) { parse_state.subtitle_nodes.push_back (*j); examine_text_nodes (xml, (*j)->text_nodes, parse_state); examine_font_nodes (xml, (*j)->font_nodes, parse_state); @@ -103,11 +103,11 @@ SubtitleAsset::examine_font_nodes ( void SubtitleAsset::examine_text_nodes ( shared_ptr xml, - list > const & text_nodes, + list > const & text_nodes, ParseState& parse_state ) { - for (list >::const_iterator i = text_nodes.begin(); i != text_nodes.end(); ++i) { + for (list >::const_iterator i = text_nodes.begin(); i != text_nodes.end(); ++i) { parse_state.text_nodes.push_back (*i); maybe_add_subtitle ((*i)->text, parse_state); examine_font_nodes (xml, (*i)->font_nodes, parse_state); @@ -129,9 +129,9 @@ SubtitleAsset::maybe_add_subtitle (string text, ParseState const & parse_state) assert (!parse_state.text_nodes.empty ()); assert (!parse_state.subtitle_nodes.empty ()); - FontNode effective_font (parse_state.font_nodes); - TextNode effective_text (*parse_state.text_nodes.back ()); - SubtitleNode effective_subtitle (*parse_state.subtitle_nodes.back ()); + 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 ()); _subtitles.push_back ( shared_ptr ( @@ -154,109 +154,6 @@ SubtitleAsset::maybe_add_subtitle (string text, ParseState const & parse_state) ); } -FontNode::FontNode (shared_ptr node) -{ - text = node->content (); - - id = node->optional_string_attribute ("Id").get_value_or (""); - size = node->optional_number_attribute ("Size").get_value_or (0); - italic = node->optional_bool_attribute ("Italic").get_value_or (false); - optional c = node->optional_string_attribute ("Color"); - if (c) { - color = Color (c.get ()); - } - optional const e = node->optional_string_attribute ("Effect"); - if (e) { - effect = string_to_effect (e.get ()); - } - c = node->optional_string_attribute ( "EffectColor"); - if (c) { - effect_color = Color (c.get ()); - } - subtitle_nodes = type_children (node, "Subtitle"); - font_nodes = type_children (node, "Font"); - text_nodes = type_children (node, "Text"); -} - -FontNode::FontNode (list > const & font_nodes) - : size (0) - , italic (false) - , color ("FFFFFFFF") - , effect_color ("FFFFFFFF") -{ - for (list >::const_iterator i = font_nodes.begin(); i != font_nodes.end(); ++i) { - if (!(*i)->id.empty ()) { - id = (*i)->id; - } - if ((*i)->size != 0) { - size = (*i)->size; - } - if ((*i)->italic) { - italic = (*i)->italic.get (); - } - if ((*i)->color) { - color = (*i)->color.get (); - } - if ((*i)->effect) { - effect = (*i)->effect.get (); - } - if ((*i)->effect_color) { - effect_color = (*i)->effect_color.get (); - } - } -} - -LoadFontNode::LoadFontNode (shared_ptr node) -{ - id = node->string_attribute ("Id"); - uri = node->string_attribute ("URI"); -} - - -SubtitleNode::SubtitleNode (shared_ptr node) -{ - in = Time (node->string_attribute ("TimeIn")); - out = Time (node->string_attribute ("TimeOut")); - font_nodes = type_children (node, "Font"); - text_nodes = type_children (node, "Text"); - fade_up_time = fade_time (node, "FadeUpTime"); - fade_down_time = fade_time (node, "FadeDownTime"); -} - -Time -SubtitleNode::fade_time (shared_ptr node, string name) -{ - string const u = node->optional_string_attribute (name).get_value_or (""); - Time t; - - if (u.empty ()) { - t = Time (0, 0, 0, 20); - } else if (u.find (":") != string::npos) { - t = Time (u); - } else { - t = Time (0, 0, 0, lexical_cast (u)); - } - - if (t > Time (0, 0, 8, 0)) { - t = Time (0, 0, 8, 0); - } - - return t; -} - -TextNode::TextNode (shared_ptr node) - : v_align (CENTER) -{ - text = node->content (); - v_position = node->number_attribute ("VPosition"); - optional v = node->optional_string_attribute ("VAlign"); - if (v) { - v_align = string_to_valign (v.get ()); - } - - font_nodes = type_children (node, "Font"); -} - list > SubtitleAsset::subtitles_at (Time t) const { @@ -273,7 +170,7 @@ SubtitleAsset::subtitles_at (Time t) const std::string SubtitleAsset::font_id_to_name (string id) const { - list >::const_iterator i = _load_font_nodes.begin(); + list >::const_iterator i = _load_font_nodes.begin(); while (i != _load_font_nodes.end() && (*i)->id != id) { ++i; } diff --git a/src/subtitle_asset.h b/src/subtitle_asset.h index 591985d1..0d662d6c 100644 --- a/src/subtitle_asset.h +++ b/src/subtitle_asset.h @@ -20,71 +20,11 @@ #include "asset.h" #include "xml.h" #include "dcp_time.h" +#include "parse/subtitle.h" namespace libdcp { -class FontNode; - -class TextNode -{ -public: - TextNode () {} - TextNode (boost::shared_ptr node); - - float v_position; - VAlign v_align; - std::string text; - std::list > font_nodes; -}; - -class SubtitleNode -{ -public: - SubtitleNode () {} - SubtitleNode (boost::shared_ptr node); - - Time in; - Time out; - Time fade_up_time; - Time fade_down_time; - std::list > font_nodes; - std::list > text_nodes; - -private: - Time fade_time (boost::shared_ptr, std::string name); -}; - -class FontNode -{ -public: - FontNode () {} - FontNode (boost::shared_ptr node); - FontNode (std::list > const & font_nodes); - - std::string text; - std::string id; - int size; - boost::optional italic; - boost::optional color; - boost::optional effect; - boost::optional effect_color; - - std::list > subtitle_nodes; - std::list > font_nodes; - std::list > text_nodes; -}; - -class LoadFontNode -{ -public: - LoadFontNode () {} - LoadFontNode (boost::shared_ptr node); - - std::string id; - std::string uri; -}; - class Subtitle { public: @@ -210,22 +150,22 @@ private: std::string escape (std::string) const; struct ParseState { - std::list > font_nodes; - std::list > text_nodes; - std::list > subtitle_nodes; + std::list > font_nodes; + std::list > text_nodes; + std::list > subtitle_nodes; }; void maybe_add_subtitle (std::string text, ParseState const & parse_state); void examine_font_nodes ( boost::shared_ptr xml, - std::list > const & font_nodes, + std::list > const & font_nodes, ParseState& parse_state ); void examine_text_nodes ( boost::shared_ptr xml, - std::list > const & text_nodes, + std::list > const & text_nodes, ParseState& parse_state ); @@ -233,7 +173,7 @@ private: /* strangely, this is sometimes a string */ std::string _reel_number; std::string _language; - std::list > _load_font_nodes; + std::list > _load_font_nodes; std::list > _subtitles; bool _need_sort; diff --git a/src/wscript b/src/wscript index fb8f688e..37151e51 100644 --- a/src/wscript +++ b/src/wscript @@ -11,8 +11,6 @@ def build(bld): obj.use = 'libkumu-libdcp libasdcp-libdcp' obj.source = """ asset.cc - asset_map.cc - cpl_file.cc dcp.cc cpl.cc dcp_time.cc @@ -21,7 +19,6 @@ def build(bld): mxf_asset.cc picture_asset.cc picture_frame.cc - pkl_file.cc reel.cc argb_frame.cc sound_asset.cc @@ -30,6 +27,10 @@ def build(bld): types.cc util.cc version.cc + parse/asset_map.cc + parse/cpl.cc + parse/pkl.cc + parse/subtitle.cc """ headers = """ @@ -55,3 +56,4 @@ def build(bld): bld.install_files('${PREFIX}/include/libdcp', headers) if bld.env.STATIC: bld.install_files('${PREFIX}/lib', 'libdcp.a') + -- cgit v1.2.3 From 8526058d24faec5f83ffd66758fef8d8c8159f73 Mon Sep 17 00:00:00 2001 From: Carl Hetherington Date: Mon, 13 May 2013 15:57:00 +0100 Subject: Use libxml++ for writing XML. --- src/asset.cc | 37 +++++++-------- src/asset.h | 7 +-- src/cpl.cc | 75 +++++++++++++++---------------- src/cpl.h | 5 ++- src/dcp.cc | 92 ++++++++++++++++++-------------------- src/picture_asset.cc | 21 +++++---- src/picture_asset.h | 6 +-- src/reel.cc | 17 +++---- src/reel.h | 3 +- src/sound_asset.cc | 17 ++++--- src/sound_asset.h | 6 +-- src/subtitle_asset.cc | 121 ++++++++++++++++++++++---------------------------- src/subtitle_asset.h | 5 +-- 13 files changed, 192 insertions(+), 220 deletions(-) diff --git a/src/asset.cc b/src/asset.cc index 58c821a7..84bdd2bd 100644 --- a/src/asset.cc +++ b/src/asset.cc @@ -25,6 +25,7 @@ #include #include #include +#include #include "AS_DCP.h" #include "KM_util.h" #include "asset.h" @@ -50,31 +51,27 @@ Asset::Asset (string directory, string file_name, int edit_rate, int intrinsic_d } void -Asset::write_to_pkl (ostream& s) const +Asset::write_to_pkl (xmlpp::Node* node) const { - s << " \n" - << " urn:uuid:" << _uuid << "\n" - << " " << _file_name << "\n" - << " " << digest() << "\n" - << " " << filesystem::file_size(path()) << "\n" - << " application/mxf\n" - << " \n"; + xmlpp::Node* asset = node->add_child ("Asset"); + asset->add_child("Id")->add_child_text ("urn:uuid:" + _uuid); + asset->add_child("AnnotationText")->add_child_text (_file_name); + asset->add_child("Hash")->add_child_text (digest ()); + asset->add_child("Size")->add_child_text (lexical_cast (filesystem::file_size(path()))); + asset->add_child("Type")->add_child_text ("application/mxf"); } void -Asset::write_to_assetmap (ostream& s) const +Asset::write_to_assetmap (xmlpp::Node* node) const { - s << " \n" - << " urn:uuid:" << _uuid << "\n" - << " \n" - << " \n" - << " " << _file_name << "\n" - << " 1\n" - << " 0\n" - << " " << filesystem::file_size(path()) << "\n" - << " \n" - << " \n" - << " \n"; + xmlpp::Node* asset = node->add_child ("Asset"); + asset->add_child("Id")->add_child_text ("urn:uuid:" + _uuid); + xmlpp::Node* chunk_list = asset->add_child ("ChunkList"); + xmlpp::Node* chunk = chunk_list->add_child ("Chunk"); + chunk->add_child("Path")->add_child_text (_file_name); + chunk->add_child("VolumeIndex")->add_child_text ("1"); + chunk->add_child("Offset")->add_child_text ("0"); + chunk->add_child("Length")->add_child_text (lexical_cast (filesystem::file_size(path()))); } filesystem::path diff --git a/src/asset.h b/src/asset.h index 06c66356..3bc713a3 100644 --- a/src/asset.h +++ b/src/asset.h @@ -28,6 +28,7 @@ #include #include #include +#include #include "types.h" namespace ASDCP { @@ -55,17 +56,17 @@ public: /** Write details of the asset to a CPL stream. * @param s Stream. */ - virtual void write_to_cpl (std::ostream& s) const = 0; + virtual void write_to_cpl (xmlpp::Node *) const = 0; /** Write details of the asset to a PKL stream. * @param s Stream. */ - void write_to_pkl (std::ostream& s) const; + void write_to_pkl (xmlpp::Node *) const; /** Write details of the asset to a ASSETMAP stream. * @param s Stream. */ - void write_to_assetmap (std::ostream& s) const; + void write_to_assetmap (xmlpp::Node *) const; std::string uuid () const { return _uuid; diff --git a/src/cpl.cc b/src/cpl.cc index 3a2ad0b3..e7eb1ced 100644 --- a/src/cpl.cc +++ b/src/cpl.cc @@ -34,6 +34,7 @@ using std::ofstream; using std::ostream; using std::list; using boost::shared_ptr; +using boost::lexical_cast; using namespace libdcp; CPL::CPL (string directory, string name, ContentKind content_kind, int length, int frames_per_second) @@ -180,45 +181,42 @@ CPL::write_xml (XMLMetadata const & metadata) const stringstream s; s << _uuid << "_cpl.xml"; p /= s.str(); - ofstream os (p.string().c_str()); - - os << "\n" - << "\n" - << " urn:uuid:" << _uuid << "\n" - << " " << _name << "\n" - << " " << metadata.issue_date << "\n" - << " " << metadata.creator << "\n" - << " " << _name << "\n" - << " " << content_kind_to_string (_content_kind) << "\n" - << " \n" - << " urn:uri:" << _uuid << "_" << metadata.issue_date << "\n" - << " " << _uuid << "_" << metadata.issue_date << "\n" - << " \n" - << " \n" - << " \n"; + + xmlpp::Document doc; + xmlpp::Element* root = doc.create_root_node ("CompositionPlaylist", "http://www.smpte-ra.org/schemas/429-7/2006/CPL"); + root->add_child("Id")->add_child_text ("urn:uuid:" + _uuid); + root->add_child("AnnotationText")->add_child_text (_name); + root->add_child("IssueDate")->add_child_text (metadata.issue_date); + root->add_child("Creator")->add_child_text (metadata.creator); + root->add_child("ContentTitleText")->add_child_text (_name); + root->add_child("ContentKind")->add_child_text (content_kind_to_string (_content_kind)); + { + xmlpp::Node* cv = root->add_child ("ContentVersion"); + cv->add_child ("Id")->add_child_text ("urn:uri:" + _uuid + "_" + metadata.issue_date); + cv->add_child ("LabelText")->add_child_text (_uuid + "_" + metadata.issue_date); + } + root->add_child("RatingList"); + + xmlpp::Node* reel_list = root->add_child ("ReelList"); for (list >::const_iterator i = _reels.begin(); i != _reels.end(); ++i) { - (*i)->write_to_cpl (os); + (*i)->write_to_cpl (reel_list); } - os << " \n" - << "\n"; - - os.close (); + doc.write_to_file_formatted (p.string (), "UTF-8"); _digest = make_digest (p.string ()); _length = boost::filesystem::file_size (p.string ()); } void -CPL::write_to_pkl (ostream& s) const +CPL::write_to_pkl (xmlpp::Node* node) const { - s << " \n" - << " urn:uuid:" << _uuid << "\n" - << " " << _digest << "\n" - << " " << _length << "\n" - << " text/xml\n" - << " \n"; + xmlpp::Node* asset = node->add_child ("Asset"); + asset->add_child("Id")->add_child_text ("urn:uuid:" + _uuid); + asset->add_child("Hash")->add_child_text (_digest); + asset->add_child("Size")->add_child_text (lexical_cast (_length)); + asset->add_child("Type")->add_child_text ("text/xml"); } list > @@ -241,19 +239,16 @@ CPL::assets () const } void -CPL::write_to_assetmap (ostream& s) const +CPL::write_to_assetmap (xmlpp::Node* node) const { - s << " \n" - << " urn:uuid:" << _uuid << "\n" - << " \n" - << " \n" - << " " << _uuid << "_cpl.xml\n" - << " 1\n" - << " 0\n" - << " " << _length << "\n" - << " \n" - << " \n" - << " \n"; + xmlpp::Node* asset = node->add_child ("Asset"); + asset->add_child("Id")->add_child_text ("urn:uuid:" + _uuid); + xmlpp::Node* chunk_list = asset->add_child ("ChunkList"); + xmlpp::Node* chunk = chunk_list->add_child ("Chunk"); + chunk->add_child("Path")->add_child_text (_uuid + "_cpl.xml"); + chunk->add_child("VolumeIndex")->add_child_text ("1"); + chunk->add_child("Offset")->add_child_text("0"); + chunk->add_child("Length")->add_child_text(lexical_cast (_length)); } diff --git a/src/cpl.h b/src/cpl.h index c04fd6ad..0c86b91e 100644 --- a/src/cpl.h +++ b/src/cpl.h @@ -20,6 +20,7 @@ #include #include #include +#include #include "types.h" namespace libdcp { @@ -74,8 +75,8 @@ public: bool equals (CPL const & other, EqualityOptions options, boost::function note) const; void write_xml (XMLMetadata const &) const; - void write_to_assetmap (std::ostream& s) const; - void write_to_pkl (std::ostream& s) const; + void write_to_assetmap (xmlpp::Node *) const; + void write_to_pkl (xmlpp::Node *) const; private: std::string _directory; diff --git a/src/dcp.cc b/src/dcp.cc index 7a43e9b2..c7634b5d 100644 --- a/src/dcp.cc +++ b/src/dcp.cc @@ -28,6 +28,7 @@ #include #include #include +#include #include #include "dcp.h" #include "asset.h" @@ -48,6 +49,7 @@ using std::stringstream; using std::ofstream; using std::ostream; using boost::shared_ptr; +using boost::lexical_cast; using namespace libdcp; DCP::DCP (string directory) @@ -80,30 +82,29 @@ DCP::write_pkl (string pkl_uuid, XMLMetadata const & metadata) const stringstream s; s << pkl_uuid << "_pkl.xml"; p /= s.str(); - ofstream pkl (p.string().c_str()); - - pkl << "\n" - << "\n" - << " urn:uuid:" << pkl_uuid << "\n" - /* XXX: this is a bit of a hack */ - << " " << _cpls.front()->name() << "\n" - << " " << metadata.issue_date << "\n" - << " " << metadata.issuer << "\n" - << " " << metadata.creator << "\n" - << " \n"; + + xmlpp::Document doc; + xmlpp::Element* root = doc.create_root_node ("PackingList", "http://www.smpte-ra.org/schemas/429-8/2007/PKL"); + + root->add_child("Id")->add_child_text ("urn:uuid:" + pkl_uuid); + /* XXX: this is a bit of a hack */ + root->add_child("AnnotationText")->add_child_text (_cpls.front()->name()); + root->add_child("IssueDate")->add_child_text (metadata.issue_date); + root->add_child("Issuer")->add_child_text (metadata.issuer); + root->add_child("Creator")->add_child_text (metadata.creator); + + xmlpp::Node* asset_list = root->add_child ("AssetList"); list > a = assets (); for (list >::const_iterator i = a.begin(); i != a.end(); ++i) { - (*i)->write_to_pkl (pkl); + (*i)->write_to_pkl (asset_list); } for (list >::const_iterator i = _cpls.begin(); i != _cpls.end(); ++i) { - (*i)->write_to_pkl (pkl); + (*i)->write_to_pkl (asset_list); } - pkl << " \n" - << "\n"; - + doc.write_to_file_formatted (p.string (), "UTF-8"); return p.string (); } @@ -113,12 +114,11 @@ DCP::write_volindex () const boost::filesystem::path p; p /= _directory; p /= "VOLINDEX.xml"; - ofstream vi (p.string().c_str()); - vi << "\n" - << "\n" - << " 1\n" - << "\n"; + xmlpp::Document doc; + xmlpp::Element* root = doc.create_root_node ("VolumeIndex", "http://www.smpte-ra.org/schemas/429-9/2007/AM"); + root->add_child("Index")->add_child_text ("1"); + doc.write_to_file_formatted (p.string (), "UTF-8"); } void @@ -127,41 +127,37 @@ DCP::write_assetmap (string pkl_uuid, int pkl_length, XMLMetadata const & metada boost::filesystem::path p; p /= _directory; p /= "ASSETMAP.xml"; - ofstream am (p.string().c_str()); - - am << "\n" - << "\n" - << " urn:uuid:" << make_uuid() << "\n" - << " " << metadata.creator << "\n" - << " 1\n" - << " " << metadata.issue_date << "\n" - << " " << metadata.issuer << "\n" - << " \n"; - - am << " \n" - << " urn:uuid:" << pkl_uuid << "\n" - << " true\n" - << " \n" - << " \n" - << " " << pkl_uuid << "_pkl.xml\n" - << " 1\n" - << " 0\n" - << " " << pkl_length << "\n" - << " \n" - << " \n" - << " \n"; + + xmlpp::Document doc; + xmlpp::Element* root = doc.create_root_node ("AssetMap", "http://www.smpte-ra.org/schemas/429-9/2007/AM"); + + root->add_child("Id")->add_child_text ("urn:uuid:" + make_uuid()); + root->add_child("Creator")->add_child_text (metadata.creator); + root->add_child("VolumeCount")->add_child_text ("1"); + 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"); + asset->add_child("Id")->add_child_text ("urn:uuid:" + pkl_uuid); + asset->add_child("PackingList")->add_child_text ("true"); + xmlpp::Node* chunk_list = asset->add_child ("ChunkList"); + xmlpp::Node* chunk = chunk_list->add_child ("Chunk"); + chunk->add_child("Path")->add_child_text (pkl_uuid + "_pkl.xml"); + chunk->add_child("VolumeIndex")->add_child_text ("1"); + chunk->add_child("Offset")->add_child_text ("0"); + chunk->add_child("Length")->add_child_text (lexical_cast (pkl_length)); for (list >::const_iterator i = _cpls.begin(); i != _cpls.end(); ++i) { - (*i)->write_to_assetmap (am); + (*i)->write_to_assetmap (asset_list); } list > a = assets (); for (list >::const_iterator i = a.begin(); i != a.end(); ++i) { - (*i)->write_to_assetmap (am); + (*i)->write_to_assetmap (asset_list); } - am << " \n" - << "\n"; + doc.write_to_file_formatted (p.string (), "UTF-8"); } diff --git a/src/picture_asset.cc b/src/picture_asset.cc index 788e3dc4..72a63173 100644 --- a/src/picture_asset.cc +++ b/src/picture_asset.cc @@ -64,18 +64,17 @@ PictureAsset::PictureAsset (string directory, string mxf_name) } void -PictureAsset::write_to_cpl (ostream& s) const +PictureAsset::write_to_cpl (xmlpp::Node* node) const { - s << " \n" - << " urn:uuid:" << _uuid << "\n" - << " " << _file_name << "\n" - << " " << _edit_rate << " 1\n" - << " " << _intrinsic_duration << "\n" - << " " << _entry_point << "\n" - << " " << _duration << "\n" - << " " << _edit_rate << " 1\n" - << " " << _size.width << " " << _size.height << "\n" - << " \n"; + xmlpp::Node* mp = node->add_child ("MainPicture"); + mp->add_child ("Id")->add_child_text ("urn:uuid:" + _uuid); + mp->add_child ("AnnotationText")->add_child_text (_file_name); + mp->add_child ("EditRate")->add_child_text (lexical_cast (_edit_rate) + " 1"); + mp->add_child ("IntrinsicDuration")->add_child_text (lexical_cast (_intrinsic_duration)); + mp->add_child ("EntryPoint")->add_child_text (lexical_cast (_entry_point)); + mp->add_child ("Duration")->add_child_text (lexical_cast (_duration)); + mp->add_child ("FrameRate")->add_child_text (lexical_cast (_edit_rate) + " 1"); + mp->add_child ("ScreenAspectRatio")->add_child_text (lexical_cast (_size.width) + " " + lexical_cast (_size.height)); } bool diff --git a/src/picture_asset.h b/src/picture_asset.h index 59c4dc00..3edf3a1c 100644 --- a/src/picture_asset.h +++ b/src/picture_asset.h @@ -59,10 +59,10 @@ public: */ PictureAsset (std::string directory, std::string mxf_name, boost::signals2::signal* progress, int fps, int intrinsic_duration, Size size); - /** Write details of this asset to a CPL stream. - * @param s Stream. + /** Write details of this asset to a CPL XML node. + * @param node Node. */ - void write_to_cpl (std::ostream& s) const; + void write_to_cpl (xmlpp::Node* node) const; bool equals (boost::shared_ptr other, EqualityOptions opt, boost::function note) const; diff --git a/src/reel.cc b/src/reel.cc index 86533ea2..481b153b 100644 --- a/src/reel.cc +++ b/src/reel.cc @@ -27,26 +27,23 @@ using namespace std; using namespace libdcp; void -Reel::write_to_cpl (ostream& s) const +Reel::write_to_cpl (xmlpp::Node* node) const { - s << " \n" - << " urn:uuid:" << make_uuid() << "\n" - << " \n"; + xmlpp::Node* reel = node->add_child ("Reel"); + reel->add_child("Id")->add_child_text ("urn:uuid:" + make_uuid()); + xmlpp::Node* asset_list = reel->add_child ("AssetList"); if (_main_picture) { - _main_picture->write_to_cpl (s); + _main_picture->write_to_cpl (asset_list); } if (_main_sound) { - _main_sound->write_to_cpl (s); + _main_sound->write_to_cpl (asset_list); } if (_main_subtitle) { - _main_subtitle->write_to_cpl (s); + _main_subtitle->write_to_cpl (asset_list); } - - s << " \n" - << " \n"; } bool diff --git a/src/reel.h b/src/reel.h index 93dc0920..49a756ad 100644 --- a/src/reel.h +++ b/src/reel.h @@ -20,6 +20,7 @@ #include #include #include +#include #include "types.h" namespace libdcp { @@ -54,7 +55,7 @@ public: return _main_subtitle; } - void write_to_cpl (std::ostream & s) const; + void write_to_cpl (xmlpp::Node *) const; bool equals (boost::shared_ptr other, EqualityOptions opt, boost::function notes) const; diff --git a/src/sound_asset.cc b/src/sound_asset.cc index 9b6b48aa..4a7abd4d 100644 --- a/src/sound_asset.cc +++ b/src/sound_asset.cc @@ -211,16 +211,15 @@ SoundAsset::construct (boost::function get_path, MXFMetadata c } void -SoundAsset::write_to_cpl (ostream& s) const +SoundAsset::write_to_cpl (xmlpp::Node* node) const { - s << " \n" - << " urn:uuid:" << _uuid << "\n" - << " " << _file_name << "\n" - << " " << _edit_rate << " 1\n" - << " " << _intrinsic_duration << "\n" - << " " << _entry_point << "\n" - << " " << _duration << "\n" - << " \n"; + xmlpp::Node* ms = node->add_child ("MainSound"); + ms->add_child ("Id")->add_child_text ("urn:uuid:" + _uuid); + ms->add_child ("AnnotationText")->add_child_text (_file_name); + ms->add_child ("EditRate")->add_child_text (lexical_cast (_edit_rate) + " 1"); + ms->add_child ("IntrinsicDuration")->add_child_text (lexical_cast (_intrinsic_duration)); + ms->add_child ("EntryPoint")->add_child_text (lexical_cast (_entry_point)); + ms->add_child ("Duration")->add_child_text (lexical_cast (_duration)); } bool diff --git a/src/sound_asset.h b/src/sound_asset.h index 5c230e06..1e3553a0 100644 --- a/src/sound_asset.h +++ b/src/sound_asset.h @@ -127,10 +127,10 @@ public: boost::shared_ptr start_write (MXFMetadata const & metadata = MXFMetadata ()); - /** Write details of this asset to a CPL stream. - * @param s Stream. + /** Write details of this asset to a CPL XML node. + * @param node Node. */ - void write_to_cpl (std::ostream& s) const; + void write_to_cpl (xmlpp::Node* node) const; bool equals (boost::shared_ptr other, EqualityOptions opt, boost::function note) const; diff --git a/src/subtitle_asset.cc b/src/subtitle_asset.cc index d89d52de..5decc1e3 100644 --- a/src/subtitle_asset.cc +++ b/src/subtitle_asset.cc @@ -276,15 +276,15 @@ SubtitleAsset::add (shared_ptr s) } void -SubtitleAsset::write_to_cpl (ostream& s) const +SubtitleAsset::write_to_cpl (xmlpp::Node* node) const { /* XXX: should EditRate, Duration and IntrinsicDuration be in here? */ - - s << " \n" - << " urn:uuid:" << _uuid << "\n" - << " " << _file_name << "\n" - << " 0\n" - << " \n"; + + xmlpp::Node* ms = node->add_child ("MainSubtitle"); + ms->add_child("Id")->add_child_text("urn:uuid:" + _uuid); + ms->add_child("AnnotationText")->add_child_text (_file_name); + /* XXX */ + ms->add_child("EntryPoint")->add_child_text ("0"); } struct SubtitleSorter { @@ -299,26 +299,30 @@ struct SubtitleSorter { void SubtitleAsset::write_xml () const { - ofstream f (path().string().c_str()); - write_xml (f); + ofstream s (path().string().c_str()); + write_xml (s); } void SubtitleAsset::write_xml (ostream& s) const { - s << "\n" - << "\n" - << " " << _uuid << "\n" - << " " << _movie_title << "\n" - << " " << _reel_number << "\n" - << " " << _language << "\n"; + xmlpp::Document doc; + xmlpp::Element* root = doc.create_root_node ("DCSubtitle"); + root->set_attribute ("Version", "1.0"); + + root->add_child("SubtitleID")->add_child_text (_uuid); + root->add_child("MovieTitle")->add_child_text (_movie_title); + root->add_child("ReelNumber")->add_child_text (lexical_cast (_reel_number)); + root->add_child("Language")->add_child_text (_language); if (_load_font_nodes.size() > 1) { boost::throw_exception (MiscError ("multiple LoadFont nodes not supported")); } if (!_load_font_nodes.empty ()) { - s << " id << "\" URI=\"" << _load_font_nodes.front()->uri << "\"/>\n"; + xmlpp::Element* load_font = root->add_child("LoadFont"); + load_font->set_attribute("Id", _load_font_nodes.front()->id); + load_font->set_attribute("URI", _load_font_nodes.front()->uri); } list > sorted = _subtitles; @@ -329,7 +333,6 @@ SubtitleAsset::write_xml (ostream& s) const /* XXX: multiple fonts not supported */ /* XXX: script, underlined, weight not supported */ - bool first = true; bool italic = false; Color color; int size = 0; @@ -341,66 +344,61 @@ SubtitleAsset::write_xml (ostream& s) const Time last_fade_up_time; Time last_fade_down_time; + xmlpp::Element* font = 0; + xmlpp::Element* subtitle = 0; + for (list >::iterator i = sorted.begin(); i != sorted.end(); ++i) { /* We will start a new ... whenever some font property changes. - I suppose should really make an optimal hierarchy of tags, but + I suppose we should really make an optimal hierarchy of tags, but that seems hard. */ - bool const font_changed = first || + bool const font_changed = italic != (*i)->italic() || color != (*i)->color() || size != (*i)->size() || effect != (*i)->effect() || effect_color != (*i)->effect_color(); - stringstream a; if (font_changed) { italic = (*i)->italic (); - a << "Italic=\"" << (italic ? "yes" : "no") << "\" "; color = (*i)->color (); - a << "Color=\"" << color.to_argb_string() << "\" "; size = (*i)->size (); - a << "Size=\"" << size << "\" "; effect = (*i)->effect (); - a << "Effect=\"" << effect_to_string(effect) << "\" "; effect_color = (*i)->effect_color (); - a << "EffectColor=\"" << effect_color.to_argb_string() << "\" "; - a << "Script=\"normal\" Underlined=\"no\" Weight=\"normal\""; } - if (first || font_changed || + if (!font || font_changed) { + font = root->add_child ("Font"); + string id = "theFontId"; + if (!_load_font_nodes.empty()) { + id = _load_font_nodes.front()->id; + } + font->set_attribute ("Id", id); + font->set_attribute ("Italic", italic ? "yes" : "no"); + font->set_attribute ("Color", color.to_argb_string()); + font->set_attribute ("Size", lexical_cast (size)); + font->set_attribute ("Effect", effect_to_string (effect)); + font->set_attribute ("EffectColor", effect_color.to_argb_string()); + font->set_attribute ("Script", "normal"); + font->set_attribute ("Underlined", "no"); + font->set_attribute ("Weight", "normal"); + } + + if (!subtitle || (last_in != (*i)->in() || last_out != (*i)->out() || last_fade_up_time != (*i)->fade_up_time() || last_fade_down_time != (*i)->fade_down_time() )) { - if (!first) { - s << " \n"; - } - - if (font_changed) { - if (!first) { - s << " \n"; - } - - string id = "theFontId"; - if (!_load_font_nodes.empty()) { - id = _load_font_nodes.front()->id; - } - - s << " \n"; - } - - s << " in().to_string() << "\" " - << "TimeOut=\"" << (*i)->out().to_string() << "\" " - << "FadeUpTime=\"" << (*i)->fade_up_time().to_ticks() << "\" " - << "FadeDownTime=\"" << (*i)->fade_down_time().to_ticks() << "\"" - << ">\n"; + subtitle = font->add_child ("Subtitle"); + subtitle->set_attribute ("SpotNumber", lexical_cast (spot_number++)); + subtitle->set_attribute ("TimeIn", (*i)->in().to_string()); + subtitle->set_attribute ("TimeOut", (*i)->out().to_string()); + subtitle->set_attribute ("FadeUpTime", lexical_cast ((*i)->fade_up_time().to_ticks())); + subtitle->set_attribute ("FadeDownTime", lexical_cast ((*i)->fade_down_time().to_ticks())); last_in = (*i)->in (); last_out = (*i)->out (); @@ -408,23 +406,12 @@ SubtitleAsset::write_xml (ostream& s) const last_fade_down_time = (*i)->fade_down_time (); } - s << " v_align()) << "\" " - << "VPosition=\"" << (*i)->v_position() << "\"" - << ">" << escape ((*i)->text()) << "\n"; - - first = false; + xmlpp::Element* text = subtitle->add_child ("Text"); + text->set_attribute ("VAlign", valign_to_string ((*i)->v_align())); + text->set_attribute ("VPosition", lexical_cast ((*i)->v_position())); + text->add_child_text ((*i)->text()); } - s << " \n"; - s << " \n"; - s << "\n"; + doc.write_to_stream_formatted (s); } -/** XXX: Another reason why we should be writing with libxml++ */ -string -SubtitleAsset::escape (string s) const -{ - boost::replace_all (s, "&", "&"); - return s; -} diff --git a/src/subtitle_asset.h b/src/subtitle_asset.h index 0d662d6c..2da1ce7b 100644 --- a/src/subtitle_asset.h +++ b/src/subtitle_asset.h @@ -123,7 +123,7 @@ public: SubtitleAsset (std::string directory, std::string xml_file); SubtitleAsset (std::string directory, std::string movie_title, std::string language); - void write_to_cpl (std::ostream&) const; + void write_to_cpl (xmlpp::Node *) const; virtual bool equals (boost::shared_ptr, EqualityOptions, boost::function note) const { /* XXX */ note (ERROR, "subtitle assets not compared yet"); @@ -143,11 +143,10 @@ public: void read_xml (std::string); void write_xml () const; - void write_xml (std::ostream& s) const; + void write_xml (std::ostream &) const; private: std::string font_id_to_name (std::string id) const; - std::string escape (std::string) const; struct ParseState { std::list > font_nodes; -- cgit v1.2.3 From b172ecbede672bdef982e5b45376ac3517440263 Mon Sep 17 00:00:00 2001 From: Carl Hetherington Date: Tue, 14 May 2013 16:22:54 +0100 Subject: Fix corpus tests wrt alphabetical sorting; fix some bugs with subtitles that were shown up. --- run-tests.sh | 4 ++-- src/parse/subtitle.cc | 2 +- src/subtitle_asset.cc | 4 ++-- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/run-tests.sh b/run-tests.sh index 888968ad..7ed965cf 100755 --- a/run-tests.sh +++ b/run-tests.sh @@ -29,7 +29,7 @@ if [ ! -e "../libdcp-test" ]; then exit 1 fi -for d in `find ../libdcp-test -mindepth 1 -maxdepth 1 -type d`; do +for d in `find ../libdcp-test -mindepth 1 -maxdepth 1 -type d | sort`; do if [ `basename $d` != ".git" ]; then LD_LIBRARY_PATH=build/src:build/asdcplib/src build/tools/dcpinfo -s $d >> build/test/info.log if [ "$?" != "0" ]; then @@ -49,7 +49,7 @@ rm -f build/test/info2.log rm -rf build/test/libdcp-test cp -r ../libdcp-test build/test -for d in `find build/test/libdcp-test -mindepth 1 -maxdepth 1 -type d`; do +for d in `find build/test/libdcp-test -mindepth 1 -maxdepth 1 -type d | sort`; do if [ `basename $d` != ".git" ]; then LD_LIBRARY_PATH=build/src:build/asdcplib/src build/test/rewrite_subs $d LD_LIBRARY_PATH=build/src:build/asdcplib/src build/tools/dcpinfo -s $d >> build/test/info2.log diff --git a/src/parse/subtitle.cc b/src/parse/subtitle.cc index 471d62b7..612af716 100644 --- a/src/parse/subtitle.cc +++ b/src/parse/subtitle.cc @@ -36,7 +36,7 @@ Font::Font (shared_ptr node) id = node->optional_string_attribute ("Id").get_value_or (""); size = node->optional_number_attribute ("Size").get_value_or (0); - italic = node->optional_bool_attribute ("Italic").get_value_or (false); + italic = node->optional_bool_attribute ("Italic"); optional c = node->optional_string_attribute ("Color"); if (c) { color = Color (c.get ()); diff --git a/src/subtitle_asset.cc b/src/subtitle_asset.cc index 5decc1e3..ca91e2c7 100644 --- a/src/subtitle_asset.cc +++ b/src/subtitle_asset.cc @@ -386,7 +386,7 @@ SubtitleAsset::write_xml (ostream& s) const font->set_attribute ("Weight", "normal"); } - if (!subtitle || + if (!subtitle || font_changed || (last_in != (*i)->in() || last_out != (*i)->out() || last_fade_up_time != (*i)->fade_up_time() || @@ -412,6 +412,6 @@ SubtitleAsset::write_xml (ostream& s) const text->add_child_text ((*i)->text()); } - doc.write_to_stream_formatted (s); + doc.write_to_stream_formatted (s, "UTF-8"); } -- cgit v1.2.3 From 96f8d3ab8b59cbcaf7b8b78f958dd7c10c9aada2 Mon Sep 17 00:00:00 2001 From: Carl Hetherington Date: Wed, 29 May 2013 10:18:37 +0100 Subject: Try to fix compile on OS X --- src/lut.h | 2 +- wscript | 7 ++++++- 2 files changed, 7 insertions(+), 2 deletions(-) diff --git a/src/lut.h b/src/lut.h index 8363e6a4..bdb5f37f 100644 --- a/src/lut.h +++ b/src/lut.h @@ -33,7 +33,7 @@ public: , _bit_depth (bit_depth) , _gamma (gamma) { - _lut = new T[int(std::pow(2, _bit_depth))]; + _lut = new T[int(std::pow(2.0f, _bit_depth))]; } virtual ~LUT() { diff --git a/wscript b/wscript index e8de8385..0bb36223 100644 --- a/wscript +++ b/wscript @@ -7,16 +7,18 @@ VERSION = '0.51pre' def options(opt): opt.load('compiler_cxx') opt.add_option('--target-windows', action='store_true', default = False, help = 'set up to do a cross-compile to Windows') + opt.add_option('--osx', action='store_true', default = False, help = 'set up to build on OS X') opt.add_option('--enable-debug', action='store_true', default = False, help = 'build with debugging information and without optimisation') opt.add_option('--static-openjpeg', action='store_true', default = False, help = 'link statically to openjpeg') opt.add_option('--static-libdcp', action='store_true', default = False, help = 'build libdcp and in-tree dependencies statically') def configure(conf): conf.load('compiler_cxx') - conf.env.append_value('CXXFLAGS', ['-Wall', '-Wextra', '-Wno-unused-result', '-O2', '-D_FILE_OFFSET_BITS=64']) + conf.env.append_value('CXXFLAGS', ['-Wall', '-Wextra', '-O2', '-D_FILE_OFFSET_BITS=64']) conf.env.append_value('CXXFLAGS', ['-DLIBDCP_VERSION="%s"' % VERSION]) conf.env.TARGET_WINDOWS = conf.options.target_windows + conf.env.OSX = conf.options.osx conf.env.STATIC_OPENJPEG = conf.options.static_openjpeg conf.env.STATIC_LIBDCP = conf.options.static_libdcp conf.env.ENABLE_DEBUG = conf.options.enable_debug @@ -26,6 +28,9 @@ def configure(conf): else: conf.env.append_value('CXXFLAGS', '-DLIBDCP_POSIX') + if not conf.options.osx: + conf.env.append_value('CXXFLAGS', ['-Wno-unused-result']) + conf.check_cfg(package = 'openssl', args = '--cflags --libs', uselib_store = 'OPENSSL', mandatory = True) conf.check_cfg(package = 'libxml++-2.6', args = '--cflags --libs', uselib_store = 'LIBXML++', mandatory = True) if conf.options.static_openjpeg: -- cgit v1.2.3 From dff750a2603be9b4bc585b202da37e3acd064204 Mon Sep 17 00:00:00 2001 From: Carl Hetherington Date: Wed, 29 May 2013 10:19:01 +0100 Subject: Using cdist for releases now. --- release | 85 ----------------------------------------------------------------- 1 file changed, 85 deletions(-) delete mode 100755 release diff --git a/release b/release deleted file mode 100755 index 12e7b7fe..00000000 --- a/release +++ /dev/null @@ -1,85 +0,0 @@ -#!/usr/bin/python - -import os -import sys -import datetime -import shutil - -def command(c): - os.system(c) - print c - -def release_version(s): - s = s[1:-1] - if s.endswith('pre'): - s = s[0:-3] - p = s.split('.') - return '0.%02d' % int(p[1]) - -def new_pre_version(s): - s = s[1:-1] - p = s.split('.') - return '0.%02dpre' % (int(p[1]) + 1) - -def rewrite_wscript(version_maker): - f = open('wscript', 'rw') - o = open('wscript.tmp', 'w') - while 1: - l = f.readline() - if l == '': - break - - s = l.split() - if len(s) == 3 and s[0] == "VERSION": - v = version_maker(s[2]) - print "REWRITE %s -> %s" % (s[2], v) - print >>o,"VERSION = '%s'" % v - else: - print >>o,l, - f.close() - o.close() - - os.rename('wscript.tmp', 'wscript') - return v - -def append_to_changelog(version): - f = open('ChangeLog', 'r') - c = f.read() - f.close() - - f = open('ChangeLog', 'w') - now = datetime.datetime.now() - f.write('%d-%02d-%02d Carl Hetherington \n\n\t* Version %s released.\n\n' % (now.year, now.month, now.day, version)) - f.write(c) - -release_version_string = rewrite_wscript(release_version) -#append_to_changelog(release_version_string) - -command("git diff") -if raw_input() != "y": - command("git reset --hard") - print 'Aborted' - sys.exit(1) - -command("git commit -a -m \"Bump version\"") -print "git cleaning..." -command("git clean -n") -if raw_input() != "y": - print 'Aborted' - sys.exit(1) -command("git clean -f") -command("git tag -m \"v%s\" v%s" % (release_version_string, release_version_string)) -command("./waf clean") -command("./waf configure") -command("./waf") -command("./waf dist") - -rewrite_wscript(new_pre_version) - -command("git diff") -if raw_input() != "y": - command("git reset --hard") - print 'Aborted' - sys.exit(1) - -command("git commit -a -m \"Bump version\"") -- cgit v1.2.3 From c598264f1247ae444f502199c6e4b8f857d94fce Mon Sep 17 00:00:00 2001 From: Carl Hetherington Date: Wed, 29 May 2013 10:19:18 +0100 Subject: Bump version --- wscript | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/wscript b/wscript index 0bb36223..b643aebe 100644 --- a/wscript +++ b/wscript @@ -2,7 +2,7 @@ import subprocess import os APPNAME = 'libdcp' -VERSION = '0.51pre' +VERSION = '0.51' def options(opt): opt.load('compiler_cxx') -- cgit v1.2.3 From f510146decac46d5e792fe0b476c58a5ed61df08 Mon Sep 17 00:00:00 2001 From: Carl Hetherington Date: Wed, 29 May 2013 10:19:18 +0100 Subject: Bump version --- wscript | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/wscript b/wscript index b643aebe..e02e239f 100644 --- a/wscript +++ b/wscript @@ -2,7 +2,7 @@ import subprocess import os APPNAME = 'libdcp' -VERSION = '0.51' +VERSION = '0.52pre' def options(opt): opt.load('compiler_cxx') -- cgit v1.2.3 From efc228537094ecb30fe485709f03b9560bcad718 Mon Sep 17 00:00:00 2001 From: Carl Hetherington Date: Wed, 29 May 2013 17:47:39 +0100 Subject: Tweak cscript for OS X --- cscript | 2 ++ 1 file changed, 2 insertions(+) diff --git a/cscript b/cscript index 18913fa1..5413fdbc 100644 --- a/cscript +++ b/cscript @@ -6,6 +6,8 @@ def build(env, target): cmd += ' --static-libdcp --static-openjpeg' elif target.platform == 'windows': cmd += ' --target-windows' + elif target.platform == 'osx': + cmd += ' --osx' env.command(cmd) env.command('./waf build install') -- cgit v1.2.3 From 85d473fee3588e4f36cd42dc7781277d70025d3d Mon Sep 17 00:00:00 2001 From: Carl Hetherington Date: Wed, 29 May 2013 21:50:03 +0100 Subject: Bump version --- wscript | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/wscript b/wscript index e02e239f..53b1c30f 100644 --- a/wscript +++ b/wscript @@ -2,7 +2,7 @@ import subprocess import os APPNAME = 'libdcp' -VERSION = '0.52pre' +VERSION = '0.52' def options(opt): opt.load('compiler_cxx') -- cgit v1.2.3 From e6e329c27b5b48c4341860810dea4616cdc8e7b0 Mon Sep 17 00:00:00 2001 From: Carl Hetherington Date: Wed, 29 May 2013 21:50:03 +0100 Subject: Bump version --- wscript | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/wscript b/wscript index 53b1c30f..1a64812a 100644 --- a/wscript +++ b/wscript @@ -2,7 +2,7 @@ import subprocess import os APPNAME = 'libdcp' -VERSION = '0.52' +VERSION = '0.53pre' def options(opt): opt.load('compiler_cxx') -- cgit v1.2.3 From 52528d511935d95b1a2f0dbf62bcd2af3a6288ad Mon Sep 17 00:00:00 2001 From: Carl Hetherington Date: Sun, 2 Jun 2013 22:16:17 +0100 Subject: Tweaks to diffing routines. --- src/cpl.cc | 6 ++++-- src/types.h | 2 ++ 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/src/cpl.cc b/src/cpl.cc index e7eb1ced..fd705680 100644 --- a/src/cpl.cc +++ b/src/cpl.cc @@ -256,8 +256,10 @@ CPL::write_to_assetmap (xmlpp::Node* node) const bool CPL::equals (CPL const & other, EqualityOptions opt, boost::function note) const { - if (_name != other._name) { - note (ERROR, "names differ"); + if (_name != other._name && !opt.cpl_names_can_differ) { + stringstream s; + s << "names differ: " << _name << " vs " << other._name << "\n"; + note (ERROR, s.str ()); return false; } diff --git a/src/types.h b/src/types.h index b1de4a0f..edabb9e2 100644 --- a/src/types.h +++ b/src/types.h @@ -100,12 +100,14 @@ struct EqualityOptions { : max_mean_pixel_error (0) , max_std_dev_pixel_error (0) , max_audio_sample_error (0) + , cpl_names_can_differ (false) , mxf_names_can_differ (false) {} double max_mean_pixel_error; double max_std_dev_pixel_error; int max_audio_sample_error; + bool cpl_names_can_differ; bool mxf_names_can_differ; }; -- cgit v1.2.3 From 02a275302dc62e4af3a9dc6873e1dd08022bfabf Mon Sep 17 00:00:00 2001 From: Carl Hetherington Date: Tue, 4 Jun 2013 11:29:19 +0100 Subject: Allow SoundAssetWriter to be destroyed without being finalised. --- src/sound_asset.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/sound_asset.cc b/src/sound_asset.cc index 9b6b48aa..3335f2e3 100644 --- a/src/sound_asset.cc +++ b/src/sound_asset.cc @@ -404,5 +404,5 @@ SoundAssetWriter::finalize () SoundAssetWriter::~SoundAssetWriter () { - assert (_finalized); + } -- cgit v1.2.3 From e1e4934599bc244817ae63f4bc9f4a2ba81b1a29 Mon Sep 17 00:00:00 2001 From: Carl Hetherington Date: Tue, 4 Jun 2013 11:35:58 +0100 Subject: Remove _finalized check from picture writer too. --- src/picture_asset.cc | 5 ----- src/picture_asset.h | 2 -- src/sound_asset.cc | 5 ----- src/sound_asset.h | 2 -- 4 files changed, 14 deletions(-) diff --git a/src/picture_asset.cc b/src/picture_asset.cc index 788e3dc4..0019d562 100644 --- a/src/picture_asset.cc +++ b/src/picture_asset.cc @@ -534,8 +534,3 @@ MonoPictureAssetWriter::finalize () _asset->set_intrinsic_duration (_frames_written); _asset->set_duration (_frames_written); } - -MonoPictureAssetWriter::~MonoPictureAssetWriter () -{ - assert (_finalized); -} diff --git a/src/picture_asset.h b/src/picture_asset.h index 59c4dc00..2041abb3 100644 --- a/src/picture_asset.h +++ b/src/picture_asset.h @@ -113,8 +113,6 @@ struct FrameInfo class MonoPictureAssetWriter { public: - ~MonoPictureAssetWriter (); - FrameInfo write (uint8_t* data, int size); void fake_write (int size); void finalize (); diff --git a/src/sound_asset.cc b/src/sound_asset.cc index 3335f2e3..efef3ba7 100644 --- a/src/sound_asset.cc +++ b/src/sound_asset.cc @@ -401,8 +401,3 @@ SoundAssetWriter::finalize () _asset->set_intrinsic_duration (_frames_written); _asset->set_duration (_frames_written); } - -SoundAssetWriter::~SoundAssetWriter () -{ - -} diff --git a/src/sound_asset.h b/src/sound_asset.h index 5c230e06..b95b34be 100644 --- a/src/sound_asset.h +++ b/src/sound_asset.h @@ -37,8 +37,6 @@ class SoundAsset; class SoundAssetWriter { public: - ~SoundAssetWriter (); - void write (float const * const *, int); void finalize (); -- cgit v1.2.3 From 9713e449ddb65393bf9b6fc3eef0f799efa1cbc8 Mon Sep 17 00:00:00 2001 From: Carl Hetherington Date: Tue, 4 Jun 2013 22:56:36 +0100 Subject: Bump version --- wscript | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/wscript b/wscript index 1a64812a..fc6f4110 100644 --- a/wscript +++ b/wscript @@ -2,7 +2,7 @@ import subprocess import os APPNAME = 'libdcp' -VERSION = '0.53pre' +VERSION = '0.53' def options(opt): opt.load('compiler_cxx') -- cgit v1.2.3 From 02b1073f910aeb4eeaa914d15a68b76b3969e690 Mon Sep 17 00:00:00 2001 From: Carl Hetherington Date: Tue, 4 Jun 2013 22:56:36 +0100 Subject: Bump version --- wscript | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/wscript b/wscript index fc6f4110..2d759193 100644 --- a/wscript +++ b/wscript @@ -2,7 +2,7 @@ import subprocess import os APPNAME = 'libdcp' -VERSION = '0.53' +VERSION = '0.54pre' def options(opt): opt.load('compiler_cxx') -- cgit v1.2.3