-# Doxyfile 1.8.1.2
+# Doxyfile 1.8.4
# This file describes the settings to be used by the documentation system
# doxygen (www.doxygen.org) for a project.
#
+# All text after a double hash (##) is considered a comment and is placed
+# in front of the TAG it is preceding .
# All text after a hash (#) is considered a comment and will be ignored.
# The format is:
# TAG = value [value, ...]
# Afrikaans, Arabic, Brazilian, Catalan, Chinese, Chinese-Traditional,
# Croatian, Czech, Danish, Dutch, Esperanto, Farsi, Finnish, French, German,
# Greek, Hungarian, Italian, Japanese, Japanese-en (Japanese with English
-# messages), Korean, Korean-en, Lithuanian, Norwegian, Macedonian, Persian,
-# Polish, Portuguese, Romanian, Russian, Serbian, Serbian-Cyrillic, Slovak,
-# Slovene, Spanish, Swedish, Ukrainian, and Vietnamese.
+# messages), Korean, Korean-en, Latvian, Lithuanian, Norwegian, Macedonian,
+# Persian, Polish, Portuguese, Romanian, Russian, Serbian, Serbian-Cyrillic,
+# Slovak, Slovene, Spanish, Swedish, Ukrainian, and Vietnamese.
OUTPUT_LANGUAGE = English
# only done if one of the specified strings matches the left-hand part of
# the path. The tag can be used to show relative paths in the file list.
# If left blank the directory from which doxygen is run is used as the
-# path to strip.
+# path to strip. Note that you specify absolute paths here, but also
+# relative paths, which will be relative from the directory where doxygen is
+# started.
STRIP_FROM_PATH =
OPTIMIZE_OUTPUT_VHDL = NO
# Doxygen selects the parser to use depending on the extension of the files it
-# parses. With this tag you can assign which parser to use for a given extension.
-# Doxygen has a built-in mapping, but you can override or extend it using this
-# tag. The format is ext=language, where ext is a file extension, and language
-# is one of the parsers supported by doxygen: IDL, Java, Javascript, CSharp, C,
-# C++, D, PHP, Objective-C, Python, Fortran, VHDL, C, C++. For instance to make
-# doxygen treat .inc files as Fortran files (default is PHP), and .f files as C
-# (default is Fortran), use: inc=Fortran f=C. Note that for custom extensions
-# you also need to set FILE_PATTERNS otherwise the files are not read by doxygen.
+# parses. With this tag you can assign which parser to use for a given
+# extension. Doxygen has a built-in mapping, but you can override or extend it
+# using this tag. The format is ext=language, where ext is a file extension,
+# and language is one of the parsers supported by doxygen: IDL, Java,
+# Javascript, CSharp, C, C++, D, PHP, Objective-C, Python, Fortran, VHDL, C,
+# C++. For instance to make doxygen treat .inc files as Fortran files (default
+# is PHP), and .f files as C (default is Fortran), use: inc=Fortran f=C. Note
+# that for custom extensions you also need to set FILE_PATTERNS otherwise the
+# files are not read by doxygen.
EXTENSION_MAPPING =
MARKDOWN_SUPPORT = YES
+# When enabled doxygen tries to link words that correspond to documented
+# classes, or namespaces to their corresponding documentation. Such a link can
+# be prevented in individual cases by by putting a % sign in front of the word
+# or globally by setting AUTOLINK_SUPPORT to NO.
+
+AUTOLINK_SUPPORT = YES
+
# If you use STL classes (i.e. std::string, std::vector, etc.) but do not want
# to include (a tag file for) the STL sources as input, then you should
# set this tag to YES in order to let doxygen match functions declarations and
SIP_SUPPORT = NO
-# For Microsoft's IDL there are propget and propput attributes to indicate getter
-# and setter methods for a property. Setting this option to YES (the default)
-# will make doxygen replace the get and set methods by a property in the
-# documentation. This will only work if the methods are indeed getting or
+# For Microsoft's IDL there are propget and propput attributes to indicate
+# getter and setter methods for a property. Setting this option to YES (the
+# default) will make doxygen replace the get and set methods by a property in
+# the documentation. This will only work if the methods are indeed getting or
# setting a simple type. If this is not the case, or you want to show the
# methods anyway, you should set this option to NO.
INLINE_GROUPED_CLASSES = NO
# When the INLINE_SIMPLE_STRUCTS tag is set to YES, structs, classes, and
-# unions with only public data fields will be shown inline in the documentation
-# of the scope in which they are defined (i.e. file, namespace, or group
-# documentation), provided this scope is documented. If set to NO (the default),
-# structs, classes, and unions are shown on a separate page (for HTML and Man
-# pages) or section (for LaTeX and RTF).
+# unions with only public data fields or simple typedef fields will be shown
+# inline in the documentation of the scope in which they are defined (i.e. file,
+# namespace, or group documentation), provided this scope is documented. If set
+# to NO (the default), structs, classes, and unions are shown on a separate
+# page (for HTML and Man pages) or section (for LaTeX and RTF).
INLINE_SIMPLE_STRUCTS = NO
TYPEDEF_HIDES_STRUCT = NO
-# The SYMBOL_CACHE_SIZE determines the size of the internal cache use to
-# determine which symbols to keep in memory and which to flush to disk.
-# When the cache is full, less often used symbols will be written to disk.
-# For small to medium size projects (<1000 input files) the default value is
-# probably good enough. For larger projects a too small cache size can cause
-# doxygen to be busy swapping symbols to and from disk most of the time
-# causing a significant performance penalty.
-# If the system has enough physical memory increasing the cache will improve the
-# performance by keeping more symbols in memory. Note that the value works on
-# a logarithmic scale so increasing the size by one will roughly double the
-# memory usage. The cache size is given by this formula:
-# 2^(16+SYMBOL_CACHE_SIZE). The valid range is 0..9, the default is 0,
-# corresponding to a cache size of 2^16 = 65536 symbols.
-
-SYMBOL_CACHE_SIZE = 0
-
-# Similar to the SYMBOL_CACHE_SIZE the size of the symbol lookup cache can be
-# set using LOOKUP_CACHE_SIZE. This cache is used to resolve symbols given
-# their name and scope. Since this can be an expensive process and often the
-# same symbol appear multiple times in the code, doxygen keeps a cache of
-# pre-resolved symbols. If the cache is too small doxygen will become slower.
-# If the cache is too large, memory is wasted. The cache size is given by this
-# formula: 2^(16+LOOKUP_CACHE_SIZE). The valid range is 0..9, the default is 0,
-# corresponding to a cache size of 2^16 = 65536 symbols.
+# The size of the symbol lookup cache can be set using LOOKUP_CACHE_SIZE. This
+# cache is used to resolve symbols given their name and scope. Since this can
+# be an expensive process and often the same symbol appear multiple times in
+# the code, doxygen keeps a cache of pre-resolved symbols. If the cache is too
+# small doxygen will become slower. If the cache is too large, memory is wasted.
+# The cache size is given by this formula: 2^(16+LOOKUP_CACHE_SIZE). The valid
+# range is 0..9, the default is 0, corresponding to a cache size of 2^16 = 65536
+# symbols.
LOOKUP_CACHE_SIZE = 0
# If the EXTRACT_ALL tag is set to YES doxygen will assume all entities in
# documentation are documented, even if no documentation was available.
# Private class members and static file members will be hidden unless
-# the EXTRACT_PRIVATE and EXTRACT_STATIC tags are set to YES
+# the EXTRACT_PRIVATE respectively EXTRACT_STATIC tags are set to YES
-EXTRACT_ALL = YES
+EXTRACT_ALL = NO
# If the EXTRACT_PRIVATE tag is set to YES all private members of a class
# will be included in the documentation.
-EXTRACT_PRIVATE = NO
+EXTRACT_PRIVATE = YES
-# If the EXTRACT_PACKAGE tag is set to YES all members with package or internal scope will be included in the documentation.
+# If the EXTRACT_PACKAGE tag is set to YES all members with package or internal
+# scope will be included in the documentation.
EXTRACT_PACKAGE = NO
GENERATE_DEPRECATEDLIST= YES
# The ENABLED_SECTIONS tag can be used to enable conditional
-# documentation sections, marked by \if sectionname ... \endif.
+# documentation sections, marked by \if section-label ... \endif
+# and \cond section-label ... \endcond blocks.
ENABLED_SECTIONS =
# requires the bibtex tool to be installed. See also
# http://en.wikipedia.org/wiki/BibTeX for more info. For LaTeX the style
# of the bibliography can be controlled using LATEX_BIB_STYLE. To use this
-# feature you need bibtex and perl available in the search path.
+# feature you need bibtex and perl available in the search path. Do not use
+# file names with spaces, bibtex cannot handle them.
CITE_BIB_FILES =
# with spaces.
INPUT = src \
- examples \
+ examples \
doc/mainpage.txt
# This tag can be used to specify the character encoding of the source files
# is the value of the INPUT_FILTER tag, and <input-file> is the name of an
# input file. Doxygen will then use the output that the filter program writes
# to standard output.
-# If FILTER_PATTERNS is specified, this tag will be
-# ignored.
+# If FILTER_PATTERNS is specified, this tag will be ignored.
+# Note that the filter must not add or remove lines; it is applied before the
+# code is scanned, but not when the output code is generated. If lines are added
+# or removed, the anchors will not be placed correctly.
INPUT_FILTER =
FILTER_SOURCE_PATTERNS =
+# If the USE_MD_FILE_AS_MAINPAGE tag refers to the name of a markdown file that
+# is part of the input, its contents will be placed on the main page
+# (index.html). This can be useful if you have a project on for instance GitHub
+# and want reuse the introduction page also for the doxygen output.
+
+USE_MDFILE_AS_MAINPAGE =
+
#---------------------------------------------------------------------------
# configuration options related to source browsing
#---------------------------------------------------------------------------
# The HTML_STYLESHEET tag can be used to specify a user-defined cascading
# style sheet that is used by each HTML page. It can be used to
-# fine-tune the look of the HTML output. If the tag is left blank doxygen
-# will generate a default style sheet. Note that doxygen will try to copy
-# the style sheet file to the HTML output directory, so don't put your own
-# style sheet in the HTML output directory as well, or it will be erased!
+# fine-tune the look of the HTML output. If left blank doxygen will
+# generate a default style sheet. Note that it is recommended to use
+# HTML_EXTRA_STYLESHEET instead of this one, as it is more robust and this
+# tag will in the future become obsolete.
HTML_STYLESHEET =
+# The HTML_EXTRA_STYLESHEET tag can be used to specify an additional
+# user-defined cascading style sheet that is included after the standard
+# style sheets created by doxygen. Using this option one can overrule
+# certain style aspects. This is preferred over using HTML_STYLESHEET
+# since it does not replace the standard style sheet and is therefor more
+# robust against future updates. Doxygen will copy the style sheet file to
+# the output directory.
+
+HTML_EXTRA_STYLESHEET =
+
# The HTML_EXTRA_FILES tag can be used to specify one or more extra images or
# other source files which should be copied to the HTML output directory. Note
# that these files will be copied to the base HTML output directory. Use the
-# $relpath$ marker in the HTML_HEADER and/or HTML_FOOTER files to load these
+# $relpath^ marker in the HTML_HEADER and/or HTML_FOOTER files to load these
# files. In the HTML_STYLESHEET file, use the file name only. Also note that
# the files will be copied as-is; there are no commands or markers available.
DOCSET_BUNDLE_ID = org.doxygen.Project
-# When GENERATE_PUBLISHER_ID tag specifies a string that should uniquely identify
-# the documentation publisher. This should be a reverse domain-name style
-# string, e.g. com.mycompany.MyDocSet.documentation.
+# When GENERATE_PUBLISHER_ID tag specifies a string that should uniquely
+# identify the documentation publisher. This should be a reverse domain-name
+# style string, e.g. com.mycompany.MyDocSet.documentation.
DOCSET_PUBLISHER_ID = org.doxygen.Publisher
USE_MATHJAX = NO
+# When MathJax is enabled you can set the default output format to be used for
+# the MathJax output. Supported types are HTML-CSS, NativeMML (i.e. MathML) and
+# SVG. The default value is HTML-CSS, which is slower, but has the best
+# compatibility.
+
+MATHJAX_FORMAT = HTML-CSS
+
# When MathJax is enabled you need to specify the location relative to the
# HTML output directory using the MATHJAX_RELPATH option. The destination
# directory should contain the MathJax.js script. For instance, if the mathjax
MATHJAX_EXTENSIONS =
+# The MATHJAX_CODEFILE tag can be used to specify a file with javascript
+# pieces of code that will be used on startup of the MathJax code.
+
+MATHJAX_CODEFILE =
+
# When the SEARCHENGINE tag is enabled doxygen will generate a search box
# for the HTML output. The underlying search engine uses javascript
# and DHTML and should work on any modern browser. Note that when using
SEARCHENGINE = YES
# When the SERVER_BASED_SEARCH tag is enabled the search engine will be
-# implemented using a PHP enabled web server instead of at the web client
-# using Javascript. Doxygen will generate the search PHP script and index
-# file to put on the web server. The advantage of the server
-# based approach is that it scales better to large projects and allows
-# full text search. The disadvantages are that it is more difficult to setup
-# and does not have live searching capabilities.
+# implemented using a web server instead of a web client using Javascript.
+# There are two flavours of web server based search depending on the
+# EXTERNAL_SEARCH setting. When disabled, doxygen will generate a PHP script for
+# searching and an index file used by the script. When EXTERNAL_SEARCH is
+# enabled the indexing and searching needs to be provided by external tools.
+# See the manual for details.
SERVER_BASED_SEARCH = NO
+# When EXTERNAL_SEARCH is enabled doxygen will no longer generate the PHP
+# script for searching. Instead the search results are written to an XML file
+# which needs to be processed by an external indexer. Doxygen will invoke an
+# external search engine pointed to by the SEARCHENGINE_URL option to obtain
+# the search results. Doxygen ships with an example indexer (doxyindexer) and
+# search engine (doxysearch.cgi) which are based on the open source search
+# engine library Xapian. See the manual for configuration details.
+
+EXTERNAL_SEARCH = NO
+
+# The SEARCHENGINE_URL should point to a search engine hosted by a web server
+# which will returned the search results when EXTERNAL_SEARCH is enabled.
+# Doxygen ships with an example search engine (doxysearch) which is based on
+# the open source search engine library Xapian. See the manual for configuration
+# details.
+
+SEARCHENGINE_URL =
+
+# When SERVER_BASED_SEARCH and EXTERNAL_SEARCH are both enabled the unindexed
+# search data is written to a file for indexing by an external tool. With the
+# SEARCHDATA_FILE tag the name of this file can be specified.
+
+SEARCHDATA_FILE = searchdata.xml
+
+# When SERVER_BASED_SEARCH AND EXTERNAL_SEARCH are both enabled the
+# EXTERNAL_SEARCH_ID tag can be used as an identifier for the project. This is
+# useful in combination with EXTRA_SEARCH_MAPPINGS to search through multiple
+# projects and redirect the results back to the right project.
+
+EXTERNAL_SEARCH_ID =
+
+# The EXTRA_SEARCH_MAPPINGS tag can be used to enable searching through doxygen
+# projects other than the one defined by this configuration file, but that are
+# all added to the same external search index. Each project needs to have a
+# unique id set via EXTERNAL_SEARCH_ID. The search mapping then maps the id
+# of to a relative location where the documentation can be found.
+# The format is: EXTRA_SEARCH_MAPPINGS = id1=loc1 id2=loc2 ...
+
+EXTRA_SEARCH_MAPPINGS =
+
#---------------------------------------------------------------------------
# configuration options related to the LaTeX output
#---------------------------------------------------------------------------
# The PAPER_TYPE tag can be used to set the paper type that is used
# by the printer. Possible values are: a4, letter, legal and
-# executive. If left blank a4wide will be used.
+# executive. If left blank a4 will be used.
PAPER_TYPE = a4wide
LATEX_FOOTER =
+# The LATEX_EXTRA_FILES tag can be used to specify one or more extra images
+# or other source files which should be copied to the LaTeX output directory.
+# Note that the files will be copied as-is; there are no commands or markers
+# available.
+
+LATEX_EXTRA_FILES =
+
# If the PDF_HYPERLINKS tag is set to YES, the LaTeX that is generated
# is prepared for conversion to pdf (using ps2pdf). The pdf file will
# contain links (just like the HTML output) instead of page references
XML_PROGRAMLISTING = YES
+#---------------------------------------------------------------------------
+# configuration options related to the DOCBOOK output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_DOCBOOK tag is set to YES Doxygen will generate DOCBOOK files
+# that can be used to generate PDF.
+
+GENERATE_DOCBOOK = NO
+
+# The DOCBOOK_OUTPUT tag is used to specify where the DOCBOOK pages will be put.
+# If a relative path is entered the value of OUTPUT_DIRECTORY will be put in
+# front of it. If left blank docbook will be used as the default path.
+
+DOCBOOK_OUTPUT = docbook
+
#---------------------------------------------------------------------------
# configuration options for the AutoGen Definitions output
#---------------------------------------------------------------------------
EXTERNAL_GROUPS = YES
+# If the EXTERNAL_PAGES tag is set to YES all external pages will be listed
+# in the related pages index. If set to NO, only the current project's
+# pages will be listed.
+
+EXTERNAL_PAGES = YES
+
# The PERL_PATH should be the absolute path and name of the perl script
# interpreter (i.e. the result of `which perl').
# the DOTFONTPATH environment variable or by setting DOT_FONTPATH to the
# directory containing the font.
-DOT_FONTNAME = FreeSans.ttf
+DOT_FONTNAME =
# The DOT_FONTSIZE tag can be used to set the size of the font of dot graphs.
# The default size is 10pt.
# the class node. If there are many fields or methods and many nodes the
# graph may become too big to be useful. The UML_LIMIT_NUM_FIELDS
# threshold limits the number of items for each type to make the size more
-# managable. Set this to 0 for no limit. Note that the threshold may be
+# manageable. Set this to 0 for no limit. Note that the threshold may be
# exceeded by 50% before the limit is enforced.
UML_LIMIT_NUM_FIELDS = 10
else:
obj = bld(features = 'cxx cxxshlib')
- obj.name = 'libkumu-libdcp'
- obj.target = 'kumu-libdcp'
+ obj.name = 'libkumu-libdcp%s' % bld.env.API_VERSION
+ obj.target = 'kumu-libdcp%s' % bld.env.API_VERSION
obj.uselib = 'OPENSSL BOOST_FILESYSTEM'
obj.includes = ['.']
obj.export_includes = ['.']
else:
obj = bld(features = 'cxx cxxshlib')
- obj.name = 'libasdcp-libdcp'
- obj.target = 'asdcp-libdcp'
+ obj.name = 'libasdcp-libdcp%s' % bld.env.API_VERSION
+ obj.target = 'asdcp-libdcp%s' % bld.env.API_VERSION
obj.uselib = 'OPENSSL'
- obj.use = 'libkumu-libdcp'
+ obj.use = 'libkumu-libdcp%s' % bld.env.API_VERSION
obj.includes = ['.']
obj.export_includes = ['.']
obj.source = """
"""
if bld.env.STATIC:
- bld.install_files('${PREFIX}/lib', 'libkumu-libdcp.a')
- bld.install_files('${PREFIX}/lib', 'libasdcp-libdcp.a')
+ bld.install_files('${PREFIX}/lib', 'libkumu-libdcp%s.a' % bld.env.API_VERSION)
+ bld.install_files('${PREFIX}/lib', 'libasdcp-libdcp%s.a' % bld.env.API_VERSION)
@mainpage libdcp
-libdcp is a library to create Digital Cinema Packages (DCPs) from JPEG2000 and WAV files, and also to
-read and process existing DCPs.
+libdcp is a library to create Digital Cinema Packages (DCPs) from
+video, audio and subtitle data, and also to read and process existing
+DCPs.
-Most of the hard work is done by a (slightly patched) version of asdcplib (http://www.cinecert.com/asdcplib/)
-which is included in the source distribution for libdcp.
+Most of the hard work is done by a (slightly patched) version of
+asdcplib (http://www.cinecert.com/asdcplib/) which is included in the
+source distribution for libdcp.
libdcp is distributed under the GNU GPL.
Reading existing DCPs
--
-libdcp can be used to read existing DCPs and examine their content. You might do
-
-@code
-#include <libdcp/dcp.h>
-using namespace std;
-
-libdcp::DCP dcp ("some-DCP-directory");
-@endcode
-
-libdcp will look at the XML files that make up the DCP and find its assets. You can then
-do things like
-
-@code
-boost::shared_ptr<Reel> reel = dcp.reels.front ();
-boost::shared_ptr<libdcp::PictureAsset> p = reel->main_picture ();
-boost::shared_ptr<libdcp::MonoPictureAsset> mp = boost::dynamic_pointer_cast<libdcp::MonoPictureAsset> (p);
-boost::shared_ptr<libdcp::ARGBFrame> f = mp->get_frame(42)->argb_frame ();
-uint8_t* data = f->data ();
-int size = f->size ();
-@endcode
-
-This will extract the image of frame 42 from the first reel of the DCP and make its ARGB data available
-for examination. We have to do a <code>dynamic_pointer_cast</code> from <code>libdcp::PictureAsset</code>
-to <code>libdcp::MonoPictureAsset</code>, as the picture asset may be either 2D (monoscopic) or 3D (stereoscopic).
-
-Audio data is accessed in chunks equal in length to the duration of a video frame. To
-get the audio that accompanies frame 66, you can do
-
-@code
-boost::shared_ptr<libdcp::SoundAsset> s = reel->main_sound ();
-cout << "Sound has " << s->channels() << " channels at " << s->sampling_rate() << "Hz\n";
-boost::shared_ptr<libdcp::SoundFrame> f = s->get_frame(66);
-uint8_t* data = f->data ();
-int size = f->size ();
-@endcode
-
-The returned data are interleaved 24-bit samples, so that
-
-@code
-int left = data[0] | (data[1] << 8) | (data[2] << 16);
-data += 3;
-int right = data[0] | (data[1] << 8) | (data[2] << 16);
-data += 3;
-int centre = data[0] | (data[1] << 8) | (data[2] << 16);
-data += 3;
-int lfe = data[0] | (data[1] << 8) | (data[2] << 16);
-data += 3;
-int ls = data[0] | (data[1] << 8) | (data[2] << 16);
-data += 3;
-int rs = data[0] | (data[1] << 8) | (data[2] << 16);
-data += 3;
-@endcode
-
-would obtain the first sample from each of the 6 channels for that frame.
-
-Subtitles can be read using code like
-
-@code
-boost::shared_ptr<SubtitleAsset> s = dcp.subtitle_asset ();
-list<boost::shared_ptr<libdcp::Text> > texts = s->subtitles_at (libdcp::Time (0, 3, 2, 5));
-@endcode
-
-This returns the subtitles that should be shown at 3 minutes, 2
-seconds, 5 ticks (where 1 tick is 4ms) into the DCP.
-
+An example of DCP reading is given in examples/read_dcp.cc.
*/
/*
- Copyright (C) 2012 Carl Hetherington <cth@carlh.net>
+ Copyright (C) 2012-2014 Carl Hetherington <cth@carlh.net>
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
*/
/** @file examples/make_dcp.cc
- * @brief Shows how to make a DCP from some JPEG2000 and WAV files.
+ * @brief Shows how to make a DCP from some JPEG2000 and audio data.
*/
#include <vector>
#include "dcp.h"
#include "cpl.h"
-#include "mono_picture_asset.h"
-#include "sound_asset.h"
+#include "mono_picture_mxf.h"
+#include "mono_picture_mxf_writer.h"
+#include "sound_mxf.h"
+#include "sound_mxf_writer.h"
#include "reel.h"
-
-/* This method returns the filename of the JPEG2000 file to use for a given frame.
- In this example, we are using the same file for each frame, so we don't bother
- looking at the frame parameter, but it will called with frame=0, frame=1, ...
-*/
-std::string
-video_frame (int /* frame */)
-{
- return "examples/help.j2c";
-}
+#include "file.h"
+#include "reel_mono_picture_asset.h"
+#include "reel_sound_asset.h"
int
main ()
{
- /* Make a DCP object. "My Film DCP" is the directory name for the DCP */
- libdcp::DCP dcp ("My Film DCP");
+ /* Create a directory to put the DCP in */
+ boost::filesystem::create_directory ("DCP");
- /* Now make a CPL object.
-
- "My Film" is the title that will be shown on the projector / TMS when the DCP is ingested.
- FEATURE is the type that the projector will list the DCP as.
- 24 is the frame rate, and the DCP will be 48 frames long (ie 2 seconds at 24 fps).
- */
- boost::shared_ptr<libdcp::CPL> cpl (new libdcp::CPL ("My Film DCP", "My Film", libdcp::FEATURE, 24, 48));
-
- /* And add the CPL to the DCP */
- dcp.add_cpl (cpl);
-
- /* Now make a `picture asset'. This is a collection of the JPEG2000 files that make up the picture; one per frame.
- First, create the object.
+ /* Make a picture MXF. This is a file which combines JPEG2000 files together to make
+ up the video of the DCP. First, create the object, specifying a frame rate of 24 frames
+ per second.
*/
- boost::shared_ptr<libdcp::MonoPictureAsset> picture_asset (
- new libdcp::MonoPictureAsset ("My Film DCP", "video.mxf")
- );
+ boost::shared_ptr<dcp::MonoPictureMXF> picture_mxf (new dcp::MonoPictureMXF (dcp::Fraction (24, 1)));
- /* Now set up its parameters; we have the frame rate, the
- number of frames and the resolution of the frames;
- 1998x1080 is the DCI Flat specification for 2K projectors.
- */
-
- picture_asset->set_edit_rate (24);
- picture_asset->set_intrinsic_duration (24);
- picture_asset->set_size (libdcp::Size (1998, 1080));
-
- /* Now we can create the asset itself. Here using a function (video_frame) to obtain the name of the JPEG2000 file for each frame.
- The result will be an MXF file written to the directory "My Film DCP" (which should be the same as the DCP's
- directory above) called "video.mxf".
- */
+ /* Start off a write to it */
+ boost::shared_ptr<dcp::PictureMXFWriter> picture_writer = picture_mxf->start_write ("DCP/picture.mxf", dcp::SMPTE, false);
- picture_asset->create (video_frame);
+ /* Write 24 frames of the same JPEG2000 file */
+ dcp::File picture ("examples/help.j2c");
+ for (int i = 0; i < 24; ++i) {
+ picture_writer->write (picture.data(), picture.size());
+ }
- /* Now we will create a `sound asset', which is made up of a WAV file for each channel of audio. Here we're using
- stereo, so we add two WAV files to a vector.
+ /* And finish off */
+ picture_writer->finalize ();
- We could add more files here to use more channels; the file order is:
- Left
- Right
- Centre
- LFE (sub)
- Left surround
- Right surround
+ /* Now create a sound MXF. As before, create an object and a writer.
+ When creating the object we specify the sampling rate (48kHz) and the number of channels (2).
*/
- std::vector<boost::filesystem::path> sound_files;
- sound_files.push_back ("examples/sine_440_-12dB.wav");
- sound_files.push_back ("examples/sine_880_-12dB.wav");
-
- /* Now we can create the sound asset using these files */
- boost::shared_ptr<libdcp::SoundAsset> sound_asset (new libdcp::SoundAsset ("My Film DCP", "audio.mxf"));
- sound_asset->set_edit_rate (24);
- sound_asset->set_intrinsic_duration (48);
- sound_asset->create (sound_files);
-
- /* Now that we have the assets, we can create a Reel to put them in and add it to the CPL */
- cpl->add_reel (
- boost::shared_ptr<libdcp::Reel> (
- new libdcp::Reel (picture_asset, sound_asset, boost::shared_ptr<libdcp::SubtitleAsset> ())
- )
- );
-
- /* Finally, we call this to write the XML description files to the DCP. After this, the DCP
- is ready to ingest and play.
+ boost::shared_ptr<dcp::SoundMXF> sound_mxf (new dcp::SoundMXF (dcp::Fraction (24, 1), 48000, 2));
+ boost::shared_ptr<dcp::SoundMXFWriter> sound_writer = sound_mxf->start_write ("DCP/sound.mxf", dcp::SMPTE);
+
+ /* Write some sine waves */
+ float* audio[2];
+ audio[0] = new float[48000];
+ audio[1] = new float[48000];
+ for (int i = 0; i < 48000; ++i) {
+ audio[0][i] = sin (2 * M_PI * i * 440 / 48000) * 0.25;
+ audio[1][i] = sin (2 * M_PI * i * 880 / 48000) * 0.25;
+ }
+ sound_writer->write (audio, 48000);
+
+ /* And tidy up */
+ delete[] audio[0];
+ delete[] audio[1];
+ sound_writer->finalize ();
+
+ /* Now create a reel */
+ boost::shared_ptr<dcp::Reel> reel (new dcp::Reel ());
+
+ /* Add picture and sound to it. The zeros are the `entry points', i.e. the first
+ (video) frame from the MXFs that the reel should play.
*/
- libdcp::XMLMetadata metadata;
- dcp.write_xml (false, metadata);
-
+ reel->add (boost::shared_ptr<dcp::ReelPictureAsset> (new dcp::ReelMonoPictureAsset (picture_mxf, 0)));
+ reel->add (boost::shared_ptr<dcp::ReelSoundAsset> (new dcp::ReelSoundAsset (sound_mxf, 0)));
+
+ /* Make a CPL with this reel */
+ boost::shared_ptr<dcp::CPL> cpl (new dcp::CPL ("My film", dcp::FEATURE));
+ cpl->add (reel);
+
+ /* Write the DCP */
+ dcp::DCP dcp ("DCP");
+ dcp.add (cpl);
+ dcp.add (picture_mxf);
+ dcp.add (sound_mxf);
+ dcp.write_xml (dcp::SMPTE);
+
return 0;
}
--- /dev/null
+/*
+ Copyright (C) 2012-2014 Carl Hetherington <cth@carlh.net>
+
+ 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.
+
+*/
+
+/* If you are using an installed libdcp, these #includes would need to be changed to
+#include <libdcp/dcp.h>
+#include <libdcp/picture_mxf.h>
+... etc. ...
+*/
+
+#include "dcp.h"
+#include "cpl.h"
+#include "reel.h"
+#include "reel_picture_asset.h"
+#include "mono_picture_frame.h"
+#include "mono_picture_mxf.h"
+#include "stereo_picture_mxf.h"
+#include "sound_mxf.h"
+#include "subtitle_content.h"
+#include "argb_frame.h"
+#include <Magick++.h>
+
+/** @file examples/read_dcp.cc
+ * @brief Shows how to read a DCP.
+ */
+
+int
+main ()
+{
+ /* Create a DCP, specifying where our existing data is */
+ dcp::DCP dcp ("/home/carl/diagonal.com/APPASSIONATA_TLR_F_UK-DEFR_CH_51_2K_LOK_20121115_DGL_OV");
+ /* Read the DCP to find out about it */
+ dcp.read ();
+
+ if (dcp.encrypted ()) {
+ std::cout << "DCP is encrypted.\n";
+ } else {
+ std::cout << "DCP is not encrypted.\n";
+ }
+
+ std::cout << "DCP has " << dcp.cpls().size() << " CPLs.\n";
+ std::list<boost::shared_ptr<dcp::Asset> > assets = dcp.assets ();
+ std::cout << "DCP has " << assets.size() << " assets.\n";
+ for (std::list<boost::shared_ptr<dcp::Asset> >::const_iterator i = assets.begin(); i != assets.end(); ++i) {
+ if (boost::dynamic_pointer_cast<dcp::MonoPictureMXF> (*i)) {
+ std::cout << "2D picture\n";
+ } else if (boost::dynamic_pointer_cast<dcp::StereoPictureMXF> (*i)) {
+ std::cout << "3D picture\n";
+ } else if (boost::dynamic_pointer_cast<dcp::SoundMXF> (*i)) {
+ std::cout << "Sound\n";
+ } else if (boost::dynamic_pointer_cast<dcp::SubtitleContent> (*i)) {
+ std::cout << "Subtitle\n";
+ } else if (boost::dynamic_pointer_cast<dcp::CPL> (*i)) {
+ std::cout << "CPL\n";
+ }
+ std::cout << "\t" << (*i)->file().leaf().string() << "\n";
+ }
+
+ /* Take the first CPL */
+ boost::shared_ptr<dcp::CPL> cpl = dcp.cpls().front ();
+
+ /* Get the MXF of the picture asset in the first reel */
+ boost::shared_ptr<dcp::MonoPictureMXF> picture_mxf = boost::dynamic_pointer_cast<dcp::MonoPictureMXF> (cpl->reels().front()->main_picture()->mxf ());
+
+ /* Get the 1000th frame of it */
+ boost::shared_ptr<const dcp::MonoPictureFrame> picture_frame_j2k = picture_mxf->get_frame(999);
+
+ /* Get a ARGB copy of it */
+ boost::shared_ptr<dcp::ARGBFrame> picture_frame_rgb = picture_frame_j2k->argb_frame ();
+
+ Magick::Image image (picture_frame_rgb->size().width, picture_frame_rgb->size().height, "BGRA", Magick::CharPixel, picture_frame_rgb->data ());
+ image.write ("frame.png");
+
+ return 0;
+}
def build(bld):
obj = bld(features = 'cxx cxxprogram')
- obj.name = 'examples'
- obj.use = 'libdcp'
+ obj.name = 'make_dcp'
+ obj.use = 'libdcp%s' % bld.env.API_VERSION
obj.uselib = 'OPENJPEG CXML'
obj.source = 'make_dcp.cc'
obj.target = 'make_dcp'
obj.install_path = ''
+
+ obj = bld(features = 'cxx cxxprogram')
+ obj.name = 'read_dcp'
+ obj.use = 'libdcp%s' % bld.env.API_VERSION
+ obj.uselib = 'OPENJPEG CXML MAGICK'
+ obj.source = 'read_dcp.cc'
+ obj.target = 'read_dcp'
+ obj.install_path = ''
--- /dev/null
+prefix=@prefix@
+libdir=@libdir@
+includedir=@includedir@
+
+Name: libdcp
+Description: DCP reading and writing library
+Version: @version@
+Requires: sigc++-2.0 openssl libxml++-2.6 xmlsec1
+Libs: @libs@
+Cflags: -I${includedir}
+++ /dev/null
-prefix=@prefix@
-libdir=@libdir@
-includedir=@includedir@
-
-Name: libdcp
-Description: DCP reading and writing library
-Version: @version@
-Requires: sigc++-2.0 openssl libxml++-2.6 xmlsec1
-Libs: @libs@
-Cflags: -I${includedir}
--- /dev/null
+#!/bin/bash
+
+export LD_LIBRARY_PATH=build/src
+if [ "$1" == "--debug" ]; then
+ shift
+ gdb --args build/examples/read_dcp "$@"
+elif [ "$1" == "--valgrind" ]; then
+ shift
+ valgrind --tool="memcheck" --leak-check=full --show-reachable=yes build/examples/read_dcp "$@"
+else
+ build/examples/read_dcp "$@"
+fi
/*
- Copyright (C) 2012 Carl Hetherington <cth@carlh.net>
+ Copyright (C) 2012-2014 Carl Hetherington <cth@carlh.net>
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
*/
+/** @file src/argb_frame.cc
+ * @brief ARGBFrame class.
+ */
+
#include "argb_frame.h"
-using namespace libdcp;
+using namespace dcp;
/** Construct an empty ARGBFrame of a given size and with
* undefined contents.
/*
- Copyright (C) 2012 Carl Hetherington <cth@carlh.net>
+ Copyright (C) 2012-2014 Carl Hetherington <cth@carlh.net>
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
*/
/** @file src/argb_frame.h
- * @brief Container for a single image from a picture asset.
+ * @brief ARGBFrame class.
*/
-#include <stdint.h>
#include "util.h"
+#include <stdint.h>
-namespace libdcp
+namespace dcp
{
/** @class ARGBFrame
*
* Lines are packed so that the second row directly follows the first.
*/
-class ARGBFrame
+class ARGBFrame : boost::noncopyable
{
public:
ARGBFrame (Size size);
~ARGBFrame ();
+ /** @return pointer to the image data */
uint8_t* data () const {
return _data;
}
- /** Length of one picture row in bytes */
+ /** @return length of one picture row in bytes */
int stride () const;
+ /** @return size of the picture in pixels */
Size size () const {
return _size;
}
private:
- Size _size;
- uint8_t* _data;
+ Size _size; ///< frame size in pixels
+ uint8_t* _data; ///< pointer to image data
};
}
/*
- Copyright (C) 2012 Carl Hetherington <cth@carlh.net>
+ Copyright (C) 2014 Carl Hetherington <cth@carlh.net>
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
*/
/** @file src/asset.cc
- * @brief Parent class for assets of DCPs.
+ * @brief Asset class.
*/
-#include <iostream>
-#include <boost/filesystem.hpp>
-#include <boost/lexical_cast.hpp>
-#include <boost/function.hpp>
-#include <libxml++/nodes/element.h>
-#include "AS_DCP.h"
-#include "KM_util.h"
#include "asset.h"
#include "util.h"
-#include "metadata.h"
+#include "exceptions.h"
#include "compose.hpp"
+#include <libxml++/libxml++.h>
+#include <boost/lexical_cast.hpp>
+
+using std::string;
+using boost::lexical_cast;
+using boost::function;
+using boost::optional;
+using namespace dcp;
-using namespace std;
-using namespace boost;
-using namespace libdcp;
-
-Asset::Asset (boost::filesystem::path directory, boost::filesystem::path file_name)
- : _directory (directory)
- , _file_name (file_name)
- , _uuid (make_uuid ())
- , _edit_rate (0)
- , _entry_point (0)
- , _intrinsic_duration (0)
- , _duration (0)
+/** Create an Asset with a randomly-generated ID */
+Asset::Asset ()
{
- if (_file_name.empty ()) {
- _file_name = _uuid + ".xml";
- }
+
+}
+
+/** Create an Asset from a given file. The ID will
+ * be extracted from the file.
+ * @param file File name.
+ */
+Asset::Asset (boost::filesystem::path file)
+ : _file (file)
+{
+
+}
+
+/** Create an Asset with a specified ID.
+ * @param id ID to use.
+ */
+Asset::Asset (string id)
+ : Object (id)
+{
+
}
void
-Asset::write_to_pkl (xmlpp::Node* node, bool interop) const
+Asset::write_to_pkl (xmlpp::Node* node, Standard standard) const
{
+ assert (!_file.empty ());
+
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.string ());
- asset->add_child("Hash")->add_child_text (digest ());
- asset->add_child("Size")->add_child_text (lexical_cast<string> (filesystem::file_size(path())));
- if (interop) {
- asset->add_child("Type")->add_child_text (String::compose ("application/x-smpte-mxf;asdcpKind=%1", asdcp_kind ()));
- } else {
- asset->add_child("Type")->add_child_text ("application/mxf");
- }
+ asset->add_child("Id")->add_child_text ("urn:uuid:" + _id);
+ asset->add_child("AnnotationText")->add_child_text (_id);
+ asset->add_child("Hash")->add_child_text (hash ());
+ asset->add_child("Size")->add_child_text (lexical_cast<string> (boost::filesystem::file_size (_file)));
+ asset->add_child("Type")->add_child_text (pkl_type (standard));
}
void
-Asset::write_to_assetmap (xmlpp::Node* node) const
+Asset::write_to_assetmap (xmlpp::Node* node, boost::filesystem::path root) const
{
+ assert (!_file.empty ());
+
xmlpp::Node* asset = node->add_child ("Asset");
- asset->add_child("Id")->add_child_text ("urn:uuid:" + _uuid);
+ asset->add_child("Id")->add_child_text ("urn:uuid:" + _id);
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.string ());
+ optional<boost::filesystem::path> path = relative_to_root (root, _file);
+ if (!path) {
+ throw MiscError (String::compose ("Asset %1 is not within the directory %2", _file, root));
+ }
+ chunk->add_child("Path")->add_child_text (path.get().string ());
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<string> (filesystem::file_size(path())));
-}
-
-filesystem::path
-Asset::path () const
-{
- filesystem::path p;
- p /= _directory;
- p /= _file_name;
- return p;
+ chunk->add_child("Length")->add_child_text (lexical_cast<string> (boost::filesystem::file_size (_file)));
}
string
-Asset::digest () const
-{
- if (_digest.empty ()) {
- _digest = make_digest (path().string(), 0);
- }
-
- return _digest;
-}
-
-void
-Asset::compute_digest (boost::function<void (float)> progress)
+Asset::hash (function<void (float)> progress) const
{
- if (!_digest.empty ()) {
- return;
+ assert (!_file.empty ());
+
+ if (_hash.empty ()) {
+ _hash = make_digest (_file, progress);
}
- _digest = make_digest (path().string(), &progress);
+ return _hash;
}
bool
-Asset::equals (shared_ptr<const Asset> other, EqualityOptions, boost::function<void (NoteType, string)> note) const
+Asset::equals (boost::shared_ptr<const Asset> other, EqualityOptions, function<void (NoteType, string)> note) const
{
- if (_edit_rate != other->_edit_rate) {
- note (ERROR, "asset edit rates differ");
+ if (_hash != other->_hash) {
+ note (ERROR, "Asset hashes differ");
return false;
}
-
- if (_intrinsic_duration != other->_intrinsic_duration) {
- note (ERROR, "asset intrinsic durations differ");
- }
-
- if (_duration != other->_duration) {
- note (ERROR, "asset durations differ");
- }
return true;
}
+
+void
+Asset::set_file (boost::filesystem::path file) const
+{
+ _file = boost::filesystem::absolute (file);
+ _hash.clear ();
+}
+
/*
- Copyright (C) 2012 Carl Hetherington <cth@carlh.net>
+ Copyright (C) 2014 Carl Hetherington <cth@carlh.net>
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
*/
/** @file src/asset.h
- * @brief Parent class for assets of DCPs.
- */
+ * @brief Asset class.
+ */
#ifndef LIBDCP_ASSET_H
#define LIBDCP_ASSET_H
-#include <string>
-#include <list>
+#include "object.h"
+#include "types.h"
#include <boost/filesystem.hpp>
#include <boost/function.hpp>
-#include <libxml++/libxml++.h>
-#include "types.h"
-
-namespace ASDCP {
- class WriterInfo;
-}
+#include <boost/bind.hpp>
namespace xmlpp {
- class Element;
+ class Node;
}
-namespace libdcp
-{
+namespace dcp {
-/** @brief Parent class for assets of DCPs
+/** @class Asset
+ * @brief Parent class for DCP assets, i.e. picture/sound/subtitles and CPLs.
*
- * These are collections of pictures or sound.
+ * Note that this class is not used for ReelAssets; those are just for the metadata
+ * that gets put into <Reel>s.
*/
-class Asset
+class Asset : public Object
{
public:
- /** Construct an Asset.
- * @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 ();
+ Asset (boost::filesystem::path file);
+ Asset (std::string id);
+
+ virtual bool equals (
+ boost::shared_ptr<const Asset> other,
+ EqualityOptions opt,
+ boost::function<void (NoteType, std::string)> note
+ ) const;
+
+ /** Write details of the asset to a ASSETMAP.
+ * @param node Parent node.
*/
- Asset (boost::filesystem::path directory, boost::filesystem::path file_name = "");
-
- virtual ~Asset() {}
-
- /** Write details of the asset to a CPL AssetList node.
- * @param p Parent element.
- */
- virtual void write_to_cpl (xmlpp::Element* p) const = 0;
+ void write_to_assetmap (xmlpp::Node* node, boost::filesystem::path root) const;
/** Write details of the asset to a PKL AssetList node.
- * @param p Parent node.
- */
- void write_to_pkl (xmlpp::Node *, bool interop) const;
-
- /** Write details of the asset to a ASSETMAP stream.
- * @param s Stream.
+ * @param node Parent node.
+ * @param standard Standard to use.
*/
- void write_to_assetmap (xmlpp::Node *) const;
-
- /** Compute the digest for this asset. Calling this is optional: if
- * it is not called, the digest will be computed when required. However,
- * calling this method allows the caller to see the progress of the
- * computation, which can be long for large assets.
- * @param Called with progress between 0 and 1.
- */
- void compute_digest (boost::function<void (float)> progress);
-
- std::string uuid () const {
- return _uuid;
- }
+ void write_to_pkl (xmlpp::Node* node, Standard standard) const;
- boost::filesystem::path path () const;
-
- void set_directory (boost::filesystem::path d) {
- _directory = d;
- }
-
- void set_file_name (boost::filesystem::path f) {
- _file_name = f;
- }
-
- int entry_point () const {
- return _entry_point;
+ boost::filesystem::path file () const {
+ return _file;
}
- int duration () const {
- return _duration;
- }
-
- int intrinsic_duration () const {
- return _intrinsic_duration;
- }
-
- int edit_rate () const {
- return _edit_rate;
- }
-
- void set_entry_point (int e) {
- _entry_point = e;
- }
-
- void set_duration (int d) {
- _duration = d;
- }
-
- void set_intrinsic_duration (int d) {
- _intrinsic_duration = d;
- }
-
- void set_edit_rate (int r) {
- _edit_rate = r;
- }
+ void set_file (boost::filesystem::path file) const;
- virtual bool equals (boost::shared_ptr<const Asset> other, EqualityOptions opt, boost::function<void (NoteType, std::string)>) const;
+ /** @return the hash of this asset's file */
+ std::string hash (boost::function<void (float)> progress = 0) const;
protected:
+ virtual std::string pkl_type (Standard standard) const = 0;
- /** @return Interop PKL asdcpKind for the <Type> tag e.g. Picture, Sound etc. */
- virtual std::string asdcp_kind () const = 0;
-
- std::string digest () const;
-
- /** Directory that our MXF or XML file is in */
- boost::filesystem::path _directory;
- /** Name of our MXF or XML file */
- boost::filesystem::path _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 */
- mutable std::string _digest;
+ /** The disk file that represents this asset, if one exists */
+ mutable boost::filesystem::path _file;
+ /** Hash of _file, or empty if the hash has not yet been computed */
+ mutable std::string _hash;
};
}
/*
- Copyright (C) 2012 Carl Hetherington <cth@carlh.net>
+ Copyright (C) 2012-2014 Carl Hetherington <cth@carlh.net>
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
*/
-#include <sstream>
-#include <vector>
-#include <cerrno>
-#include <boost/algorithm/string.hpp>
-#include <openssl/x509.h>
-#include <openssl/ssl.h>
-#include <openssl/asn1.h>
-#include <openssl/err.h>
-#include <libxml++/nodes/element.h>
+/** @file src/certificates.cc
+ * @brief Certificate and CertificateChain classes.
+ */
+
#include "KM_util.h"
#include "certificates.h"
#include "compose.hpp"
#include "exceptions.h"
#include "util.h"
+#include <libxml++/nodes/element.h>
+#include <openssl/x509.h>
+#include <openssl/ssl.h>
+#include <openssl/asn1.h>
+#include <openssl/err.h>
+#include <boost/algorithm/string.hpp>
+#include <cerrno>
using std::list;
using std::string;
-using std::stringstream;
-using std::vector;
using boost::shared_ptr;
-using namespace libdcp;
+using namespace dcp;
/** @param c X509 certificate, which this object will take ownership of */
Certificate::Certificate (X509* c)
}
+/** Load an X509 certificate from a file.
+ * @param filename File to load.
+ */
Certificate::Certificate (boost::filesystem::path filename)
: _certificate (0)
, _public_key (0)
}
}
+/** Load an X509 certificate from a string.
+ * @param cert String to read from.
+ */
Certificate::Certificate (string cert)
: _certificate (0)
, _public_key (0)
read_string (cert);
}
+/** Copy constructor.
+ * @param other Certificate to copy.
+ */
Certificate::Certificate (Certificate const & other)
: _certificate (0)
, _public_key (0)
read_string (other.certificate (true));
}
+/** Read a certificate from a string.
+ * @param cert String to read.
+ */
void
Certificate::read_string (string cert)
{
BIO_free (bio);
}
+/** Destructor */
Certificate::~Certificate ()
{
X509_free (_certificate);
RSA_free (_public_key);
}
+/** operator= for Certificate.
+ * @param other Certificate to read from.
+ */
Certificate &
Certificate::operator= (Certificate const & other)
{
return *this;
}
+/** Return the certificate as a string.
+ * @param with_begin_end true to include the -----BEGIN CERTIFICATE--- / -----END CERTIFICATE----- markers.
+ * @return Certificate string.
+ */
string
Certificate::certificate (bool with_begin_end) const
{
return s;
}
+/** @return Certificate's issuer, in the form
+ * dnqualifier=<dnQualififer>,CN=<commonName>,OU=<organizationalUnitName>,O=<organizationName>
+ * and with + signs escaped to \+
+ */
string
Certificate::issuer () const
{
return Kumu::base64encode (digest, 20, digest_base64, 64);
}
+/** @return RSA public key from this Certificate. Caller must not free the returned value. */
RSA *
Certificate::public_key () const
{
return _public_key;
}
+/** @return Root certificate */
shared_ptr<Certificate>
CertificateChain::root () const
{
return _certificates.front ();
}
+/** @return Leaf certificate */
shared_ptr<Certificate>
CertificateChain::leaf () const
{
return _certificates.back ();
}
+/** @return Certificates in order from leaf to root */
list<shared_ptr<Certificate> >
CertificateChain::leaf_to_root () const
{
return c;
}
+/** Add a certificate to the end of the chain.
+ * @param c Certificate to add.
+ */
void
CertificateChain::add (shared_ptr<Certificate> c)
{
/*
- Copyright (C) 2012 Carl Hetherington <cth@carlh.net>
+ Copyright (C) 2012-2014 Carl Hetherington <cth@carlh.net>
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
*/
+/** @file src/certificates.h
+ * @brief Certificate and CertificateChain classes.
+ */
+
#ifndef LIBDCP_CERTIFICATES_H
#define LIBDCP_CERTIFICATES_H
-#include <string>
-#include <list>
-#include <boost/noncopyable.hpp>
-#include <boost/shared_ptr.hpp>
-#include <boost/filesystem.hpp>
#undef X509_NAME
#include <openssl/x509.h>
+#include <boost/shared_ptr.hpp>
+#include <boost/filesystem.hpp>
+#include <string>
+#include <list>
class certificates;
class Element;
}
-namespace libdcp {
+namespace dcp {
+/** @class Certificate
+ * @brief A wrapper for an X509 certificate.
+ *
+ * This class can take a Certificate from a file, a string or an OpenSSL X509 object.
+ */
class Certificate
{
public:
Certificate& operator= (Certificate const &);
- /** @param with_begin_end true to include BEGIN CERTIFICATE / END CERTIFICATE markers
- * @return the whole certificate as a string.
- */
std::string certificate (bool with_begin_end = false) const;
std::string issuer () const;
std::string serial () const;
std::string subject () const;
std::string common_name () const;
- /** @return RSA public key from this Certificate. Caller must not free the returned value. */
RSA* public_key () const;
std::string thumbprint () const;
mutable RSA* _public_key;
};
+/** @class CertificateChain
+ * @brief A chain of any number of certificates, from root to leaf.
+ */
class CertificateChain
{
public:
CertificateChain () {}
- void add (boost::shared_ptr<Certificate>);
+ void add (boost::shared_ptr<Certificate> c);
boost::shared_ptr<Certificate> root () const;
boost::shared_ptr<Certificate> leaf () const;
/*
- Copyright (C) 2013 Carl Hetherington <cth@carlh.net>
+ Copyright (C) 2013-2014 Carl Hetherington <cth@carlh.net>
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
EasyDCP player, I think.
*/
-double const libdcp::colour_matrix::xyz_to_rgb[3][3] = {
+double const dcp::colour_matrix::xyz_to_rgb[3][3] = {
{ 3.24096989631653, -1.5373831987381, -0.498610764741898 },
{ -0.96924364566803, 1.87596750259399, 0.0415550582110882 },
{ 0.0556300804018974, -0.203976958990097, 1.05697154998779 }
};
-double const libdcp::colour_matrix::srgb_to_xyz[3][3] = {
+double const dcp::colour_matrix::srgb_to_xyz[3][3] = {
{0.4124564, 0.3575761, 0.1804375},
{0.2126729, 0.7151522, 0.0721750},
{0.0193339, 0.1191920, 0.9503041}
};
-double const libdcp::colour_matrix::rec709_to_xyz[3][3] = {
+double const dcp::colour_matrix::rec709_to_xyz[3][3] = {
{ 0.412390799265959, 0.357584339383878, 0.180480788401834 },
{ 0.21263900587151, 0.715168678767756, 0.0721923153607337 },
{ 0.0193308187155918, 0.119194779794626, 0.950532152249661 }
/*
- Copyright (C) 2013 Carl Hetherington <cth@carlh.net>
+ Copyright (C) 2013-2014 Carl Hetherington <cth@carlh.net>
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
*/
-namespace libdcp {
+namespace dcp {
namespace colour_matrix {
--- /dev/null
+/*
+ Copyright (C) 2012-2014 Carl Hetherington <cth@carlh.net>
+
+ 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 "content.h"
+#include "util.h"
+#include "metadata.h"
+#include "AS_DCP.h"
+#include "KM_util.h"
+#include <libxml++/nodes/element.h>
+#include <boost/filesystem.hpp>
+#include <boost/function.hpp>
+#include <iostream>
+
+/* We need this here for the #undef ERROR for Windows */
+#include "types.h"
+
+using namespace std;
+using namespace boost;
+using namespace dcp;
+
+Content::Content (boost::filesystem::path file)
+ : Asset (file)
+ , _edit_rate (24, 1)
+ , _intrinsic_duration (0)
+{
+
+}
+
+Content::Content (Fraction edit_rate)
+ : _edit_rate (edit_rate)
+ , _intrinsic_duration (0)
+{
+
+}
+
+bool
+Content::equals (shared_ptr<const Content> other, EqualityOptions opt, boost::function<void (NoteType, string)> note) const
+{
+ if (!Asset::equals (other, opt, note)) {
+ return false;
+ }
+
+ if (_edit_rate != other->_edit_rate) {
+ note (ERROR, "content edit rates differ");
+ return false;
+ }
+
+ if (_intrinsic_duration != other->_intrinsic_duration) {
+ note (ERROR, "asset intrinsic durations differ");
+ return false;
+ }
+
+ return true;
+}
--- /dev/null
+/*
+ Copyright (C) 2012-2014 Carl Hetherington <cth@carlh.net>
+
+ 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/content.h
+ * @brief Content class.
+ */
+
+#ifndef LIBDCP_CONTENT_H
+#define LIBDCP_CONTENT_H
+
+#include "types.h"
+#include "asset.h"
+#include <libxml++/libxml++.h>
+#include <boost/filesystem.hpp>
+#include <boost/function.hpp>
+#include <string>
+#include <list>
+
+namespace ASDCP {
+ class WriterInfo;
+}
+
+namespace xmlpp {
+ class Element;
+}
+
+namespace dcp
+{
+
+/** @class Content
+ * @brief An asset that represents a piece of content, i.e. picture, sound or subtitle.
+ *
+ * Such a piece of content will be contained in a file (either MXF or XML) within a DCP.
+ */
+class Content : public Asset
+{
+public:
+ Content (boost::filesystem::path file);
+ Content (Fraction edit_rate);
+ virtual ~Content () {}
+
+ bool equals (
+ boost::shared_ptr<const Content> other,
+ EqualityOptions opt,
+ boost::function<void (NoteType, std::string)>
+ ) const;
+
+ Fraction edit_rate () const {
+ return _edit_rate;
+ }
+
+ int64_t intrinsic_duration () const {
+ return _intrinsic_duration;
+ }
+
+protected:
+ friend class MXFWriter;
+
+ virtual std::string asdcp_kind () const = 0;
+
+ Fraction _edit_rate;
+ int64_t _intrinsic_duration;
+};
+
+}
+
+#endif
/*
- Copyright (C) 2012-2013 Carl Hetherington <cth@carlh.net>
+ Copyright (C) 2012-2014 Carl Hetherington <cth@carlh.net>
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
*/
-#include <libxml/parser.h>
#include "cpl.h"
-#include "parse/cpl.h"
#include "util.h"
-#include "mono_picture_asset.h"
-#include "stereo_picture_asset.h"
-#include "sound_asset.h"
-#include "subtitle_asset.h"
-#include "parse/asset_map.h"
+#include "mono_picture_mxf.h"
+#include "stereo_picture_mxf.h"
+#include "sound_mxf.h"
+#include "subtitle_content.h"
#include "reel.h"
#include "metadata.h"
#include "signer.h"
#include "exceptions.h"
+#include "xml.h"
#include "compose.hpp"
+#include "reel_picture_asset.h"
+#include "reel_sound_asset.h"
+#include "reel_subtitle_asset.h"
+#include <libxml/parser.h>
using std::string;
using std::stringstream;
using boost::shared_ptr;
using boost::lexical_cast;
using boost::optional;
-using namespace libdcp;
+using namespace dcp;
-CPL::CPL (boost::filesystem::path directory, string name, ContentKind content_kind, int length, int frames_per_second)
- : _directory (directory)
- , _name (name)
+CPL::CPL (string annotation_text, ContentKind content_kind)
+ : _annotation_text (annotation_text)
+ /* default _content_title_text to _annotation_text */
+ , _content_title_text (annotation_text)
, _content_kind (content_kind)
- , _length (length)
- , _fps (frames_per_second)
+ , _content_version_id ("urn:uuid:" + make_uuid ())
{
- _id = make_uuid ();
+ /* default _content_version_id to and _content_version_label to
+ a random ID and the current time.
+ */
+ time_t now = time (0);
+ struct tm* tm = localtime (&now);
+ _content_version_id = "urn:uuid:" + make_uuid() + tm_to_string (tm);
+ _content_version_label_text = _content_version_id;
}
-/** 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_maps AssetMaps to look for assets in.
- * @param require_mxfs true to throw an exception if a required MXF file does not exist.
- */
-CPL::CPL (boost::filesystem::path directory, string file, list<PathAssetMap> asset_maps, bool require_mxfs)
- : _directory (directory)
+/** Construct a CPL object from a XML file */
+CPL::CPL (boost::filesystem::path file)
+ : Asset (file)
, _content_kind (FEATURE)
- , _length (0)
- , _fps (0)
{
- /* Read the XML */
- shared_ptr<parse::CPL> cpl;
- try {
- cpl.reset (new parse::CPL (file));
- } catch (FileError& e) {
- boost::throw_exception (FileError ("could not load CPL file", file, e.number ()));
- }
-
- /* Now cherry-pick the required bits into our own data structure */
-
- _name = cpl->annotation_text;
- _content_kind = cpl->content_kind;
-
- /* Trim urn:uuid: off the front */
- _id = cpl->id.substr (9);
-
- for (list<shared_ptr<parse::Reel> >::iterator i = cpl->reels.begin(); i != cpl->reels.end(); ++i) {
-
- shared_ptr<parse::Picture> 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<PictureAsset> picture;
- shared_ptr<SoundAsset> sound;
- shared_ptr<SubtitleAsset> 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 {
- pair<string, shared_ptr<const parse::AssetMapAsset> > asset = asset_from_id (asset_maps, p->id);
-
- picture.reset (new MonoPictureAsset (asset.first, asset.second->chunks.front()->path));
+ cxml::Document f ("CompositionPlaylist");
+ f.read_file (file);
- picture->read ();
- picture->set_edit_rate (_fps);
- picture->set_entry_point (p->entry_point);
- picture->set_duration (p->duration);
- if (p->key_id.length() > 9) {
- /* Trim urn:uuid: */
- picture->set_key_id (p->key_id.substr (9));
- }
- } catch (MXFFileError) {
- if (require_mxfs) {
- throw;
- }
- }
-
- } else {
- try {
- pair<string, shared_ptr<const parse::AssetMapAsset> > asset = asset_from_id (asset_maps, p->id);
-
- picture.reset (new StereoPictureAsset (asset.first, asset.second->chunks.front()->path));
-
- picture->read ();
- picture->set_edit_rate (_fps);
- picture->set_entry_point (p->entry_point);
- picture->set_duration (p->duration);
- if (p->key_id.length() > 9) {
- /* Trim urn:uuid: */
- picture->set_key_id (p->key_id.substr (9));
- }
-
- } catch (MXFFileError) {
- if (require_mxfs) {
- throw;
- }
- }
-
- }
-
- if ((*i)->asset_list->main_sound) {
-
- try {
- pair<string, shared_ptr<const parse::AssetMapAsset> > asset = asset_from_id (asset_maps, (*i)->asset_list->main_sound->id);
-
- sound.reset (new SoundAsset (asset.first, asset.second->chunks.front()->path));
- shared_ptr<parse::MainSound> s = (*i)->asset_list->main_sound;
-
- sound->read ();
- sound->set_entry_point (s->entry_point);
- sound->set_duration (s->duration);
- if (s->key_id.length() > 9) {
- /* Trim urn:uuid: */
- sound->set_key_id (s->key_id.substr (9));
- }
- } catch (MXFFileError) {
- if (require_mxfs) {
- throw;
- }
- }
- }
-
- if ((*i)->asset_list->main_subtitle) {
-
- pair<string, shared_ptr<const parse::AssetMapAsset> > asset = asset_from_id (asset_maps, (*i)->asset_list->main_subtitle->id);
+ _id = f.string_child ("Id");
+ if (_id.length() > 9) {
+ _id = _id.substr (9);
+ }
+ _annotation_text = f.optional_string_child ("AnnotationText").get_value_or ("");
+ _metadata.issuer = f.optional_string_child ("Issuer").get_value_or ("");
+ _metadata.creator = f.optional_string_child ("Creator").get_value_or ("");
+ _metadata.issue_date = f.string_child ("IssueDate");
+ _content_title_text = f.string_child ("ContentTitleText");
+ _content_kind = content_kind_from_string (f.string_child ("ContentKind"));
+ shared_ptr<cxml::Node> content_version = f.optional_node_child ("ContentVersion");
+ if (content_version) {
+ _content_version_id = content_version->optional_string_child ("Id").get_value_or ("");
+ _content_version_label_text = content_version->string_child ("LabelText");
+ content_version->done ();
+ }
+ f.ignore_child ("RatingList");
+ _reels = type_grand_children<Reel> (f, "ReelList", "Reel");
- subtitle.reset (new SubtitleAsset (asset.first, asset.second->chunks.front()->path));
+ f.ignore_child ("Issuer");
+ f.ignore_child ("Signer");
+ f.ignore_child ("Signature");
- subtitle->set_entry_point ((*i)->asset_list->main_subtitle->entry_point);
- subtitle->set_duration ((*i)->asset_list->main_subtitle->duration);
- }
-
- _reels.push_back (shared_ptr<Reel> (new Reel (picture, sound, subtitle)));
- }
+ f.done ();
}
+/** Add a reel to this CPL.
+ * @param reel Reel to add.
+ */
void
-CPL::add_reel (shared_ptr<Reel> reel)
+CPL::add (boost::shared_ptr<Reel> reel)
{
_reels.push_back (reel);
}
+/** Write an CompositonPlaylist XML file.
+ * @param file Filename to write.
+ * @param standard INTEROP or SMPTE.
+ * @param signer Signer to sign the CPL, or 0 to add no signature.
+ */
void
-CPL::write_xml (bool interop, XMLMetadata const & metadata, shared_ptr<const Signer> signer) const
+CPL::write_xml (boost::filesystem::path file, Standard standard, shared_ptr<const Signer> signer) const
{
- boost::filesystem::path p;
- p /= _directory;
- stringstream s;
- s << _id << "_cpl.xml";
- p /= s.str();
-
xmlpp::Document doc;
xmlpp::Element* root;
- if (interop) {
+ if (standard == INTEROP) {
root = doc.create_root_node ("CompositionPlaylist", "http://www.digicine.com/PROTO-ASDCP-CPL-20040511#");
} else {
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:" + _id);
- root->add_child("AnnotationText")->add_child_text (_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);
- root->add_child("ContentTitleText")->add_child_text (_name);
+ root->add_child("AnnotationText")->add_child_text (_annotation_text);
+ 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);
+ root->add_child("ContentTitleText")->add_child_text (_content_title_text);
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:" + _id + "_" + metadata.issue_date);
- cv->add_child ("LabelText")->add_child_text (_id + "_" + metadata.issue_date);
+ cv->add_child ("Id")->add_child_text (_content_version_id);
+ cv->add_child ("LabelText")->add_child_text (_content_version_label_text);
}
root->add_child("RatingList");
xmlpp::Element* reel_list = root->add_child ("ReelList");
for (list<shared_ptr<Reel> >::const_iterator i = _reels.begin(); i != _reels.end(); ++i) {
- (*i)->write_to_cpl (reel_list);
+ (*i)->write_to_cpl (reel_list, standard);
}
if (signer) {
- signer->sign (root, interop);
+ signer->sign (root, standard);
}
/* This must not be the _formatted version otherwise signature digests will be wrong */
- doc.write_to_file (p.string (), "UTF-8");
+ doc.write_to_file (file.string (), "UTF-8");
- _digest = make_digest (p.string (), 0);
- _length = boost::filesystem::file_size (p.string ());
+ set_file (file);
}
-void
-CPL::write_to_pkl (xmlpp::Node* node, bool interop) const
+list<shared_ptr<const Content> >
+CPL::content () const
{
- xmlpp::Node* asset = node->add_child ("Asset");
- asset->add_child("Id")->add_child_text ("urn:uuid:" + _id);
- asset->add_child("Hash")->add_child_text (_digest);
- asset->add_child("Size")->add_child_text (lexical_cast<string> (_length));
- if (interop) {
- asset->add_child("Type")->add_child_text ("text/xml;asdcpKind=CPL");
- } else {
- asset->add_child("Type")->add_child_text ("text/xml");
- }
-}
+ list<shared_ptr<const Content> > c;
-list<shared_ptr<const Asset> >
-CPL::assets () const
-{
- list<shared_ptr<const Asset> > a;
for (list<shared_ptr<Reel> >::const_iterator i = _reels.begin(); i != _reels.end(); ++i) {
if ((*i)->main_picture ()) {
- a.push_back ((*i)->main_picture ());
+ c.push_back ((*i)->main_picture()->mxf ());
}
if ((*i)->main_sound ()) {
- a.push_back ((*i)->main_sound ());
+ c.push_back ((*i)->main_sound()->mxf ());
}
if ((*i)->main_subtitle ()) {
- a.push_back ((*i)->main_subtitle ());
+ c.push_back ((*i)->main_subtitle()->subtitle_content ());
}
}
- return a;
-}
-
-void
-CPL::write_to_assetmap (xmlpp::Node* node) const
-{
- xmlpp::Node* asset = node->add_child ("Asset");
- asset->add_child("Id")->add_child_text ("urn:uuid:" + _id);
- xmlpp::Node* chunk_list = asset->add_child ("ChunkList");
- xmlpp::Node* chunk = chunk_list->add_child ("Chunk");
- chunk->add_child("Path")->add_child_text (_id + "_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<string> (_length));
+ return c;
}
-
-
bool
CPL::equals (CPL const & other, EqualityOptions opt, boost::function<void (NoteType, string)> note) const
{
- if (_name != other._name && !opt.cpl_names_can_differ) {
+ if (_annotation_text != other._annotation_text && !opt.cpl_annotation_texts_can_differ) {
stringstream s;
- s << "names differ: " << _name << " vs " << other._name << "\n";
+ s << "annotation texts differ: " << _annotation_text << " vs " << other._annotation_text << "\n";
note (ERROR, s.str ());
return false;
}
return false;
}
- if (_fps != other._fps) {
- note (ERROR, String::compose ("frames per second differ (%1 vs %2)", _fps, other._fps));
- return false;
- }
-
- if (_length != other._length) {
- stringstream s;
- note (ERROR, String::compose ("lengths differ (%1 vs %2)", _length, other._length));
- }
-
if (_reels.size() != other._reels.size()) {
note (ERROR, String::compose ("reel counts differ (%1 vs %2)", _reels.size(), other._reels.size()));
return false;
return false;
}
+/** Add a KDM to this CPL. If the KDM is for any of this CPLs assets it will be used
+ * to decrypt those assets.
+ * @param kdm KDM.
+ */
void
-CPL::add_kdm (KDM const & kdm)
+CPL::add (KDM const & kdm)
{
for (list<shared_ptr<Reel> >::const_iterator i = _reels.begin(); i != _reels.end(); ++i) {
- (*i)->add_kdm (kdm);
+ (*i)->add (kdm);
}
}
-pair<string, shared_ptr<const parse::AssetMapAsset> >
-CPL::asset_from_id (list<PathAssetMap> asset_maps, string id) const
+/** Set a private key for every MXF referenced by this CPL. This will allow the data
+ * to be decrypted or encrypted.
+ * @param key Key to use.
+ */
+void
+CPL::set_mxf_keys (Key key)
{
- for (list<PathAssetMap>::const_iterator i = asset_maps.begin(); i != asset_maps.end(); ++i) {
- shared_ptr<parse::AssetMapAsset> a = i->second->asset_from_id (id);
- if (a) {
- return make_pair (i->first, a);
- }
+ for (list<shared_ptr<Reel> >::const_iterator i = _reels.begin(); i != _reels.end(); ++i) {
+ (*i)->set_mxf_keys (key);
}
-
- return make_pair ("", shared_ptr<const parse::AssetMapAsset> ());
}
void
-CPL::set_mxf_keys (Key key)
+CPL::resolve_refs (list<shared_ptr<Object> > objects)
{
for (list<shared_ptr<Reel> >::const_iterator i = _reels.begin(); i != _reels.end(); ++i) {
- (*i)->set_mxf_keys (key);
+ (*i)->resolve_refs (objects);
}
}
+
+string
+CPL::pkl_type (Standard standard) const
+{
+ switch (standard) {
+ case INTEROP:
+ return "text/xml;asdcpKind=CPL";
+ case SMPTE:
+ return "text/xml";
+ default:
+ assert (false);
+ }
+}
+
/*
- Copyright (C) 2012 Carl Hetherington <cth@carlh.net>
+ Copyright (C) 2014 Carl Hetherington <cth@carlh.net>
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
#ifndef LIBDCP_CPL_H
#define LIBDCP_CPL_H
-#include <list>
+#include "types.h"
+#include "certificates.h"
+#include "key.h"
+#include "asset.h"
+#include "metadata.h"
+#include <libxml++/libxml++.h>
#include <boost/shared_ptr.hpp>
#include <boost/function.hpp>
#include <boost/date_time/posix_time/posix_time.hpp>
#include <boost/optional.hpp>
#include <boost/filesystem.hpp>
-#include <libxml++/libxml++.h>
-#include "types.h"
-#include "certificates.h"
-#include "key.h"
-
-namespace libdcp {
+#include <list>
-namespace parse {
- class AssetMap;
- class AssetMapAsset;
-}
+namespace dcp {
-class Asset;
+class Content;
class Reel;
class XMLMetadata;
class MXFMetadata;
class Signer;
class KDM;
-/** @brief A CPL within a DCP */
-class CPL
+/** @class CPL
+ * @brief A Composition Playlist.
+ */
+class CPL : public Asset
{
public:
- CPL (boost::filesystem::path directory, std::string name, ContentKind content_kind, int length, int frames_per_second);
- CPL (boost::filesystem::path, std::string file, std::list<PathAssetMap> asset_maps, bool require_mxfs = true);
+ CPL (std::string annotation_text, ContentKind content_kind);
+ CPL (boost::filesystem::path file);
- void add_reel (boost::shared_ptr<Reel> reel);
+ bool equals (
+ CPL const & other,
+ EqualityOptions options,
+ boost::function<void (NoteType, std::string)> note
+ ) const;
+
+ void add (boost::shared_ptr<Reel> reel);
+ void add (KDM const &);
+
+ /** @return contents of the <AnnotationText> node */
+ std::string annotation_text () const {
+ return _annotation_text;
+ }
- /** @return the length in frames */
- int length () const {
- return _length;
+ /** @return contents of the <ContentTitleText> node */
+ std::string content_title_text () const {
+ return _content_title_text;
+ }
+
+ /** @return contents of the <Id> node within <ContentVersion> */
+ void set_content_version_id (std::string id) {
+ _content_version_id = id;
}
+ /** @return contents of the <LabelText> node within <ContentVersion> */
+ void set_content_version_label_text (std::string text) {
+ _content_version_label_text = text;
+ }
+
/** @return the type of the content, used by media servers
* to categorise things (e.g. feature, trailer, etc.)
*/
return _content_kind;
}
+ /** @return the reels in this CPL */
std::list<boost::shared_ptr<Reel> > reels () const {
return _reels;
}
- /** @return the CPL's name, as will be presented on projector
- * media servers and theatre management systems.
+ /** @return the Content in this CPL across all its reels
+ * (Content is picture, sound and subtitles)
*/
- std::string name () const {
- return _name;
- }
-
- /** @return the number of frames per second */
- int frames_per_second () const {
- return _fps;
- }
-
- std::list<boost::shared_ptr<const Asset> > assets () const;
+ std::list<boost::shared_ptr<const Content> > content () const;
bool encrypted () const;
void set_mxf_keys (Key);
- std::string id () const {
- return _id;
- }
-
- bool equals (CPL const & other, EqualityOptions options, boost::function<void (NoteType, std::string)> note) const;
-
- void write_xml (bool, XMLMetadata const &, boost::shared_ptr<const Signer>) const;
- void write_to_assetmap (xmlpp::Node *) const;
- void write_to_pkl (xmlpp::Node *, bool) const;
+ void write_xml (
+ boost::filesystem::path file,
+ Standard standard,
+ boost::shared_ptr<const Signer>
+ ) const;
+
+ void resolve_refs (std::list<boost::shared_ptr<Object> >);
+
+protected:
+ /** @return type string for PKLs for this asset */
+ std::string pkl_type (Standard standard) const;
- void add_kdm (KDM const &);
-
private:
- std::pair<std::string, boost::shared_ptr<const parse::AssetMapAsset> > asset_from_id (std::list<PathAssetMap>, std::string id) const;
-
- boost::filesystem::path _directory;
- /** the name of the DCP */
- std::string _name;
- /** the content kind of the CPL */
- ContentKind _content_kind;
- /** length in frames */
- mutable int _length;
- /** frames per second */
- int _fps;
- /** reels */
+ std::string _annotation_text; ///< <AnnotationText>
+ /** <Issuer>, <Creator> and <IssueDate>. These are grouped
+ * because they occur together in a few places.
+ */
+ XMLMetadata _metadata;
+ std::string _content_title_text; ///< <ContentTitleText>
+ ContentKind _content_kind; ///< <ContentKind>
+ std::string _content_version_id; ///< <Id> in <ContentVersion>
+ std::string _content_version_label_text; ///< <LabelText> in <ContentVersion>
std::list<boost::shared_ptr<Reel> > _reels;
-
- /** our UUID */
- std::string _id;
- /** a SHA1 digest of our XML */
- mutable std::string _digest;
};
}
/*
- Copyright (C) 2012 Carl Hetherington <cth@carlh.net>
+ Copyright (C) 2012-2014 Carl Hetherington <cth@carlh.net>
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
*/
/** @file src/dcp.cc
- * @brief A class to create a DCP.
+ * @brief DCP class.
*/
-#include <sstream>
-#include <iomanip>
-#include <cassert>
-#include <iostream>
-#include <boost/filesystem.hpp>
-#include <boost/lexical_cast.hpp>
-#include <boost/algorithm/string.hpp>
-#include <boost/lexical_cast.hpp>
-#include <libxml++/libxml++.h>
-#include <xmlsec/xmldsig.h>
-#include <xmlsec/app.h>
#include "dcp.h"
-#include "asset.h"
-#include "sound_asset.h"
-#include "picture_asset.h"
-#include "subtitle_asset.h"
+#include "sound_mxf.h"
+#include "picture_mxf.h"
+#include "subtitle_content.h"
+#include "mono_picture_mxf.h"
+#include "stereo_picture_mxf.h"
#include "util.h"
#include "metadata.h"
#include "exceptions.h"
-#include "parse/pkl.h"
-#include "parse/asset_map.h"
#include "reel.h"
#include "cpl.h"
#include "signer.h"
#include "kdm.h"
+#include "compose.hpp"
+#include "AS_DCP.h"
+#include <xmlsec/xmldsig.h>
+#include <xmlsec/app.h>
+#include <libxml++/libxml++.h>
+#include <boost/filesystem.hpp>
+#include <boost/algorithm/string.hpp>
+#include <boost/lexical_cast.hpp>
+#include <sstream>
+#include <iomanip>
+#include <cassert>
+#include <iostream>
using std::string;
using std::list;
using std::stringstream;
using std::ostream;
-using std::copy;
-using std::back_inserter;
using std::make_pair;
+using std::map;
using boost::shared_ptr;
using boost::lexical_cast;
-using namespace libdcp;
+using namespace dcp;
DCP::DCP (boost::filesystem::path directory)
: _directory (directory)
{
boost::filesystem::create_directories (directory);
+ _directory = boost::filesystem::canonical (_directory);
}
void
-DCP::write_xml (bool interop, XMLMetadata const & metadata, shared_ptr<const Signer> signer) const
+DCP::read ()
{
- for (list<shared_ptr<CPL> >::const_iterator i = _cpls.begin(); i != _cpls.end(); ++i) {
- (*i)->write_xml (interop, metadata, signer);
+ /* Read the ASSETMAP */
+
+ boost::filesystem::path asset_map_file;
+ if (boost::filesystem::exists (_directory / "ASSETMAP")) {
+ asset_map_file = _directory / "ASSETMAP";
+ } else if (boost::filesystem::exists (_directory / "ASSETMAP.xml")) {
+ asset_map_file = _directory / "ASSETMAP.xml";
+ } else {
+ boost::throw_exception (DCPReadError ("could not find AssetMap file"));
}
- string pkl_uuid = make_uuid ();
- string pkl_path = write_pkl (pkl_uuid, interop, metadata, signer);
+ cxml::Document asset_map ("AssetMap");
+ asset_map.read_file (asset_map_file);
+ list<shared_ptr<cxml::Node> > asset_nodes = asset_map.node_child("AssetList")->node_children ("Asset");
+ map<string, boost::filesystem::path> paths;
+ for (list<shared_ptr<cxml::Node> >::const_iterator i = asset_nodes.begin(); i != asset_nodes.end(); ++i) {
+ if ((*i)->node_child("ChunkList")->node_children("Chunk").size() != 1) {
+ boost::throw_exception (XMLError ("unsupported asset chunk count"));
+ }
+ paths.insert (make_pair (
+ (*i)->string_child ("Id"),
+ (*i)->node_child("ChunkList")->node_child("Chunk")->string_child ("Path")
+ ));
+ }
+
+ /* Read all the assets from the asset map */
- write_volindex (interop);
- write_assetmap (pkl_uuid, boost::filesystem::file_size (pkl_path), interop, metadata);
+ for (map<string, boost::filesystem::path>::const_iterator i = paths.begin(); i != paths.end(); ++i) {
+ boost::filesystem::path path = _directory / i->second;
+ if (boost::algorithm::ends_with (path.string(), ".xml")) {
+ xmlpp::DomParser* p = new xmlpp::DomParser;
+ try {
+ p->parse_file (path.string());
+ } catch (std::exception& e) {
+ delete p;
+ continue;
+ }
+
+ string const root = p->get_document()->get_root_node()->get_name ();
+ delete p;
+
+ if (root == "CompositionPlaylist") {
+ _assets.push_back (shared_ptr<CPL> (new CPL (path)));
+ } else if (root == "DCSubtitle") {
+ _assets.push_back (shared_ptr<SubtitleContent> (new SubtitleContent (path)));
+ }
+ } else if (boost::algorithm::ends_with (path.string(), ".mxf")) {
+ ASDCP::EssenceType_t type;
+ if (ASDCP::EssenceType (path.string().c_str(), type) != ASDCP::RESULT_OK) {
+ throw DCPReadError ("Could not find essence type");
+ }
+ switch (type) {
+ case ASDCP::ESS_UNKNOWN:
+ case ASDCP::ESS_MPEG2_VES:
+ throw DCPReadError ("MPEG2 video essences are not supported");
+ case ASDCP::ESS_JPEG_2000:
+ _assets.push_back (shared_ptr<MonoPictureMXF> (new MonoPictureMXF (path)));
+ break;
+ case ASDCP::ESS_PCM_24b_48k:
+ case ASDCP::ESS_PCM_24b_96k:
+ _assets.push_back (shared_ptr<SoundMXF> (new SoundMXF (path)));
+ break;
+ case ASDCP::ESS_JPEG_2000_S:
+ _assets.push_back (shared_ptr<StereoPictureMXF> (new StereoPictureMXF (path)));
+ break;
+ default:
+ throw DCPReadError ("Unknown MXF essence type");
+ }
+ }
+ }
+
+ list<shared_ptr<CPL> > cpl = cpls ();
+ for (list<shared_ptr<CPL> >::const_iterator i = cpl.begin(); i != cpl.end(); ++i) {
+ (*i)->resolve_refs (list_of_type<Asset, Object> (assets ()));
+ }
}
-std::string
-DCP::write_pkl (string pkl_uuid, bool interop, XMLMetadata const & metadata, shared_ptr<const Signer> signer) const
+bool
+DCP::equals (DCP const & other, EqualityOptions opt, boost::function<void (NoteType, string)> note) const
{
- assert (!_cpls.empty ());
+ if (_assets.size() != other._assets.size()) {
+ note (ERROR, "Asset counts differ");
+ return false;
+ }
+
+ list<shared_ptr<Asset> >::const_iterator a = _assets.begin ();
+ list<shared_ptr<Asset> >::const_iterator b = other._assets.begin ();
+
+ while (a != _assets.end ()) {
+ if (!(*a)->equals (*b, opt, note)) {
+ return false;
+ }
+ ++a;
+ ++b;
+ }
+
+ return true;
+}
+
+void
+DCP::add (boost::shared_ptr<Asset> asset)
+{
+ _assets.push_back (asset);
+}
+
+class AssetComparator
+{
+public:
+ bool operator() (shared_ptr<const Content> a, shared_ptr<const Content> b) {
+ return a->id() < b->id();
+ }
+};
+
+bool
+DCP::encrypted () const
+{
+ list<shared_ptr<CPL> > cpl = cpls ();
+ for (list<shared_ptr<CPL> >::const_iterator i = cpl.begin(); i != cpl.end(); ++i) {
+ if ((*i)->encrypted ()) {
+ return true;
+ }
+ }
+
+ return false;
+}
+
+void
+DCP::add (KDM const & kdm)
+{
+ list<KDMKey> keys = kdm.keys ();
+ list<shared_ptr<CPL> > cpl = cpls ();
- boost::filesystem::path p;
- p /= _directory;
+ for (list<shared_ptr<CPL> >::iterator i = cpl.begin(); i != cpl.end(); ++i) {
+ for (list<KDMKey>::iterator j = keys.begin(); j != keys.end(); ++j) {
+ if (j->cpl_id() == (*i)->id()) {
+ (*i)->add (kdm);
+ }
+ }
+ }
+}
+
+boost::filesystem::path
+DCP::write_pkl (Standard standard, string pkl_uuid, XMLMetadata metadata, shared_ptr<const Signer> signer) const
+{
+ boost::filesystem::path p = _directory;
stringstream s;
s << pkl_uuid << "_pkl.xml";
p /= s.str();
xmlpp::Document doc;
xmlpp::Element* pkl;
- if (interop) {
+ if (standard == INTEROP) {
pkl = doc.create_root_node("PackingList", "http://www.digicine.com/PROTO-ASDCP-PKL-20040311#");
} else {
pkl = doc.create_root_node("PackingList", "http://www.smpte-ra.org/schemas/429-8/2007/PKL");
}
pkl->add_child("Id")->add_child_text ("urn:uuid:" + pkl_uuid);
+
/* XXX: this is a bit of a hack */
- pkl->add_child("AnnotationText")->add_child_text(_cpls.front()->name());
+ assert (cpls().size() > 0);
+ pkl->add_child("AnnotationText")->add_child_text (cpls().front()->annotation_text ());
+
pkl->add_child("IssueDate")->add_child_text (metadata.issue_date);
pkl->add_child("Issuer")->add_child_text (metadata.issuer);
pkl->add_child("Creator")->add_child_text (metadata.creator);
xmlpp::Element* asset_list = pkl->add_child("AssetList");
- list<shared_ptr<const Asset> > a = assets ();
- for (list<shared_ptr<const Asset> >::const_iterator i = a.begin(); i != a.end(); ++i) {
- (*i)->write_to_pkl (asset_list, interop);
- }
-
- for (list<shared_ptr<CPL> >::const_iterator i = _cpls.begin(); i != _cpls.end(); ++i) {
- (*i)->write_to_pkl (asset_list, interop);
+ for (list<shared_ptr<Asset> >::const_iterator i = _assets.begin(); i != _assets.end(); ++i) {
+ (*i)->write_to_pkl (asset_list, standard);
}
if (signer) {
- signer->sign (pkl, interop);
+ signer->sign (pkl, standard);
}
doc.write_to_file (p.string (), "UTF-8");
return p.string ();
}
+/** Write the VOLINDEX file.
+ * @param standard DCP standard to use (INTEROP or SMPTE)
+ */
void
-DCP::write_volindex (bool interop) const
+DCP::write_volindex (Standard standard) const
{
- boost::filesystem::path p;
- p /= _directory;
- if (interop) {
+ boost::filesystem::path p = _directory;
+ switch (standard) {
+ case INTEROP:
p /= "VOLINDEX";
- } else {
+ break;
+ case SMPTE:
p /= "VOLINDEX.xml";
+ break;
+ default:
+ assert (false);
}
xmlpp::Document doc;
xmlpp::Element* root;
- if (interop) {
+
+ switch (standard) {
+ case INTEROP:
root = doc.create_root_node ("VolumeIndex", "http://www.digicine.com/PROTO-ASDCP-AM-20040311#");
- } else {
+ break;
+ case SMPTE:
root = doc.create_root_node ("VolumeIndex", "http://www.smpte-ra.org/schemas/429-9/2007/AM");
+ break;
+ default:
+ assert (false);
}
+
root->add_child("Index")->add_child_text ("1");
doc.write_to_file (p.string (), "UTF-8");
}
void
-DCP::write_assetmap (string pkl_uuid, int pkl_length, bool interop, XMLMetadata const & metadata) const
+DCP::write_assetmap (Standard standard, string pkl_uuid, int pkl_length, XMLMetadata metadata) const
{
- boost::filesystem::path p;
- p /= _directory;
- if (interop) {
+ boost::filesystem::path p = _directory;
+
+ switch (standard) {
+ case INTEROP:
p /= "ASSETMAP";
- } else {
+ break;
+ case SMPTE:
p /= "ASSETMAP.xml";
+ break;
+ default:
+ assert (false);
}
xmlpp::Document doc;
xmlpp::Element* root;
- if (interop) {
+
+ switch (standard) {
+ case INTEROP:
root = doc.create_root_node ("AssetMap", "http://www.digicine.com/PROTO-ASDCP-AM-20040311#");
- } else {
+ break;
+ case SMPTE:
root = doc.create_root_node ("AssetMap", "http://www.smpte-ra.org/schemas/429-9/2007/AM");
+ break;
+ default:
+ assert (false);
}
root->add_child("Id")->add_child_text ("urn:uuid:" + make_uuid());
root->add_child("AnnotationText")->add_child_text ("Created by " + metadata.creator);
- if (interop) {
+
+ switch (standard) {
+ case INTEROP:
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);
root->add_child("Creator")->add_child_text (metadata.creator);
- } else {
+ break;
+ case SMPTE:
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);
+ break;
+ default:
+ assert (false);
}
xmlpp::Node* asset_list = root->add_child ("AssetList");
chunk->add_child("Offset")->add_child_text ("0");
chunk->add_child("Length")->add_child_text (lexical_cast<string> (pkl_length));
- for (list<shared_ptr<CPL> >::const_iterator i = _cpls.begin(); i != _cpls.end(); ++i) {
- (*i)->write_to_assetmap (asset_list);
- }
-
- list<shared_ptr<const Asset> > a = assets ();
- for (list<shared_ptr<const Asset> >::const_iterator i = a.begin(); i != a.end(); ++i) {
- (*i)->write_to_assetmap (asset_list);
+ for (list<shared_ptr<Asset> >::const_iterator i = _assets.begin(); i != _assets.end(); ++i) {
+ (*i)->write_to_assetmap (asset_list, _directory);
}
/* This must not be the _formatted version otherwise signature digests will be wrong */
doc.write_to_file (p.string (), "UTF-8");
}
+/** Write all the XML files for this DCP.
+ * @param standand INTEROP or SMPTE.
+ * @param metadata Metadata to use for PKL and asset map files.
+ * @param signer Signer to use, or 0.
+ */
void
-DCP::read (bool require_mxfs)
-{
- read_assets ();
- read_cpls (require_mxfs);
-}
-
-void
-DCP::read_assets ()
-{
- shared_ptr<parse::AssetMap> asset_map;
- try {
- boost::filesystem::path p = _directory;
- p /= "ASSETMAP";
- if (boost::filesystem::exists (p)) {
- asset_map.reset (new libdcp::parse::AssetMap (p.string ()));
- } else {
- p = _directory;
- p /= "ASSETMAP.xml";
- if (boost::filesystem::exists (p)) {
- asset_map.reset (new libdcp::parse::AssetMap (p.string ()));
- } else {
- boost::throw_exception (DCPReadError ("could not find AssetMap file"));
- }
- }
-
- } catch (FileError& e) {
- boost::throw_exception (FileError ("could not load AssetMap file", _files.asset_map, e.number ()));
- }
-
- for (list<shared_ptr<libdcp::parse::AssetMapAsset> >::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"));
- }
-
- boost::filesystem::path t = _directory;
- t /= (*i)->chunks.front()->path;
-
- if (boost::algorithm::ends_with (t.string(), ".mxf") || boost::algorithm::ends_with (t.string(), ".ttf")) {
- continue;
- }
-
- xmlpp::DomParser* p = new xmlpp::DomParser;
- try {
- p->parse_file (t.string());
- } catch (std::exception& e) {
- delete p;
- continue;
- }
-
- string const root = p->get_document()->get_root_node()->get_name ();
- delete p;
-
- if (root == "CompositionPlaylist") {
- _files.cpls.push_back (t.string());
- } else if (root == "PackingList") {
- if (_files.pkl.empty ()) {
- _files.pkl = t.string();
- } else {
- boost::throw_exception (DCPReadError ("duplicate PKLs found"));
- }
- }
- }
-
- if (_files.cpls.empty ()) {
- boost::throw_exception (DCPReadError ("no CPL files found"));
- }
-
- if (_files.pkl.empty ()) {
- boost::throw_exception (DCPReadError ("no PKL file found"));
- }
-
- shared_ptr<parse::PKL> pkl;
- try {
- pkl.reset (new parse::PKL (_files.pkl));
- } catch (FileError& e) {
- boost::throw_exception (FileError ("could not load PKL file", _files.pkl, e.number ()));
- }
-
- _asset_maps.push_back (make_pair (boost::filesystem::absolute (_directory).string(), asset_map));
-}
-
-void
-DCP::read_cpls (bool require_mxfs)
-{
- for (list<string>::iterator i = _files.cpls.begin(); i != _files.cpls.end(); ++i) {
- _cpls.push_back (shared_ptr<CPL> (new CPL (_directory, *i, _asset_maps, require_mxfs)));
- }
-}
-
-bool
-DCP::equals (DCP const & other, EqualityOptions opt, boost::function<void (NoteType, string)> note) const
-{
- if (_cpls.size() != other._cpls.size()) {
- note (ERROR, "CPL counts differ");
- return false;
- }
-
- list<shared_ptr<CPL> >::const_iterator a = _cpls.begin ();
- list<shared_ptr<CPL> >::const_iterator b = other._cpls.begin ();
-
- while (a != _cpls.end ()) {
- if (!(*a)->equals (*b->get(), opt, note)) {
- return false;
- }
- ++a;
- ++b;
- }
-
- return true;
-}
-
-void
-DCP::add_cpl (shared_ptr<CPL> cpl)
-{
- _cpls.push_back (cpl);
-}
-
-class AssetComparator
-{
-public:
- bool operator() (shared_ptr<const Asset> a, shared_ptr<const Asset> b) {
- return a->uuid() < b->uuid();
- }
-};
-
-list<shared_ptr<const Asset> >
-DCP::assets () const
-{
- list<shared_ptr<const Asset> > a;
- for (list<shared_ptr<CPL> >::const_iterator i = _cpls.begin(); i != _cpls.end(); ++i) {
- list<shared_ptr<const Asset> > t = (*i)->assets ();
- a.merge (t);
- }
-
- a.sort (AssetComparator ());
- a.unique ();
- return a;
-}
-
-bool
-DCP::encrypted () const
+DCP::write_xml (
+ Standard standard,
+ XMLMetadata metadata,
+ shared_ptr<const Signer> signer
+ )
{
- for (list<shared_ptr<CPL> >::const_iterator i = _cpls.begin(); i != _cpls.end(); ++i) {
- if ((*i)->encrypted ()) {
- return true;
- }
+ list<shared_ptr<CPL> > cpl = cpls ();
+ for (list<shared_ptr<CPL> >::const_iterator i = cpl.begin(); i != cpl.end(); ++i) {
+ string const filename = (*i)->id() + "_cpl.xml";
+ (*i)->write_xml (_directory / filename, standard, signer);
}
- return false;
-}
-
-void
-DCP::add_kdm (KDM const & kdm)
-{
- list<KDMKey> keys = kdm.keys ();
+ string const pkl_uuid = make_uuid ();
+ boost::filesystem::path const pkl_path = write_pkl (standard, pkl_uuid, metadata, signer);
- for (list<shared_ptr<CPL> >::iterator i = _cpls.begin(); i != _cpls.end(); ++i) {
- for (list<KDMKey>::iterator j = keys.begin(); j != keys.end(); ++j) {
- if (j->cpl_id() == (*i)->id()) {
- (*i)->add_kdm (kdm);
- }
- }
- }
+ write_volindex (standard);
+ write_assetmap (standard, pkl_uuid, boost::filesystem::file_size (pkl_path), metadata);
}
-void
-DCP::add_assets_from (DCP const & ov)
+list<shared_ptr<CPL> >
+DCP::cpls () const
{
- copy (ov._asset_maps.begin(), ov._asset_maps.end(), back_inserter (_asset_maps));
+ return list_of_type<Asset, CPL> (_assets);
}
/*
- Copyright (C) 2012 Carl Hetherington <cth@carlh.net>
+ Copyright (C) 2012-2014 Carl Hetherington <cth@carlh.net>
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
*/
/** @file src/dcp.h
- * @brief A class to create or read a DCP.
+ * @brief DCP class.
*/
#ifndef LIBDCP_DCP_H
#define LIBDCP_DCP_H
-#include <string>
-#include <vector>
-#include <boost/shared_ptr.hpp>
-#include <boost/signals2.hpp>
#include "types.h"
#include "certificates.h"
+#include "metadata.h"
+#include <boost/shared_ptr.hpp>
+#include <boost/signals2.hpp>
+#include <string>
+#include <vector>
namespace xmlpp {
class Document;
}
/** @brief Namespace for everything in libdcp */
-namespace libdcp
+namespace dcp
{
-class Asset;
-class PictureAsset;
-class SoundAsset;
-class SubtitleAsset;
+class Content;
class Reel;
class CPL;
class XMLMetadata;
class Signer;
class KDM;
+class Asset;
namespace parse {
class AssetMap;
*/
DCP (boost::filesystem::path directory);
- void read (bool require_mxfs = true);
-
- /** Read an existing DCP's assets.
- *
- * The DCP's XML metadata will be examined, and you can then look at the contents
- * of the DCP.
- */
- void read_assets ();
-
- void read_cpls (bool require_mxfs = true);
-
- /** Write the required XML files to the directory that was
- * passed into the constructor.
- */
- void write_xml (bool interop, XMLMetadata const &, boost::shared_ptr<const Signer> signer = boost::shared_ptr<const Signer> ()) const;
+ void read ();
/** Compare this DCP with another, according to various options.
* @param other DCP to compare this one to.
* @param options Options to define what "equality" means.
+ * @param note Functor to handle notes made by the equality operation.
* @return true if the DCPs are equal according to EqualityOptions, otherwise false.
*/
bool equals (DCP const & other, EqualityOptions options, boost::function<void (NoteType, std::string)> note) const;
- /** Add a CPL to this DCP.
- * @param cpl CPL to add.
- */
- void add_cpl (boost::shared_ptr<CPL> cpl);
+ void add (boost::shared_ptr<Asset> asset);
- /** @return The list of CPLs in this DCP */
- std::list<boost::shared_ptr<CPL> > cpls () const {
- return _cpls;
- }
+ std::list<boost::shared_ptr<CPL> > cpls () const;
- /** Add another DCP as a source of assets for this DCP. This should be called before
- * ::read() on the DCP that needs the extra assets. For example
- *
- * DCP original_version ("my_dcp_OV");
- * DCP supplemental ("my_dcp_VF");
- * supplemental.add_assets_from (original_version);
- * supplemental.read ();
- */
- void add_assets_from (libdcp::DCP const &);
+ /** @return All this DCP's assets (note that CPLs are assets) */
+ std::list<boost::shared_ptr<Asset> > assets () const {
+ return _assets;
+ }
bool encrypted () const;
- void add_kdm (KDM const &);
+ void add (KDM const &);
- /** Emitted with a parameter between 0 and 1 to indicate progress
- * for long jobs.
- */
- boost::signals2::signal<void (float)> Progress;
+ void write_xml (
+ Standard standard,
+ XMLMetadata metadata = XMLMetadata (),
+ boost::shared_ptr<const Signer> signer = boost::shared_ptr<const Signer> ()
+ );
private:
/** Write the PKL file.
* @param pkl_uuid UUID to use.
*/
- std::string write_pkl (std::string pkl_uuid, bool, XMLMetadata const &, boost::shared_ptr<const Signer>) const;
+ boost::filesystem::path write_pkl (
+ Standard standard,
+ std::string pkl_uuid,
+ XMLMetadata metadata,
+ boost::shared_ptr<const Signer> signer
+ ) const;
- /** Write the VOLINDEX file */
- void write_volindex (bool) const;
+ void write_volindex (Standard standard) const;
/** Write the ASSETMAP file.
* @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, bool, XMLMetadata const &) const;
-
- /** @return Assets in all the CPLs in this DCP */
- std::list<boost::shared_ptr<const Asset> > assets () const;
-
- struct Files {
- std::list<std::string> cpls;
- std::string pkl;
- std::string asset_map;
- };
-
- Files _files;
+ void write_assetmap (Standard standard, std::string pkl_uuid, int pkl_length, XMLMetadata metadata) const;
/** the directory that we are writing to */
boost::filesystem::path _directory;
- /** our CPLs */
- std::list<boost::shared_ptr<CPL> > _cpls;
-
- std::list<PathAssetMap> _asset_maps;
+ /** the assets that make up this DCP */
+ std::list<boost::shared_ptr<Asset> > _assets;
};
}
/*
- Copyright (C) 2012 Carl Hetherington <cth@carlh.net>
+ Copyright (C) 2012-2014 Carl Hetherington <cth@carlh.net>
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
*/
/** @file src/dcp_time.cc
- * @brief A representation of time within a DCP.
+ * @brief Time class.
*/
-#include <iostream>
-#include <vector>
+#include "dcp_time.h"
+#include "exceptions.h"
#include <boost/algorithm/string.hpp>
#include <boost/lexical_cast.hpp>
+#include <iostream>
+#include <vector>
#include <cmath>
-#include "dcp_time.h"
-#include "exceptions.h"
using namespace std;
using namespace boost;
-using namespace libdcp;
+using namespace dcp;
Time::Time (int frame, int frames_per_second)
: h (0)
}
bool
-libdcp::operator== (Time const & a, Time const & b)
+dcp::operator== (Time const & a, Time const & b)
{
return (a.h == b.h && a.m == b.m && a.s == b.s && a.t == b.t);
}
bool
-libdcp::operator!= (Time const & a, Time const & b)
+dcp::operator!= (Time const & a, Time const & b)
{
return !(a == b);
}
bool
-libdcp::operator<= (Time const & a, Time const & b)
+dcp::operator<= (Time const & a, Time const & b)
{
if (a.h != b.h) {
return a.h <= b.h;
}
bool
-libdcp::operator< (Time const & a, Time const & b)
+dcp::operator< (Time const & a, Time const & b)
{
if (a.h != b.h) {
return a.h < b.h;
}
bool
-libdcp::operator> (Time const & a, Time const & b)
+dcp::operator> (Time const & a, Time const & b)
{
if (a.h != b.h) {
return a.h > b.h;
}
ostream &
-libdcp::operator<< (ostream& s, Time const & t)
+dcp::operator<< (ostream& s, Time const & t)
{
s << t.h << ":" << t.m << ":" << t.s << "." << t.t;
return s;
}
-libdcp::Time
-libdcp::operator+ (Time a, Time const & b)
+dcp::Time
+dcp::operator+ (Time a, Time const & b)
{
Time r;
return r;
}
-libdcp::Time
-libdcp::operator- (Time a, Time const & b)
+dcp::Time
+dcp::operator- (Time a, Time const & b)
{
Time r;
}
float
-libdcp::operator/ (Time a, Time const & b)
+dcp::operator/ (Time a, Time const & b)
{
int64_t const at = a.h * 3600 * 250 + a.m * 60 * 250 + a.s * 250 + a.t;
int64_t const bt = b.h * 3600 * 250 + b.m * 60 * 250 + b.s * 250 + b.t;
/*
- Copyright (C) 2012 Carl Hetherington <cth@carlh.net>
+ Copyright (C) 2012-2014 Carl Hetherington <cth@carlh.net>
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
*/
/** @file src/dcp_time.h
- * @brief A representation of time within a DCP.
+ * @brief Time class.
*/
#ifndef LIBDCP_TIME_H
#define LIBDCP_TIME_H
+#include <stdint.h>
#include <string>
#include <iostream>
-#include <stdint.h>
-namespace libdcp {
+namespace dcp {
/** @class Time
* @brief A representation of time within a DCP.
*/
+/** @file src/exceptions.cc
+ * @brief Exceptions thrown by libdcp.
+ */
+
#include "exceptions.h"
#include "compose.hpp"
using std::string;
-using namespace libdcp;
+using namespace dcp;
-FileError::FileError (std::string const & message, boost::filesystem::path filename, int number)
+FileError::FileError (string message, boost::filesystem::path filename, int number)
: _message (String::compose ("%1 (error %2) (%3)", message, filename.string(), number))
, _filename (filename)
, _number (number)
}
+UnresolvedRefError::UnresolvedRefError (string id)
+ : _message (String::compose ("Unresolved reference to asset id %1", id))
+{
+
+}
+
/*
- Copyright (C) 2012 Carl Hetherington <cth@carlh.net>
+ Copyright (C) 2012-2014 Carl Hetherington <cth@carlh.net>
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
* @brief Exceptions thrown by libdcp.
*/
-namespace libdcp
+namespace dcp
{
-/** @brief An exception related to a file */
+/** @class FileError
+ * @brief An exception related to a file
+ */
class FileError : public std::exception
{
public:
- FileError (std::string const & message, boost::filesystem::path filename, int number);
+ FileError (std::string message, boost::filesystem::path filename, int number);
~FileError () throw () {}
/** @return error message */
int _number;
};
-/** @brief An exception related to an MXF file */
+/** @class MXFFileError
+ * @brief An exception related to an MXF file
+ */
class MXFFileError : public FileError
{
public:
- MXFFileError (std::string const & message, boost::filesystem::path filename, int number)
+ MXFFileError (std::string message, boost::filesystem::path filename, int number)
: FileError (message, filename, number)
{}
};
-/** @brief A miscellaneous exception */
+/** @class MiscError
+ * @brief A miscellaneous exception
+ */
class MiscError : public std::exception
{
public:
- MiscError (std::string const & message) : _message (message) {}
+ MiscError (std::string message) : _message (message) {}
~MiscError () throw () {}
/** @return error message */
std::string _message;
};
-/** @brief A DCP read exception */
+/** @class DCPReadError
+ * @brief A DCP read exception
+ */
class DCPReadError : public std::exception
{
public:
- DCPReadError (std::string const & message) : _message (message) {}
+ DCPReadError (std::string message) : _message (message) {}
~DCPReadError () throw () {}
/** @return error message */
std::string _message;
};
-/** @brief An XML error */
+/** @class XMLError
+ * @brief An XML error
+ */
class XMLError : public std::exception
{
public:
- XMLError (std::string const & message) : _message (message) {}
+ XMLError (std::string message) : _message (message) {}
~XMLError () throw () {}
/** @return error message */
/** error message */
std::string _message;
};
+
+/** @class UnresolvedRefError
+ * @brief An exception caused by a reference (by UUID) to something which is not known
+ */
+class UnresolvedRefError : public std::exception
+{
+public:
+ UnresolvedRefError (std::string id);
+ ~UnresolvedRefError () throw () {}
+
+ /** @return error message */
+ char const * what () const throw () {
+ return _message.c_str ();
+ }
+
+private:
+ std::string _message;
+};
}
--- /dev/null
+/*
+ Copyright (C) 2014 Carl Hetherington <cth@carlh.net>
+
+ 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/file.cc
+ * @brief File class.
+ */
+
+#include "file.h"
+#include "util.h"
+
+using namespace dcp;
+
+/** Read a file into memory.
+ * @param file to read.
+ */
+File::File (boost::filesystem::path file)
+{
+ _size = boost::filesystem::file_size (file);
+ _data = new uint8_t[_size];
+ FILE* f = dcp::fopen_boost (file, "r");
+ assert (f);
+ fread (_data, 1, _size, f);
+ fclose (f);
+}
+
+/** File destructor */
+File::~File ()
+{
+ delete[] _data;
+}
--- /dev/null
+/*
+ Copyright (C) 2014 Carl Hetherington <cth@carlh.net>
+
+ 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/file.h
+ * @brief File class.
+ */
+
+#ifndef LIBDCP_FILE_H
+#define LIBDCP_FILE_H
+
+#include <boost/filesystem.hpp>
+
+namespace dcp {
+
+/** @class File
+ * @brief Helper class which loads a file into memory.
+ */
+class File
+{
+public:
+ File (boost::filesystem::path file);
+ ~File ();
+
+ uint8_t* data () const {
+ return _data;
+ }
+
+ int64_t size () const {
+ return _size;
+ }
+
+private:
+ uint8_t* _data; ///< file's data
+ int64_t _size; ///< data size in bytes
+};
+
+}
+
+#endif
--- /dev/null
+/*
+ Copyright (C) 2012-2014 Carl Hetherington <cth@carlh.net>
+
+ 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 "font.h"
+#include "xml.h"
+#include "text.h"
+#include <libcxml/cxml.h>
+
+using std::string;
+using std::list;
+using boost::shared_ptr;
+using boost::optional;
+using namespace dcp;
+
+Font::Font (boost::shared_ptr<const cxml::Node> node)
+{
+ text = node->content ();
+
+ id = node->optional_string_attribute ("Id").get_value_or ("");
+ size = node->optional_number_attribute<int64_t> ("Size").get_value_or (0);
+ italic = node->optional_bool_attribute ("Italic");
+ optional<string> c = node->optional_string_attribute ("Color");
+ if (c) {
+ color = Color (c.get ());
+ }
+ optional<string> 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<Subtitle> (node, "Subtitle");
+ font_nodes = type_children<Font> (node, "Font");
+ text_nodes = type_children<Text> (node, "Text");
+}
+
+Font::Font (std::list<boost::shared_ptr<Font> > const & font_nodes)
+ : size (0)
+ , italic (false)
+ , color ("FFFFFFFF")
+ , effect_color ("FFFFFFFF")
+{
+ for (list<shared_ptr<Font> >::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 ();
+ }
+ }
+}
--- /dev/null
+/*
+ Copyright (C) 2012-2014 Carl Hetherington <cth@carlh.net>
+
+ 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 "types.h"
+#include "subtitle.h"
+#include <boost/shared_ptr.hpp>
+#include <boost/optional.hpp>
+#include <list>
+
+namespace cxml {
+ class Node;
+}
+
+namespace dcp {
+
+class Font
+{
+public:
+ Font ()
+ : size (0)
+ {}
+
+ Font (boost::shared_ptr<const cxml::Node> node);
+ Font (std::list<boost::shared_ptr<Font> > const & font_nodes);
+
+ std::string text;
+ std::string id;
+ int size;
+ boost::optional<bool> italic;
+ boost::optional<Color> color;
+ boost::optional<Effect> effect;
+ boost::optional<Color> effect_color;
+
+ std::list<boost::shared_ptr<Subtitle> > subtitle_nodes;
+ std::list<boost::shared_ptr<Font> > font_nodes;
+ std::list<boost::shared_ptr<Text> > text_nodes;
+};
+
+}
/*
- Copyright (C) 2012-2013 Carl Hetherington <cth@carlh.net>
+ Copyright (C) 2012-2014 Carl Hetherington <cth@carlh.net>
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
*/
-#include <cmath>
#include "gamma_lut.h"
#include "lut_cache.h"
+#include <cmath>
-using namespace libdcp;
+using namespace dcp;
LUTCache<GammaLUT> GammaLUT::cache;
-GammaLUT::GammaLUT(int bits, float gamma)
- : LUT (bits, gamma)
+GammaLUT::GammaLUT (int bit_depth, float gamma, bool linearised)
+ : _bit_depth (bit_depth)
+ , _gamma (gamma)
+ , _linearised (linearised)
{
- int const bit_length = pow(2, bits);
- for (int i = 0; i < bit_length; ++i) {
- _lut[i] = pow(float(i) / (bit_length - 1), gamma);
+ _lut = new float[int(std::pow(2.0f, _bit_depth))];
+ int const bit_length = pow (2, _bit_depth);
+
+ if (_linearised) {
+ for (int i = 0; i < bit_length; ++i) {
+ float const p = static_cast<float> (i) / (bit_length - 1);
+ if (p > 0.04045) {
+ _lut[i] = pow ((p + 0.055) / 1.055, gamma);
+ } else {
+ _lut[i] = p / 12.92;
+ }
+ }
+ } else {
+ for (int i = 0; i < bit_length; ++i) {
+ _lut[i] = pow(float(i) / (bit_length - 1), gamma);
+ }
}
}
/*
- Copyright (C) 2012-2013 Carl Hetherington <cth@carlh.net>
+ Copyright (C) 2012-2014 Carl Hetherington <cth@carlh.net>
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
#ifndef LIBDCP_GAMMA_LUT_H
#define LIBDCP_GAMMA_LUT_H
-#include "lut.h"
#include "lut_cache.h"
-namespace libdcp {
+namespace dcp {
-class GammaLUT : public LUT
+class GammaLUT
{
public:
- GammaLUT (int bit_length, float gamma);
+ GammaLUT (int bit_depth, float gamma, bool linearised);
+
+ ~GammaLUT () {
+ delete[] _lut;
+ }
+
+ float const * lut () const {
+ return _lut;
+ }
+
+ int bit_depth () const {
+ return _bit_depth;
+ }
+
+ float gamma () const {
+ return _gamma;
+ }
+
+ bool linearised () const {
+ return _linearised;
+ }
+
static LUTCache<GammaLUT> cache;
+
+private:
+ float* _lut;
+ int _bit_depth;
+ float _gamma;
+ bool _linearised;
};
}
/*
- Copyright (C) 2012 Carl Hetherington <cth@carlh.net>
+ Copyright (C) 2012-2014 Carl Hetherington <cth@carlh.net>
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
#include "image.h"
using boost::shared_ptr;
-using namespace libdcp;
+using namespace dcp;
Image::Image (Size s)
: _size (s)
}
-Image::Image (shared_ptr<const Image> other)
+Image::Image (boost::shared_ptr<const Image> other)
: _size (other->_size)
{
/*
- Copyright (C) 2012 Carl Hetherington <cth@carlh.net>
+ Copyright (C) 2012-2014 Carl Hetherington <cth@carlh.net>
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
#include "util.h"
-namespace libdcp {
+namespace dcp {
class Image
{
/*
- Copyright (C) 2013 Carl Hetherington <cth@carlh.net>
+ Copyright (C) 2013-2014 Carl Hetherington <cth@carlh.net>
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
*/
-#include <iomanip>
-#include <algorithm>
-#include <boost/algorithm/string.hpp>
-#include <openssl/rsa.h>
-#include <openssl/pem.h>
-#include <openssl/err.h>
-#include <libcxml/cxml.h>
-#include "AS_DCP.h"
-#include "KM_util.h"
+/** @file src/kdm.cc
+ * @brief KDM and KDMKey classes.
+ */
+
#include "util.h"
#include "kdm.h"
#include "compose.hpp"
#include "exceptions.h"
#include "signer.h"
#include "cpl.h"
-#include "mxf_asset.h"
-#include "xml/kdm_smpte.h"
+#include "mxf.h"
+#include "kdm_smpte_xml.h"
+#include "AS_DCP.h"
+#include "KM_util.h"
+#include <libcxml/cxml.h>
+#include <openssl/rsa.h>
+#include <openssl/pem.h>
+#include <openssl/err.h>
+#include <boost/algorithm/string.hpp>
+#include <iomanip>
+#include <algorithm>
using std::list;
using std::string;
using std::setfill;
using std::cout;
using boost::shared_ptr;
-using namespace libdcp;
+using namespace dcp;
KDM::KDM (boost::filesystem::path kdm, boost::filesystem::path private_key)
: _xml_kdm (new xml::DCinemaSecurityMessage (kdm))
}
KDM::KDM (
- shared_ptr<const CPL> cpl, shared_ptr<const Signer> signer, shared_ptr<const Certificate> recipient_cert,
+ boost::shared_ptr<const CPL> cpl,
+ boost::shared_ptr<const Signer> signer,
+ boost::shared_ptr<const Certificate> recipient_cert,
boost::posix_time::ptime not_valid_before, boost::posix_time::ptime not_valid_after,
string annotation_text, string issue_date
)
apu.recipient.x509_subject_name = recipient_cert->subject ();
apu.composition_playlist_id = "urn:uuid:" + cpl->id ();
// apu.content_authenticator = signer->certificates().leaf()->thumbprint ();
- apu.content_title_text = cpl->name ();
+ apu.content_title_text = cpl->content_title_text ();
apu.content_keys_not_valid_before = ptime_to_string (not_valid_before);
apu.content_keys_not_valid_after = ptime_to_string (not_valid_after);
apu.authorized_device_info.device_list_identifier = "urn:uuid:" + make_uuid ();
*/
apu.authorized_device_info.device_list.push_back ("2jmj7l5rSw0yVb/vlWAYkK/YBwk=");
- list<shared_ptr<const Asset> > assets = cpl->assets ();
- for (list<shared_ptr<const Asset> >::iterator i = assets.begin(); i != assets.end(); ++i) {
+ list<shared_ptr<const Content> > content = cpl->content ();
+ for (list<shared_ptr<const Content> >::iterator i = content.begin(); i != content.end(); ++i) {
/* XXX: non-MXF assets? */
- shared_ptr<const MXFAsset> mxf = boost::dynamic_pointer_cast<const MXFAsset> (*i);
+ shared_ptr<const MXF> mxf = boost::dynamic_pointer_cast<const MXF> (*i);
if (mxf) {
apu.key_id_list.push_back (xml::TypedKeyId (mxf->key_type(), "urn:uuid:" + mxf->key_id()));
}
/* AuthenticatedPrivate */
- for (list<shared_ptr<const Asset> >::iterator i = assets.begin(); i != assets.end(); ++i) {
+ for (list<shared_ptr<const Content> >::iterator i = content.begin(); i != content.end(); ++i) {
/* XXX: non-MXF assets? */
- shared_ptr<const MXFAsset> mxf = boost::dynamic_pointer_cast<const MXFAsset> (*i);
+ shared_ptr<const MXF> mxf = boost::dynamic_pointer_cast<const MXF> (*i);
if (mxf) {
KDMKey kkey (
signer, cpl->id (), mxf->key_type (), mxf->key_id (),
}
KDMKey::KDMKey (
- shared_ptr<const Signer> signer, string cpl_id, string key_type, string key_id, boost::posix_time::ptime from, boost::posix_time::ptime until, Key key
+ boost::shared_ptr<const Signer> signer,
+ string cpl_id,
+ string key_type,
+ string key_id,
+ boost::posix_time::ptime from,
+ boost::posix_time::ptime until,
+ Key key
)
: _cpl_id (cpl_id)
, _key_type (key_type)
}
string
-KDMKey::encrypted_base64 (shared_ptr<const Certificate> recipient_cert) const
+KDMKey::encrypted_base64 (boost::shared_ptr<const Certificate> recipient_cert) const
{
assert (_key_type.length() == 4);
assert (_not_valid_before.length() == 25);
}
bool
-libdcp::operator== (libdcp::KDMKey const & a, libdcp::KDMKey const & b)
+dcp::operator== (dcp::KDMKey const & a, dcp::KDMKey const & b)
{
if (memcmp (a._signer_thumbprint, b._signer_thumbprint, 20) != 0) {
return false;
/*
- Copyright (C) 2013 Carl Hetherington <cth@carlh.net>
+ Copyright (C) 2013-2014 Carl Hetherington <cth@carlh.net>
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
*/
/** @file src/kdm.h
- * @brief Handling of Key Delivery Messages (KDMs).
+ * @brief KDM and KDMKey classes.
*/
#ifndef LIBDCP_KDM_H
#define LIBDCP_KDM_H
+#include "key.h"
+#include "metadata.h"
#include <boost/filesystem.hpp>
#include <boost/scoped_ptr.hpp>
#include <boost/date_time/posix_time/posix_time.hpp>
-#include "key.h"
-#include "metadata.h"
class kdm_key_test;
-namespace libdcp {
+namespace dcp {
namespace xml {
class DCinemaSecurityMessage;
* @param recipient_cert Certificate of the projector that this KDM is targeted at.
* @param not_valid_before Start of validity period.
* @param not_valid_after End of validity period.
- * @param annotation_text Text for the <AnnotationText> node.
- * @param issue_date Text for the <IssueDate> node.
+ * @param annotation_text Text for the <AnnotationText> node.
+ * @param issue_date Text for the <IssueDate> node.
*/
KDM (
boost::shared_ptr<const CPL> cpl, boost::shared_ptr<const Signer> signer, boost::shared_ptr<const Certificate> recipient_cert,
--- /dev/null
+/*
+ Copyright (C) 2013-2014 Carl Hetherington <cth@carlh.net>
+
+ 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/kdm_smpte_xml.h
+ * @brief 1:1ish C++ representations of the XML schema for a SMPTE KDM.
+ *
+ * This file contains classes which map pretty-much 1:1 to the elements in a SMPTE KDM
+ * (Key Delivery Message). The `main' KDM class contains a pointer to a DCinemaSecurityMessage
+ * from this file.
+ *
+ * This should probably have been automatically generated from the XSD,
+ * but I think it's too much trouble considering that the XSD does not
+ * change very often.
+ */
+
+#ifndef LIBDCP_KDM_SMPTE_XML_H
+#define LIBDCP_KDM_SMPTE_XML_H
+
+#include "exceptions.h"
+#include <libcxml/cxml.h>
+#include <libxml/parser.h>
+#include <libxml++/libxml++.h>
+#include <boost/optional.hpp>
+#include <boost/filesystem.hpp>
+#include <string>
+#include <list>
+
+namespace dcp {
+namespace xml {
+
+class Writer
+{
+public:
+ Writer ()
+ : document (new xmlpp::Document)
+ {}
+
+ boost::shared_ptr<xmlpp::Document> document;
+ std::map<std::string, xmlpp::Attribute *> references;
+};
+
+class Signer
+{
+public:
+ Signer () {}
+ Signer (boost::shared_ptr<const cxml::Node> node)
+ : x509_issuer_name (node->string_child ("X509IssuerName"))
+ , x509_serial_number (node->string_child ("X509SerialNumber"))
+ {
+ node->done ();
+ }
+
+ void as_xml (xmlpp::Element* node) const
+ {
+ node->add_child("X509IssuerName", "ds")->add_child_text (x509_issuer_name);
+ node->add_child("X509SerialNumber", "ds")->add_child_text (x509_serial_number);
+ }
+
+ std::string x509_issuer_name;
+ std::string x509_serial_number;
+};
+
+class Recipient
+{
+public:
+ Recipient () {}
+ Recipient (boost::shared_ptr<const cxml::Node> node)
+ : x509_issuer_serial (node->node_child ("X509IssuerSerial"))
+ , x509_subject_name (node->string_child ("X509SubjectName"))
+ {
+ node->done ();
+ }
+
+ void as_xml (xmlpp::Element* node) const
+ {
+ x509_issuer_serial.as_xml (node->add_child ("X509IssuerSerial"));
+ node->add_child("X509SubjectName")->add_child_text (x509_subject_name);
+ }
+
+ Signer x509_issuer_serial;
+ std::string x509_subject_name;
+};
+
+class AuthorizedDeviceInfo
+{
+public:
+ AuthorizedDeviceInfo () {}
+ AuthorizedDeviceInfo (boost::shared_ptr<const cxml::Node> node)
+ : device_list_identifier (node->string_child ("DeviceListIdentifier"))
+ , device_list_description (node->string_child ("DeviceListDescription"))
+ {
+ std::list<boost::shared_ptr<cxml::Node> > ct = node->node_child("DeviceList")->node_children("CertificateThumbprint");
+ for (std::list<boost::shared_ptr<cxml::Node> >::const_iterator i = ct.begin(); i != ct.end(); ++i) {
+ device_list.push_back ((*i)->content ());
+ }
+
+ node->done ();
+ }
+
+ void as_xml (xmlpp::Element* node) const
+ {
+ node->add_child ("DeviceListIdentifier")->add_child_text (device_list_identifier);
+ node->add_child ("DeviceListDescription")->add_child_text (device_list_description);
+ xmlpp::Element* dl = node->add_child ("DeviceList");
+ for (std::list<std::string>::const_iterator i = device_list.begin(); i != device_list.end(); ++i) {
+ dl->add_child("CertificateThumbprint")->add_child_text (*i);
+ }
+ }
+
+ std::string device_list_identifier;
+ std::string device_list_description;
+ std::list<std::string> device_list;
+};
+
+class TypedKeyId
+{
+public:
+ TypedKeyId () {}
+
+ TypedKeyId (std::string t, std::string i)
+ : key_type (t)
+ , key_id (i)
+ {}
+
+ TypedKeyId (boost::shared_ptr<const cxml::Node> node)
+ : key_type (node->string_child ("KeyType"))
+ , key_id (node->string_child ("KeyId"))
+ {
+ node->done ();
+ }
+
+ void as_xml (xmlpp::Element* node) const
+ {
+ node->add_child("KeyType")->add_child_text (key_type);
+ node->add_child("KeyId")->add_child_text (key_id);
+ }
+
+ std::string key_type;
+ std::string key_id;
+};
+
+class AuthenticatedPublic
+{
+public:
+ AuthenticatedPublic () {}
+ AuthenticatedPublic (boost::shared_ptr<const cxml::Node> node)
+ : message_id (node->string_child ("MessageId"))
+ , message_type (node->string_child ("MessageType"))
+ , annotation_text (node->optional_string_child ("AnnotationText"))
+ , issue_date (node->string_child ("IssueDate"))
+ , signer (node->node_child ("Signer"))
+ {
+ boost::shared_ptr<const cxml::Node> c = node->node_child ("RequiredExtensions");
+ c = c->node_child ("KDMRequiredExtensions");
+ recipient = Recipient (c->node_child ("Recipient"));
+ composition_playlist_id = c->string_child ("CompositionPlaylistId");
+ content_authenticator = c->optional_string_child ("ContentAuthenticator");
+ content_title_text = c->string_child ("ContentTitleText");
+ content_keys_not_valid_before = c->string_child ("ContentKeysNotValidBefore");
+ content_keys_not_valid_after = c->string_child ("ContentKeysNotValidAfter");
+ authorized_device_info = AuthorizedDeviceInfo (c->node_child ("AuthorizedDeviceInfo"));
+
+ std::list<boost::shared_ptr<cxml::Node> > kil = c->node_child("KeyIdList")->node_children("TypedKeyId");
+ for (std::list<boost::shared_ptr<cxml::Node> >::iterator i = kil.begin(); i != kil.end(); ++i) {
+ key_id_list.push_back (TypedKeyId (*i));
+ }
+
+ boost::shared_ptr<cxml::Node> fmfl = c->optional_node_child("ForensicMarkFlagList");
+ if (fmfl) {
+ std::list<boost::shared_ptr<cxml::Node> > fmf = fmfl->node_children("ForensicMarkFlag");
+ for (std::list<boost::shared_ptr<cxml::Node> >::iterator i = fmf.begin(); i != fmf.end(); ++i) {
+ forensic_mark_flag_list.push_back ((*i)->content ());
+ }
+ }
+
+ node->ignore_child ("NonCriticalExtensions");
+ node->done ();
+ }
+
+ void as_xml (Writer& writer, xmlpp::Element* node) const
+ {
+ writer.references["ID_AuthenticatedPublic"] = node->set_attribute ("Id", "ID_AuthenticatedPublic");
+
+ node->add_child("MessageId")->add_child_text (message_id);
+ node->add_child("MessageType")->add_child_text (message_type);
+ if (annotation_text) {
+ node->add_child("AnnotationText")->add_child_text (annotation_text.get ());
+ }
+ node->add_child("IssueDate")->add_child_text (issue_date);
+ signer.as_xml (node->add_child("Signer"));
+
+ xmlpp::Element* kdm_required_extensions = node->add_child("RequiredExtensions")->add_child("KDMRequiredExtensions");
+ kdm_required_extensions->set_attribute ("xmlns", "http://www.smpte-ra.org/schemas/430-1/2006/KDM");
+ recipient.as_xml (kdm_required_extensions->add_child ("Recipient"));
+
+ kdm_required_extensions->add_child("CompositionPlaylistId")->add_child_text (composition_playlist_id);
+ if (content_authenticator) {
+ kdm_required_extensions->add_child("ContentAuthenticator")->add_child_text (content_authenticator.get ());
+ }
+ kdm_required_extensions->add_child("ContentTitleText")->add_child_text (content_title_text);
+ kdm_required_extensions->add_child("ContentKeysNotValidBefore")->add_child_text (content_keys_not_valid_before);
+ kdm_required_extensions->add_child("ContentKeysNotValidAfter")->add_child_text (content_keys_not_valid_after);
+ authorized_device_info.as_xml (kdm_required_extensions->add_child("AuthorizedDeviceInfo"));
+
+ xmlpp::Element* kil = kdm_required_extensions->add_child("KeyIdList");
+ for (std::list<TypedKeyId>::const_iterator i = key_id_list.begin(); i != key_id_list.end(); ++i) {
+ i->as_xml (kil->add_child ("TypedKeyId"));
+ }
+
+ xmlpp::Element* fmfl = kdm_required_extensions->add_child ("ForensicMarkFlagList");
+ for (std::list<std::string>::const_iterator i = forensic_mark_flag_list.begin(); i != forensic_mark_flag_list.end(); ++i) {
+ fmfl->add_child("ForensicMarkFlag")->add_child_text (*i);
+ }
+
+ node->add_child ("NonCriticalExtensions");
+ }
+
+ std::string message_id;
+ std::string message_type;
+ boost::optional<std::string> annotation_text;
+ std::string issue_date;
+ Signer signer;
+ Recipient recipient;
+ std::string composition_playlist_id;
+ boost::optional<std::string> content_authenticator;
+ std::string content_title_text;
+ std::string content_keys_not_valid_before;
+ std::string content_keys_not_valid_after;
+ AuthorizedDeviceInfo authorized_device_info;
+ std::list<TypedKeyId> key_id_list;
+ std::list<std::string> forensic_mark_flag_list;
+};
+
+class AuthenticatedPrivate
+{
+public:
+ AuthenticatedPrivate () {}
+
+ AuthenticatedPrivate (boost::shared_ptr<const cxml::Node> node)
+ {
+ std::list<boost::shared_ptr<cxml::Node> > ek = node->node_children ("EncryptedKey");
+ for (std::list<boost::shared_ptr<cxml::Node> >::const_iterator i = ek.begin(); i != ek.end(); ++i) {
+ encrypted_keys.push_back ((*i)->node_child("CipherData")->string_child("CipherValue"));
+ }
+
+ node->done ();
+ }
+
+ void as_xml (Writer& writer, xmlpp::Element* node) const
+ {
+ writer.references["ID_AuthenticatedPrivate"] = node->set_attribute ("Id", "ID_AuthenticatedPrivate");
+
+ for (std::list<std::string>::const_iterator i = encrypted_keys.begin(); i != encrypted_keys.end(); ++i) {
+ xmlpp::Element* encrypted_key = node->add_child ("EncryptedKey", "enc");
+ xmlpp::Element* encryption_method = encrypted_key->add_child ("EncryptionMethod", "enc");
+ encryption_method->set_attribute ("Algorithm", "http://www.w3.org/2001/04/xmlenc#rsa-oaep-mgf1p");
+ xmlpp::Element* digest_method = encryption_method->add_child ("DigestMethod", "ds");
+ digest_method->set_attribute ("Algorithm", "http://www.w3.org/2000/09/xmldsig#sha1");
+ xmlpp::Element* cipher_data = encrypted_key->add_child ("CipherData", "enc");
+ cipher_data->add_child("CipherValue", "enc")->add_child_text (*i);
+ }
+ }
+
+ std::list<std::string> encrypted_keys;
+};
+
+class X509Data
+{
+public:
+ X509Data () {}
+ X509Data (boost::shared_ptr<const cxml::Node> node)
+ : x509_issuer_serial (Signer (node->node_child ("X509IssuerSerial")))
+ , x509_certificate (node->string_child ("X509Certificate"))
+ {
+ node->done ();
+ }
+
+ void as_xml (xmlpp::Element* node) const
+ {
+ x509_issuer_serial.as_xml (node->add_child ("X509IssuerSerial", "ds"));
+ node->add_child("X509Certificate", "ds")->add_child_text (x509_certificate);
+ }
+
+ Signer x509_issuer_serial;
+ std::string x509_certificate;
+};
+
+class Reference
+{
+public:
+ Reference () {}
+ Reference (std::string u)
+ : uri (u)
+ {}
+
+ Reference (boost::shared_ptr<const cxml::Node> node)
+ : uri (node->string_attribute ("URI"))
+ , digest_value (node->string_child ("DigestValue"))
+ {
+ node->ignore_child ("DigestMethod");
+ node->done ();
+ }
+
+ void as_xml (xmlpp::Element* node) const
+ {
+ xmlpp::Element* reference = node->add_child ("Reference", "ds");
+ reference->set_attribute ("URI", uri);
+ reference->add_child("DigestMethod", "ds")->set_attribute ("Algorithm", "http://www.w3.org/2001/04/xmlenc#sha256");
+ reference->add_child("DigestValue", "ds")->add_child_text (digest_value);
+ }
+
+ std::string uri;
+ std::string digest_value;
+};
+
+class Signature
+{
+public:
+ Signature ()
+ : authenticated_public ("#ID_AuthenticatedPublic")
+ , authenticated_private ("#ID_AuthenticatedPrivate")
+ {}
+
+ Signature (boost::shared_ptr<const cxml::Node> node)
+ {
+ std::list<boost::shared_ptr<cxml::Node> > refs = node->node_child("SignedInfo")->node_children ("Reference");
+ for (std::list<boost::shared_ptr<cxml::Node> >::const_iterator i = refs.begin(); i != refs.end(); ++i) {
+ if ((*i)->string_attribute("URI") == "#ID_AuthenticatedPublic") {
+ authenticated_public = Reference (*i);
+ } else if ((*i)->string_attribute("URI") == "#ID_AuthenticatedPrivate") {
+ authenticated_private = Reference (*i);
+ } else {
+ throw XMLError ("unrecognised reference URI");
+ }
+ }
+
+ std::list<boost::shared_ptr<cxml::Node> > data = node->node_child("KeyInfo")->node_children ("X509Data");
+ for (std::list<boost::shared_ptr<cxml::Node> >::const_iterator i = data.begin(); i != data.end(); ++i) {
+ key_info.push_back (X509Data (*i));
+ }
+
+ signature_value = node->string_child ("SignatureValue");
+
+ node->done ();
+ }
+
+ void as_xml (xmlpp::Element* node) const
+ {
+ xmlpp::Element* si = node->add_child ("SignedInfo", "ds");
+ si->add_child ("CanonicalizationMethod", "ds")->set_attribute ("Algorithm", "http://www.w3.org/TR/2001/REC-xml-c14n-20010315#WithComments");
+ si->add_child ("SignatureMethod", "ds")->set_attribute ("Algorithm", "http://www.w3.org/2001/04/xmldsig-more#rsa-sha256");
+
+ authenticated_public.as_xml (si);
+ authenticated_private.as_xml (si);
+
+ node->add_child("SignatureValue", "ds")->add_child_text (signature_value);
+
+ xmlpp::Element* ki = node->add_child ("KeyInfo", "ds");
+ for (std::list<X509Data>::const_iterator i = key_info.begin(); i != key_info.end(); ++i) {
+ i->as_xml (ki->add_child ("X509Data", "ds"));
+ }
+ }
+
+ Reference authenticated_public;
+ Reference authenticated_private;
+ std::string signature_value;
+ std::list<X509Data> key_info;
+};
+
+class DCinemaSecurityMessage
+{
+public:
+ DCinemaSecurityMessage () {}
+ DCinemaSecurityMessage (boost::filesystem::path file)
+ {
+ cxml::Document f ("DCinemaSecurityMessage");
+ f.read_file (file.string ());
+
+ authenticated_public = AuthenticatedPublic (f.node_child ("AuthenticatedPublic"));
+ authenticated_private = AuthenticatedPrivate (f.node_child ("AuthenticatedPrivate"));
+ signature = Signature (f.node_child ("Signature"));
+
+ f.done ();
+ }
+
+ boost::shared_ptr<xmlpp::Document> as_xml () const
+ {
+ Writer writer;
+
+ xmlpp::Element* root = writer.document->create_root_node ("DCinemaSecurityMessage", "http://www.smpte-ra.org/schemas/430-3/2006/ETM");
+ root->set_namespace_declaration ("http://www.w3.org/2000/09/xmldsig#", "ds");
+ root->set_namespace_declaration ("http://www.w3.org/2001/04/xmlenc#", "enc");
+
+ authenticated_public.as_xml (writer, root->add_child ("AuthenticatedPublic"));
+ authenticated_private.as_xml (writer, root->add_child ("AuthenticatedPrivate"));
+ signature.as_xml (root->add_child ("Signature", "ds"));
+
+ for (std::map<std::string, xmlpp::Attribute*>::const_iterator i = writer.references.begin(); i != writer.references.end(); ++i) {
+ xmlAddID (0, writer.document->cobj(), (const xmlChar *) i->first.c_str(), i->second->cobj ());
+ }
+
+ return writer.document;
+ }
+
+ AuthenticatedPublic authenticated_public;
+ AuthenticatedPrivate authenticated_private;
+ Signature signature;
+};
+
+}
+}
+
+#endif
+
/*
- Copyright (C) 2013 Carl Hetherington <cth@carlh.net>
+ Copyright (C) 2013-2014 Carl Hetherington <cth@carlh.net>
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
*/
-#include <sstream>
-#include <string>
-#include <iomanip>
+/** @file src/key.cc
+ * @brief Key class.
+ */
+
+#include "key.h"
#include "AS_DCP.h"
#include "KM_prng.h"
#include "KM_util.h"
-#include "key.h"
+#include <sstream>
+#include <string>
+#include <iomanip>
using std::string;
using std::stringstream;
using std::setw;
using std::setfill;
-using namespace libdcp;
+using namespace dcp;
Key::Key ()
: _value (new uint8_t[ASDCP::KeyLen])
}
bool
-libdcp::operator== (Key const & a, Key const & b)
+dcp::operator== (Key const & a, Key const & b)
{
return memcmp (a.value(), b.value(), ASDCP::KeyLen) == 0;
}
bool
-libdcp::operator!= (Key const & a, Key const & b)
+dcp::operator!= (Key const & a, Key const & b)
{
return !(a == b);
}
/*
- Copyright (C) 2013 Carl Hetherington <cth@carlh.net>
+ Copyright (C) 2013-2014 Carl Hetherington <cth@carlh.net>
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
*/
/** @file src/key.h
- * @brief Class to hold a key for encrypting MXFs.
+ * @brief Key class.
*/
#ifndef LIBDCP_KEY_H
#define LIBDCP_KEY_H
#include <stdint.h>
+#include <string>
-namespace libdcp {
+namespace dcp {
/** @class Key
- * @brief A key for encrypting MXFs.
+ * @brief A key for decrypting/encrypting MXFs.
*/
class Key
{
--- /dev/null
+/*
+ Copyright (C) 2012-2014 Carl Hetherington <cth@carlh.net>
+
+ 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 "load_font.h"
+#include <libcxml/cxml.h>
+
+using boost::shared_ptr;
+using namespace dcp;
+
+LoadFont::LoadFont (boost::shared_ptr<const cxml::Node> node)
+{
+ id = node->string_attribute ("Id");
+ uri = node->string_attribute ("URI");
+}
--- /dev/null
+/*
+ Copyright (C) 2012-2014 Carl Hetherington <cth@carlh.net>
+
+ 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 <boost/shared_ptr.hpp>
+
+namespace cxml {
+ class Node;
+}
+
+namespace dcp {
+
+class LoadFont
+{
+public:
+ LoadFont () {}
+ LoadFont (boost::shared_ptr<const cxml::Node> node);
+
+ std::string id;
+ std::string uri;
+};
+
+}
+++ /dev/null
-/*
- Copyright (C) 2012 Carl Hetherington <cth@carlh.net>
-
- 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 <cmath>
-#include <boost/utility.hpp>
-
-namespace libdcp {
-
-class LUT : boost::noncopyable
-{
-public:
- LUT(int bit_depth, float gamma)
- : _lut(0)
- , _bit_depth (bit_depth)
- , _gamma (gamma)
- {
- _lut = new float[int(std::pow(2.0f, _bit_depth))];
- }
-
- virtual ~LUT() {
- delete[] _lut;
- }
-
- float const * lut() const {
- return _lut;
- }
-
- int bit_depth () const {
- return _bit_depth;
- }
-
- float gamma () const {
- return _gamma;
- }
-
-protected:
- float* _lut;
- int _bit_depth;
- float _gamma;
-};
-
-}
-
-#endif
+/*
+ Copyright (C) 2013-2014 Carl Hetherington <cth@carlh.net>
+
+ 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_CACHE_H
#define LIBDCP_LUT_CACHE_H
#include <list>
#include <boost/shared_ptr.hpp>
+#include <boost/noncopyable.hpp>
template<class T>
-class LUTCache
+class LUTCache : public boost::noncopyable
{
public:
- boost::shared_ptr<T> get (int bit_depth, float gamma)
+ boost::shared_ptr<T> get (int bit_depth, float gamma, bool linearised)
{
for (typename std::list<boost::shared_ptr<T> >::iterator i = _cache.begin(); i != _cache.end(); ++i) {
if ((*i)->bit_depth() == bit_depth && (*i)->gamma() == gamma) {
}
}
- boost::shared_ptr<T> lut (new T (bit_depth, gamma));
+ boost::shared_ptr<T> lut (new T (bit_depth, gamma, linearised));
_cache.push_back (lut);
return lut;
}
/*
- Copyright (C) 2012 Carl Hetherington <cth@carlh.net>
+ Copyright (C) 2012-2014 Carl Hetherington <cth@carlh.net>
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
*/
/** @file src/metadata.cc
- * @brief Metadata for writing to the DCP.
+ * @brief XMLMetadata and MXFMetadata classes.
*/
-#include <sstream>
-#include <iomanip>
-#include <time.h>
+#include "metadata.h"
+#include "util.h"
#ifdef LIBDCP_WINDOWS
#include <windows.h>
#endif
-#include "metadata.h"
-#include "util.h"
+#include <sstream>
+#include <iomanip>
+#include <time.h>
using namespace std;
-using namespace libdcp;
+using namespace dcp;
MXFMetadata::MXFMetadata ()
: company_name ("libdcp")
/*
- Copyright (C) 2012 Carl Hetherington <cth@carlh.net>
+ Copyright (C) 2012-2014 Carl Hetherington <cth@carlh.net>
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
#define LIBDCP_METADATA_H
/** @file src/metadata.h
- * @brief Metadata for writing to the DCP.
+ * @brief XMLMetadata and MXFMetadata classes.
*/
#include <string>
class utc_offset_to_string_test;
-namespace libdcp
+namespace dcp
{
+/** @class MXFMetadata
+ * @brief Metadata that is written to a MXF file's header
+ */
class MXFMetadata
{
public:
std::string product_version;
};
+/** @class XMLMetadata
+ * @brief Common metadata that is written to a few different XML files
+ */
class XMLMetadata
{
public:
+++ /dev/null
-/*
- Copyright (C) 2012-2013 Carl Hetherington <cth@carlh.net>
-
- 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 "mono_picture_asset.h"
-#include "mono_picture_asset_writer.h"
-#include "AS_DCP.h"
-#include "KM_fileio.h"
-#include "exceptions.h"
-#include "mono_picture_frame.h"
-
-using std::string;
-using std::vector;
-using boost::shared_ptr;
-using boost::dynamic_pointer_cast;
-using boost::lexical_cast;
-using namespace libdcp;
-
-MonoPictureAsset::MonoPictureAsset (boost::filesystem::path directory, boost::filesystem::path mxf_name)
- : PictureAsset (directory, mxf_name)
-{
-
-}
-
-void
-MonoPictureAsset::create (vector<boost::filesystem::path> const & files)
-{
- create (boost::bind (&MonoPictureAsset::path_from_list, this, _1, files));
-}
-
-void
-MonoPictureAsset::create (boost::function<boost::filesystem::path (int)> get_path)
-{
- ASDCP::JP2K::CodestreamParser j2k_parser;
- ASDCP::JP2K::FrameBuffer frame_buffer (4 * Kumu::Megabyte);
- Kumu::Result_t r = j2k_parser.OpenReadFrame (get_path(0).string().c_str(), frame_buffer);
- if (ASDCP_FAILURE (r)) {
- boost::throw_exception (FileError ("could not open JPEG2000 file for reading", get_path(0), r));
- }
-
- ASDCP::JP2K::PictureDescriptor picture_desc;
- j2k_parser.FillPictureDescriptor (picture_desc);
- picture_desc.EditRate = ASDCP::Rational (_edit_rate, 1);
-
- ASDCP::WriterInfo writer_info;
- fill_writer_info (&writer_info);
-
- ASDCP::JP2K::MXFWriter mxf_writer;
- r = mxf_writer.OpenWrite (path().string().c_str(), writer_info, picture_desc, 16384, false);
- if (ASDCP_FAILURE (r)) {
- boost::throw_exception (MXFFileError ("could not open MXF file for writing", path().string(), r));
- }
-
- for (int i = 0; i < _intrinsic_duration; ++i) {
-
- boost::filesystem::path const path = get_path (i);
-
- Kumu::Result_t r = j2k_parser.OpenReadFrame (path.string().c_str(), frame_buffer);
- if (ASDCP_FAILURE (r)) {
- boost::throw_exception (FileError ("could not open JPEG2000 file for reading", path, r));
- }
-
- r = mxf_writer.WriteFrame (frame_buffer, _encryption_context, 0);
- if (ASDCP_FAILURE (r)) {
- boost::throw_exception (MXFFileError ("error in writing video MXF", this->path().string(), r));
- }
-
- if (_progress) {
- (*_progress) (0.5 * float (i) / _intrinsic_duration);
- }
- }
-
- r = mxf_writer.Finalize();
- if (ASDCP_FAILURE (r)) {
- boost::throw_exception (MXFFileError ("error in finalising video MXF", path().string(), r));
- }
-}
-
-void
-MonoPictureAsset::read ()
-{
- ASDCP::JP2K::MXFReader reader;
- Kumu::Result_t r = reader.OpenRead (path().string().c_str());
- if (ASDCP_FAILURE (r)) {
- boost::throw_exception (MXFFileError ("could not open MXF file for reading", path().string(), r));
- }
-
- ASDCP::JP2K::PictureDescriptor desc;
- if (ASDCP_FAILURE (reader.FillPictureDescriptor (desc))) {
- boost::throw_exception (DCPReadError ("could not read video MXF information"));
- }
-
- _size.width = desc.StoredWidth;
- _size.height = desc.StoredHeight;
- _edit_rate = desc.EditRate.Numerator;
- assert (desc.EditRate.Denominator == 1);
- _intrinsic_duration = desc.ContainerDuration;
-}
-
-boost::filesystem::path
-MonoPictureAsset::path_from_list (int f, vector<boost::filesystem::path> const & files) const
-{
- return files[f];
-}
-
-shared_ptr<const MonoPictureFrame>
-MonoPictureAsset::get_frame (int n) const
-{
- return shared_ptr<const MonoPictureFrame> (new MonoPictureFrame (path(), n, _decryption_context));
-}
-
-bool
-MonoPictureAsset::equals (shared_ptr<const Asset> other, EqualityOptions opt, boost::function<void (NoteType, string)> note) const
-{
- if (!MXFAsset::equals (other, opt, note)) {
- return false;
- }
-
- ASDCP::JP2K::MXFReader reader_A;
- Kumu::Result_t r = reader_A.OpenRead (path().string().c_str());
- if (ASDCP_FAILURE (r)) {
- boost::throw_exception (MXFFileError ("could not open MXF file for reading", path().string(), r));
- }
-
- ASDCP::JP2K::MXFReader reader_B;
- r = reader_B.OpenRead (other->path().string().c_str());
- if (ASDCP_FAILURE (r)) {
- boost::throw_exception (MXFFileError ("could not open MXF file for reading", path().string(), r));
- }
-
- ASDCP::JP2K::PictureDescriptor desc_A;
- if (ASDCP_FAILURE (reader_A.FillPictureDescriptor (desc_A))) {
- boost::throw_exception (DCPReadError ("could not read video MXF information"));
- }
- ASDCP::JP2K::PictureDescriptor desc_B;
- if (ASDCP_FAILURE (reader_B.FillPictureDescriptor (desc_B))) {
- boost::throw_exception (DCPReadError ("could not read video MXF information"));
- }
-
- if (!descriptor_equals (desc_A, desc_B, note)) {
- return false;
- }
-
- shared_ptr<const MonoPictureAsset> other_picture = dynamic_pointer_cast<const MonoPictureAsset> (other);
- assert (other_picture);
-
- for (int i = 0; i < _intrinsic_duration; ++i) {
- if (i >= other_picture->intrinsic_duration()) {
- return false;
- }
-
- note (PROGRESS, "Comparing video frame " + lexical_cast<string> (i) + " of " + lexical_cast<string> (_intrinsic_duration));
- shared_ptr<const MonoPictureFrame> frame_A = get_frame (i);
- shared_ptr<const MonoPictureFrame> frame_B = other_picture->get_frame (i);
-
- if (!frame_buffer_equals (
- i, opt, note,
- frame_A->j2k_data(), frame_A->j2k_size(),
- frame_B->j2k_data(), frame_B->j2k_size()
- )) {
- return false;
- }
- }
-
- return true;
-}
-
-shared_ptr<PictureAssetWriter>
-MonoPictureAsset::start_write (bool overwrite)
-{
- /* XXX: can't we use shared_ptr here? */
- return shared_ptr<MonoPictureAssetWriter> (new MonoPictureAssetWriter (this, overwrite));
-}
-
-string
-MonoPictureAsset::cpl_node_name () const
-{
- return "MainPicture";
-}
-
-int
-MonoPictureAsset::edit_rate_factor () const
-{
- return 1;
-}
+++ /dev/null
-/*
- Copyright (C) 2012-2013 Carl Hetherington <cth@carlh.net>
-
- 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_MONO_PICTURE_ASSET_H
-#define LIBDCP_MONO_PICTURE_ASSET_H
-
-#include "picture_asset.h"
-
-namespace libdcp {
-
-/** A 2D (monoscopic) picture asset */
-class MonoPictureAsset : public PictureAsset
-{
-public:
- MonoPictureAsset (boost::filesystem::path directory, boost::filesystem::path mxf_name);
-
- void read ();
-
- /** The following parameters must be set up (if required) before calling this:
- * Interop mode (set_interop)
- * Edit rate (set_edit_rate)
- * MXF Metadata (set_metadata)
- */
- void create (std::vector<boost::filesystem::path> const & files);
-
- /** The following parameters must be set up (if required) before calling this:
- * Interop mode (set_interop)
- * Edit rate (set_edit_rate)
- * MXF Metadata (set_metadata)
- */
- void create (boost::function<boost::filesystem::path (int)> get_path);
-
- /** Start a progressive write to a MonoPictureAsset */
- boost::shared_ptr<PictureAssetWriter> start_write (bool);
-
- boost::shared_ptr<const MonoPictureFrame> get_frame (int n) const;
- bool equals (boost::shared_ptr<const Asset> other, EqualityOptions opt, boost::function<void (NoteType, std::string)> note) const;
-
-private:
- boost::filesystem::path path_from_list (int f, std::vector<boost::filesystem::path> const & files) const;
- void construct (boost::function<boost::filesystem::path (int)>, bool, MXFMetadata const &);
- std::string cpl_node_name () const;
- int edit_rate_factor () const;
-};
-
-}
-
-#endif
+++ /dev/null
-/*
- Copyright (C) 2012-2013 Carl Hetherington <cth@carlh.net>
-
- 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 "AS_DCP.h"
-#include "KM_fileio.h"
-#include "mono_picture_asset_writer.h"
-#include "exceptions.h"
-#include "picture_asset.h"
-
-#include "picture_asset_writer_common.cc"
-
-using std::istream;
-using std::ostream;
-using std::string;
-using boost::shared_ptr;
-using boost::lexical_cast;
-using namespace libdcp;
-
-struct MonoPictureAssetWriter::ASDCPState : public ASDCPStateBase
-{
- ASDCP::JP2K::MXFWriter mxf_writer;
-};
-
-/** @param a Asset to write to. `a' must not be deleted while
- * this writer class still exists, or bad things will happen.
- */
-MonoPictureAssetWriter::MonoPictureAssetWriter (PictureAsset* asset, bool overwrite)
- : PictureAssetWriter (asset, overwrite)
- , _state (new MonoPictureAssetWriter::ASDCPState)
-{
- _state->encryption_context = asset->encryption_context ();
-}
-
-void
-MonoPictureAssetWriter::start (uint8_t* data, int size)
-{
- libdcp::start (this, _state, _asset, data, size);
-}
-
-FrameInfo
-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))) {
- boost::throw_exception (MiscError ("could not parse J2K frame"));
- }
-
- uint64_t const before_offset = _state->mxf_writer.Tell ();
-
- string hash;
- ASDCP::Result_t const r = _state->mxf_writer.WriteFrame (_state->frame_buffer, _state->encryption_context, 0, &hash);
- if (ASDCP_FAILURE (r)) {
- boost::throw_exception (MXFFileError ("error in writing video MXF", _asset->path().string(), r));
- }
-
- ++_frames_written;
- return FrameInfo (before_offset, _state->mxf_writer.Tell() - before_offset, hash);
-}
-
-void
-MonoPictureAssetWriter::fake_write (int size)
-{
- assert (_started);
- assert (!_finalized);
-
- Kumu::Result_t r = _state->mxf_writer.FakeWriteFrame (size);
- if (ASDCP_FAILURE (r)) {
- boost::throw_exception (MXFFileError ("error in writing video MXF", _asset->path().string(), r));
- }
-
- ++_frames_written;
-}
-
-void
-MonoPictureAssetWriter::finalize ()
-{
- assert (!_finalized);
-
- Kumu::Result_t r = _state->mxf_writer.Finalize();
- if (ASDCP_FAILURE (r)) {
- boost::throw_exception (MXFFileError ("error in finalizing video MXF", _asset->path().string(), r));
- }
-
- _finalized = true;
- _asset->set_intrinsic_duration (_frames_written);
- _asset->set_duration (_frames_written);
-}
-
+++ /dev/null
-/*
- Copyright (C) 2012-2013 Carl Hetherington <cth@carlh.net>
-
- 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 <stdint.h>
-#include <string>
-#include <fstream>
-#include <boost/shared_ptr.hpp>
-#include <boost/utility.hpp>
-#include "picture_asset_writer.h"
-
-namespace libdcp {
-
-/** 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 .j2c 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 PictureAssetWriter
-{
-public:
- FrameInfo write (uint8_t *, int);
- void fake_write (int size);
- void finalize ();
-
-private:
- friend class MonoPictureAsset;
-
- MonoPictureAssetWriter (PictureAsset *, bool);
- void start (uint8_t *, int);
-
- /* do this with an opaque pointer so we don't have to include
- ASDCP headers
- */
-
- struct ASDCPState;
- boost::shared_ptr<ASDCPState> _state;
-};
-
-}
/*
- Copyright (C) 2012 Carl Hetherington <cth@carlh.net>
+ Copyright (C) 2012-2014 Carl Hetherington <cth@carlh.net>
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
*/
-#include <openjpeg.h>
-#include "AS_DCP.h"
-#include "KM_fileio.h"
+/** @file src/mono_picture_frame.cc
+ * @brief MonoPictureFrame class.
+ */
+
#include "mono_picture_frame.h"
#include "exceptions.h"
#include "argb_frame.h"
-#include "lut.h"
-#include "util.h"
#include "gamma_lut.h"
+#include "util.h"
#include "rgb_xyz.h"
+#include "KM_fileio.h"
+#include "AS_DCP.h"
+#include <openjpeg.h>
#define DCI_GAMMA 2.6
using std::string;
using boost::shared_ptr;
-using namespace libdcp;
+using namespace dcp;
/** Make a picture frame from a 2D (monoscopic) asset.
* @param mxf_path Path to the asset's MXF file.
* @param n Frame within the asset, not taking EntryPoint into account.
+ * @param c Context for decryption, or 0.
*/
MonoPictureFrame::MonoPictureFrame (boost::filesystem::path mxf_path, int n, ASDCP::AESDecContext* c)
{
}
}
+/** MonoPictureFrame destructor */
MonoPictureFrame::~MonoPictureFrame ()
{
delete _buffer;
}
+/** @return Pointer to JPEG2000 data */
uint8_t const *
MonoPictureFrame::j2k_data () const
{
return _buffer->RoData ();
}
+/** @return Size of JPEG2000 data in bytes */
int
MonoPictureFrame::j2k_size () const
{
/** @param reduce a factor by which to reduce the resolution
* of the image, expressed as a power of two (pass 0 for no
* reduction).
+ * @param srgb_gamma Reciprocal of output gamma to use after
+ * the conversion from XYZ to RGB.
*
* @return An ARGB representation of this frame. This is ARGB in the
* Cairo sense, so that each pixel takes up 4 bytes; the first byte
* is blue, second green, third red and fourth alpha (always 255).
- *
*/
shared_ptr<ARGBFrame>
MonoPictureFrame::argb_frame (int reduce, float srgb_gamma) const
{
return xyz_to_rgb (
decompress_j2k (const_cast<uint8_t*> (_buffer->RoData()), _buffer->Size(), reduce),
- GammaLUT::cache.get (12, DCI_GAMMA), GammaLUT::cache.get (12, 1 / srgb_gamma)
+ GammaLUT::cache.get (12, DCI_GAMMA, false), GammaLUT::cache.get (12, 1 / srgb_gamma, false)
);
}
/*
- Copyright (C) 2012-2013 Carl Hetherington <cth@carlh.net>
+ Copyright (C) 2012-2014 Carl Hetherington <cth@carlh.net>
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
*/
+/** @file src/mono_picture_frame.h
+ * @brief MonoPictureFrame class.
+ */
+
+#include "types.h"
+#include <boost/shared_ptr.hpp>
+#include <boost/noncopyable.hpp>
+#include <boost/filesystem.hpp>
#include <string>
#include <stdint.h>
-#include <boost/shared_ptr.hpp>
-#include "types.h"
namespace ASDCP {
namespace JP2K {
class AESDecContext;
}
-namespace libdcp {
+namespace dcp {
class ARGBFrame;
-/** A single frame of a 2D (monoscopic) picture asset */
-class MonoPictureFrame
+/** @class MonoPictureFrame
+ * @brief A single frame of a 2D (monoscopic) picture asset.
+ */
+class MonoPictureFrame : public boost::noncopyable
{
public:
MonoPictureFrame (boost::filesystem::path mxf_path, int n, ASDCP::AESDecContext *);
--- /dev/null
+/*
+ Copyright (C) 2012-2014 Carl Hetherington <cth@carlh.net>
+
+ 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 "mono_picture_mxf.h"
+#include "mono_picture_mxf_writer.h"
+#include "AS_DCP.h"
+#include "KM_fileio.h"
+#include "exceptions.h"
+#include "mono_picture_frame.h"
+#include "compose.hpp"
+
+using std::string;
+using std::vector;
+using boost::shared_ptr;
+using boost::dynamic_pointer_cast;
+using namespace dcp;
+
+MonoPictureMXF::MonoPictureMXF (boost::filesystem::path file)
+ : PictureMXF (file)
+{
+ ASDCP::JP2K::MXFReader reader;
+ Kumu::Result_t r = reader.OpenRead (file.string().c_str());
+ if (ASDCP_FAILURE (r)) {
+ boost::throw_exception (MXFFileError ("could not open MXF file for reading", file.string(), r));
+ }
+
+ ASDCP::JP2K::PictureDescriptor desc;
+ if (ASDCP_FAILURE (reader.FillPictureDescriptor (desc))) {
+ boost::throw_exception (DCPReadError ("could not read video MXF information"));
+ }
+
+ read_picture_descriptor (desc);
+
+ ASDCP::WriterInfo info;
+ if (ASDCP_FAILURE (reader.FillWriterInfo (info))) {
+ boost::throw_exception (DCPReadError ("could not read video MXF information"));
+ }
+
+ read_writer_info (info);
+}
+
+MonoPictureMXF::MonoPictureMXF (Fraction edit_rate)
+ : PictureMXF (edit_rate)
+{
+
+}
+
+shared_ptr<const MonoPictureFrame>
+MonoPictureMXF::get_frame (int n) const
+{
+ return shared_ptr<const MonoPictureFrame> (new MonoPictureFrame (_file, n, _decryption_context));
+}
+
+bool
+MonoPictureMXF::equals (shared_ptr<const Content> other, EqualityOptions opt, boost::function<void (NoteType, string)> note) const
+{
+ if (!MXF::equals (other, opt, note)) {
+ return false;
+ }
+
+ ASDCP::JP2K::MXFReader reader_A;
+ Kumu::Result_t r = reader_A.OpenRead (_file.string().c_str());
+ if (ASDCP_FAILURE (r)) {
+ boost::throw_exception (MXFFileError ("could not open MXF file for reading", _file.string(), r));
+ }
+
+ ASDCP::JP2K::MXFReader reader_B;
+ r = reader_B.OpenRead (other->file().string().c_str());
+ if (ASDCP_FAILURE (r)) {
+ boost::throw_exception (MXFFileError ("could not open MXF file for reading", other->file().string(), r));
+ }
+
+ ASDCP::JP2K::PictureDescriptor desc_A;
+ if (ASDCP_FAILURE (reader_A.FillPictureDescriptor (desc_A))) {
+ boost::throw_exception (DCPReadError ("could not read video MXF information"));
+ }
+ ASDCP::JP2K::PictureDescriptor desc_B;
+ if (ASDCP_FAILURE (reader_B.FillPictureDescriptor (desc_B))) {
+ boost::throw_exception (DCPReadError ("could not read video MXF information"));
+ }
+
+ if (!descriptor_equals (desc_A, desc_B, note)) {
+ return false;
+ }
+
+ shared_ptr<const MonoPictureMXF> other_picture = dynamic_pointer_cast<const MonoPictureMXF> (other);
+ assert (other_picture);
+
+ for (int i = 0; i < _intrinsic_duration; ++i) {
+ if (i >= other_picture->intrinsic_duration()) {
+ return false;
+ }
+
+ note (PROGRESS, String::compose ("Comparing video frame %1 of %2", i, _intrinsic_duration));
+ shared_ptr<const MonoPictureFrame> frame_A = get_frame (i);
+ shared_ptr<const MonoPictureFrame> frame_B = other_picture->get_frame (i);
+
+ if (!frame_buffer_equals (
+ i, opt, note,
+ frame_A->j2k_data(), frame_A->j2k_size(),
+ frame_B->j2k_data(), frame_B->j2k_size()
+ )) {
+ return false;
+ }
+ }
+
+ return true;
+}
+
+shared_ptr<PictureMXFWriter>
+MonoPictureMXF::start_write (boost::filesystem::path file, Standard standard, bool overwrite)
+{
+ /* XXX: can't we use shared_ptr here? */
+ return shared_ptr<MonoPictureMXFWriter> (new MonoPictureMXFWriter (this, file, standard, overwrite));
+}
+
+string
+MonoPictureMXF::cpl_node_name () const
+{
+ return "MainPicture";
+}
--- /dev/null
+/*
+ Copyright (C) 2012-2014 Carl Hetherington <cth@carlh.net>
+
+ 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_MONO_PICTURE_MXF_H
+#define LIBDCP_MONO_PICTURE_MXF_H
+
+#include "picture_mxf.h"
+
+namespace dcp {
+
+class MonoPictureMXFWriter;
+
+/** @class MonoPictureMXF
+ * @brief A 2D (monoscopic) picture MXF.
+ */
+class MonoPictureMXF : public PictureMXF
+{
+public:
+ /** Create a MonoPictureMXF by reading a file.
+ * @param file MXF file to read.
+ */
+ MonoPictureMXF (boost::filesystem::path file);
+
+ /** Create a MonoPictureMXF with a given edit rate.
+ * @param edit_rate Edit rate (i.e. frame rate) in frames per second.
+ */
+ MonoPictureMXF (Fraction edit_rate);
+
+ /** Start a progressive write to a MonoPictureMXF */
+ boost::shared_ptr<PictureMXFWriter> start_write (boost::filesystem::path, Standard standard, bool);
+
+ bool equals (
+ boost::shared_ptr<const Content> other,
+ EqualityOptions opt,
+ boost::function<void (NoteType, std::string)> note
+ ) const;
+
+ boost::shared_ptr<const MonoPictureFrame> get_frame (int n) const;
+
+private:
+ std::string cpl_node_name () const;
+};
+
+}
+
+#endif
--- /dev/null
+/*
+ Copyright (C) 2012-2014 Carl Hetherington <cth@carlh.net>
+
+ 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/mono_picture_mxf_writer.cc
+ * @brief MonoPictureMXFWriter class
+ */
+
+#include "AS_DCP.h"
+#include "KM_fileio.h"
+#include "mono_picture_mxf_writer.h"
+#include "exceptions.h"
+#include "picture_mxf.h"
+
+#include "picture_mxf_writer_common.cc"
+
+using std::istream;
+using std::ostream;
+using std::string;
+using boost::shared_ptr;
+using namespace dcp;
+
+struct MonoPictureMXFWriter::ASDCPState : public ASDCPStateBase
+{
+ ASDCP::JP2K::MXFWriter mxf_writer;
+};
+
+/** @param a Asset to write to. `a' must not be deleted while
+ * this writer class still exists, or bad things will happen.
+ */
+MonoPictureMXFWriter::MonoPictureMXFWriter (PictureMXF* asset, boost::filesystem::path file, Standard standard, bool overwrite)
+ : PictureMXFWriter (asset, file, standard, overwrite)
+ , _state (new MonoPictureMXFWriter::ASDCPState)
+{
+ _state->encryption_context = asset->encryption_context ();
+}
+
+void
+MonoPictureMXFWriter::start (uint8_t* data, int size)
+{
+ dcp::start (this, _state, _standard, _picture_mxf, data, size);
+ _picture_mxf->set_frame_rate (_picture_mxf->edit_rate());
+}
+
+FrameInfo
+MonoPictureMXFWriter::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))) {
+ boost::throw_exception (MiscError ("could not parse J2K frame"));
+ }
+
+ uint64_t const before_offset = _state->mxf_writer.Tell ();
+
+ string hash;
+ ASDCP::Result_t const r = _state->mxf_writer.WriteFrame (_state->frame_buffer, _state->encryption_context, 0, &hash);
+ if (ASDCP_FAILURE (r)) {
+ boost::throw_exception (MXFFileError ("error in writing video MXF", _file.string(), r));
+ }
+
+ ++_frames_written;
+ return FrameInfo (before_offset, _state->mxf_writer.Tell() - before_offset, hash);
+}
+
+void
+MonoPictureMXFWriter::fake_write (int size)
+{
+ assert (_started);
+ assert (!_finalized);
+
+ Kumu::Result_t r = _state->mxf_writer.FakeWriteFrame (size);
+ if (ASDCP_FAILURE (r)) {
+ boost::throw_exception (MXFFileError ("error in writing video MXF", _mxf->file().string(), r));
+ }
+
+ ++_frames_written;
+}
+
+void
+MonoPictureMXFWriter::finalize ()
+{
+ Kumu::Result_t r = _state->mxf_writer.Finalize();
+ if (ASDCP_FAILURE (r)) {
+ boost::throw_exception (MXFFileError ("error in finalizing video MXF", _mxf->file().string(), r));
+ }
+
+ PictureMXFWriter::finalize ();
+}
+
--- /dev/null
+/*
+ Copyright (C) 2012-2014 Carl Hetherington <cth@carlh.net>
+
+ 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/mono_picture_mxf_writer.h
+ * @brief MonoPictureMXFWriter class
+ */
+
+#ifndef LIBDCP_MONO_PICTURE_MXF_WRITER_H
+#define LIBDCP_MONO_PICTURE_MXF_WRITER_H
+
+#include "picture_mxf_writer.h"
+#include <boost/shared_ptr.hpp>
+#include <boost/utility.hpp>
+#include <stdint.h>
+#include <string>
+#include <fstream>
+
+namespace dcp {
+
+/** @class MonoPictureMXFWriter
+ * @brief A helper class for writing to MonoPictureMXFs
+ *
+ * Objects of this class can only be created with MonoPictureMXF::start_write().
+ *
+ * Frames can be written to the MonoPictureAsset by calling write() with a JPEG2000 image
+ * (a verbatim .j2c 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 MonoPictureMXFWriter : public PictureMXFWriter
+{
+public:
+ FrameInfo write (uint8_t *, int);
+ void fake_write (int size);
+ void finalize ();
+
+private:
+ friend class MonoPictureMXF;
+
+ MonoPictureMXFWriter (PictureMXF *, boost::filesystem::path file, Standard standard, bool);
+ void start (uint8_t *, int);
+
+ /* do this with an opaque pointer so we don't have to include
+ ASDCP headers
+ */
+
+ struct ASDCPState;
+ boost::shared_ptr<ASDCPState> _state;
+};
+
+}
+
+#endif
--- /dev/null
+/*
+ Copyright (C) 2012-2014 Carl Hetherington <cth@carlh.net>
+
+ 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.cc
+ * @brief Parent class for assets of DCPs made up of MXF files.
+ */
+
+#include "AS_DCP.h"
+#include "KM_prng.h"
+#include "KM_util.h"
+#include "mxf.h"
+#include "util.h"
+#include "metadata.h"
+#include "exceptions.h"
+#include "kdm.h"
+#include "compose.hpp"
+#include <libxml++/nodes/element.h>
+#include <boost/filesystem.hpp>
+#include <iostream>
+
+using std::string;
+using std::list;
+using std::pair;
+using boost::shared_ptr;
+using boost::lexical_cast;
+using boost::dynamic_pointer_cast;
+using namespace dcp;
+
+MXF::MXF (Fraction edit_rate)
+ : Content (edit_rate)
+ , _encryption_context (0)
+ , _decryption_context (0)
+{
+
+}
+
+MXF::MXF (boost::filesystem::path file)
+ : Content (file)
+ , _encryption_context (0)
+ , _decryption_context (0)
+{
+
+}
+
+MXF::~MXF ()
+{
+ delete _encryption_context;
+ delete _decryption_context;
+}
+
+void
+MXF::fill_writer_info (ASDCP::WriterInfo* writer_info, Standard standard)
+{
+ writer_info->ProductVersion = _metadata.product_version;
+ writer_info->CompanyName = _metadata.company_name;
+ writer_info->ProductName = _metadata.product_name.c_str();
+
+ if (standard == INTEROP) {
+ writer_info->LabelSetType = ASDCP::LS_MXF_INTEROP;
+ } else {
+ writer_info->LabelSetType = ASDCP::LS_MXF_SMPTE;
+ }
+ unsigned int c;
+ Kumu::hex2bin (_id.c_str(), writer_info->AssetUUID, Kumu::UUID_Length, &c);
+ assert (c == Kumu::UUID_Length);
+
+ if (_key) {
+ Kumu::GenRandomUUID (writer_info->ContextID);
+ writer_info->EncryptedEssence = true;
+
+ unsigned int c;
+ Kumu::hex2bin (_key_id.c_str(), writer_info->CryptographicKeyID, Kumu::UUID_Length, &c);
+ assert (c == Kumu::UUID_Length);
+ }
+}
+
+bool
+MXF::equals (shared_ptr<const Content> other, EqualityOptions opt, boost::function<void (NoteType, string)> note) const
+{
+ if (!Content::equals (other, opt, note)) {
+ return false;
+ }
+
+ shared_ptr<const MXF> other_mxf = dynamic_pointer_cast<const MXF> (other);
+ if (!other_mxf) {
+ note (ERROR, "comparing an MXF asset with a non-MXF asset");
+ return false;
+ }
+
+ if (_file != other_mxf->file ()) {
+ note (ERROR, "MXF names differ");
+ if (!opt.mxf_names_can_differ) {
+ return false;
+ }
+ }
+
+ return true;
+}
+
+/** Set the (private) key that will be used to encrypt or decrypt this MXF's content.
+ * This is the top-secret key that is distributed (itself encrypted) to cinemas
+ * via Key Delivery Messages (KDMs).
+ * @param key Key to use.
+ */
+void
+MXF::set_key (Key key)
+{
+ _key = key;
+
+ if (_key_id.empty ()) {
+ /* No key ID so far; we now need one */
+ _key_id = make_uuid ();
+ }
+
+ _decryption_context = new ASDCP::AESDecContext;
+ if (ASDCP_FAILURE (_decryption_context->InitKey (_key->value ()))) {
+ throw MiscError ("could not set up decryption context");
+ }
+
+ _encryption_context = new ASDCP::AESEncContext;
+ if (ASDCP_FAILURE (_encryption_context->InitKey (_key->value ()))) {
+ throw MiscError ("could not set up encryption context");
+ }
+
+ uint8_t cbc_buffer[ASDCP::CBC_BLOCK_SIZE];
+
+ Kumu::FortunaRNG rng;
+ if (ASDCP_FAILURE (_encryption_context->SetIVec (rng.FillRandom (cbc_buffer, ASDCP::CBC_BLOCK_SIZE)))) {
+ throw MiscError ("could not set up CBC initialization vector");
+ }
+}
+
+void
+MXF::read_writer_info (ASDCP::WriterInfo const & info)
+{
+ char buffer[64];
+ Kumu::bin2UUIDhex (info.AssetUUID, 16, buffer, 64);
+ _id = buffer;
+}
+
+string
+MXF::pkl_type (Standard standard) const
+{
+ switch (standard) {
+ case INTEROP:
+ return String::compose ("application/x-smpte-mxf;asdcpKind=%1", asdcp_kind ());
+ case SMPTE:
+ return "application/x-smpte-mxf";
+ default:
+ assert (false);
+ }
+}
--- /dev/null
+/*
+ Copyright (C) 2012-2014 Carl Hetherington <cth@carlh.net>
+
+ 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_MXF_H
+#define LIBDCP_MXF_H
+
+#include "content.h"
+#include "key.h"
+#include "metadata.h"
+#include <boost/signals2.hpp>
+
+namespace ASDCP {
+ class AESEncContext;
+ class AESDecContext;
+}
+
+namespace dcp
+{
+
+class MXFMetadata;
+
+/** @class MXF
+ * @brief Parent class for classes which represent MXF files.
+ */
+class MXF : public Content
+{
+public:
+ MXF (Fraction edit_rate);
+ MXF (boost::filesystem::path file);
+ ~MXF ();
+
+ /** @return the 4-character key type for this MXF (MDIK, MDAK, etc.) */
+ virtual std::string key_type () const = 0;
+
+ bool equals (
+ boost::shared_ptr<const Content> other,
+ EqualityOptions opt,
+ boost::function<void (NoteType, std::string)> note
+ ) const;
+
+ /** Fill in a ADSCP::WriteInfo struct.
+ * @param w struct to fill in.
+ * @param standard INTEROP or SMPTE.
+ */
+ void fill_writer_info (ASDCP::WriterInfo* w, Standard standard);
+
+ /** @return true if the data is encrypted */
+ bool encrypted () const {
+ return !_key_id.empty ();
+ }
+
+ /** Set the ID of the key that is used for encryption/decryption.
+ * @param i key ID.
+ */
+ void set_key_id (std::string i) {
+ _key_id = i;
+ }
+
+ /** @return the ID of the key used for encryption/decryption, or an empty string */
+ std::string key_id () const {
+ return _key_id;
+ }
+
+ void set_key (Key);
+
+ /** @return encryption/decryption key, if one has been set */
+ boost::optional<Key> key () const {
+ return _key;
+ }
+
+ /** @return encryption context, set up with any key that has been passed to set_key() */
+ ASDCP::AESEncContext* encryption_context () const {
+ return _encryption_context;
+ }
+
+ /** Set the metadata that is written to the MXF file.
+ * @param m Metadata.
+ */
+ void set_metadata (MXFMetadata m) {
+ _metadata = m;
+ }
+
+ /** @return metadata from the MXF file */
+ MXFMetadata metadata () const {
+ return _metadata;
+ }
+
+protected:
+ std::string pkl_type (Standard standard) const;
+ void read_writer_info (ASDCP::WriterInfo const &);
+
+ ASDCP::AESEncContext* _encryption_context;
+ ASDCP::AESDecContext* _decryption_context;
+ /** ID of the key used for encryption/decryption, or an empty string */
+ std::string _key_id;
+ /** Key used for encryption/decryption, if there is one */
+ boost::optional<Key> _key;
+ MXFMetadata _metadata;
+};
+
+}
+
+#endif
+++ /dev/null
-/*
- Copyright (C) 2012 Carl Hetherington <cth@carlh.net>
-
- 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.cc
- * @brief Parent class for assets of DCPs made up of MXF files.
- */
-
-#include <iostream>
-#include <boost/filesystem.hpp>
-#include <boost/lexical_cast.hpp>
-#include <libxml++/nodes/element.h>
-#include "AS_DCP.h"
-#include "KM_prng.h"
-#include "KM_util.h"
-#include "mxf_asset.h"
-#include "util.h"
-#include "metadata.h"
-#include "exceptions.h"
-#include "kdm.h"
-
-using std::string;
-using std::list;
-using std::pair;
-using boost::shared_ptr;
-using boost::lexical_cast;
-using boost::dynamic_pointer_cast;
-using namespace libdcp;
-
-MXFAsset::MXFAsset (boost::filesystem::path directory, boost::filesystem::path file_name)
- : Asset (directory, file_name)
- , _progress (0)
- , _encryption_context (0)
- , _decryption_context (0)
- , _interop (false)
-{
-
-}
-
-MXFAsset::~MXFAsset ()
-{
- delete _encryption_context;
- delete _decryption_context;
-}
-
-void
-MXFAsset::fill_writer_info (ASDCP::WriterInfo* writer_info)
-{
- writer_info->ProductVersion = _metadata.product_version;
- writer_info->CompanyName = _metadata.company_name;
- writer_info->ProductName = _metadata.product_name.c_str();
-
- if (_interop) {
- writer_info->LabelSetType = ASDCP::LS_MXF_INTEROP;
- } else {
- writer_info->LabelSetType = ASDCP::LS_MXF_SMPTE;
- }
- unsigned int c;
- Kumu::hex2bin (_uuid.c_str(), writer_info->AssetUUID, Kumu::UUID_Length, &c);
- assert (c == Kumu::UUID_Length);
-
- if (_key) {
- Kumu::GenRandomUUID (writer_info->ContextID);
- writer_info->EncryptedEssence = true;
-
- unsigned int c;
- Kumu::hex2bin (_key_id.c_str(), writer_info->CryptographicKeyID, Kumu::UUID_Length, &c);
- assert (c == Kumu::UUID_Length);
- }
-}
-
-bool
-MXFAsset::equals (shared_ptr<const Asset> other, EqualityOptions opt, boost::function<void (NoteType, string)> note) const
-{
- if (!Asset::equals (other, opt, note)) {
- return false;
- }
-
- shared_ptr<const MXFAsset> other_mxf = dynamic_pointer_cast<const MXFAsset> (other);
- if (!other_mxf) {
- note (ERROR, "comparing an MXF asset with a non-MXF asset");
- return false;
- }
-
- if (_file_name != other_mxf->_file_name) {
- note (ERROR, "MXF names differ");
- if (!opt.mxf_names_can_differ) {
- return false;
- }
- }
-
- return true;
-}
-
-void
-MXFAsset::write_to_cpl (xmlpp::Element* node) const
-{
- pair<string, string> const attr = cpl_node_attribute ();
- xmlpp::Element* a = node->add_child (cpl_node_name ());
- if (!attr.first.empty ()) {
- a->set_attribute (attr.first, attr.second);
- }
- a->add_child ("Id")->add_child_text ("urn:uuid:" + _uuid);
- a->add_child ("AnnotationText")->add_child_text (_file_name.string ());
- a->add_child ("EditRate")->add_child_text (lexical_cast<string> (_edit_rate) + " 1");
- a->add_child ("IntrinsicDuration")->add_child_text (lexical_cast<string> (_intrinsic_duration));
- a->add_child ("EntryPoint")->add_child_text (lexical_cast<string> (_entry_point));
- a->add_child ("Duration")->add_child_text (lexical_cast<string> (_duration));
- if (!_key_id.empty ()) {
- a->add_child("KeyId")->add_child_text ("urn:uuid:" + _key_id);
- }
-}
-
-void
-MXFAsset::set_key (Key key)
-{
- _key = key;
-
- if (_key_id.empty ()) {
- /* No key ID so far; we now need one */
- _key_id = make_uuid ();
- }
-
- _decryption_context = new ASDCP::AESDecContext;
- if (ASDCP_FAILURE (_decryption_context->InitKey (_key->value ()))) {
- throw MiscError ("could not set up decryption context");
- }
-
- _encryption_context = new ASDCP::AESEncContext;
- if (ASDCP_FAILURE (_encryption_context->InitKey (_key->value ()))) {
- throw MiscError ("could not set up encryption context");
- }
-
- uint8_t cbc_buffer[ASDCP::CBC_BLOCK_SIZE];
-
- Kumu::FortunaRNG rng;
- if (ASDCP_FAILURE (_encryption_context->SetIVec (rng.FillRandom (cbc_buffer, ASDCP::CBC_BLOCK_SIZE)))) {
- throw MiscError ("could not set up CBC initialization vector");
- }
-}
+++ /dev/null
-/*
- Copyright (C) 2012 Carl Hetherington <cth@carlh.net>
-
- 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_MXF_ASSET_H
-#define LIBDCP_MXF_ASSET_H
-
-#include <boost/signals2.hpp>
-#include "asset.h"
-#include "key.h"
-#include "metadata.h"
-
-namespace ASDCP {
- class AESEncContext;
- class AESDecContext;
-}
-
-namespace libdcp
-{
-
-class MXFMetadata;
-
-/** @brief Parent class for assets which have MXF files */
-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 (boost::filesystem::path directory, boost::filesystem::path file_name);
-
- ~MXFAsset ();
-
- virtual bool equals (boost::shared_ptr<const Asset> other, EqualityOptions opt, boost::function<void (NoteType, std::string)> note) const;
- virtual void write_to_cpl (xmlpp::Element *) const;
- virtual std::string key_type () const = 0;
-
- /** Fill in a ADSCP::WriteInfo struct.
- * @param w struct to fill in.
- */
- void fill_writer_info (ASDCP::WriterInfo* w);
-
- void set_progress (boost::signals2::signal<void (float)>* progress) {
- _progress = progress;
- }
-
- bool encrypted () const {
- return !_key_id.empty ();
- }
-
- void set_key_id (std::string i) {
- _key_id = i;
- }
-
- std::string key_id () const {
- return _key_id;
- }
-
- void set_key (Key);
-
- boost::optional<Key> key () const {
- return _key;
- }
-
- ASDCP::AESEncContext* encryption_context () const {
- return _encryption_context;
- }
-
- void set_metadata (MXFMetadata m) {
- _metadata = m;
- }
-
- MXFMetadata metadata () const {
- return _metadata;
- }
-
- /** Set whether or not the asset should be written in Interop mode.
- * @param i true to use interop.
- */
- void set_interop (bool i) {
- _interop = i;
- }
-
- bool interop () const {
- return _interop;
- }
-
-protected:
- virtual std::string cpl_node_name () const = 0;
- virtual std::pair<std::string, std::string> cpl_node_attribute () const {
- return std::make_pair ("", "");
- }
-
- /** Signal to emit to report progress, or 0 */
- boost::signals2::signal<void (float)>* _progress;
- ASDCP::AESEncContext* _encryption_context;
- ASDCP::AESDecContext* _decryption_context;
- std::string _key_id;
- boost::optional<Key> _key;
- MXFMetadata _metadata;
- bool _interop;
-};
-
-}
-
-#endif
--- /dev/null
+/*
+ Copyright (C) 2012-2014 Carl Hetherington <cth@carlh.net>
+
+ 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/mxf_writer.h
+ * @brief MXFWriter class.
+ */
+
+#include "mxf_writer.h"
+#include "mxf.h"
+
+using namespace dcp;
+
+/** Create an MXFWriter.
+ * @param mxf MXF that we are writing.
+ * @param file File to write to.
+ */
+MXFWriter::MXFWriter (MXF* mxf, boost::filesystem::path file)
+ : _mxf (mxf)
+ , _file (file)
+ , _frames_written (0)
+ , _finalized (false)
+{
+ mxf->set_file (file);
+}
+
+MXFWriter::~MXFWriter ()
+{
+ assert (_finalized);
+}
+
+void
+MXFWriter::finalize ()
+{
+ assert (!_finalized);
+ _finalized = true;
+ _mxf->_intrinsic_duration = _frames_written;
+}
--- /dev/null
+/*
+ Copyright (C) 2012-2014 Carl Hetherington <cth@carlh.net>
+
+ 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/mxf_writer.h
+ * @brief MXFWriter class.
+ */
+
+#ifndef LIBDCP_MXF_WRITER_H
+#define LIBDCP_MXF_WRITER_H
+
+#include <boost/filesystem.hpp>
+
+namespace dcp {
+
+class MXF;
+
+/** @class MXFWriter
+ * @brief Parent class for classes which can write MXF files.
+ *
+ * The MXFWriter lasts for the duration of the write and is then discarded.
+ * They can only be created by calling start_write() on an MXF object.
+ */
+class MXFWriter : public boost::noncopyable
+{
+public:
+ virtual ~MXFWriter ();
+ virtual void finalize ();
+
+protected:
+ MXFWriter (MXF* mxf, boost::filesystem::path file);
+
+ /** MXF that we are writing */
+ MXF* _mxf;
+ /** File that we are writing to */
+ boost::filesystem::path _file;
+ /** Number of `frames' written so far; the definition of a frame
+ * varies depending on the subclass.
+ */
+ int64_t _frames_written;
+ /** true if finalize() has been called on this object */
+ bool _finalized;
+};
+
+}
+
+#endif
--- /dev/null
+/*
+ Copyright (C) 2014 Carl Hetherington <cth@carlh.net>
+
+ 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/object.cc
+ * @brief Object class.
+ */
+
+#include "object.h"
+#include "util.h"
+
+using std::string;
+using namespace dcp;
+
+/** Create an Object with a random ID. */
+Object::Object ()
+ : _id (make_uuid ())
+{
+
+}
+
+/** Create an Object with a given ID.
+ * @param id ID to use.
+ */
+Object::Object (string id)
+ : _id (id)
+{
+
+}
--- /dev/null
+/*
+ Copyright (C) 2014 Carl Hetherington <cth@carlh.net>
+
+ 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/object.h
+ * @brief Object class.
+ */
+
+#ifndef LIBDCP_OBJECT_H
+#define LIBDCP_OBJECT_H
+
+#include <boost/noncopyable.hpp>
+#include <string>
+
+namespace dcp {
+
+/** @class Object
+ * @brief Some part of a DCP that has a UUID.
+ */
+class Object : public boost::noncopyable
+{
+public:
+ Object ();
+ Object (std::string id);
+ virtual ~Object () {}
+
+ /** @return ID */
+ std::string id () const {
+ return _id;
+ }
+
+protected:
+ /** ID */
+ std::string _id;
+};
+
+}
+
+#endif
+++ /dev/null
-/*
- Copyright (C) 2012 Carl Hetherington <cth@carlh.net>
-
- 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 <boost/algorithm/string.hpp>
-#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::Document f ("AssetMap");
- f.read_file (file);
-
- id = f.string_child ("Id");
- creator = f.string_child ("Creator");
- volume_count = f.number_child<int64_t> ("VolumeCount");
- issue_date = f.string_child ("IssueDate");
- issuer = f.string_child ("Issuer");
- assets = type_grand_children<AssetMapAsset> (f, "AssetList", "Asset");
-}
-
-AssetMapAsset::AssetMapAsset (shared_ptr<const cxml::Node> node)
-{
- id = node->string_child ("Id");
- packing_list = node->optional_string_child ("PackingList").get_value_or ("");
- chunks = type_grand_children<Chunk> (node, "ChunkList", "Chunk");
-}
-
-Chunk::Chunk (shared_ptr<const cxml::Node> 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<int64_t> ("VolumeIndex").get_value_or (0);
- offset = node->optional_number_child<int64_t> ("Offset").get_value_or (0);
- length = node->optional_number_child<int64_t> ("Length").get_value_or (0);
-}
-
-shared_ptr<AssetMapAsset>
-AssetMap::asset_from_id (string id) const
-{
- for (list<shared_ptr<AssetMapAsset> >::const_iterator i = assets.begin (); i != assets.end(); ++i) {
- if ((*i)->id == id) {
- return *i;
- }
- }
-
- return shared_ptr<AssetMapAsset> ();
-}
+++ /dev/null
-/*
- Copyright (C) 2012 Carl Hetherington <cth@carlh.net>
-
- 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 <stdint.h>
-#include <boost/shared_ptr.hpp>
-#include <libcxml/cxml.h>
-
-namespace libdcp {
-
-namespace parse {
-
-/** @class Chunk
- * @brief A simple parser for and representation of a \<Chunk\> node within an asset map.
- */
-class Chunk
-{
-public:
- Chunk ();
- Chunk (boost::shared_ptr<const cxml::Node> 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 \<AssetMap\> node within an asset map.
- */
-class AssetMapAsset
-{
-public:
- AssetMapAsset ();
- AssetMapAsset (boost::shared_ptr<const cxml::Node> node);
-
- std::string id;
- std::string packing_list;
- std::list<boost::shared_ptr<Chunk> > 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<AssetMapAsset> 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<boost::shared_ptr<AssetMapAsset> > assets;
-};
-
-}
-
-}
+++ /dev/null
-/*
- Copyright (C) 2012 Carl Hetherington <cth@carlh.net>
-
- 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 <iostream>
-#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::Document f ("CompositionPlaylist");
- f.read_file (file);
-
- 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<ContentVersion> (f, "ContentVersion");
- f.ignore_child ("RatingList");
- reels = type_grand_children<Reel> (f, "ReelList", "Reel");
-
- f.ignore_child ("Issuer");
- f.ignore_child ("Signer");
- f.ignore_child ("Signature");
-
- f.done ();
-}
-
-ContentVersion::ContentVersion (shared_ptr<const cxml::Node> node)
-{
- id = node->optional_string_child ("Id").get_value_or ("");
- label_text = node->string_child ("LabelText");
- node->done ();
-}
-
-Reel::Reel (shared_ptr<const cxml::Node> node)
-{
- id = node->string_child ("Id");
- asset_list = type_child<CPLAssetList> (node, "AssetList");
-
- node->ignore_child ("AnnotationText");
- node->done ();
-}
-
-CPLAssetList::CPLAssetList (shared_ptr<const cxml::Node> node)
-{
- main_picture = optional_type_child<MainPicture> (node, "MainPicture");
- main_stereoscopic_picture = optional_type_child<MainStereoscopicPicture> (node, "MainStereoscopicPicture");
- main_sound = optional_type_child<MainSound> (node, "MainSound");
- main_subtitle = optional_type_child<MainSubtitle> (node, "MainSubtitle");
-
- node->done ();
-}
-
-MainPicture::MainPicture (shared_ptr<const cxml::Node> node)
- : Picture (node)
-{
-
-}
-
-MainStereoscopicPicture::MainStereoscopicPicture (shared_ptr<const cxml::Node> node)
- : Picture (node)
-{
-
-}
-
-Picture::Picture (shared_ptr<const cxml::Node> 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<int64_t> ("IntrinsicDuration");
- entry_point = node->number_child<int64_t> ("EntryPoint");
- duration = node->number_child<int64_t> ("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<float> ("ScreenAspectRatio");
- screen_aspect_ratio = Fraction (f * 1000, 1000);
- } catch (bad_cast& e) {
-
- }
-
- key_id = node->optional_string_child ("KeyId").get_value_or ("");
-
- node->ignore_child ("Hash");
-
- node->done ();
-}
-
-MainSound::MainSound (shared_ptr<const cxml::Node> 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<int64_t> ("IntrinsicDuration");
- entry_point = node->number_child<int64_t> ("EntryPoint");
- duration = node->number_child<int64_t> ("Duration");
- key_id = node->optional_string_child ("KeyId").get_value_or ("");
-
- node->ignore_child ("Hash");
- node->ignore_child ("Language");
-
- node->done ();
-}
-
-MainSubtitle::MainSubtitle (shared_ptr<const cxml::Node> 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<int64_t> ("IntrinsicDuration");
- entry_point = node->number_child<int64_t> ("EntryPoint");
- duration = node->number_child<int64_t> ("Duration");
-
- node->ignore_child ("Hash");
- node->ignore_child ("Language");
-
- node->done ();
-}
+++ /dev/null
-/*
- Copyright (C) 2012 Carl Hetherington <cth@carlh.net>
-
- 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 <stdint.h>
-#include <boost/shared_ptr.hpp>
-#include <libcxml/cxml.h>
-#include "../types.h"
-
-namespace libdcp {
-
-namespace parse {
-
-/** @brief A simple representation of a CPL \<Picture\> node */
-class Picture
-{
-public:
- Picture () {}
- Picture (boost::shared_ptr<const cxml::Node> 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;
- std::string key_id;
-};
-
-
-/** @brief A simple parser for and representation of a CPL \<MainPicture\> node */
-class MainPicture : public Picture
-{
-public:
- MainPicture () {}
- MainPicture (boost::shared_ptr<const cxml::Node> node);
-};
-
-/** @brief A simple parser for and representation of a CPL \<MainStereoscopicPicture\> node */
-class MainStereoscopicPicture : public Picture
-{
-public:
- MainStereoscopicPicture () {}
- MainStereoscopicPicture (boost::shared_ptr<const cxml::Node> node);
-};
-
-/** @brief A simple parser for and representation of a CPL \<MainSound\> node */
-class MainSound
-{
-public:
- MainSound () {}
- MainSound (boost::shared_ptr<const cxml::Node> node);
-
- std::string id;
- std::string annotation_text;
- Fraction edit_rate;
- int64_t intrinsic_duration;
- int64_t entry_point;
- int64_t duration;
- std::string key_id;
-};
-
-/** @brief A simple parser for and representation of a CPL \<MainSubtitle\> node */
-class MainSubtitle
-{
-public:
- MainSubtitle () {}
- MainSubtitle (boost::shared_ptr<const cxml::Node> 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 \<AssetList\> node */
-class CPLAssetList
-{
-public:
- CPLAssetList () {}
- CPLAssetList (boost::shared_ptr<const cxml::Node> node);
-
- boost::shared_ptr<MainPicture> main_picture;
- boost::shared_ptr<MainStereoscopicPicture> main_stereoscopic_picture;
- boost::shared_ptr<MainSound> main_sound;
- boost::shared_ptr<MainSubtitle> main_subtitle;
-};
-
-/** @brief A simple parser for and representation of a CPL \<Reel\> node */
-class Reel
-{
-public:
- Reel () {}
- Reel (boost::shared_ptr<const cxml::Node> node);
-
- std::string id;
- boost::shared_ptr<CPLAssetList> asset_list;
-};
-
-
-/** @brief A simple parser for and representation of a CPL \<ContentVersion\> node */
-class ContentVersion
-{
-public:
- ContentVersion () {}
- ContentVersion (boost::shared_ptr<const cxml::Node> 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<ContentVersion> content_version;
- std::list<boost::shared_ptr<Reel> > reels;
-};
-
-}
-
-}
-
+++ /dev/null
-/*
- Copyright (C) 2012 Carl Hetherington <cth@carlh.net>
-
- 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 <iostream>
-#include "pkl.h"
-
-using namespace std;
-using namespace boost;
-using namespace libdcp::parse;
-
-PKL::PKL (string file)
-{
- cxml::Document f ("PackingList");
- f.read_file (file);
-
- 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<PKLAsset> (f, "AssetList", "Asset");
-}
-
-PKLAsset::PKLAsset (boost::shared_ptr<const cxml::Node> 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<int64_t> ("Size");
- type = node->string_child ("Type");
- original_file_name = node->optional_string_child ("OriginalFileName").get_value_or ("");
-}
+++ /dev/null
-/*
- Copyright (C) 2012 Carl Hetherington <cth@carlh.net>
-
- 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 <boost/shared_ptr.hpp>
-#include "../xml.h"
-
-namespace libdcp {
-
-namespace parse {
-
-class PKLAsset
-{
-public:
- PKLAsset () {}
- PKLAsset (boost::shared_ptr<const cxml::Node>);
-
- 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<boost::shared_ptr<PKLAsset> > assets;
-};
-
-}
-
-}
+++ /dev/null
-/*
- Copyright (C) 2012-2013 Carl Hetherington <cth@carlh.net>
-
- 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 <boost/shared_ptr.hpp>
-#include <boost/optional.hpp>
-#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<const cxml::Node> node)
-{
- text = node->content ();
-
- id = node->optional_string_attribute ("Id").get_value_or ("");
- size = node->optional_number_attribute<int64_t> ("Size").get_value_or (0);
- italic = node->optional_bool_attribute ("Italic");
- optional<string> c = node->optional_string_attribute ("Color");
- if (c) {
- color = Color (c.get ());
- }
- optional<string> 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<Subtitle> (node, "Subtitle");
- font_nodes = type_children<Font> (node, "Font");
- text_nodes = type_children<Text> (node, "Text");
-}
-
-Font::Font (list<shared_ptr<Font> > const & font_nodes)
- : size (0)
- , italic (false)
- , color ("FFFFFFFF")
- , effect_color ("FFFFFFFF")
-{
- for (list<shared_ptr<Font> >::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<const cxml::Node> node)
-{
- optional<string> x = node->optional_string_attribute ("Id");
- if (!x) {
- x = node->optional_string_attribute ("ID");
- }
- id = x.get_value_or ("");
-
- uri = node->optional_string_attribute ("URI");
-}
-
-Subtitle::Subtitle (shared_ptr<const cxml::Node> node)
-{
- in = Time (node->string_attribute ("TimeIn"));
- out = Time (node->string_attribute ("TimeOut"));
- font_nodes = type_children<Font> (node, "Font");
- text_nodes = type_children<Text> (node, "Text");
- fade_up_time = fade_time (node, "FadeUpTime");
- fade_down_time = fade_time (node, "FadeDownTime");
-}
-
-Time
-Subtitle::fade_time (shared_ptr<const cxml::Node> 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<int> (u));
- }
-
- if (t > Time (0, 0, 8, 0)) {
- t = Time (0, 0, 8, 0);
- }
-
- return t;
-}
-
-Text::Text (shared_ptr<const cxml::Node> node)
- : v_align (CENTER)
-{
- /* Vertical position */
- text = node->content ();
- optional<float> x = node->optional_number_attribute<float> ("VPosition");
- if (!x) {
- x = node->number_attribute<float> ("Vposition");
- }
- v_position = x.get ();
-
- /* Vertical alignment */
- optional<string> v = node->optional_string_attribute ("VAlign");
- if (!v) {
- v = node->optional_string_attribute ("Valign");
- }
- if (v) {
- v_align = string_to_valign (v.get ());
- }
-
- font_nodes = type_children<Font> (node, "Font");
-}
-
+++ /dev/null
-/*
- Copyright (C) 2012 Carl Hetherington <cth@carlh.net>
-
- 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 ()
- : v_position (0)
- , v_align (TOP)
- {}
-
- Text (boost::shared_ptr<const cxml::Node> node);
-
- float v_position;
- VAlign v_align;
- std::string text;
- std::list<boost::shared_ptr<Font> > font_nodes;
-};
-
-class Subtitle
-{
-public:
- Subtitle () {}
- Subtitle (boost::shared_ptr<const cxml::Node> node);
-
- Time in;
- Time out;
- Time fade_up_time;
- Time fade_down_time;
- std::list<boost::shared_ptr<Font> > font_nodes;
- std::list<boost::shared_ptr<Text> > text_nodes;
-
-private:
- Time fade_time (boost::shared_ptr<const cxml::Node>, std::string name);
-};
-
-class Font
-{
-public:
- Font ()
- : size (0)
- {}
-
- Font (boost::shared_ptr<const cxml::Node> node);
- Font (std::list<boost::shared_ptr<Font> > const & font_nodes);
-
- std::string text;
- std::string id;
- int size;
- boost::optional<bool> italic;
- boost::optional<Color> color;
- boost::optional<Effect> effect;
- boost::optional<Color> effect_color;
-
- std::list<boost::shared_ptr<Subtitle> > subtitle_nodes;
- std::list<boost::shared_ptr<Font> > font_nodes;
- std::list<boost::shared_ptr<Text> > text_nodes;
-};
-
-class LoadFont
-{
-public:
- LoadFont () {}
- LoadFont (boost::shared_ptr<const cxml::Node> node);
-
- std::string id;
- boost::optional<std::string> uri;
-};
-
-}
-
-}
+++ /dev/null
-/*
- Copyright (C) 2012 Carl Hetherington <cth@carlh.net>
-
- 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/picture_asset.cc
- * @brief An asset made up of JPEG2000 files
- */
-
-#include <list>
-#include <stdexcept>
-#include <iostream>
-#include <sstream>
-#include <boost/filesystem.hpp>
-#include <boost/lexical_cast.hpp>
-#include <openjpeg.h>
-#include <libxml++/nodes/element.h>
-#include "AS_DCP.h"
-#include "KM_fileio.h"
-#include "picture_asset.h"
-#include "util.h"
-#include "exceptions.h"
-#include "xyz_frame.h"
-#include "picture_asset_writer.h"
-
-using std::string;
-using std::ostream;
-using std::list;
-using std::vector;
-using std::max;
-using std::stringstream;
-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;
-using namespace libdcp;
-
-PictureAsset::PictureAsset (boost::filesystem::path directory, boost::filesystem::path mxf_name)
- : MXFAsset (directory, mxf_name)
-{
-
-}
-
-void
-PictureAsset::write_to_cpl (xmlpp::Element* node) const
-{
- MXFAsset::write_to_cpl (node);
-
- xmlpp::Node::NodeList c = node->get_children ();
- xmlpp::Node::NodeList::iterator i = c.begin();
- while (i != c.end() && (*i)->get_name() != cpl_node_name ()) {
- ++i;
- }
-
- assert (i != c.end ());
-
- (*i)->add_child ("FrameRate")->add_child_text (lexical_cast<string> (_edit_rate * edit_rate_factor ()) + " 1");
- if (_interop) {
- stringstream s;
- s << std::fixed << std::setprecision (2) << (float (_size.width) / _size.height);
- (*i)->add_child ("ScreenAspectRatio")->add_child_text (s.str ());
- } else {
- (*i)->add_child ("ScreenAspectRatio")->add_child_text (lexical_cast<string> (_size.width) + " " + lexical_cast<string> (_size.height));
- }
-}
-
-bool
-PictureAsset::descriptor_equals (
- ASDCP::JP2K::PictureDescriptor const & a, ASDCP::JP2K::PictureDescriptor const & b, boost::function<void (NoteType, string)> note
- ) const
-{
- if (
- a.EditRate != b.EditRate ||
- a.SampleRate != b.SampleRate ||
- a.StoredWidth != b.StoredWidth ||
- a.StoredHeight != b.StoredHeight ||
- a.AspectRatio != b.AspectRatio ||
- a.Rsize != b.Rsize ||
- a.Xsize != b.Xsize ||
- a.Ysize != b.Ysize ||
- a.XOsize != b.XOsize ||
- a.YOsize != b.YOsize ||
- a.XTsize != b.XTsize ||
- a.YTsize != b.YTsize ||
- a.XTOsize != b.XTOsize ||
- a.YTOsize != b.YTOsize ||
- a.Csize != b.Csize
-// a.CodingStyleDefault != b.CodingStyleDefault ||
-// a.QuantizationDefault != b.QuantizationDefault
- ) {
-
- note (ERROR, "video MXF picture descriptors differ");
- return false;
- }
-
- if (a.ContainerDuration != b.ContainerDuration) {
- note (ERROR, "video container durations differ");
- }
-
-// for (unsigned int j = 0; j < ASDCP::JP2K::MaxComponents; ++j) {
-// if (a.ImageComponents[j] != b.ImageComponents[j]) {
-// notes.pack_start ("video MXF picture descriptors differ");
-// }
-// }
-
- return true;
-}
-
-bool
-PictureAsset::frame_buffer_equals (
- int frame, EqualityOptions opt, boost::function<void (NoteType, string)> 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) {
- note (NOTE, "J2K identical");
- /* Easy result; the J2K data is identical */
- return true;
- }
-
- /* Decompress the images to bitmaps */
- shared_ptr<XYZFrame> image_A = decompress_j2k (const_cast<uint8_t*> (data_A), size_A, 0);
- shared_ptr<XYZFrame> image_B = decompress_j2k (const_cast<uint8_t*> (data_B), size_B, 0);
-
- /* Compare them */
-
- vector<int> abs_diffs (image_A->size().width * image_A->size().height * 3);
- int d = 0;
- int max_diff = 0;
-
- for (int c = 0; c < 3; ++c) {
-
- if (image_A->size() != image_B->size()) {
- note (ERROR, "image sizes for frame " + lexical_cast<string>(frame) + " differ");
- return false;
- }
-
- int const pixels = image_A->size().width * image_A->size().height;
- for (int j = 0; j < pixels; ++j) {
- int const t = abs (image_A->data(c)[j] - image_B->data(c)[j]);
- abs_diffs[d++] = t;
- max_diff = max (max_diff, t);
- }
- }
-
- uint64_t total = 0;
- for (vector<int>::iterator j = abs_diffs.begin(); j != abs_diffs.end(); ++j) {
- total += *j;
- }
-
- double const mean = double (total) / abs_diffs.size ();
-
- uint64_t total_squared_deviation = 0;
- for (vector<int>::iterator j = abs_diffs.begin(); j != abs_diffs.end(); ++j) {
- total_squared_deviation += pow (*j - mean, 2);
- }
-
- double const std_dev = sqrt (double (total_squared_deviation) / abs_diffs.size());
-
- note (NOTE, "mean difference " + lexical_cast<string> (mean) + ", deviation " + lexical_cast<string> (std_dev));
-
- if (mean > opt.max_mean_pixel_error) {
- note (
- ERROR,
- "mean " + lexical_cast<string>(mean) +
- " out of range " + lexical_cast<string>(opt.max_mean_pixel_error) +
- " in frame " + lexical_cast<string>(frame)
- );
-
- return false;
- }
-
- if (std_dev > opt.max_std_dev_pixel_error) {
- note (
- ERROR,
- "standard deviation " + lexical_cast<string>(std_dev) +
- " out of range " + lexical_cast<string>(opt.max_std_dev_pixel_error) +
- " in frame " + lexical_cast<string>(frame)
- );
-
- return false;
- }
-
- return true;
-}
-
-string
-PictureAsset::key_type () const
-{
- return "MDIK";
-}
-
-
-
+++ /dev/null
-/*
- Copyright (C) 2012 Carl Hetherington <cth@carlh.net>
-
- 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_PICTURE_ASSET_H
-#define LIBDCP_PICTURE_ASSET_H
-
-/** @file src/picture_asset.h
- * @brief An asset made up of JPEG2000 data
- */
-
-#include <openjpeg.h>
-#include "mxf_asset.h"
-#include "util.h"
-#include "metadata.h"
-
-namespace ASDCP {
- namespace JP2K {
- class PictureDescriptor;
- }
-}
-
-namespace libdcp
-{
-
-class MonoPictureFrame;
-class StereoPictureFrame;
-class PictureAssetWriter;
-
-/** @brief An asset made up of JPEG2000 data */
-class PictureAsset : public MXFAsset
-{
-public:
- /** Construct a PictureAsset.
- *
- * @param directory Directory where MXF file is.
- * @param mxf_name Name of MXF file.
- */
- PictureAsset (boost::filesystem::path directory, boost::filesystem::path mxf_name);
-
- /** Start a progressive write to this asset.
- * The following parameters must be set up (if required) before calling this:
- * Interop mode (set_interop)
- * Edit rate (set_edit_rate)
- * MXF Metadata (set_metadata)
- *
- * @param overwrite true to overwrite an existing MXF file; in this mode, writing can be resumed to a partially-written MXF; false if the
- * MXF file does not exist.
- */
- virtual boost::shared_ptr<PictureAssetWriter> start_write (bool overwrite) = 0;
-
- virtual void read () = 0;
- virtual void create (std::vector<boost::filesystem::path> const &) {}
- virtual void create (boost::function<boost::filesystem::path (int)>) {}
-
- Size size () const {
- return _size;
- }
-
- void set_size (Size s) {
- _size = s;
- }
-
- void write_to_cpl (xmlpp::Element *) const;
-
-protected:
-
- std::string asdcp_kind () const {
- return "Picture";
- }
-
- bool frame_buffer_equals (
- int frame, EqualityOptions opt, boost::function<void (NoteType, std::string)> note,
- uint8_t const * data_A, unsigned int size_A, uint8_t const * data_B, unsigned int size_B
- ) const;
-
- bool descriptor_equals (
- ASDCP::JP2K::PictureDescriptor const & a, ASDCP::JP2K::PictureDescriptor const & b, boost::function<void (NoteType, std::string)>
- ) const;
-
- /** picture size in pixels */
- Size _size;
-
-private:
- std::string key_type () const;
- virtual int edit_rate_factor () const = 0;
-};
-
-
-}
-
-#endif
+++ /dev/null
-/*
- Copyright (C) 2012-2013 Carl Hetherington <cth@carlh.net>
-
- 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 <inttypes.h>
-#include <stdint.h>
-#include "AS_DCP.h"
-#include "KM_fileio.h"
-#include "picture_asset_writer.h"
-#include "exceptions.h"
-#include "picture_asset.h"
-
-using std::istream;
-using std::ostream;
-using std::string;
-using boost::shared_ptr;
-using namespace libdcp;
-
-FrameInfo::FrameInfo (istream& s)
- : offset (0)
- , size (0)
-{
- s >> offset >> size;
-
- if (!s.good ()) {
- /* Make sure we zero these if something bad happened, otherwise
- the caller might try to alloc lots of RAM.
- */
- offset = size = 0;
- }
-
- s >> hash;
-}
-
-FrameInfo::FrameInfo (FILE* f)
-{
-#ifdef LIBDCP_WINDOWS
- fscanf (f, "%I64u", &offset);
- fscanf (f, "%I64u", &size);
-#else
- fscanf (f, "%" SCNu64, &offset);
- fscanf (f, "%" SCNu64, &size);
-#endif
-
- if (ferror (f)) {
- offset = size = 0;
- }
-
- char hash_buffer[128];
- fscanf (f, "%s", hash_buffer);
- hash = hash_buffer;
-}
-
-void
-FrameInfo::write (ostream& s) const
-{
- s << offset << " " << size << " " << hash;
-}
-
-void
-FrameInfo::write (FILE* f) const
-{
-#ifdef LIBDCP_WINDOWS
- fprintf (f, "%I64u %I64u %s", offset, size, hash.c_str ());
-#else
- fprintf (f, "%" PRIu64 " %" PRIu64 " %s", offset, size, hash.c_str ());
-#endif
-}
-
-
-PictureAssetWriter::PictureAssetWriter (PictureAsset* asset, bool overwrite)
- : _asset (asset)
- , _frames_written (0)
- , _started (false)
- , _finalized (false)
- , _overwrite (overwrite)
-{
-
-}
+++ /dev/null
-/*
- Copyright (C) 2012-2013 Carl Hetherington <cth@carlh.net>
-
- 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 <stdint.h>
-#include <string>
-#include <fstream>
-#include <boost/shared_ptr.hpp>
-#include <boost/utility.hpp>
-#include "metadata.h"
-#include "types.h"
-
-namespace libdcp {
-
-class PictureAsset;
-
-/** Information about a single frame (either a monoscopic frame or a left *or* right eye stereoscopic frame) */
-struct FrameInfo
-{
- FrameInfo (uint64_t o, uint64_t s, std::string h)
- : offset (o)
- , size (s)
- , hash (h)
- {}
-
- FrameInfo (std::istream& s);
- FrameInfo (FILE *);
-
- void write (std::ostream& s) const;
- void write (FILE *) const;
-
- uint64_t offset;
- uint64_t size;
- std::string hash;
-};
-
-class PictureAssetWriter : public boost::noncopyable
-{
-public:
- virtual ~PictureAssetWriter () {}
- virtual FrameInfo write (uint8_t *, int) = 0;
- virtual void finalize () = 0;
- virtual void fake_write (int) = 0;
-
-protected:
- template <class P, class Q>
- friend void start (PictureAssetWriter *, boost::shared_ptr<P>, Q *, uint8_t *, int);
-
- PictureAssetWriter (PictureAsset *, bool);
-
- PictureAsset* _asset;
-
- /** Number of picture frames written to the asset so far. For stereo assets
- * this will be incremented for each eye (i.e. there will be twice the number
- * of frames as in a mono asset).
- */
- int _frames_written;
- bool _started;
- /** true if finalize() has been called */
- bool _finalized;
- bool _overwrite;
-};
-
-}
+++ /dev/null
-/*
- Copyright (C) 2012-2013 Carl Hetherington <cth@carlh.net>
-
- 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.
-
-*/
-
-using boost::shared_ptr;
-
-struct ASDCPStateBase
-{
- ASDCPStateBase ()
- : frame_buffer (4 * Kumu::Megabyte)
- {}
-
- ASDCP::JP2K::CodestreamParser j2k_parser;
- ASDCP::JP2K::FrameBuffer frame_buffer;
- ASDCP::WriterInfo writer_info;
- ASDCP::JP2K::PictureDescriptor picture_descriptor;
- ASDCP::AESEncContext* encryption_context;
-};
-
-template <class P, class Q>
-void libdcp::start (PictureAssetWriter* writer, shared_ptr<P> state, Q* asset, uint8_t* data, int size)
-{
- if (ASDCP_FAILURE (state->j2k_parser.OpenReadFrame (data, size, state->frame_buffer))) {
- boost::throw_exception (MiscError ("could not parse J2K frame"));
- }
-
- state->j2k_parser.FillPictureDescriptor (state->picture_descriptor);
- state->picture_descriptor.EditRate = ASDCP::Rational (asset->edit_rate(), 1);
-
- asset->fill_writer_info (&state->writer_info);
-
- Kumu::Result_t r = state->mxf_writer.OpenWrite (
- asset->path().string().c_str(),
- state->writer_info,
- state->picture_descriptor,
- 16384,
- writer->_overwrite
- );
-
- if (ASDCP_FAILURE (r)) {
- boost::throw_exception (MXFFileError ("could not open MXF file for writing", asset->path().string(), r));
- }
-
- writer->_started = true;
-}
--- /dev/null
+/*
+ Copyright (C) 2012-2014 Carl Hetherington <cth@carlh.net>
+
+ 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 "picture_mxf.h"
+#include "util.h"
+#include "exceptions.h"
+#include "xyz_frame.h"
+#include "picture_mxf_writer.h"
+#include "compose.hpp"
+#include "AS_DCP.h"
+#include "KM_fileio.h"
+#include <libxml++/nodes/element.h>
+#include <openjpeg.h>
+#include <boost/filesystem.hpp>
+#include <list>
+#include <stdexcept>
+#include <iostream>
+#include <sstream>
+
+using std::string;
+using std::ostream;
+using std::list;
+using std::vector;
+using std::max;
+using std::stringstream;
+using std::pair;
+using std::make_pair;
+using std::istream;
+using std::cout;
+using boost::shared_ptr;
+using namespace dcp;
+
+PictureMXF::PictureMXF (boost::filesystem::path file)
+ : MXF (file)
+{
+
+}
+
+PictureMXF::PictureMXF (Fraction edit_rate)
+ : MXF (edit_rate)
+{
+
+}
+
+void
+PictureMXF::read_picture_descriptor (ASDCP::JP2K::PictureDescriptor const & desc)
+{
+ _size.width = desc.StoredWidth;
+ _size.height = desc.StoredHeight;
+ _edit_rate = Fraction (desc.EditRate.Numerator, desc.EditRate.Denominator);
+ _intrinsic_duration = desc.ContainerDuration;
+ _frame_rate = Fraction (desc.SampleRate.Numerator, desc.SampleRate.Denominator);
+ _screen_aspect_ratio = Fraction (desc.AspectRatio.Numerator, desc.AspectRatio.Denominator);
+}
+
+bool
+PictureMXF::descriptor_equals (
+ ASDCP::JP2K::PictureDescriptor const & a, ASDCP::JP2K::PictureDescriptor const & b, boost::function<void (NoteType, string)> note
+ ) const
+{
+ if (
+ a.EditRate != b.EditRate ||
+ a.SampleRate != b.SampleRate ||
+ a.StoredWidth != b.StoredWidth ||
+ a.StoredHeight != b.StoredHeight ||
+ a.AspectRatio != b.AspectRatio ||
+ a.Rsize != b.Rsize ||
+ a.Xsize != b.Xsize ||
+ a.Ysize != b.Ysize ||
+ a.XOsize != b.XOsize ||
+ a.YOsize != b.YOsize ||
+ a.XTsize != b.XTsize ||
+ a.YTsize != b.YTsize ||
+ a.XTOsize != b.XTOsize ||
+ a.YTOsize != b.YTOsize ||
+ a.Csize != b.Csize
+// a.CodingStyleDefault != b.CodingStyleDefault ||
+// a.QuantizationDefault != b.QuantizationDefault
+ ) {
+
+ note (ERROR, "video MXF picture descriptors differ");
+ return false;
+ }
+
+ if (a.ContainerDuration != b.ContainerDuration) {
+ note (ERROR, "video container durations differ");
+ }
+
+// for (unsigned int j = 0; j < ASDCP::JP2K::MaxComponents; ++j) {
+// if (a.ImageComponents[j] != b.ImageComponents[j]) {
+// notes.pack_start ("video MXF picture descriptors differ");
+// }
+// }
+
+ return true;
+}
+
+bool
+PictureMXF::frame_buffer_equals (
+ int frame, EqualityOptions opt, boost::function<void (NoteType, string)> 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) {
+ note (NOTE, "J2K identical");
+ /* Easy result; the J2K data is identical */
+ return true;
+ }
+
+ /* Decompress the images to bitmaps */
+ shared_ptr<XYZFrame> image_A = decompress_j2k (const_cast<uint8_t*> (data_A), size_A, 0);
+ shared_ptr<XYZFrame> image_B = decompress_j2k (const_cast<uint8_t*> (data_B), size_B, 0);
+
+ /* Compare them */
+
+ vector<int> abs_diffs (image_A->size().width * image_A->size().height * 3);
+ int d = 0;
+ int max_diff = 0;
+
+ for (int c = 0; c < 3; ++c) {
+
+ if (image_A->size() != image_B->size()) {
+ note (ERROR, String::compose ("image sizes for frame %1 differ", frame));
+ return false;
+ }
+
+ int const pixels = image_A->size().width * image_A->size().height;
+ for (int j = 0; j < pixels; ++j) {
+ int const t = abs (image_A->data(c)[j] - image_B->data(c)[j]);
+ abs_diffs[d++] = t;
+ max_diff = max (max_diff, t);
+ }
+ }
+
+ uint64_t total = 0;
+ for (vector<int>::iterator j = abs_diffs.begin(); j != abs_diffs.end(); ++j) {
+ total += *j;
+ }
+
+ double const mean = double (total) / abs_diffs.size ();
+
+ uint64_t total_squared_deviation = 0;
+ for (vector<int>::iterator j = abs_diffs.begin(); j != abs_diffs.end(); ++j) {
+ total_squared_deviation += pow (*j - mean, 2);
+ }
+
+ double const std_dev = sqrt (double (total_squared_deviation) / abs_diffs.size());
+
+ note (NOTE, String::compose ("mean difference %1, deviation %2", mean, std_dev));
+
+ if (mean > opt.max_mean_pixel_error) {
+ note (
+ ERROR,
+ String::compose ("mean %1 out of range %2 in frame %3", mean, opt.max_mean_pixel_error, frame)
+ );
+
+ return false;
+ }
+
+ if (std_dev > opt.max_std_dev_pixel_error) {
+ note (
+ ERROR,
+ String::compose ("standard deviation %1 out of range %2 in frame %3", std_dev, opt.max_std_dev_pixel_error, frame)
+ );
+
+ return false;
+ }
+
+ return true;
+}
+
+string
+PictureMXF::key_type () const
+{
+ return "MDIK";
+}
--- /dev/null
+/*
+ Copyright (C) 2012-2014 Carl Hetherington <cth@carlh.net>
+
+ 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_PICTURE_MXF_H
+#define LIBDCP_PICTURE_MXF_H
+
+/** @file src/picture_mxf.h
+ * @brief PictureMXF class.
+ */
+
+#include "mxf.h"
+#include "util.h"
+#include "metadata.h"
+#include <openjpeg.h>
+
+namespace ASDCP {
+ namespace JP2K {
+ class PictureDescriptor;
+ }
+}
+
+namespace dcp
+{
+
+class MonoPictureFrame;
+class StereoPictureFrame;
+class PictureMXFWriter;
+
+/** @class PictureMXF
+ * @brief An asset made up of JPEG2000 data.
+ */
+class PictureMXF : public MXF
+{
+public:
+ PictureMXF (boost::filesystem::path file);
+ PictureMXF (Fraction edit_rate);
+
+ virtual boost::shared_ptr<PictureMXFWriter> start_write (
+ boost::filesystem::path file,
+ Standard standard,
+ bool overwrite
+ ) = 0;
+
+ Size size () const {
+ return _size;
+ }
+
+ void set_size (Size s) {
+ _size = s;
+ }
+
+ Fraction frame_rate () const {
+ return _frame_rate;
+ }
+
+ void set_frame_rate (Fraction r) {
+ _frame_rate = r;
+ }
+
+ Fraction screen_aspect_ratio () const {
+ return _screen_aspect_ratio;
+ }
+
+ void set_screen_aspect_ratio (Fraction r) {
+ _screen_aspect_ratio = r;
+ }
+
+protected:
+
+ bool frame_buffer_equals (
+ int frame, EqualityOptions opt, boost::function<void (NoteType, std::string)> note,
+ uint8_t const * data_A, unsigned int size_A, uint8_t const * data_B, unsigned int size_B
+ ) const;
+
+ bool descriptor_equals (
+ ASDCP::JP2K::PictureDescriptor const & a,
+ ASDCP::JP2K::PictureDescriptor const & b,
+ boost::function<void (NoteType, std::string)>
+ ) const;
+
+ void read_picture_descriptor (ASDCP::JP2K::PictureDescriptor const &);
+
+ /** picture size in pixels */
+ Size _size;
+ Fraction _frame_rate;
+ Fraction _screen_aspect_ratio;
+
+private:
+ std::string key_type () const;
+ std::string asdcp_kind () const {
+ return "Picture";
+ }
+};
+
+
+}
+
+#endif
--- /dev/null
+/*
+ Copyright (C) 2012-2014 Carl Hetherington <cth@carlh.net>
+
+ 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 "KM_fileio.h"
+#include "picture_mxf_writer.h"
+#include "exceptions.h"
+#include "picture_mxf.h"
+#include "AS_DCP.h"
+#include <inttypes.h>
+#include <stdint.h>
+
+using std::istream;
+using std::ostream;
+using std::string;
+using boost::shared_ptr;
+using namespace dcp;
+
+FrameInfo::FrameInfo (istream& s)
+ : offset (0)
+ , size (0)
+{
+ s >> offset >> size;
+
+ if (!s.good ()) {
+ /* Make sure we zero these if something bad happened, otherwise
+ the caller might try to alloc lots of RAM.
+ */
+ offset = size = 0;
+ }
+
+ s >> hash;
+}
+
+FrameInfo::FrameInfo (FILE* f)
+{
+#ifdef LIBDCP_WINDOWS
+ fscanf (f, "%I64u", &offset);
+ fscanf (f, "%I64u", &size);
+#else
+ fscanf (f, "%" SCNu64, &offset);
+ fscanf (f, "%" SCNu64, &size);
+#endif
+
+ if (ferror (f)) {
+ offset = size = 0;
+ }
+
+ char hash_buffer[128];
+ fscanf (f, "%s", hash_buffer);
+ hash = hash_buffer;
+}
+
+void
+FrameInfo::write (ostream& s) const
+{
+ s << offset << " " << size << " " << hash;
+}
+
+void
+FrameInfo::write (FILE* f) const
+{
+#ifdef LIBDCP_WINDOWS
+ fprintf (f, "%I64u %I64u %s", offset, size, hash.c_str ());
+#else
+ fprintf (f, "%" PRIu64 " %" PRIu64 " %s", offset, size, hash.c_str ());
+#endif
+}
+
+PictureMXFWriter::PictureMXFWriter (PictureMXF* mxf, boost::filesystem::path file, Standard standard, bool overwrite)
+ : MXFWriter (mxf, file)
+ , _picture_mxf (mxf)
+ , _started (false)
+ , _standard (standard)
+ , _overwrite (overwrite)
+{
+
+}
--- /dev/null
+/*
+ Copyright (C) 2012-2014 Carl Hetherington <cth@carlh.net>
+
+ 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/picture_mxf_writer.h
+ * @brief PictureMXFWriter and FrameInfo classes.
+ */
+
+#ifndef LIBDCP_PICTURE_MXF_WRITER_H
+#define LIBDCP_PICTURE_MXF_WRITER_H
+
+#include "metadata.h"
+#include "types.h"
+#include "mxf_writer.h"
+#include <boost/shared_ptr.hpp>
+#include <boost/utility.hpp>
+#include <stdint.h>
+#include <string>
+#include <fstream>
+
+namespace dcp {
+
+class PictureMXF;
+
+/** @class FrameInfo
+ * @brief Information about a single frame (either a monoscopic frame or a left *or* right eye stereoscopic frame)
+ */
+struct FrameInfo
+{
+ FrameInfo (uint64_t o, uint64_t s, std::string h)
+ : offset (o)
+ , size (s)
+ , hash (h)
+ {}
+
+ FrameInfo (std::istream& s);
+ FrameInfo (FILE *);
+
+ void write (std::ostream& s) const;
+ void write (FILE *) const;
+
+ uint64_t offset;
+ uint64_t size;
+ std::string hash;
+};
+
+/** @class PictureMXFWriter
+ * @brief Parent class for classes which write picture MXF files.
+ */
+class PictureMXFWriter : public MXFWriter
+{
+public:
+ virtual FrameInfo write (uint8_t *, int) = 0;
+ virtual void fake_write (int) = 0;
+
+protected:
+ template <class P, class Q>
+ friend void start (PictureMXFWriter *, boost::shared_ptr<P>, Standard, Q *, uint8_t *, int);
+
+ PictureMXFWriter (PictureMXF *, boost::filesystem::path, Standard standard, bool);
+
+ PictureMXF* _picture_mxf;
+ bool _started;
+ Standard _standard;
+ bool _overwrite;
+};
+
+}
+
+#endif
--- /dev/null
+/*
+ Copyright (C) 2012-2014 Carl Hetherington <cth@carlh.net>
+
+ 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.
+
+*/
+
+using boost::shared_ptr;
+
+struct ASDCPStateBase
+{
+ ASDCPStateBase ()
+ : frame_buffer (4 * Kumu::Megabyte)
+ {}
+
+ ASDCP::JP2K::CodestreamParser j2k_parser;
+ ASDCP::JP2K::FrameBuffer frame_buffer;
+ ASDCP::WriterInfo writer_info;
+ ASDCP::JP2K::PictureDescriptor picture_descriptor;
+ ASDCP::AESEncContext* encryption_context;
+};
+
+template <class P, class Q>
+void dcp::start (PictureMXFWriter* writer, shared_ptr<P> state, Standard standard, Q* mxf, uint8_t* data, int size)
+{
+ mxf->set_file (writer->_file);
+
+ if (ASDCP_FAILURE (state->j2k_parser.OpenReadFrame (data, size, state->frame_buffer))) {
+ boost::throw_exception (MiscError ("could not parse J2K frame"));
+ }
+
+ state->j2k_parser.FillPictureDescriptor (state->picture_descriptor);
+ state->picture_descriptor.EditRate = ASDCP::Rational (mxf->edit_rate().numerator, mxf->edit_rate().denominator);
+
+ mxf->set_size (Size (state->picture_descriptor.StoredWidth, state->picture_descriptor.StoredHeight));
+ mxf->set_screen_aspect_ratio (Fraction (state->picture_descriptor.AspectRatio.Numerator, state->picture_descriptor.AspectRatio.Denominator));
+
+ mxf->fill_writer_info (&state->writer_info, standard);
+
+ Kumu::Result_t r = state->mxf_writer.OpenWrite (
+ mxf->file().string().c_str(),
+ state->writer_info,
+ state->picture_descriptor,
+ 16384,
+ writer->_overwrite
+ );
+
+ if (ASDCP_FAILURE (r)) {
+ boost::throw_exception (MXFFileError ("could not open MXF file for writing", mxf->file().string(), r));
+ }
+
+ writer->_started = true;
+}
+++ /dev/null
-/*
- Copyright (C) 2012-2013 Carl Hetherington <cth@carlh.net>
-
- 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 "rec709_linearised_gamma_lut.h"
-
-using namespace libdcp;
-
-LUTCache<Rec709LinearisedGammaLUT> Rec709LinearisedGammaLUT::cache;
-
-Rec709LinearisedGammaLUT::Rec709LinearisedGammaLUT (int bits, float gamma)
- : LUT (bits, gamma)
-{
- int const bit_length = pow (2, bits);
- for (int i = 0; i < bit_length; ++i) {
- float const p = static_cast<float> (i) / (bit_length - 1);
- if (p > 0.08125) {
- _lut[i] = pow ((p + 0.099) / 1.099, gamma);
- } else {
- _lut[i] = p / 4.5;
- }
- }
-}
+++ /dev/null
-/*
- Copyright (C) 2012-2013 Carl Hetherington <cth@carlh.net>
-
- 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 "lut.h"
-#include "lut_cache.h"
-
-namespace libdcp {
-
-class Rec709LinearisedGammaLUT : public LUT
-{
-public:
- Rec709LinearisedGammaLUT (int bit_length, float gamma);
- static LUTCache<Rec709LinearisedGammaLUT> cache;
-};
-
-}
/*
- Copyright (C) 2012 Carl Hetherington <cth@carlh.net>
+ Copyright (C) 2014 Carl Hetherington <cth@carlh.net>
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
*/
-#include <libxml++/nodes/element.h>
#include "reel.h"
#include "util.h"
-#include "picture_asset.h"
-#include "mono_picture_asset.h"
-#include "stereo_picture_asset.h"
-#include "sound_asset.h"
-#include "subtitle_asset.h"
+#include "picture_mxf.h"
+#include "mono_picture_mxf.h"
+#include "stereo_picture_mxf.h"
+#include "sound_mxf.h"
+#include "subtitle_content.h"
+#include "reel_mono_picture_asset.h"
+#include "reel_stereo_picture_asset.h"
+#include "reel_sound_asset.h"
+#include "reel_subtitle_asset.h"
#include "kdm.h"
+#include <libxml++/nodes/element.h>
using std::string;
using std::list;
using std::cout;
using boost::shared_ptr;
using boost::dynamic_pointer_cast;
-using namespace libdcp;
+using namespace dcp;
+
+Reel::Reel (boost::shared_ptr<const cxml::Node> node)
+ : Object (node->string_child ("Id"))
+{
+ shared_ptr<cxml::Node> asset_list = node->node_child ("AssetList");
+
+ shared_ptr<cxml::Node> main_picture = asset_list->optional_node_child ("MainPicture");
+ if (main_picture) {
+ _main_picture.reset (new ReelMonoPictureAsset (main_picture));
+ }
+
+ shared_ptr<cxml::Node> main_stereoscopic_picture = asset_list->optional_node_child ("MainStereoscopicPicture");
+ if (main_stereoscopic_picture) {
+ _main_picture.reset (new ReelStereoPictureAsset (main_stereoscopic_picture));
+ }
+
+ shared_ptr<cxml::Node> main_sound = asset_list->optional_node_child ("MainSound");
+ if (main_sound) {
+ _main_sound.reset (new ReelSoundAsset (main_sound));
+ }
+
+ shared_ptr<cxml::Node> main_subtitle = asset_list->optional_node_child ("MainSubtitle");
+ if (main_subtitle) {
+ _main_subtitle.reset (new ReelSubtitleAsset (main_subtitle));
+ }
+
+ node->ignore_child ("AnnotationText");
+ node->done ();
+}
void
-Reel::write_to_cpl (xmlpp::Element* node) const
+Reel::write_to_cpl (xmlpp::Element* node, Standard standard) const
{
xmlpp::Element* reel = node->add_child ("Reel");
reel->add_child("Id")->add_child_text ("urn:uuid:" + make_uuid());
xmlpp::Element* asset_list = reel->add_child ("AssetList");
- if (_main_picture && dynamic_pointer_cast<MonoPictureAsset> (_main_picture)) {
+ if (_main_picture && dynamic_pointer_cast<ReelMonoPictureAsset> (_main_picture)) {
/* Mono pictures come before other stuff... */
- _main_picture->write_to_cpl (asset_list);
+ _main_picture->write_to_cpl (asset_list, standard);
}
if (_main_sound) {
- _main_sound->write_to_cpl (asset_list);
+ _main_sound->write_to_cpl (asset_list, standard);
}
if (_main_subtitle) {
- _main_subtitle->write_to_cpl (asset_list);
+ _main_subtitle->write_to_cpl (asset_list, standard);
}
- if (_main_picture && dynamic_pointer_cast<StereoPictureAsset> (_main_picture)) {
+ if (_main_picture && dynamic_pointer_cast<ReelStereoPictureAsset> (_main_picture)) {
/* ... but stereo pictures must come after */
- _main_picture->write_to_cpl (asset_list);
+ _main_picture->write_to_cpl (asset_list, standard);
}
}
}
void
-Reel::add_kdm (KDM const & kdm)
+Reel::add (KDM const & kdm)
{
list<KDMKey> keys = kdm.keys ();
for (list<KDMKey>::iterator i = keys.begin(); i != keys.end(); ++i) {
if (i->key_id() == _main_picture->key_id()) {
- _main_picture->set_key (i->key ());
+ _main_picture->mxf()->set_key (i->key ());
}
if (i->key_id() == _main_sound->key_id()) {
- _main_sound->set_key (i->key ());
+ _main_sound->mxf()->set_key (i->key ());
}
}
}
void
Reel::set_mxf_keys (Key key)
{
- _main_picture->set_key (key);
+ _main_picture->mxf()->set_key (key);
if (_main_sound) {
- _main_sound->set_key (key);
+ _main_sound->mxf()->set_key (key);
}
/* XXX: subtitle asset? */
}
+
+void
+Reel::add (shared_ptr<ReelAsset> asset)
+{
+ shared_ptr<ReelPictureAsset> p = dynamic_pointer_cast<ReelPictureAsset> (asset);
+ shared_ptr<ReelSoundAsset> so = dynamic_pointer_cast<ReelSoundAsset> (asset);
+ shared_ptr<ReelSubtitleAsset> su = dynamic_pointer_cast<ReelSubtitleAsset> (asset);
+ if (p) {
+ _main_picture = p;
+ } else if (so) {
+ _main_sound = so;
+ } else if (su) {
+ _main_subtitle = su;
+ }
+}
+
+void
+Reel::resolve_refs (list<shared_ptr<Object> > objects)
+{
+ if (_main_picture) {
+ _main_picture->content().resolve (objects);
+ }
+
+ if (_main_sound) {
+ _main_sound->content().resolve (objects);
+ }
+
+ if (_main_subtitle) {
+ _main_subtitle->content().resolve (objects);
+ }
+}
/*
- Copyright (C) 2012 Carl Hetherington <cth@carlh.net>
+ Copyright (C) 2012-2014 Carl Hetherington <cth@carlh.net>
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
#ifndef LIBDCP_REEL_H
#define LIBDCP_REEL_H
-#include <list>
-#include <boost/shared_ptr.hpp>
-#include <boost/function.hpp>
-#include <libxml++/libxml++.h>
#include "key.h"
#include "types.h"
+#include "ref.h"
+#include <libxml++/libxml++.h>
+#include <boost/shared_ptr.hpp>
+#include <boost/function.hpp>
+#include <list>
-namespace xmlpp {
+namespace cxml {
class Node;
}
-namespace libdcp {
+namespace dcp {
-class PictureAsset;
-class SoundAsset;
-class SubtitleAsset;
-class KDM;
+class KDM;
+class ReelAsset;
+class ReelPictureAsset;
+class ReelSoundAsset;
+class ReelSubtitleAsset;
+class Content;
-/** @brief A reel within a DCP; the part which actually contains picture, sound and subtitle data */
-class Reel
+/** @brief A reel within a DCP; the part which actually refers to picture, sound and subtitle data */
+class Reel : public Object
{
public:
+ Reel () {}
+
Reel (
- boost::shared_ptr<PictureAsset> picture,
- boost::shared_ptr<SoundAsset> sound,
- boost::shared_ptr<SubtitleAsset> subtitle
+ boost::shared_ptr<ReelPictureAsset> picture,
+ boost::shared_ptr<ReelSoundAsset> sound,
+ boost::shared_ptr<ReelSubtitleAsset> subtitle
)
: _main_picture (picture)
, _main_sound (sound)
, _main_subtitle (subtitle)
{}
+
+ Reel (boost::shared_ptr<const cxml::Node>);
- boost::shared_ptr<const PictureAsset> main_picture () const {
+ boost::shared_ptr<ReelPictureAsset> main_picture () const {
return _main_picture;
}
- boost::shared_ptr<const SoundAsset> main_sound () const {
+ boost::shared_ptr<ReelSoundAsset> main_sound () const {
return _main_sound;
}
- boost::shared_ptr<const SubtitleAsset> main_subtitle () const {
+ boost::shared_ptr<ReelSubtitleAsset> main_subtitle () const {
return _main_subtitle;
}
- void write_to_cpl (xmlpp::Element *) const;
+ void add (boost::shared_ptr<ReelAsset> asset);
+
+ void write_to_cpl (xmlpp::Element* node, Standard standard) const;
bool encrypted () const;
- void set_mxf_keys (libdcp::Key);
+ void set_mxf_keys (dcp::Key);
bool equals (boost::shared_ptr<const Reel> other, EqualityOptions opt, boost::function<void (NoteType, std::string)> notes) const;
- void add_kdm (KDM const &);
+ void add (KDM const &);
+
+ void resolve_refs (std::list<boost::shared_ptr<Object> >);
private:
- boost::shared_ptr<PictureAsset> _main_picture;
- boost::shared_ptr<SoundAsset> _main_sound;
- boost::shared_ptr<SubtitleAsset> _main_subtitle;
+ boost::shared_ptr<ReelPictureAsset> _main_picture;
+ boost::shared_ptr<ReelSoundAsset> _main_sound;
+ boost::shared_ptr<ReelSubtitleAsset> _main_subtitle;
};
}
--- /dev/null
+/*
+ Copyright (C) 2014 Carl Hetherington <cth@carlh.net>
+
+ 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 "reel_asset.h"
+#include "content.h"
+#include "compose.hpp"
+#include <libcxml/cxml.h>
+
+using std::pair;
+using std::string;
+using std::make_pair;
+using boost::shared_ptr;
+using boost::lexical_cast;
+using namespace dcp;
+
+ReelAsset::ReelAsset ()
+ : Object (make_uuid ())
+ , _content (_id)
+ , _edit_rate (Fraction (24, 1))
+ , _intrinsic_duration (0)
+ , _entry_point (0)
+ , _duration (0)
+{
+
+}
+
+/** Construct a ReelAsset.
+ * @param content Content that this asset refers to.
+ * @param entry_point Entry point to use in that content.
+ */
+ReelAsset::ReelAsset (boost::shared_ptr<Content> content, int64_t entry_point)
+ : Object (content->id ())
+ , _content (content)
+ , _edit_rate (content->edit_rate ())
+ , _intrinsic_duration (content->intrinsic_duration ())
+ , _entry_point (entry_point)
+ , _duration (_intrinsic_duration - _entry_point)
+ , _hash (make_digest (content->file (), 0))
+{
+ /* default _annotation_text to the leaf name of our file */
+ _annotation_text = content->file().leaf().string ();
+}
+
+ReelAsset::ReelAsset (boost::shared_ptr<const cxml::Node> node)
+ : Object (node->string_child ("Id"))
+ , _content (_id)
+ , _annotation_text (node->optional_string_child ("AnnotationText").get_value_or (""))
+ , _edit_rate (Fraction (node->string_child ("EditRate")))
+ , _intrinsic_duration (node->number_child<int64_t> ("IntrinsicDuration"))
+ , _entry_point (node->number_child<int64_t> ("EntryPoint"))
+ , _duration (node->number_child<int64_t> ("Duration"))
+ , _hash (node->optional_string_child ("Hash").get_value_or (""))
+ , _key_id (node->optional_string_child ("KeyId").get_value_or (""))
+{
+ if (_id.length() > 9) {
+ _id = _id.substr (9);
+ _content.set_id (_id);
+ }
+
+ if (_key_id.length() > 9) {
+ _key_id = _key_id.substr (9);
+ }
+}
+
+void
+ReelAsset::write_to_cpl (xmlpp::Node* node, Standard) const
+{
+ pair<string, string> const attr = cpl_node_attribute ();
+ xmlpp::Element* a = node->add_child (cpl_node_name ());
+ if (!attr.first.empty ()) {
+ a->set_attribute (attr.first, attr.second);
+ }
+ a->add_child("Id")->add_child_text ("urn:uuid:" + _id);
+ a->add_child("AnnotationText")->add_child_text (_annotation_text);
+ a->add_child("EditRate")->add_child_text (String::compose ("%1 %2", _edit_rate.numerator, _edit_rate.denominator));
+ a->add_child("IntrinsicDuration")->add_child_text (lexical_cast<string> (_intrinsic_duration));
+ a->add_child("EntryPoint")->add_child_text (lexical_cast<string> (_entry_point));
+ a->add_child("Duration")->add_child_text (lexical_cast<string> (_duration));
+ if (!_key_id.empty ()) {
+ a->add_child("KeyId")->add_child_text ("urn:uuid:" + _key_id);
+ }
+}
+
+pair<string, string>
+ReelAsset::cpl_node_attribute () const
+{
+ return make_pair ("", "");
+}
--- /dev/null
+/*
+ Copyright (C) 2014 Carl Hetherington <cth@carlh.net>
+
+ 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_REEL_ASSET_H
+#define LIBDCP_REEL_ASSET_H
+
+#include "object.h"
+#include "util.h"
+#include "ref.h"
+#include <boost/shared_ptr.hpp>
+
+namespace cxml {
+ class Node;
+}
+
+namespace xmlpp {
+ class Node;
+}
+
+namespace dcp {
+
+class Content;
+
+/** @class ReelAsset
+ * @brief An entry in a <Reel> which refers to a use of a piece of content.
+ *
+ * This class encapsulates the XML that exists in a <Reel> to say
+ * that a piece of content is used in this reel. It does not
+ * describe the content itself (but links to a Content object which does).
+ */
+class ReelAsset : public Object
+{
+public:
+ ReelAsset ();
+ ReelAsset (boost::shared_ptr<Content> content, int64_t entry_point);
+ ReelAsset (boost::shared_ptr<const cxml::Node>);
+
+ virtual void write_to_cpl (xmlpp::Node* node, Standard standard) const;
+
+ virtual bool equals (
+ boost::shared_ptr<const ReelAsset>,
+ EqualityOptions,
+ boost::function<void (NoteType, std::string)>)
+ const {
+
+ return false;
+ }
+
+ /** @return a Ref to our actual content */
+ Ref<Content>& content () {
+ return _content;
+ }
+
+ /** @return true if a KeyId is specified for this asset, implying
+ * that its content is encrypted.
+ */
+ bool encrypted () const {
+ return !_key_id.empty ();
+ }
+
+ /** @return Key ID to describe the key that encrypts this asset's;
+ * content.
+ */
+ std::string key_id () const {
+ return _key_id;
+ }
+
+protected:
+ /** @return the node name that this asset uses in the CPL's <Reel> node
+ * e.g. MainPicture, MainSound etc.
+ */
+ virtual std::string cpl_node_name () const = 0;
+
+ /** @return Any attribute that should be used on the asset's node in the
+ * CPL.
+ */
+ virtual std::pair<std::string, std::string> cpl_node_attribute () const;
+
+ /** Reference to the content (MXF or XML file) that this reel entry
+ * applies to.
+ */
+ Ref<Content> _content;
+
+private:
+
+ std::string _annotation_text; ///< The <AnnotationText> from the reel's entry for this asset
+ Fraction _edit_rate; ///< The <EditRate> from the reel's entry for this asset
+ int64_t _intrinsic_duration; ///< The <IntrinsicDuration> from the reel's entry for this asset
+ int64_t _entry_point; ///< The <EntryPoint> from the reel's entry for this asset
+ int64_t _duration; ///< The <Duration> from the reel's entry for this asset
+ std::string _hash; ///< The <Hash> from the reel's entry for this asset
+ std::string _key_id; ///< The <KeyId> from the reel's entry for this asset, or empty if there isn't one
+};
+
+}
+
+#endif
--- /dev/null
+/*
+ Copyright (C) 2014 Carl Hetherington <cth@carlh.net>
+
+ 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/reel_mono_picture_asset.cc
+ * @brief ReelMonoPictureAsset class.
+ */
+
+#include "reel_mono_picture_asset.h"
+#include "mono_picture_mxf.h"
+#include <libcxml/cxml.h>
+
+using std::string;
+using boost::shared_ptr;
+using namespace dcp;
+
+ReelMonoPictureAsset::ReelMonoPictureAsset ()
+{
+
+}
+
+ReelMonoPictureAsset::ReelMonoPictureAsset (boost::shared_ptr<MonoPictureMXF> mxf, int64_t entry_point)
+ : ReelPictureAsset (mxf, entry_point)
+{
+
+}
+
+ReelMonoPictureAsset::ReelMonoPictureAsset (boost::shared_ptr<const cxml::Node> node)
+ : ReelPictureAsset (node)
+{
+ node->done ();
+}
+
+string
+ReelMonoPictureAsset::cpl_node_name () const
+{
+ return "MainPicture";
+}
+
--- /dev/null
+/*
+ Copyright (C) 2014 Carl Hetherington <cth@carlh.net>
+
+ 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/reel_mono_picture_asset.h
+ * @brief ReelMonoPictureAsset class.
+ */
+
+#ifndef LIBDCP_REEL_MONO_PICTURE_ASSET_H
+#define LIBDCP_REEL_MONO_PICTURE_ASSET_H
+
+#include "reel_picture_asset.h"
+
+namespace dcp {
+
+class MonoPictureMXF;
+
+/** @class ReelMonoPictureAsset
+ * @brief Part of a Reel's description which refers to a monoscopic picture MXF.
+ */
+class ReelMonoPictureAsset : public ReelPictureAsset
+{
+public:
+ ReelMonoPictureAsset ();
+ ReelMonoPictureAsset (boost::shared_ptr<MonoPictureMXF> content, int64_t entry_point);
+ ReelMonoPictureAsset (boost::shared_ptr<const cxml::Node>);
+
+private:
+ std::string cpl_node_name () const;
+};
+
+}
+
+#endif
--- /dev/null
+/*
+ Copyright (C) 2014 Carl Hetherington <cth@carlh.net>
+
+ 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/reel_picture_asset.h
+ * @brief ReelPictureAsset class.
+ */
+
+#include "content.h"
+#include "reel_picture_asset.h"
+#include "picture_mxf.h"
+#include "compose.hpp"
+#include <libcxml/cxml.h>
+
+using std::bad_cast;
+using std::string;
+using std::stringstream;
+using boost::shared_ptr;
+using namespace dcp;
+
+ReelPictureAsset::ReelPictureAsset ()
+ : _frame_rate (Fraction (24, 1))
+ , _screen_aspect_ratio (Fraction (1998, 1080))
+{
+
+}
+
+ReelPictureAsset::ReelPictureAsset (boost::shared_ptr<PictureMXF> content, int64_t entry_point)
+ : ReelAsset (content, entry_point)
+ , _frame_rate (content->frame_rate ())
+ , _screen_aspect_ratio (content->screen_aspect_ratio ())
+{
+
+}
+
+ReelPictureAsset::ReelPictureAsset (boost::shared_ptr<const cxml::Node> node)
+ : ReelAsset (node)
+{
+ _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<float> ("ScreenAspectRatio");
+ _screen_aspect_ratio = Fraction (f * 1000, 1000);
+ } catch (bad_cast& e) {
+
+ }
+}
+
+void
+ReelPictureAsset::write_to_cpl (xmlpp::Node* node, Standard standard) const
+{
+ ReelAsset::write_to_cpl (node, standard);
+
+ xmlpp::Node::NodeList c = node->get_children ();
+ xmlpp::Node::NodeList::iterator i = c.begin();
+ while (i != c.end() && (*i)->get_name() != cpl_node_name ()) {
+ ++i;
+ }
+
+ assert (i != c.end ());
+
+ (*i)->add_child ("FrameRate")->add_child_text (String::compose ("%1 %2", _frame_rate.numerator, _frame_rate.denominator));
+ if (standard == INTEROP) {
+ stringstream s;
+ s << std::fixed << std::setprecision (2) << (float (_screen_aspect_ratio.numerator) / _screen_aspect_ratio.denominator);
+ (*i)->add_child ("ScreenAspectRatio")->add_child_text (s.str ());
+ } else {
+ (*i)->add_child ("ScreenAspectRatio")->add_child_text (
+ String::compose ("%1 %2", _screen_aspect_ratio.numerator, _screen_aspect_ratio.denominator)
+ );
+ }
+}
--- /dev/null
+/*
+ Copyright (C) 2014 Carl Hetherington <cth@carlh.net>
+
+ 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/reel_picture_asset.h
+ * @brief ReelPictureAsset class.
+ */
+
+#ifndef LIBDCP_REEL_PICTURE_ASSET_H
+#define LIBDCP_REEL_PICTURE_ASSET_H
+
+#include "reel_asset.h"
+#include "picture_mxf.h"
+
+namespace dcp {
+
+/** @class ReelPictureAsset
+ * @brief Part of a Reel's description which refers to a picture MXF.
+ */
+class ReelPictureAsset : public ReelAsset
+{
+public:
+ ReelPictureAsset ();
+ ReelPictureAsset (boost::shared_ptr<PictureMXF> content, int64_t entry_point);
+ ReelPictureAsset (boost::shared_ptr<const cxml::Node>);
+
+ virtual void write_to_cpl (xmlpp::Node* node, Standard standard) const;
+
+ boost::shared_ptr<PictureMXF> mxf () {
+ return boost::dynamic_pointer_cast<PictureMXF> (_content.object ());
+ }
+
+ void set_screen_aspect_ratio (Fraction a) {
+ _screen_aspect_ratio = a;
+ }
+
+private:
+ Fraction _frame_rate;
+ Fraction _screen_aspect_ratio;
+};
+
+}
+
+#endif
--- /dev/null
+/*
+ Copyright (C) 2014 Carl Hetherington <cth@carlh.net>
+
+ 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/reel_sound_asset.cc
+ * @brief ReelSoundAsset class.
+ */
+
+#include "reel_sound_asset.h"
+#include <libcxml/cxml.h>
+
+using std::string;
+using boost::shared_ptr;
+using namespace dcp;
+
+ReelSoundAsset::ReelSoundAsset (boost::shared_ptr<Content> content, int64_t entry_point)
+ : ReelAsset (content, entry_point)
+{
+
+}
+
+ReelSoundAsset::ReelSoundAsset (boost::shared_ptr<const cxml::Node> node)
+ : ReelAsset (node)
+{
+ node->ignore_child ("Language");
+ node->done ();
+}
+
+string
+ReelSoundAsset::cpl_node_name () const
+{
+ return "MainSound";
+}
--- /dev/null
+/*
+ Copyright (C) 2014 Carl Hetherington <cth@carlh.net>
+
+ 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/reel_sound_asset.h
+ * @brief ReelSoundAsset class.
+ */
+
+#include "reel_asset.h"
+#include "sound_mxf.h"
+#include <boost/shared_ptr.hpp>
+#include <string>
+
+namespace dcp {
+
+/** @class ReelSoundAsset
+ * @brief Part of a Reel's description which refers to a sound MXF.
+ */
+class ReelSoundAsset : public ReelAsset
+{
+public:
+ ReelSoundAsset (boost::shared_ptr<Content> content, int64_t entry_point);
+ ReelSoundAsset (boost::shared_ptr<const cxml::Node>);
+
+ boost::shared_ptr<SoundMXF> mxf () {
+ return boost::dynamic_pointer_cast<SoundMXF> (_content.object ());
+ }
+
+ boost::shared_ptr<const SoundMXF> mxf () const {
+ return boost::dynamic_pointer_cast<const SoundMXF> (_content.object ());
+ }
+
+private:
+ std::string cpl_node_name () const;
+};
+
+}
+
--- /dev/null
+/*
+ Copyright (C) 2014 Carl Hetherington <cth@carlh.net>
+
+ 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/reel_stereo_picture_asset.cc
+ * @brief ReelStereoPictureAsset class.
+ */
+
+#include "reel_stereo_picture_asset.h"
+#include "stereo_picture_mxf.h"
+#include <libcxml/cxml.h>
+
+using std::string;
+using std::pair;
+using std::make_pair;
+using boost::shared_ptr;
+using namespace dcp;
+
+ReelStereoPictureAsset::ReelStereoPictureAsset ()
+{
+
+}
+
+ReelStereoPictureAsset::ReelStereoPictureAsset (boost::shared_ptr<StereoPictureMXF> mxf, int64_t entry_point)
+ : ReelPictureAsset (mxf, entry_point)
+{
+
+}
+
+ReelStereoPictureAsset::ReelStereoPictureAsset (boost::shared_ptr<const cxml::Node> node)
+ : ReelPictureAsset (node)
+{
+ node->done ();
+}
+
+string
+ReelStereoPictureAsset::cpl_node_name () const
+{
+ return "msp-cpl:MainStereoscopicPicture";
+}
+
+pair<string, string>
+ReelStereoPictureAsset::cpl_node_attribute (Standard standard) const
+{
+ if (standard == INTEROP) {
+ return make_pair ("xmlns:msp-cpl", "http://www.digicine.com/schemas/437-Y/2007/Main-Stereo-Picture-CPL");
+ } else {
+ return make_pair ("xmlns:msp-cpl", "http://www.smpte-ra.org/schemas/429-10/2008/Main-Stereo-Picture-CPL");
+ }
+
+ return make_pair ("", "");
+}
--- /dev/null
+/*
+ Copyright (C) 2014 Carl Hetherington <cth@carlh.net>
+
+ 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/reel_stereo_picture_asset.h
+ * @brief ReelStereoPictureAsset class.
+ */
+
+#ifndef LIBDCP_REEL_STEREO_PICTURE_ASSET_H
+#define LIBDCP_REEL_STEREO_PICTURE_ASSET_H
+
+#include "reel_picture_asset.h"
+
+namespace dcp {
+
+class StereoPictureMXF;
+
+/** @class ReelStereoPictureAsset
+ * @brief Part of a Reel's description which refers to a stereoscopic picture MXF.
+ */
+class ReelStereoPictureAsset : public ReelPictureAsset
+{
+public:
+ ReelStereoPictureAsset ();
+ ReelStereoPictureAsset (boost::shared_ptr<StereoPictureMXF> content, int64_t entry_point);
+ ReelStereoPictureAsset (boost::shared_ptr<const cxml::Node>);
+
+private:
+ std::string cpl_node_name () const;
+ std::pair<std::string, std::string> cpl_node_attribute (Standard standard) const;
+};
+
+}
+
+#endif
+
--- /dev/null
+/*
+ Copyright (C) 2012-2014 Carl Hetherington <cth@carlh.net>
+
+ 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/reel_subtitle_asset.cc
+ * @brief ReelSubtitleAsset class.
+ */
+
+#include "subtitle_content.h"
+#include "reel_subtitle_asset.h"
+
+using std::string;
+using boost::shared_ptr;
+using namespace dcp;
+
+ReelSubtitleAsset::ReelSubtitleAsset (boost::shared_ptr<SubtitleContent> content, int64_t entry_point)
+ : ReelAsset (content, entry_point)
+{
+
+}
+
+ReelSubtitleAsset::ReelSubtitleAsset (boost::shared_ptr<const cxml::Node> node)
+ : ReelAsset (node)
+{
+ node->ignore_child ("Language");
+ node->done ();
+}
+
+string
+ReelSubtitleAsset::cpl_node_name () const
+{
+ return "MainSubtitle";
+}
--- /dev/null
+/*
+ Copyright (C) 2012-2014 Carl Hetherington <cth@carlh.net>
+
+ 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/reel_subtitle_asset.h
+ * @brief ReelSubtitleAsset class.
+ */
+
+#ifndef LIBDCP_REEL_SUBTITLE_ASSET_H
+#define LIBDCP_REEL_SUBTITLE_ASSET_H
+
+#include "reel_asset.h"
+
+namespace dcp {
+
+class SubtitleContent;
+
+/** @class ReelSubtitleAsset
+ * @brief Part of a Reel's description which refers to a subtitle XML file.
+ */
+class ReelSubtitleAsset : public ReelAsset
+{
+public:
+ ReelSubtitleAsset (boost::shared_ptr<SubtitleContent> content, int64_t entry_point);
+ ReelSubtitleAsset (boost::shared_ptr<const cxml::Node>);
+
+ boost::shared_ptr<SubtitleContent> subtitle_content () const {
+ return boost::dynamic_pointer_cast<SubtitleContent> (_content.object ());
+ }
+
+private:
+ std::string cpl_node_name () const;
+};
+
+}
+
+#endif
--- /dev/null
+/*
+ Copyright (C) 2014 Carl Hetherington <cth@carlh.net>
+
+ 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/ref.h
+ * @brief Ref class.
+ */
+
+#ifndef LIBDCP_REF_H
+#define LIBDCP_REF_H
+
+#include "exceptions.h"
+#include "object.h"
+#include <boost/shared_ptr.hpp>
+#include <string>
+
+namespace dcp {
+
+/** @class Ref
+ * @brief A reference to an object which is identified by a universally-unique identifier (UUID).
+ *
+ * This class is a `pointer' to a thing. It will always know the
+ * UUID of the thing, and it may have a shared_ptr to the C++ object
+ * which represents the thing.
+ *
+ * If the Ref does not have a shared_ptr it may be given one by
+ * calling resolve() with a list of objects. The shared_ptr will be
+ * set up using any object on the list which has a matching ID.
+ */
+template<class T>
+class Ref
+{
+public:
+ /** Initialise a Ref with an ID but no shared_ptr */
+ Ref (std::string id)
+ : _id (id)
+ {}
+
+ /** Initialise a Ref with a shared_ptr to an object */
+ Ref (boost::shared_ptr<T> object)
+ : _id (object->id ())
+ , _object (object)
+ {}
+
+ /** Set the ID of this Ref */
+ void set_id (std::string id)
+ {
+ _id = id;
+ }
+
+ /** Look through a list of objects and copy a shared_ptr to any object
+ * which matches the ID of this one.
+ */
+ void resolve (std::list<boost::shared_ptr<Object> > objects)
+ {
+ typename std::list<boost::shared_ptr<Object> >::iterator i = objects.begin();
+ while (i != objects.end() && (*i)->id() != _id) {
+ ++i;
+ }
+
+ if (i != objects.end ()) {
+ _object = boost::dynamic_pointer_cast<T> (*i);
+ }
+ }
+
+ /** @return the ID of the thing that we are pointing to */
+ std::string id () const {
+ return _id;
+ }
+
+ /** @return a shared_ptr to the thing; an UnresolvedRefError is thrown
+ * if the shared_ptr is not known.
+ */
+ boost::shared_ptr<T> object () const {
+ if (!_object) {
+ throw UnresolvedRefError (_id);
+ }
+
+ return _object;
+ }
+
+ /** operator-> to access the shared_ptr; an UnresolvedRefError is thrown
+ * if the shared_ptr is not known.
+ */
+ T * operator->() const {
+ if (!_object) {
+ throw UnresolvedRefError (_id);
+ }
+
+ return _object.get ();
+ }
+
+ /** @return true if a shared_ptr is known for this Ref */
+ bool resolved () const {
+ return _object;
+ }
+
+private:
+ std::string _id; ///< ID; will always be known
+ boost::shared_ptr<T> _object; ///< shared_ptr to the thing, may be null.
+};
+
+}
+
+#endif
/*
- Copyright (C) 2013 Carl Hetherington <cth@carlh.net>
+ Copyright (C) 2013-2014 Carl Hetherington <cth@carlh.net>
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
using std::min;
using std::max;
using boost::shared_ptr;
-using namespace libdcp;
+using namespace dcp;
#define DCI_COEFFICIENT (48.0 / 52.37)
/** Convert an openjpeg XYZ image to RGB.
* @param xyz_frame Frame in XYZ.
+ * @param lut_in Input Gamma LUT to use.
+ * @param lut_out Output Gamma LUT to use.
* @return RGB image.
*/
shared_ptr<ARGBFrame>
-libdcp::xyz_to_rgb (shared_ptr<const XYZFrame> xyz_frame, shared_ptr<const LUT> lut_in, shared_ptr<const LUT> lut_out)
+dcp::xyz_to_rgb (
+ boost::shared_ptr<const XYZFrame> xyz_frame,
+ boost::shared_ptr<const GammaLUT> lut_in,
+ boost::shared_ptr<const GammaLUT> lut_out
+ )
{
int const max_colour = pow (2, lut_out->bit_depth()) - 1;
return argb_frame;
}
-shared_ptr<libdcp::XYZFrame>
-libdcp::rgb_to_xyz (shared_ptr<const Image> rgb, shared_ptr<const LUT> lut_in, shared_ptr<const LUT> lut_out, double const colour_matrix[3][3])
+shared_ptr<dcp::XYZFrame>
+dcp::rgb_to_xyz (
+ boost::shared_ptr<const Image> rgb,
+ boost::shared_ptr<const GammaLUT> lut_in,
+ boost::shared_ptr<const GammaLUT> lut_out,
+ double const colour_matrix[3][3]
+ )
{
assert (lut_in->bit_depth() == 12);
assert (lut_out->bit_depth() == 16);
/*
- Copyright (C) 2013 Carl Hetherington <cth@carlh.net>
+ Copyright (C) 2013-2014 Carl Hetherington <cth@carlh.net>
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
#include <boost/shared_ptr.hpp>
-namespace libdcp {
+namespace dcp {
class ARGBFrame;
class XYZFrame;
-class LUT;
+class GammaLUT;
class Image;
extern boost::shared_ptr<ARGBFrame> xyz_to_rgb (
- boost::shared_ptr<const XYZFrame>, boost::shared_ptr<const LUT>, boost::shared_ptr<const LUT>
+ boost::shared_ptr<const XYZFrame>, boost::shared_ptr<const GammaLUT>, boost::shared_ptr<const GammaLUT>
);
extern boost::shared_ptr<XYZFrame> rgb_to_xyz (
- boost::shared_ptr<const Image>, boost::shared_ptr<const LUT>, boost::shared_ptr<const LUT>, double const colour_matrix[3][3]
+ boost::shared_ptr<const Image>, boost::shared_ptr<const GammaLUT>, boost::shared_ptr<const GammaLUT>, double const colour_matrix[3][3]
);
}
/*
- Copyright (C) 2013 Carl Hetherington <cth@carlh.net>
+ Copyright (C) 2013-2014 Carl Hetherington <cth@carlh.net>
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
*/
+/** @file src/signer.cc
+ * @brief Signer class.
+ */
+
+#include "signer.h"
+#include "exceptions.h"
+#include <libcxml/cxml.h>
#include <libxml++/libxml++.h>
#include <xmlsec/xmldsig.h>
#include <xmlsec/dl.h>
#include <xmlsec/app.h>
#include <xmlsec/crypto.h>
-#include <libcxml/cxml.h>
-#include "signer.h"
-#include "exceptions.h"
using std::string;
using std::list;
using std::cout;
using boost::shared_ptr;
-using namespace libdcp;
+using namespace dcp;
-/** @param signer_key Filename of private key to sign with */
+/** Add a <Signer> and <ds:Signature> nodes to an XML node.
+ * @param parent XML node to add to.
+ * @param standard INTEROP or SMPTE.
+ */
void
-Signer::sign (xmlpp::Element* parent, bool interop) const
+Signer::sign (xmlpp::Element* parent, Standard standard) const
{
- add_signer (parent, "dsig");
+ /* <Signer> */
+
+ xmlpp::Element* signer = parent->add_child("Signer");
+ xmlpp::Element* data = signer->add_child("X509Data", "dsig");
+ xmlpp::Element* serial_element = data->add_child("X509IssuerSerial", "dsig");
+ serial_element->add_child("X509IssuerName", "dsig")->add_child_text (_certificates.leaf()->issuer());
+ serial_element->add_child("X509SerialNumber", "dsig")->add_child_text (_certificates.leaf()->serial());
+ data->add_child("X509SubjectName", "dsig")->add_child_text (_certificates.leaf()->subject());
+ /* <Signature> */
+
xmlpp::Element* signature = parent->add_child("Signature", "dsig");
xmlpp::Element* signed_info = signature->add_child ("SignedInfo", "dsig");
signed_info->add_child("CanonicalizationMethod", "dsig")->set_attribute ("Algorithm", "http://www.w3.org/TR/2001/REC-xml-c14n-20010315");
- if (interop) {
+ if (standard == INTEROP) {
signed_info->add_child("SignatureMethod", "dsig")->set_attribute("Algorithm", "http://www.w3.org/2000/09/xmldsig#rsa-sha1");
} else {
signed_info->add_child("SignatureMethod", "dsig")->set_attribute("Algorithm", "http://www.w3.org/2001/04/xmldsig-more#rsa-sha256");
xmlSecDSigCtxDestroy (signature_context);
}
-
-void
-Signer::add_signer (xmlpp::Element* parent, string ns) const
-{
- xmlpp::Element* signer = parent->add_child("Signer");
-
- {
- xmlpp::Element* data = signer->add_child("X509Data", ns);
-
- {
- xmlpp::Element* serial_element = data->add_child("X509IssuerSerial", ns);
- serial_element->add_child("X509IssuerName", ns)->add_child_text (_certificates.leaf()->issuer());
- serial_element->add_child("X509SerialNumber", ns)->add_child_text (_certificates.leaf()->serial());
- }
-
- data->add_child("X509SubjectName", ns)->add_child_text (_certificates.leaf()->subject());
- }
-}
/*
- Copyright (C) 2013 Carl Hetherington <cth@carlh.net>
+ Copyright (C) 2013-2014 Carl Hetherington <cth@carlh.net>
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
*/
-#include <boost/filesystem.hpp>
+#ifndef LIBDCP_SIGNER_H
+#define LIBDCP_SIGNER_H
+
+/** @file src/signer.h
+ * @brief Signer class.
+ */
+
#include "certificates.h"
+#include "types.h"
+#include <boost/filesystem.hpp>
namespace xmlpp {
class Element;
class Node;
}
-namespace libdcp {
+namespace dcp {
-class Signer
+/** @class Signer
+ * @brief A class which can sign XML files.
+ */
+class Signer : public boost::noncopyable
{
public:
+ /** @param c Certificate chain to sign with.
+ * @param k Key to sign with.
+ */
Signer (CertificateChain c, boost::filesystem::path k)
: _certificates (c)
, _key (k)
{}
- void sign (xmlpp::Element* parent, bool interop) const;
+ void sign (xmlpp::Element* parent, Standard standard) const;
void add_signature_value (xmlpp::Node* parent, std::string ns) const;
CertificateChain const & certificates () const {
private:
- void add_signer (xmlpp::Element* parent, std::string ns) const;
-
+ /** Certificate chain to sign with */
CertificateChain _certificates;
/** Filename of signer key */
boost::filesystem::path _key;
};
}
+
+#endif
/*
- Copyright (C) 2013 Carl Hetherington <cth@carlh.net>
+ Copyright (C) 2013-2014 Carl Hetherington <cth@carlh.net>
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
*/
-#include <fstream>
-#include <sstream>
-#include <boost/filesystem.hpp>
-#include <boost/algorithm/string.hpp>
-#include <openssl/sha.h>
-#include <openssl/bio.h>
-#include <openssl/evp.h>
-#include "KM_util.h"
+/** @file src/signer_chain.cc
+ * @brief Functions to make signer chains.
+ */
+
#include "signer_chain.h"
#include "exceptions.h"
#include "util.h"
+#include "KM_util.h"
+#include <openssl/sha.h>
+#include <openssl/bio.h>
+#include <openssl/evp.h>
+#include <boost/filesystem.hpp>
+#include <boost/algorithm/string.hpp>
+#include <fstream>
+#include <sstream>
using std::string;
using std::ofstream;
using std::stringstream;
using std::cout;
-static void command (string cmd)
+/** Run a shell command.
+ * @param cmd Command to run (UTF8-encoded).
+ */
+static void
+command (string cmd)
{
#ifdef LIBDCP_WINDOWS
/* We need to use CreateProcessW on Windows so that the UTF-8/16 mess
if (code) {
stringstream s;
s << "error " << code << " in " << cmd << " within " << boost::filesystem::current_path();
- throw libdcp::MiscError (s.str());
+ throw dcp::MiscError (s.str());
}
}
/** Extract a public key from a private key and create a SHA1 digest of it.
- * @param key Private key
+ * @param private_key Private key
* @param openssl openssl binary name (or full path if openssl is not on the system path).
* @return SHA1 digest of corresponding public key, with escaped / characters.
*/
-
static string
public_key_digest (boost::filesystem::path private_key, boost::filesystem::path openssl)
{
string pub;
ifstream f (public_name.string().c_str ());
if (!f.good ()) {
- throw libdcp::MiscError ("public key not found");
+ throw dcp::MiscError ("public key not found");
}
bool read = false;
/* Decode the base64 of the public key */
unsigned char buffer[512];
- int const N = libdcp::base64_decode (pub, buffer, 1024);
+ int const N = dcp::base64_decode (pub, buffer, 1024);
/* Hash it with SHA1 (without the first 24 bytes, for reasons that are not entirely clear) */
SHA_CTX context;
if (!SHA1_Init (&context)) {
- throw libdcp::MiscError ("could not init SHA1 context");
+ throw dcp::MiscError ("could not init SHA1 context");
}
if (!SHA1_Update (&context, buffer + 24, N - 24)) {
- throw libdcp::MiscError ("could not update SHA1 digest");
+ throw dcp::MiscError ("could not update SHA1 digest");
}
unsigned char digest[SHA_DIGEST_LENGTH];
if (!SHA1_Final (digest, &context)) {
- throw libdcp::MiscError ("could not finish SHA1 digest");
+ throw dcp::MiscError ("could not finish SHA1 digest");
}
char digest_base64[64];
return dig;
}
+/** Generate a chain of root, intermediate and leaf keys by running an OpenSSL binary.
+ * @param directory Directory to write the files to.
+ * @param openssl openssl binary path.
+ */
void
-libdcp::make_signer_chain (boost::filesystem::path directory, boost::filesystem::path openssl)
+dcp::make_signer_chain (boost::filesystem::path directory, boost::filesystem::path openssl)
{
boost::filesystem::path const cwd = boost::filesystem::current_path ();
/*
- Copyright (C) 2013 Carl Hetherington <cth@carlh.net>
+ Copyright (C) 2013-2014 Carl Hetherington <cth@carlh.net>
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
*/
+/** @file src/signer_chain.h
+ * @brief Functions to make signer chains.
+ */
+
#include <boost/filesystem.hpp>
-namespace libdcp {
+namespace dcp {
/** Create a chain of certificates for signing things.
* @param directory Directory to write files to.
+++ /dev/null
-/*
- Copyright (C) 2012 Carl Hetherington <cth@carlh.net>
-
- 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/sound_asset.cc
- * @brief An asset made up of WAV files
- */
-
-#include <iostream>
-#include <stdexcept>
-#include <boost/filesystem.hpp>
-#include <boost/lexical_cast.hpp>
-#include <libxml++/nodes/element.h>
-#include "KM_fileio.h"
-#include "AS_DCP.h"
-#include "sound_asset.h"
-#include "util.h"
-#include "exceptions.h"
-#include "sound_frame.h"
-
-using std::string;
-using std::stringstream;
-using std::ostream;
-using std::vector;
-using std::list;
-using boost::shared_ptr;
-using boost::lexical_cast;
-using namespace libdcp;
-
-SoundAsset::SoundAsset (boost::filesystem::path directory, boost::filesystem::path mxf_name)
- : MXFAsset (directory, mxf_name)
- , _channels (0)
- , _sampling_rate (0)
-{
-
-}
-
-void
-SoundAsset::create (vector<boost::filesystem::path> const & files)
-{
- create (boost::bind (&SoundAsset::path_from_channel, this, _1, files));
-}
-
-void
-SoundAsset::read ()
-{
- ASDCP::PCM::MXFReader reader;
- Kumu::Result_t r = reader.OpenRead (path().string().c_str());
- if (ASDCP_FAILURE (r)) {
- boost::throw_exception (MXFFileError ("could not open MXF file for reading", path().string(), r));
- }
-
- ASDCP::PCM::AudioDescriptor desc;
- if (ASDCP_FAILURE (reader.FillAudioDescriptor (desc))) {
- boost::throw_exception (DCPReadError ("could not read audio MXF information"));
- }
-
- _sampling_rate = desc.AudioSamplingRate.Numerator / desc.AudioSamplingRate.Denominator;
- _channels = desc.ChannelCount;
- _edit_rate = desc.EditRate.Numerator;
- assert (desc.EditRate.Denominator == 1);
- _intrinsic_duration = desc.ContainerDuration;
-}
-
-boost::filesystem::path
-SoundAsset::path_from_channel (Channel channel, vector<boost::filesystem::path> const & files)
-{
- unsigned int const c = int (channel);
- assert (c < files.size ());
- return files[c];
-}
-
-void
-SoundAsset::create (boost::function<boost::filesystem::path (Channel)> get_path)
-{
- ASDCP::Rational asdcp_edit_rate (_edit_rate, 1);
-
- assert (_channels > 0);
- ASDCP::PCM::WAVParser* pcm_parser_channel[_channels];
- for (int i = 0; i < _channels; ++i) {
- pcm_parser_channel[i] = new ASDCP::PCM::WAVParser ();
- }
-
- Kumu::Result_t r = pcm_parser_channel[0]->OpenRead (get_path(LEFT).string().c_str(), asdcp_edit_rate);
- if (ASDCP_FAILURE (r)) {
- boost::throw_exception (FileError ("could not open WAV file for reading", get_path(LEFT), r));
- }
-
- ASDCP::PCM::AudioDescriptor audio_desc;
- pcm_parser_channel[0]->FillAudioDescriptor (audio_desc);
- audio_desc.ChannelCount = 0;
- audio_desc.BlockAlign = 0;
- audio_desc.EditRate = asdcp_edit_rate;
- audio_desc.AvgBps = audio_desc.AvgBps * _channels;
-
- Channel channels[] = {
- LEFT,
- RIGHT,
- CENTRE,
- LFE,
- LS,
- RS,
- /* XXX: not quite sure what these should be yet */
- CHANNEL_7,
- CHANNEL_8
- };
-
- assert (int(_channels) <= int(sizeof(channels) / sizeof(Channel)));
-
- ASDCP::PCM::FrameBuffer* frame_buffer_channel[_channels];
- ASDCP::PCM::AudioDescriptor* audio_desc_channel[_channels];
- for (int i = 0; i < _channels; ++i) {
- frame_buffer_channel[i] = new ASDCP::PCM::FrameBuffer ();
- audio_desc_channel[i] = new ASDCP::PCM::AudioDescriptor ();
- }
-
- for (int i = 0; i < _channels; ++i) {
-
- boost::filesystem::path const path = get_path (channels[i]);
-
- Kumu::Result_t r = pcm_parser_channel[i]->OpenRead (path.string().c_str(), asdcp_edit_rate);
- if (ASDCP_FAILURE (r)) {
- boost::throw_exception (FileError ("could not open WAV file for reading", path, r));
- }
-
- pcm_parser_channel[i]->FillAudioDescriptor (*audio_desc_channel[i]);
- frame_buffer_channel[i]->Capacity (ASDCP::PCM::CalcFrameBufferSize (*audio_desc_channel[i]));
-
- audio_desc.ChannelCount += audio_desc_channel[i]->ChannelCount;
- audio_desc.BlockAlign += audio_desc_channel[i]->BlockAlign;
- }
-
- ASDCP::PCM::FrameBuffer frame_buffer;
- frame_buffer.Capacity (ASDCP::PCM::CalcFrameBufferSize (audio_desc));
- frame_buffer.Size (ASDCP::PCM::CalcFrameBufferSize (audio_desc));
-
- ASDCP::WriterInfo writer_info;
- MXFAsset::fill_writer_info (&writer_info);
-
- ASDCP::PCM::MXFWriter mxf_writer;
- r = mxf_writer.OpenWrite (path().string().c_str(), writer_info, audio_desc);
- if (ASDCP_FAILURE (r)) {
- boost::throw_exception (FileError ("could not open audio MXF for writing", path().string(), r));
- }
-
- for (int i = 0; i < _intrinsic_duration; ++i) {
-
- for (int j = 0; j < _channels; ++j) {
- memset (frame_buffer_channel[j]->Data(), 0, frame_buffer_channel[j]->Capacity());
- if (ASDCP_FAILURE (pcm_parser_channel[j]->ReadFrame (*frame_buffer_channel[j]))) {
- boost::throw_exception (MiscError ("could not read audio frame"));
- }
- }
-
- byte_t *data_s = frame_buffer.Data();
- byte_t *data_e = data_s + frame_buffer.Capacity();
- byte_t sample_size = ASDCP::PCM::CalcSampleSize (*audio_desc_channel[0]);
- int offset = 0;
-
- while (data_s < data_e) {
- for (int j = 0; j < _channels; ++j) {
- byte_t* frame = frame_buffer_channel[j]->Data() + offset;
- memcpy (data_s, frame, sample_size);
- data_s += sample_size;
- }
- offset += sample_size;
- }
-
- if (ASDCP_FAILURE (mxf_writer.WriteFrame (frame_buffer, _encryption_context, 0))) {
- boost::throw_exception (MiscError ("could not write audio MXF frame"));
- }
-
- if (_progress) {
- (*_progress) (0.5 * float (i) / _intrinsic_duration);
- }
- }
-
- bool const failed = ASDCP_FAILURE (mxf_writer.Finalize());
-
- for (int i = 0; i < _channels; ++i) {
- delete pcm_parser_channel[i];
- delete frame_buffer_channel[i];
- delete audio_desc_channel[i];
- }
-
- if (failed) {
- boost::throw_exception (MiscError ("could not finalise audio MXF"));
- }
-}
-
-string
-SoundAsset::cpl_node_name () const
-{
- return "MainSound";
-}
-
-bool
-SoundAsset::equals (shared_ptr<const Asset> other, EqualityOptions opt, boost::function<void (NoteType, string)> note) const
-{
- if (!MXFAsset::equals (other, opt, note)) {
- return false;
- }
-
- ASDCP::PCM::MXFReader reader_A;
- Kumu::Result_t r = reader_A.OpenRead (path().string().c_str());
- if (ASDCP_FAILURE (r)) {
- boost::throw_exception (MXFFileError ("could not open MXF file for reading", path().string(), r));
- }
-
- ASDCP::PCM::MXFReader reader_B;
- r = reader_B.OpenRead (other->path().string().c_str());
- if (ASDCP_FAILURE (r)) {
- boost::throw_exception (MXFFileError ("could not open MXF file for reading", path().string(), r));
- }
-
- ASDCP::PCM::AudioDescriptor desc_A;
- if (ASDCP_FAILURE (reader_A.FillAudioDescriptor (desc_A))) {
- boost::throw_exception (DCPReadError ("could not read audio MXF information"));
- }
- ASDCP::PCM::AudioDescriptor desc_B;
- if (ASDCP_FAILURE (reader_B.FillAudioDescriptor (desc_B))) {
- boost::throw_exception (DCPReadError ("could not read audio MXF information"));
- }
-
- if (
- desc_A.EditRate != desc_B.EditRate ||
- desc_A.AudioSamplingRate != desc_B.AudioSamplingRate ||
- desc_A.Locked != desc_B.Locked ||
- desc_A.ChannelCount != desc_B.ChannelCount ||
- desc_A.QuantizationBits != desc_B.QuantizationBits ||
- desc_A.BlockAlign != desc_B.BlockAlign ||
- desc_A.AvgBps != desc_B.AvgBps ||
- desc_A.LinkedTrackID != desc_B.LinkedTrackID ||
- desc_A.ContainerDuration != desc_B.ContainerDuration
-// desc_A.ChannelFormat != desc_B.ChannelFormat ||
- ) {
-
- note (ERROR, "audio MXF picture descriptors differ");
- return false;
- }
-
- ASDCP::PCM::FrameBuffer buffer_A (1 * Kumu::Megabyte);
- ASDCP::PCM::FrameBuffer buffer_B (1 * Kumu::Megabyte);
-
- for (int i = 0; i < _intrinsic_duration; ++i) {
- if (ASDCP_FAILURE (reader_A.ReadFrame (i, buffer_A))) {
- boost::throw_exception (DCPReadError ("could not read audio frame"));
- }
-
- if (ASDCP_FAILURE (reader_B.ReadFrame (i, buffer_B))) {
- boost::throw_exception (DCPReadError ("could not read audio frame"));
- }
-
- if (buffer_A.Size() != buffer_B.Size()) {
- note (ERROR, "sizes of audio data for frame " + lexical_cast<string>(i) + " differ");
- return false;
- }
-
- if (memcmp (buffer_A.RoData(), buffer_B.RoData(), buffer_A.Size()) != 0) {
- for (uint32_t i = 0; i < buffer_A.Size(); ++i) {
- int const d = abs (buffer_A.RoData()[i] - buffer_B.RoData()[i]);
- if (d > opt.max_audio_sample_error) {
- note (ERROR, "PCM data difference of " + lexical_cast<string> (d));
- return false;
- }
- }
- }
- }
-
- return true;
-}
-
-shared_ptr<const SoundFrame>
-SoundAsset::get_frame (int n) const
-{
- /* XXX: should add on entry point here? */
- return shared_ptr<const SoundFrame> (new SoundFrame (path().string(), n, _decryption_context));
-}
-
-shared_ptr<SoundAssetWriter>
-SoundAsset::start_write ()
-{
- /* XXX: can't we use a shared_ptr here? */
- return shared_ptr<SoundAssetWriter> (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;
- ASDCP::AESEncContext* encryption_context;
-};
-
-SoundAssetWriter::SoundAssetWriter (SoundAsset* a)
- : _state (new SoundAssetWriter::ASDCPState)
- , _asset (a)
- , _finalized (false)
- , _frames_written (0)
- , _frame_buffer_offset (0)
-{
- _state->encryption_context = a->encryption_context ();
-
- /* Derived from ASDCP::Wav::SimpleWaveHeader::FillADesc */
- _state->audio_desc.EditRate = ASDCP::Rational (_asset->edit_rate(), 1);
- _state->audio_desc.AudioSamplingRate = ASDCP::Rational (_asset->sampling_rate(), 1);
- _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;
-
- _state->frame_buffer.Capacity (ASDCP::PCM::CalcFrameBufferSize (_state->audio_desc));
- _state->frame_buffer.Size (ASDCP::PCM::CalcFrameBufferSize (_state->audio_desc));
- memset (_state->frame_buffer.Data(), 0, _state->frame_buffer.Capacity());
-
- _asset->fill_writer_info (&_state->writer_info);
-
- Kumu::Result_t r = _state->mxf_writer.OpenWrite (_asset->path().string().c_str(), _state->writer_info, _state->audio_desc);
- if (ASDCP_FAILURE (r)) {
- boost::throw_exception (FileError ("could not open audio MXF for writing", _asset->path().string(), r));
- }
-}
-
-void
-SoundAssetWriter::write (float const * const * data, int frames)
-{
- for (int i = 0; i < frames; ++i) {
-
- byte_t* out = _state->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 (_state->frame_buffer.Capacity()));
-
- /* Finish the MXF frame if required */
- if (_frame_buffer_offset == int (_state->frame_buffer.Capacity())) {
- write_current_frame ();
- _frame_buffer_offset = 0;
- memset (_state->frame_buffer.Data(), 0, _state->frame_buffer.Capacity());
- }
- }
-}
-
-void
-SoundAssetWriter::write_current_frame ()
-{
- ASDCP::Result_t const r = _state->mxf_writer.WriteFrame (_state->frame_buffer, _state->encryption_context, 0);
- if (ASDCP_FAILURE (r)) {
- boost::throw_exception (MiscError ("could not write audio MXF frame (" + lexical_cast<string> (int (r)) + ")"));
- }
-
- ++_frames_written;
-}
-
-void
-SoundAssetWriter::finalize ()
-{
- if (_frame_buffer_offset > 0) {
- write_current_frame ();
- }
-
- if (ASDCP_FAILURE (_state->mxf_writer.Finalize())) {
- boost::throw_exception (MiscError ("could not finalise audio MXF"));
- }
-
- _finalized = true;
- _asset->set_intrinsic_duration (_frames_written);
- _asset->set_duration (_frames_written);
-}
-
-string
-SoundAsset::key_type () const
-{
- return "MDAK";
-}
+++ /dev/null
-/*
- Copyright (C) 2012 Carl Hetherington <cth@carlh.net>
-
- 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_SOUND_ASSET_H
-#define LIBDCP_SOUND_ASSET_H
-
-/** @file src/sound_asset.h
- * @brief An asset made up of PCM audio data files
- */
-
-#include "mxf_asset.h"
-#include "types.h"
-#include "metadata.h"
-
-namespace libdcp
-{
-
-class SoundFrame;
-class SoundAsset;
-
-class SoundAssetWriter
-{
-public:
- void write (float const * const *, int);
- void finalize ();
-
-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<ASDCPState> _state;
-
- SoundAsset* _asset;
- bool _finalized;
- int _frames_written;
- int _frame_buffer_offset;
-};
-
-/** @brief An asset made up of WAV files */
-class SoundAsset : public MXFAsset
-{
-public:
- SoundAsset (boost::filesystem::path directory, boost::filesystem::path mxf_name);
-
- void read ();
-
- /** The following parameters must be set up (if required) before calling this:
- * Interop mode (set_interop)
- * Edit rate (set_edit_rate)
- * MXF Metadata (set_metadata)
- * Channels (set_channels)
- * Intrinsic duration (set_intrinsic_duration)
- */
- void create (std::vector<boost::filesystem::path> const & files);
-
- /** The following parameters must be set up (if required) before calling this:
- * Interop mode (set_interop)
- * Edit rate (set_edit_rate)
- * MXF Metadata (set_metadata)
- * Channels (set_channels)
- * Intrinsic duration (set_intrinsic_duration)
- */
- void create (boost::function<boost::filesystem::path (Channel)> get_path);
-
- boost::shared_ptr<SoundAssetWriter> start_write ();
-
- bool equals (boost::shared_ptr<const Asset> other, EqualityOptions opt, boost::function<void (NoteType, std::string)> note) const;
-
- boost::shared_ptr<const SoundFrame> get_frame (int n) const;
-
- void set_channels (int c) {
- _channels = c;
- }
-
- int channels () const {
- return _channels;
- }
-
- void set_sampling_rate (int s) {
- _sampling_rate = s;
- }
-
- int sampling_rate () const {
- return _sampling_rate;
- }
-
-protected:
-
- std::string asdcp_kind () const {
- return "Sound";
- }
-
-private:
- std::string key_type () const;
- void construct (boost::function<boost::filesystem::path (Channel)> get_path);
- boost::filesystem::path path_from_channel (Channel channel, std::vector<boost::filesystem::path> const & files);
- std::string cpl_node_name () const;
-
- /** Number of channels in the asset */
- int _channels;
- int _sampling_rate;
-};
-
-}
-
-#endif
/*
- Copyright (C) 2012 Carl Hetherington <cth@carlh.net>
+ Copyright (C) 2012-2014 Carl Hetherington <cth@carlh.net>
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
*/
-#include "AS_DCP.h"
-#include "KM_fileio.h"
+/** @file src/sound_frame.cc
+ * @brief SoundFrame class.
+ */
+
#include "sound_frame.h"
#include "exceptions.h"
+#include "AS_DCP.h"
+#include "KM_fileio.h"
using namespace std;
-using namespace libdcp;
+using namespace dcp;
-SoundFrame::SoundFrame (string mxf_path, int n, ASDCP::AESDecContext* c)
+SoundFrame::SoundFrame (boost::filesystem::path mxf_path, int n, ASDCP::AESDecContext* c)
{
ASDCP::PCM::MXFReader reader;
- Kumu::Result_t r = reader.OpenRead (mxf_path.c_str());
+ Kumu::Result_t r = reader.OpenRead (mxf_path.string().c_str());
if (ASDCP_FAILURE (r)) {
boost::throw_exception (FileError ("could not open MXF file for reading", mxf_path, r));
}
/*
- Copyright (C) 2012 Carl Hetherington <cth@carlh.net>
+ Copyright (C) 2012-2014 Carl Hetherington <cth@carlh.net>
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
*/
+/** @file src/sound_frame.h
+ * @brief SoundFrame class.
+ */
+
#ifndef LIBDCP_SOUND_FRAME_H
#define LIBDCP_SOUND_FRAME_H
-#include <string>
+#include <boost/noncopyable.hpp>
+#include <boost/filesystem.hpp>
#include <stdint.h>
+#include <string>
namespace ASDCP {
namespace PCM {
class AESDecContext;
}
-namespace libdcp {
+namespace dcp {
-class SoundFrame
+/** @class SoundFrame
+ * @brief One ‘frame’ of sound data from a MXF.
+ */
+class SoundFrame : public boost::noncopyable
{
public:
- SoundFrame (std::string mxf_path, int n, ASDCP::AESDecContext *);
+ SoundFrame (boost::filesystem::path mxf_path, int n, ASDCP::AESDecContext *);
~SoundFrame ();
uint8_t const * data () const;
int size () const;
private:
+ /** a buffer to hold the frame */
ASDCP::PCM::FrameBuffer* _buffer;
};
--- /dev/null
+/*
+ Copyright (C) 2012-2014 Carl Hetherington <cth@carlh.net>
+
+ 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/sound_mxf.cc
+ * @brief SoundMXF class.
+ */
+
+#include "sound_mxf.h"
+#include "util.h"
+#include "exceptions.h"
+#include "sound_frame.h"
+#include "sound_mxf_writer.h"
+#include "compose.hpp"
+#include "KM_fileio.h"
+#include "AS_DCP.h"
+#include <libxml++/nodes/element.h>
+#include <boost/filesystem.hpp>
+#include <iostream>
+#include <stdexcept>
+
+using std::string;
+using std::stringstream;
+using std::ostream;
+using std::vector;
+using std::list;
+using boost::shared_ptr;
+using namespace dcp;
+
+SoundMXF::SoundMXF (boost::filesystem::path file)
+ : MXF (file)
+ , _channels (0)
+ , _sampling_rate (0)
+{
+ ASDCP::PCM::MXFReader reader;
+ Kumu::Result_t r = reader.OpenRead (file.string().c_str());
+ if (ASDCP_FAILURE (r)) {
+ boost::throw_exception (MXFFileError ("could not open MXF file for reading", file.string(), r));
+ }
+
+ ASDCP::PCM::AudioDescriptor desc;
+ if (ASDCP_FAILURE (reader.FillAudioDescriptor (desc))) {
+ boost::throw_exception (DCPReadError ("could not read audio MXF information"));
+ }
+
+ _sampling_rate = desc.AudioSamplingRate.Numerator / desc.AudioSamplingRate.Denominator;
+ _channels = desc.ChannelCount;
+ _edit_rate = Fraction (desc.EditRate.Numerator, desc.EditRate.Denominator);
+
+ _intrinsic_duration = desc.ContainerDuration;
+
+ ASDCP::WriterInfo info;
+ if (ASDCP_FAILURE (reader.FillWriterInfo (info))) {
+ boost::throw_exception (DCPReadError ("could not read audio MXF information"));
+ }
+
+ read_writer_info (info);
+
+}
+
+SoundMXF::SoundMXF (Fraction edit_rate, int sampling_rate, int channels)
+ : MXF (edit_rate)
+ , _channels (channels)
+ , _sampling_rate (sampling_rate)
+{
+
+}
+
+bool
+SoundMXF::equals (shared_ptr<const Content> other, EqualityOptions opt, boost::function<void (NoteType, string)> note) const
+{
+ if (!MXF::equals (other, opt, note)) {
+ return false;
+ }
+
+ ASDCP::PCM::MXFReader reader_A;
+ Kumu::Result_t r = reader_A.OpenRead (file().string().c_str());
+ if (ASDCP_FAILURE (r)) {
+ boost::throw_exception (MXFFileError ("could not open MXF file for reading", file().string(), r));
+ }
+
+ ASDCP::PCM::MXFReader reader_B;
+ r = reader_B.OpenRead (other->file().string().c_str());
+ if (ASDCP_FAILURE (r)) {
+ boost::throw_exception (MXFFileError ("could not open MXF file for reading", file().string(), r));
+ }
+
+ ASDCP::PCM::AudioDescriptor desc_A;
+ if (ASDCP_FAILURE (reader_A.FillAudioDescriptor (desc_A))) {
+ boost::throw_exception (DCPReadError ("could not read audio MXF information"));
+ }
+ ASDCP::PCM::AudioDescriptor desc_B;
+ if (ASDCP_FAILURE (reader_B.FillAudioDescriptor (desc_B))) {
+ boost::throw_exception (DCPReadError ("could not read audio MXF information"));
+ }
+
+ if (
+ desc_A.EditRate != desc_B.EditRate ||
+ desc_A.AudioSamplingRate != desc_B.AudioSamplingRate ||
+ desc_A.Locked != desc_B.Locked ||
+ desc_A.ChannelCount != desc_B.ChannelCount ||
+ desc_A.QuantizationBits != desc_B.QuantizationBits ||
+ desc_A.BlockAlign != desc_B.BlockAlign ||
+ desc_A.AvgBps != desc_B.AvgBps ||
+ desc_A.LinkedTrackID != desc_B.LinkedTrackID ||
+ desc_A.ContainerDuration != desc_B.ContainerDuration
+// desc_A.ChannelFormat != desc_B.ChannelFormat ||
+ ) {
+
+ note (ERROR, "audio MXF picture descriptors differ");
+ return false;
+ }
+
+ ASDCP::PCM::FrameBuffer buffer_A (1 * Kumu::Megabyte);
+ ASDCP::PCM::FrameBuffer buffer_B (1 * Kumu::Megabyte);
+
+ for (int i = 0; i < _intrinsic_duration; ++i) {
+ if (ASDCP_FAILURE (reader_A.ReadFrame (i, buffer_A))) {
+ boost::throw_exception (DCPReadError ("could not read audio frame"));
+ }
+
+ if (ASDCP_FAILURE (reader_B.ReadFrame (i, buffer_B))) {
+ boost::throw_exception (DCPReadError ("could not read audio frame"));
+ }
+
+ if (buffer_A.Size() != buffer_B.Size()) {
+ note (ERROR, String::compose ("sizes of audio data for frame %1 differ", i));
+ return false;
+ }
+
+ if (memcmp (buffer_A.RoData(), buffer_B.RoData(), buffer_A.Size()) != 0) {
+ for (uint32_t i = 0; i < buffer_A.Size(); ++i) {
+ int const d = abs (buffer_A.RoData()[i] - buffer_B.RoData()[i]);
+ if (d > opt.max_audio_sample_error) {
+ note (ERROR, String::compose ("PCM data difference of %1", d));
+ return false;
+ }
+ }
+ }
+ }
+
+ return true;
+}
+
+shared_ptr<const SoundFrame>
+SoundMXF::get_frame (int n) const
+{
+ /* XXX: should add on entry point here? */
+ return shared_ptr<const SoundFrame> (new SoundFrame (file(), n, _decryption_context));
+}
+
+shared_ptr<SoundMXFWriter>
+SoundMXF::start_write (boost::filesystem::path file, Standard standard)
+{
+ /* XXX: can't we use a shared_ptr here? */
+ return shared_ptr<SoundMXFWriter> (new SoundMXFWriter (this, file, standard));
+}
+
+string
+SoundMXF::key_type () const
+{
+ return "MDAK";
+}
--- /dev/null
+/*
+ Copyright (C) 2012-2014 Carl Hetherington <cth@carlh.net>
+
+ 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/sound_mxf.h
+ * @brief SoundMXF class
+ */
+
+#ifndef LIBDCP_SOUND_MXF_H
+#define LIBDCP_SOUND_MXF_H
+
+#include "mxf.h"
+#include "types.h"
+#include "metadata.h"
+
+namespace dcp
+{
+
+class SoundFrame;
+class SoundMXFWriter;
+
+/** @class SoundMXF
+ * @brief Representation of a MXF file containing sound
+ */
+class SoundMXF : public MXF
+{
+public:
+ SoundMXF (boost::filesystem::path file);
+ SoundMXF (Fraction edit_rate, int sampling_rate, int channels);
+
+ boost::shared_ptr<SoundMXFWriter> start_write (boost::filesystem::path file, Standard standard);
+
+ bool equals (
+ boost::shared_ptr<const Content> other,
+ EqualityOptions opt,
+ boost::function<void (NoteType, std::string)> note
+ ) const;
+
+ boost::shared_ptr<const SoundFrame> get_frame (int n) const;
+
+ /** @return number of channels */
+ int channels () const {
+ return _channels;
+ }
+
+ /** @return sampling rate in Hz */
+ int sampling_rate () const {
+ return _sampling_rate;
+ }
+
+private:
+ std::string key_type () const;
+ std::string asdcp_kind () const {
+ return "Sound";
+ }
+
+ int _channels; ///< number of channels
+ int _sampling_rate; ///< sampling rate in Hz
+};
+
+}
+
+#endif
--- /dev/null
+/*
+ Copyright (C) 2012-2014 Carl Hetherington <cth@carlh.net>
+
+ 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 "sound_mxf_writer.h"
+#include "sound_mxf.h"
+#include "exceptions.h"
+#include "compose.hpp"
+#include "AS_DCP.h"
+
+using namespace dcp;
+
+struct SoundMXFWriter::ASDCPState
+{
+ ASDCP::PCM::MXFWriter mxf_writer;
+ ASDCP::PCM::FrameBuffer frame_buffer;
+ ASDCP::WriterInfo writer_info;
+ ASDCP::PCM::AudioDescriptor audio_desc;
+ ASDCP::AESEncContext* encryption_context;
+};
+
+SoundMXFWriter::SoundMXFWriter (SoundMXF* m, boost::filesystem::path file, Standard standard)
+ : MXFWriter (m, file)
+ , _state (new SoundMXFWriter::ASDCPState)
+ , _sound_mxf (m)
+ , _frame_buffer_offset (0)
+{
+ _state->encryption_context = m->encryption_context ();
+
+ /* Derived from ASDCP::Wav::SimpleWaveHeader::FillADesc */
+ _state->audio_desc.EditRate = ASDCP::Rational (_sound_mxf->edit_rate().numerator, _sound_mxf->edit_rate().denominator);
+ _state->audio_desc.AudioSamplingRate = ASDCP::Rational (_sound_mxf->sampling_rate(), 1);
+ _state->audio_desc.Locked = 0;
+ _state->audio_desc.ChannelCount = _sound_mxf->channels ();
+ _state->audio_desc.QuantizationBits = 24;
+ _state->audio_desc.BlockAlign = 3 * _sound_mxf->channels();
+ _state->audio_desc.AvgBps = _sound_mxf->sampling_rate() * _state->audio_desc.BlockAlign;
+ _state->audio_desc.LinkedTrackID = 0;
+ _state->audio_desc.ChannelFormat = ASDCP::PCM::CF_NONE;
+
+ _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());
+
+ _sound_mxf->fill_writer_info (&_state->writer_info, standard);
+
+ Kumu::Result_t r = _state->mxf_writer.OpenWrite (file.string().c_str(), _state->writer_info, _state->audio_desc);
+ if (ASDCP_FAILURE (r)) {
+ boost::throw_exception (FileError ("could not open audio MXF for writing", file.string(), r));
+ }
+}
+
+void
+SoundMXFWriter::write (float const * const * data, int frames)
+{
+ assert (!_finalized);
+
+ for (int i = 0; i < frames; ++i) {
+
+ byte_t* out = _state->frame_buffer.Data() + _frame_buffer_offset;
+
+ /* Write one sample per channel */
+ for (int j = 0; j < _sound_mxf->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 * _sound_mxf->channels();
+
+ assert (_frame_buffer_offset <= int (_state->frame_buffer.Capacity()));
+
+ /* Finish the MXF frame if required */
+ if (_frame_buffer_offset == int (_state->frame_buffer.Capacity())) {
+ write_current_frame ();
+ _frame_buffer_offset = 0;
+ memset (_state->frame_buffer.Data(), 0, _state->frame_buffer.Capacity());
+ }
+ }
+}
+
+void
+SoundMXFWriter::write_current_frame ()
+{
+ ASDCP::Result_t const r = _state->mxf_writer.WriteFrame (_state->frame_buffer, _state->encryption_context, 0);
+ if (ASDCP_FAILURE (r)) {
+ boost::throw_exception (MiscError (String::compose ("could not write audio MXF frame (%1)", int (r))));
+ }
+
+ ++_frames_written;
+}
+
+void
+SoundMXFWriter::finalize ()
+{
+ if (_frame_buffer_offset > 0) {
+ write_current_frame ();
+ }
+
+ if (ASDCP_FAILURE (_state->mxf_writer.Finalize())) {
+ boost::throw_exception (MiscError ("could not finalise audio MXF"));
+ }
+
+ MXFWriter::finalize ();
+}
--- /dev/null
+/*
+ Copyright (C) 2012-2014 Carl Hetherington <cth@carlh.net>
+
+ 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 "mxf_writer.h"
+#include "types.h"
+#include <boost/shared_ptr.hpp>
+#include <boost/filesystem.hpp>
+
+namespace dcp {
+
+class SoundFrame;
+class SoundMXF;
+
+class SoundMXFWriter : public MXFWriter
+{
+public:
+ void write (float const * const *, int);
+ void finalize ();
+
+private:
+ friend class SoundMXF;
+
+ SoundMXFWriter (SoundMXF *, boost::filesystem::path, Standard standard);
+
+ void write_current_frame ();
+
+ /* do this with an opaque pointer so we don't have to include
+ ASDCP headers
+ */
+
+ struct ASDCPState;
+ boost::shared_ptr<ASDCPState> _state;
+
+ SoundMXF* _sound_mxf;
+ int _frame_buffer_offset;
+};
+
+}
+
+++ /dev/null
-/*
- Copyright (C) 2012-2013 Carl Hetherington <cth@carlh.net>
-
- 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 "srgb_linearised_gamma_lut.h"
-
-using namespace libdcp;
-
-LUTCache<SRGBLinearisedGammaLUT> SRGBLinearisedGammaLUT::cache;
-
-SRGBLinearisedGammaLUT::SRGBLinearisedGammaLUT (int bits, float gamma)
- : LUT (bits, gamma)
-{
- int const bit_length = pow (2, bits);
- for (int i = 0; i < bit_length; ++i) {
- float const p = static_cast<float> (i) / (bit_length - 1);
- if (p > 0.04045) {
- _lut[i] = pow ((p + 0.055) / 1.055, gamma);
- } else {
- _lut[i] = p / 12.92;
- }
- }
-}
+++ /dev/null
-/*
- Copyright (C) 2012-2013 Carl Hetherington <cth@carlh.net>
-
- 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 "lut.h"
-#include "lut_cache.h"
-
-namespace libdcp {
-
-class SRGBLinearisedGammaLUT : public LUT
-{
-public:
- SRGBLinearisedGammaLUT (int bit_length, float gamma);
- static LUTCache<SRGBLinearisedGammaLUT> cache;
-};
-
-}
+++ /dev/null
-/*
- Copyright (C) 2012-2013 Carl Hetherington <cth@carlh.net>
-
- 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 "AS_DCP.h"
-#include "stereo_picture_asset.h"
-#include "stereo_picture_frame.h"
-#include "exceptions.h"
-#include "stereo_picture_asset_writer.h"
-
-using std::string;
-using std::pair;
-using std::make_pair;
-using boost::shared_ptr;
-using boost::dynamic_pointer_cast;
-using namespace libdcp;
-
-bool
-StereoPictureAsset::equals (shared_ptr<const Asset> other, EqualityOptions opt, boost::function<void (NoteType, string)> note) const
-{
- if (!MXFAsset::equals (other, opt, note)) {
- return false;
- }
-
- ASDCP::JP2K::MXFSReader reader_A;
- Kumu::Result_t r = reader_A.OpenRead (path().string().c_str());
- if (ASDCP_FAILURE (r)) {
- boost::throw_exception (MXFFileError ("could not open MXF file for reading", path().string(), r));
- }
-
- ASDCP::JP2K::MXFSReader reader_B;
- r = reader_B.OpenRead (other->path().string().c_str());
- if (ASDCP_FAILURE (r)) {
- boost::throw_exception (MXFFileError ("could not open MXF file for reading", path().string(), r));
- }
-
- ASDCP::JP2K::PictureDescriptor desc_A;
- if (ASDCP_FAILURE (reader_A.FillPictureDescriptor (desc_A))) {
- boost::throw_exception (DCPReadError ("could not read video MXF information"));
- }
- ASDCP::JP2K::PictureDescriptor desc_B;
- if (ASDCP_FAILURE (reader_B.FillPictureDescriptor (desc_B))) {
- boost::throw_exception (DCPReadError ("could not read video MXF information"));
- }
-
- if (!descriptor_equals (desc_A, desc_B, note)) {
- return false;
- }
-
- shared_ptr<const StereoPictureAsset> other_picture = dynamic_pointer_cast<const StereoPictureAsset> (other);
- assert (other_picture);
-
- for (int i = 0; i < _intrinsic_duration; ++i) {
- shared_ptr<const StereoPictureFrame> frame_A = get_frame (i);
- shared_ptr<const StereoPictureFrame> frame_B = other_picture->get_frame (i);
-
- if (!frame_buffer_equals (
- i, opt, note,
- frame_A->left_j2k_data(), frame_A->left_j2k_size(),
- frame_B->left_j2k_data(), frame_B->left_j2k_size()
- )) {
- return false;
- }
-
- if (!frame_buffer_equals (
- i, opt, note,
- frame_A->right_j2k_data(), frame_A->right_j2k_size(),
- frame_B->right_j2k_data(), frame_B->right_j2k_size()
- )) {
- return false;
- }
- }
-
- return true;
-}
-
-StereoPictureAsset::StereoPictureAsset (boost::filesystem::path directory, boost::filesystem::path mxf_name)
- : PictureAsset (directory, mxf_name)
-{
-
-}
-
-void
-StereoPictureAsset::read ()
-{
- ASDCP::JP2K::MXFSReader reader;
- Kumu::Result_t r = reader.OpenRead (path().string().c_str());
- if (ASDCP_FAILURE (r)) {
- boost::throw_exception (MXFFileError ("could not open MXF file for reading", path().string(), r));
- }
-
- ASDCP::JP2K::PictureDescriptor desc;
- if (ASDCP_FAILURE (reader.FillPictureDescriptor (desc))) {
- boost::throw_exception (DCPReadError ("could not read video MXF information"));
- }
-
- _size.width = desc.StoredWidth;
- _size.height = desc.StoredHeight;
-}
-
-shared_ptr<const StereoPictureFrame>
-StereoPictureAsset::get_frame (int n) const
-{
- return shared_ptr<const StereoPictureFrame> (new StereoPictureFrame (path().string(), n));
-}
-
-shared_ptr<PictureAssetWriter>
-StereoPictureAsset::start_write (bool overwrite)
-{
- return shared_ptr<StereoPictureAssetWriter> (new StereoPictureAssetWriter (this, overwrite));
-}
-
-string
-StereoPictureAsset::cpl_node_name () const
-{
- return "msp-cpl:MainStereoscopicPicture";
-}
-
-pair<string, string>
-StereoPictureAsset::cpl_node_attribute () const
-{
- if (_interop) {
- return make_pair ("xmlns:msp-cpl", "http://www.digicine.com/schemas/437-Y/2007/Main-Stereo-Picture-CPL");
- } else {
- return make_pair ("xmlns:msp-cpl", "http://www.smpte-ra.org/schemas/429-10/2008/Main-Stereo-Picture-CPL");
- }
-
- return make_pair ("", "");
-}
-
-int
-StereoPictureAsset::edit_rate_factor () const
-{
- return 2;
-}
+++ /dev/null
-/*
- Copyright (C) 2012-2013 Carl Hetherington <cth@carlh.net>
-
- 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_STEREO_PICTURE_ASSET_H
-#define LIBDCP_STEREO_PICTURE_ASSET_H
-
-#include "picture_asset.h"
-
-namespace libdcp {
-
-/** A 3D (stereoscopic) picture asset */
-class StereoPictureAsset : public PictureAsset
-{
-public:
- StereoPictureAsset (boost::filesystem::path directory, boost::filesystem::path mxf_name);
-
- void read ();
-
- /** Start a progressive write to a StereoPictureAsset */
- boost::shared_ptr<PictureAssetWriter> start_write (bool);
-
- boost::shared_ptr<const StereoPictureFrame> get_frame (int n) const;
- bool equals (boost::shared_ptr<const Asset> other, EqualityOptions opt, boost::function<void (NoteType, std::string)> note) const;
-
-private:
- std::string cpl_node_name () const;
- std::pair<std::string, std::string> cpl_node_attribute () const;
- int edit_rate_factor () const;
-};
-
-}
-
-#endif
+++ /dev/null
-/*
- Copyright (C) 2012-2013 Carl Hetherington <cth@carlh.net>
-
- 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 "AS_DCP.h"
-#include "KM_fileio.h"
-#include "stereo_picture_asset_writer.h"
-#include "exceptions.h"
-#include "picture_asset.h"
-
-#include "picture_asset_writer_common.cc"
-
-using std::istream;
-using std::ostream;
-using std::string;
-using boost::shared_ptr;
-using namespace libdcp;
-
-struct StereoPictureAssetWriter::ASDCPState : public ASDCPStateBase
-{
- ASDCP::JP2K::MXFSWriter mxf_writer;
-};
-
-StereoPictureAssetWriter::StereoPictureAssetWriter (PictureAsset* asset, bool overwrite)
- : PictureAssetWriter (asset, overwrite)
- , _state (new StereoPictureAssetWriter::ASDCPState)
- , _next_eye (EYE_LEFT)
-{
- _state->encryption_context = asset->encryption_context ();
-}
-
-void
-StereoPictureAssetWriter::start (uint8_t* data, int size)
-{
- libdcp::start (this, _state, _asset, data, size);
-}
-
-/** Write a frame for one eye. Frames must be written left, then right, then left etc.
- * @param data JPEG2000 data.
- * @param size Size of data.
- */
-FrameInfo
-StereoPictureAssetWriter::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))) {
- boost::throw_exception (MiscError ("could not parse J2K frame"));
- }
-
- uint64_t const before_offset = _state->mxf_writer.Tell ();
-
- string hash;
- Kumu::Result_t r = _state->mxf_writer.WriteFrame (
- _state->frame_buffer,
- _next_eye == EYE_LEFT ? ASDCP::JP2K::SP_LEFT : ASDCP::JP2K::SP_RIGHT,
- _state->encryption_context,
- 0,
- &hash
- );
-
- if (ASDCP_FAILURE (r)) {
- boost::throw_exception (MXFFileError ("error in writing video MXF", _asset->path().string(), r));
- }
-
- _next_eye = _next_eye == EYE_LEFT ? EYE_RIGHT : EYE_LEFT;
-
- ++_frames_written;
- return FrameInfo (before_offset, _state->mxf_writer.Tell() - before_offset, hash);
-}
-
-void
-StereoPictureAssetWriter::fake_write (int size)
-{
- assert (_started);
- assert (!_finalized);
-
- Kumu::Result_t r = _state->mxf_writer.FakeWriteFrame (size, _next_eye == EYE_LEFT ? ASDCP::JP2K::SP_LEFT : ASDCP::JP2K::SP_RIGHT);
- if (ASDCP_FAILURE (r)) {
- boost::throw_exception (MXFFileError ("error in writing video MXF", _asset->path().string(), r));
- }
-
- _next_eye = _next_eye == EYE_LEFT ? EYE_RIGHT : EYE_LEFT;
- ++_frames_written;
-}
-
-void
-StereoPictureAssetWriter::finalize ()
-{
- assert (!_finalized);
-
- Kumu::Result_t r = _state->mxf_writer.Finalize();
- if (ASDCP_FAILURE (r)) {
- boost::throw_exception (MXFFileError ("error in finalizing video MXF", _asset->path().string(), r));
- }
-
- _finalized = true;
- _asset->set_intrinsic_duration (_frames_written / 2);
- _asset->set_duration (_frames_written / 2);
-}
+++ /dev/null
-/*
- Copyright (C) 2012-2013 Carl Hetherington <cth@carlh.net>
-
- 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 <stdint.h>
-#include <string>
-#include <fstream>
-#include <boost/shared_ptr.hpp>
-#include <boost/utility.hpp>
-#include "picture_asset_writer.h"
-
-namespace libdcp {
-
-/** A helper class for writing to StereoPictureAssets 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 StereoPictureAsset::start_write().
- *
- * Frames can be written to the MonoPictureAsset by calling write() with a JPEG2000 image
- * (a verbatim .j2c 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 StereoPictureAssetWriter : public PictureAssetWriter
-{
-public:
- FrameInfo write (uint8_t *, int);
- void fake_write (int size);
- void finalize ();
-
-private:
- friend class StereoPictureAsset;
-
- StereoPictureAssetWriter (PictureAsset *, bool);
- void start (uint8_t *, int);
-
- /* do this with an opaque pointer so we don't have to include
- ASDCP headers
- */
-
- struct ASDCPState;
- boost::shared_ptr<ASDCPState> _state;
-
- libdcp::Eye _next_eye;
-};
-
-}
/*
- Copyright (C) 2012 Carl Hetherington <cth@carlh.net>
+ Copyright (C) 2012-2014 Carl Hetherington <cth@carlh.net>
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
*/
-#include <openjpeg.h>
-#include "AS_DCP.h"
-#include "KM_fileio.h"
#include "stereo_picture_frame.h"
#include "exceptions.h"
#include "argb_frame.h"
-#include "lut.h"
#include "util.h"
#include "gamma_lut.h"
#include "rgb_xyz.h"
+#include "AS_DCP.h"
+#include "KM_fileio.h"
+#include <openjpeg.h>
#define DCI_GAMMA 2.6
using std::string;
using boost::shared_ptr;
-using namespace libdcp;
+using namespace dcp;
/** Make a picture frame from a 3D (stereoscopic) asset.
* @param mxf_path Path to the asset's MXF file.
delete _buffer;
}
-/** @param reduce a factor by which to reduce the resolution
+/** @param eye Eye to return (EYE_LEFT or EYE_RIGHT).
+ * @param reduce a factor by which to reduce the resolution
* of the image, expressed as a power of two (pass 0 for no
* reduction).
- *
- * @param eye Eye to return (EYE_LEFT or EYE_RIGHT).
+ * @param srgb_gamma Reciprocal of gamma to use when doing the
+ * output gamma correction (after conversion from XYZ to RGB).
*
* @return An ARGB representation of one of the eyes (left or right)
* of this frame. This is ARGB in the Cairo sense, so that each
break;
}
- return xyz_to_rgb (xyz_frame, GammaLUT::cache.get (12, DCI_GAMMA), GammaLUT::cache.get (12, 1 / srgb_gamma));
+ return xyz_to_rgb (xyz_frame, GammaLUT::cache.get (12, DCI_GAMMA, false), GammaLUT::cache.get (12, 1 / srgb_gamma, false));
}
uint8_t const *
/*
- Copyright (C) 2012-2013 Carl Hetherington <cth@carlh.net>
+ Copyright (C) 2012-2014 Carl Hetherington <cth@carlh.net>
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
*/
-#include <string>
-#include <stdint.h>
-#include <boost/shared_ptr.hpp>
#include "types.h"
+#include <boost/shared_ptr.hpp>
+#include <boost/noncopyable.hpp>
+#include <boost/filesystem.hpp>
+#include <stdint.h>
+#include <string>
namespace ASDCP {
namespace JP2K {
class AESDecContext;
}
-namespace libdcp {
+namespace dcp {
class ARGBFrame;
/** A single frame of a 3D (stereoscopic) picture asset */
-class StereoPictureFrame
+class StereoPictureFrame : public boost::noncopyable
{
public:
StereoPictureFrame (boost::filesystem::path mxf_path, int n);
--- /dev/null
+/*
+ Copyright (C) 2012-2014 Carl Hetherington <cth@carlh.net>
+
+ 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 "AS_DCP.h"
+#include "stereo_picture_mxf.h"
+#include "stereo_picture_frame.h"
+#include "exceptions.h"
+#include "stereo_picture_mxf_writer.h"
+
+using std::string;
+using std::pair;
+using std::make_pair;
+using boost::shared_ptr;
+using boost::dynamic_pointer_cast;
+using namespace dcp;
+
+StereoPictureMXF::StereoPictureMXF (boost::filesystem::path file)
+ : PictureMXF (file)
+{
+ ASDCP::JP2K::MXFSReader reader;
+ Kumu::Result_t r = reader.OpenRead (file.string().c_str());
+ if (ASDCP_FAILURE (r)) {
+ boost::throw_exception (MXFFileError ("could not open MXF file for reading", file.string(), r));
+ }
+
+ ASDCP::JP2K::PictureDescriptor desc;
+ if (ASDCP_FAILURE (reader.FillPictureDescriptor (desc))) {
+ boost::throw_exception (DCPReadError ("could not read video MXF information"));
+ }
+
+ read_picture_descriptor (desc);
+
+ ASDCP::WriterInfo info;
+ if (ASDCP_FAILURE (reader.FillWriterInfo (info))) {
+ boost::throw_exception (DCPReadError ("could not read video MXF information"));
+ }
+
+ read_writer_info (info);
+}
+
+StereoPictureMXF::StereoPictureMXF (Fraction edit_rate)
+ : PictureMXF
+ (edit_rate)
+{
+
+}
+
+shared_ptr<const StereoPictureFrame>
+StereoPictureMXF::get_frame (int n) const
+{
+ return shared_ptr<const StereoPictureFrame> (new StereoPictureFrame (file().string(), n));
+}
+
+shared_ptr<PictureMXFWriter>
+StereoPictureMXF::start_write (boost::filesystem::path file, Standard standard, bool overwrite)
+{
+ return shared_ptr<StereoPictureMXFWriter> (new StereoPictureMXFWriter (this, file, standard, overwrite));
+}
+
+bool
+StereoPictureMXF::equals (shared_ptr<const Content> other, EqualityOptions opt, boost::function<void (NoteType, string)> note) const
+{
+ if (!MXF::equals (other, opt, note)) {
+ return false;
+ }
+
+ ASDCP::JP2K::MXFSReader reader_A;
+ Kumu::Result_t r = reader_A.OpenRead (file().string().c_str());
+ if (ASDCP_FAILURE (r)) {
+ boost::throw_exception (MXFFileError ("could not open MXF file for reading", file().string(), r));
+ }
+
+ ASDCP::JP2K::MXFSReader reader_B;
+ r = reader_B.OpenRead (other->file().string().c_str());
+ if (ASDCP_FAILURE (r)) {
+ boost::throw_exception (MXFFileError ("could not open MXF file for reading", file().string(), r));
+ }
+
+ ASDCP::JP2K::PictureDescriptor desc_A;
+ if (ASDCP_FAILURE (reader_A.FillPictureDescriptor (desc_A))) {
+ boost::throw_exception (DCPReadError ("could not read video MXF information"));
+ }
+ ASDCP::JP2K::PictureDescriptor desc_B;
+ if (ASDCP_FAILURE (reader_B.FillPictureDescriptor (desc_B))) {
+ boost::throw_exception (DCPReadError ("could not read video MXF information"));
+ }
+
+ if (!descriptor_equals (desc_A, desc_B, note)) {
+ return false;
+ }
+
+ shared_ptr<const StereoPictureMXF> other_picture = dynamic_pointer_cast<const StereoPictureMXF> (other);
+ assert (other_picture);
+
+ for (int i = 0; i < _intrinsic_duration; ++i) {
+ shared_ptr<const StereoPictureFrame> frame_A = get_frame (i);
+ shared_ptr<const StereoPictureFrame> frame_B = other_picture->get_frame (i);
+
+ if (!frame_buffer_equals (
+ i, opt, note,
+ frame_A->left_j2k_data(), frame_A->left_j2k_size(),
+ frame_B->left_j2k_data(), frame_B->left_j2k_size()
+ )) {
+ return false;
+ }
+
+ if (!frame_buffer_equals (
+ i, opt, note,
+ frame_A->right_j2k_data(), frame_A->right_j2k_size(),
+ frame_B->right_j2k_data(), frame_B->right_j2k_size()
+ )) {
+ return false;
+ }
+ }
+
+ return true;
+}
--- /dev/null
+/*
+ Copyright (C) 2012-2014 Carl Hetherington <cth@carlh.net>
+
+ 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_STEREO_PICTURE_MXF_H
+#define LIBDCP_STEREO_PICTURE_MXF_H
+
+#include "picture_mxf.h"
+
+namespace dcp {
+
+/** A 3D (stereoscopic) picture asset */
+class StereoPictureMXF : public PictureMXF
+{
+public:
+ StereoPictureMXF (boost::filesystem::path file);
+ StereoPictureMXF (Fraction edit_rate);
+
+ /** Start a progressive write to a StereoPictureMXF */
+ boost::shared_ptr<PictureMXFWriter> start_write (boost::filesystem::path file, Standard, bool);
+
+ bool equals (
+ boost::shared_ptr<const Content> other,
+ EqualityOptions opt,
+ boost::function<void (NoteType, std::string)> note
+ ) const;
+
+ boost::shared_ptr<const StereoPictureFrame> get_frame (int n) const;
+};
+
+}
+
+#endif
--- /dev/null
+/*
+ Copyright (C) 2012-2014 Carl Hetherington <cth@carlh.net>
+
+ 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 "stereo_picture_mxf_writer.h"
+#include "exceptions.h"
+#include "picture_mxf.h"
+#include "AS_DCP.h"
+#include "KM_fileio.h"
+
+#include "picture_mxf_writer_common.cc"
+
+using std::istream;
+using std::ostream;
+using std::string;
+using boost::shared_ptr;
+using namespace dcp;
+
+struct StereoPictureMXFWriter::ASDCPState : public ASDCPStateBase
+{
+ ASDCP::JP2K::MXFSWriter mxf_writer;
+};
+
+StereoPictureMXFWriter::StereoPictureMXFWriter (PictureMXF* mxf, boost::filesystem::path file, Standard standard, bool overwrite)
+ : PictureMXFWriter (mxf, file, standard, overwrite)
+ , _state (new StereoPictureMXFWriter::ASDCPState)
+ , _next_eye (EYE_LEFT)
+{
+ _state->encryption_context = mxf->encryption_context ();
+}
+
+void
+StereoPictureMXFWriter::start (uint8_t* data, int size)
+{
+ dcp::start (this, _state, _standard, _picture_mxf, data, size);
+ _picture_mxf->set_frame_rate (Fraction (_picture_mxf->edit_rate().numerator * 2, _picture_mxf->edit_rate().denominator));
+}
+
+/** Write a frame for one eye. Frames must be written left, then right, then left etc.
+ * @param data JPEG2000 data.
+ * @param size Size of data.
+ */
+FrameInfo
+StereoPictureMXFWriter::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))) {
+ boost::throw_exception (MiscError ("could not parse J2K frame"));
+ }
+
+ uint64_t const before_offset = _state->mxf_writer.Tell ();
+
+ string hash;
+ Kumu::Result_t r = _state->mxf_writer.WriteFrame (
+ _state->frame_buffer,
+ _next_eye == EYE_LEFT ? ASDCP::JP2K::SP_LEFT : ASDCP::JP2K::SP_RIGHT,
+ _state->encryption_context,
+ 0,
+ &hash
+ );
+
+ if (ASDCP_FAILURE (r)) {
+ boost::throw_exception (MXFFileError ("error in writing video MXF", _mxf->file().string(), r));
+ }
+
+ _next_eye = _next_eye == EYE_LEFT ? EYE_RIGHT : EYE_LEFT;
+
+ if (_next_eye == EYE_LEFT) {
+ ++_frames_written;
+ }
+
+ return FrameInfo (before_offset, _state->mxf_writer.Tell() - before_offset, hash);
+}
+
+void
+StereoPictureMXFWriter::fake_write (int size)
+{
+ assert (_started);
+ assert (!_finalized);
+
+ Kumu::Result_t r = _state->mxf_writer.FakeWriteFrame (size, _next_eye == EYE_LEFT ? ASDCP::JP2K::SP_LEFT : ASDCP::JP2K::SP_RIGHT);
+ if (ASDCP_FAILURE (r)) {
+ boost::throw_exception (MXFFileError ("error in writing video MXF", _mxf->file().string(), r));
+ }
+
+ _next_eye = _next_eye == EYE_LEFT ? EYE_RIGHT : EYE_LEFT;
+ if (_next_eye == EYE_LEFT) {
+ ++_frames_written;
+ }
+}
+
+void
+StereoPictureMXFWriter::finalize ()
+{
+ Kumu::Result_t r = _state->mxf_writer.Finalize();
+ if (ASDCP_FAILURE (r)) {
+ boost::throw_exception (MXFFileError ("error in finalizing video MXF", _mxf->file().string(), r));
+ }
+
+ PictureMXFWriter::finalize ();
+}
--- /dev/null
+/*
+ Copyright (C) 2012-2014 Carl Hetherington <cth@carlh.net>
+
+ 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 "picture_mxf_writer.h"
+#include "types.h"
+#include <boost/shared_ptr.hpp>
+#include <boost/utility.hpp>
+#include <stdint.h>
+#include <string>
+#include <fstream>
+
+namespace dcp {
+
+/** A helper class for writing to StereoPictureAssets 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 StereoPictureAsset::start_write().
+ *
+ * Frames can be written to the MonoPictureAsset by calling write() with a JPEG2000 image
+ * (a verbatim .j2c 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 StereoPictureMXFWriter : public PictureMXFWriter
+{
+public:
+ FrameInfo write (uint8_t *, int);
+ void fake_write (int size);
+ void finalize ();
+
+private:
+ friend class StereoPictureMXF;
+
+ StereoPictureMXFWriter (PictureMXF *, boost::filesystem::path file, Standard, bool);
+ void start (uint8_t *, int);
+
+ /* do this with an opaque pointer so we don't have to include
+ ASDCP headers
+ */
+
+ struct ASDCPState;
+ boost::shared_ptr<ASDCPState> _state;
+
+ dcp::Eye _next_eye;
+};
+
+}
--- /dev/null
+/*
+ Copyright (C) 2012-2014 Carl Hetherington <cth@carlh.net>
+
+ 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 "subtitle.h"
+#include "xml.h"
+#include "font.h"
+#include "text.h"
+#include <libcxml/cxml.h>
+
+using std::string;
+using boost::shared_ptr;
+using boost::lexical_cast;
+using namespace dcp;
+
+Subtitle::Subtitle (boost::shared_ptr<const cxml::Node> node)
+{
+ in = Time (node->string_attribute ("TimeIn"));
+ out = Time (node->string_attribute ("TimeOut"));
+ font_nodes = type_children<Font> (node, "Font");
+ text_nodes = type_children<Text> (node, "Text");
+ fade_up_time = fade_time (node, "FadeUpTime");
+ fade_down_time = fade_time (node, "FadeDownTime");
+}
+
+Time
+Subtitle::fade_time (shared_ptr<const cxml::Node> 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<int> (u));
+ }
+
+ if (t > Time (0, 0, 8, 0)) {
+ t = Time (0, 0, 8, 0);
+ }
+
+ return t;
+}
--- /dev/null
+/*
+ Copyright (C) 2012-2014 Carl Hetherington <cth@carlh.net>
+
+ 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_SUBTITLE_H
+#define LIBDCP_SUBTITLE_H
+
+#include "dcp_time.h"
+#include <boost/shared_ptr.hpp>
+#include <list>
+
+namespace cxml {
+ class Node;
+}
+
+namespace dcp {
+
+class Font;
+class Text;
+
+class Subtitle
+{
+public:
+ Subtitle () {}
+ Subtitle (boost::shared_ptr<const cxml::Node> node);
+
+ Time in;
+ Time out;
+ Time fade_up_time;
+ Time fade_down_time;
+ std::list<boost::shared_ptr<Font> > font_nodes;
+ std::list<boost::shared_ptr<Text> > text_nodes;
+
+private:
+ Time fade_time (boost::shared_ptr<const cxml::Node>, std::string name);
+};
+
+}
+
+#endif
+++ /dev/null
-/*
- Copyright (C) 2012 Carl Hetherington <cth@carlh.net>
-
- 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 <fstream>
-#include <cerrno>
-#include <boost/lexical_cast.hpp>
-#include <boost/algorithm/string.hpp>
-#include <libxml++/nodes/element.h>
-#include "AS_DCP.h"
-#include "KM_util.h"
-#include "subtitle_asset.h"
-#include "parse/subtitle.h"
-#include "util.h"
-#include "xml.h"
-
-using std::string;
-using std::list;
-using std::ostream;
-using std::ofstream;
-using std::stringstream;
-using std::cout;
-using boost::shared_ptr;
-using boost::lexical_cast;
-using boost::optional;
-using namespace libdcp;
-
-SubtitleAsset::SubtitleAsset (string directory, string file)
- : Asset (directory, file)
- , _need_sort (false)
-{
- /* Grotesque hack: we should look in the PKL to see what type this file is;
- instead we'll look at the first character to decide what to do.
- I think this is easily fixable (properly) in 1.0.
- */
-
- FILE* f = fopen_boost (path(), "r");
- if (!f) {
- throw FileError ("Could not open file for reading", file, errno);
- }
- unsigned char test[1];
- fread (test, 1, 1, f);
- fclose (f);
-
- if (test[0] == '<' || test[0] == 0xef) {
- read_xml (path().string());
- } else {
- read_mxf (path().string());
- }
-}
-
-SubtitleAsset::SubtitleAsset (string directory, string movie_title, string language)
- : Asset (directory)
- , _movie_title (movie_title)
- , _reel_number ("1")
- , _language (language)
- , _need_sort (false)
-{
-
-}
-
-void
-SubtitleAsset::read_mxf (string mxf_file)
-{
- ASDCP::TimedText::MXFReader reader;
- Kumu::Result_t r = reader.OpenRead (mxf_file.c_str ());
- if (ASDCP_FAILURE (r)) {
- boost::throw_exception (MXFFileError ("could not open MXF file for reading", mxf_file, r));
- }
-
- string s;
- reader.ReadTimedTextResource (s, 0, 0);
- shared_ptr<cxml::Document> xml (new cxml::Document ("SubtitleReel"));
- stringstream t;
- t << s;
- xml->read_stream (t);
- read_xml (xml);
-}
-
-void
-SubtitleAsset::read_xml (string xml_file)
-{
- shared_ptr<cxml::Document> xml (new cxml::Document ("DCSubtitle"));
- xml->read_file (xml_file);
- read_xml (xml);
-}
-
-void
-SubtitleAsset::read_xml (shared_ptr<cxml::Document> xml)
-{
- /* XXX: hacks aplenty in here; need separate parsers for DCSubtitle and SubtitleReel */
-
- /* DCSubtitle */
- optional<string> x = xml->optional_string_child ("SubtitleID");
- if (!x) {
- /* SubtitleReel */
- x = xml->optional_string_child ("Id");
- }
- _uuid = x.get_value_or ("");
-
- _movie_title = xml->optional_string_child ("MovieTitle");
- _reel_number = xml->string_child ("ReelNumber");
- _language = xml->string_child ("Language");
-
- xml->ignore_child ("LoadFont");
-
- list<shared_ptr<libdcp::parse::Font> > font_nodes = type_children<libdcp::parse::Font> (xml, "Font");
- _load_font_nodes = type_children<libdcp::parse::LoadFont> (xml, "LoadFont");
-
- /* Now make Subtitle objects to represent the raw XML nodes
- in a sane way.
- */
-
- shared_ptr<cxml::Node> subtitle_list = xml->optional_node_child ("SubtitleList");
- if (subtitle_list) {
- list<shared_ptr<libdcp::parse::Font> > font = type_children<libdcp::parse::Font> (subtitle_list, "Font");
- copy (font.begin(), font.end(), back_inserter (font_nodes));
- }
-
- ParseState parse_state;
- examine_font_nodes (xml, font_nodes, parse_state);
-}
-
-void
-SubtitleAsset::examine_font_nodes (
- shared_ptr<const cxml::Node> xml,
- list<shared_ptr<libdcp::parse::Font> > const & font_nodes,
- ParseState& parse_state
- )
-{
- for (list<shared_ptr<libdcp::parse::Font> >::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<shared_ptr<libdcp::parse::Subtitle> >::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);
- parse_state.subtitle_nodes.pop_back ();
- }
-
- examine_font_nodes (xml, (*i)->font_nodes, parse_state);
- examine_text_nodes (xml, (*i)->text_nodes, parse_state);
-
- parse_state.font_nodes.pop_back ();
- }
-}
-
-void
-SubtitleAsset::examine_text_nodes (
- shared_ptr<const cxml::Node> xml,
- list<shared_ptr<libdcp::parse::Text> > const & text_nodes,
- ParseState& parse_state
- )
-{
- for (list<shared_ptr<libdcp::parse::Text> >::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);
- parse_state.text_nodes.pop_back ();
- }
-}
-
-void
-SubtitleAsset::maybe_add_subtitle (string text, ParseState const & parse_state)
-{
- if (empty_or_white_space (text)) {
- return;
- }
-
- if (parse_state.text_nodes.empty() || parse_state.subtitle_nodes.empty ()) {
- return;
- }
-
- assert (!parse_state.text_nodes.empty ());
- assert (!parse_state.subtitle_nodes.empty ());
-
- libdcp::parse::Font effective_font (parse_state.font_nodes);
- libdcp::parse::Text effective_text (*parse_state.text_nodes.back ());
- libdcp::parse::Subtitle effective_subtitle (*parse_state.subtitle_nodes.back ());
-
- _subtitles.push_back (
- shared_ptr<Subtitle> (
- new Subtitle (
- font_id_to_name (effective_font.id),
- effective_font.italic.get(),
- effective_font.color.get(),
- effective_font.size,
- effective_subtitle.in,
- effective_subtitle.out,
- effective_text.v_position,
- effective_text.v_align,
- text,
- effective_font.effect ? effective_font.effect.get() : NONE,
- effective_font.effect_color.get(),
- effective_subtitle.fade_up_time,
- effective_subtitle.fade_down_time
- )
- )
- );
-}
-
-list<shared_ptr<Subtitle> >
-SubtitleAsset::subtitles_at (Time t) const
-{
- list<shared_ptr<Subtitle> > s;
- for (list<shared_ptr<Subtitle> >::const_iterator i = _subtitles.begin(); i != _subtitles.end(); ++i) {
- if ((*i)->in() <= t && t <= (*i)->out ()) {
- s.push_back (*i);
- }
- }
-
- return s;
-}
-
-std::string
-SubtitleAsset::font_id_to_name (string id) const
-{
- list<shared_ptr<libdcp::parse::LoadFont> >::const_iterator i = _load_font_nodes.begin();
- while (i != _load_font_nodes.end() && (*i)->id != id) {
- ++i;
- }
-
- if (i == _load_font_nodes.end ()) {
- return "";
- }
-
- if ((*i)->uri && (*i)->uri.get() == "arial.ttf") {
- return "Arial";
- }
-
- return "";
-}
-
-Subtitle::Subtitle (
- string font,
- bool italic,
- Color color,
- int size,
- Time in,
- Time out,
- float v_position,
- VAlign v_align,
- string text,
- Effect effect,
- Color effect_color,
- Time fade_up_time,
- Time fade_down_time
- )
- : _font (font)
- , _italic (italic)
- , _color (color)
- , _size (size)
- , _in (in)
- , _out (out)
- , _v_position (v_position)
- , _v_align (v_align)
- , _text (text)
- , _effect (effect)
- , _effect_color (effect_color)
- , _fade_up_time (fade_up_time)
- , _fade_down_time (fade_down_time)
-{
-
-}
-
-int
-Subtitle::size_in_pixels (int screen_height) const
-{
- /* Size in the subtitle file is given in points as if the screen
- height is 11 inches, so a 72pt font would be 1/11th of the screen
- height.
- */
-
- return _size * screen_height / (11 * 72);
-}
-
-bool
-libdcp::operator== (Subtitle const & a, Subtitle const & b)
-{
- return (
- a.font() == b.font() &&
- a.italic() == b.italic() &&
- a.color() == b.color() &&
- a.size() == b.size() &&
- a.in() == b.in() &&
- a.out() == b.out() &&
- a.v_position() == b.v_position() &&
- a.v_align() == b.v_align() &&
- a.text() == b.text() &&
- a.effect() == b.effect() &&
- a.effect_color() == b.effect_color() &&
- a.fade_up_time() == b.fade_up_time() &&
- a.fade_down_time() == b.fade_down_time()
- );
-}
-
-ostream&
-libdcp::operator<< (ostream& s, Subtitle const & sub)
-{
- s << "\n`" << sub.text() << "' from " << sub.in() << " to " << sub.out() << ";\n"
- << "fade up " << sub.fade_up_time() << ", fade down " << sub.fade_down_time() << ";\n"
- << "font " << sub.font() << ", ";
-
- if (sub.italic()) {
- s << "italic";
- } else {
- s << "non-italic";
- }
-
- s << ", size " << sub.size() << ", color " << sub.color() << ", vpos " << sub.v_position() << ", valign " << ((int) sub.v_align()) << ";\n"
- << "effect " << ((int) sub.effect()) << ", effect color " << sub.effect_color();
-
- return s;
-}
-
-void
-SubtitleAsset::add (shared_ptr<Subtitle> s)
-{
- _subtitles.push_back (s);
- _need_sort = true;
-}
-
-void
-SubtitleAsset::write_to_cpl (xmlpp::Element* node) const
-{
- /* XXX: should EditRate, Duration and IntrinsicDuration be in here? */
-
- 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.string ());
- /* XXX */
- ms->add_child("EntryPoint")->add_child_text ("0");
-}
-
-struct SubtitleSorter {
- bool operator() (shared_ptr<Subtitle> a, shared_ptr<Subtitle> b) {
- if (a->in() != b->in()) {
- return a->in() < b->in();
- }
- return a->v_position() < b->v_position();
- }
-};
-
-void
-SubtitleAsset::write_xml () const
-{
- FILE* f = fopen_boost (path (), "r");
- Glib::ustring const s = xml_as_string ();
- fwrite (s.c_str(), 1, s.length(), f);
- fclose (f);
-}
-
-Glib::ustring
-SubtitleAsset::xml_as_string () const
-{
- 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);
- if (_movie_title) {
- root->add_child("MovieTitle")->add_child_text (_movie_title.get ());
- }
- root->add_child("ReelNumber")->add_child_text (lexical_cast<string> (_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 ()) {
- xmlpp::Element* load_font = root->add_child("LoadFont");
- load_font->set_attribute("Id", _load_font_nodes.front()->id);
- if (_load_font_nodes.front()->uri) {
- load_font->set_attribute("URI", _load_font_nodes.front()->uri.get ());
- }
- }
-
- list<shared_ptr<Subtitle> > sorted = _subtitles;
- if (_need_sort) {
- sorted.sort (SubtitleSorter ());
- }
-
- /* XXX: multiple fonts not supported */
- /* XXX: script, underlined, weight not supported */
-
- bool italic = false;
- Color color;
- int size = 0;
- Effect effect = NONE;
- Color effect_color;
- int spot_number = 1;
- Time last_in;
- Time last_out;
- Time last_fade_up_time;
- Time last_fade_down_time;
-
- xmlpp::Element* font = 0;
- xmlpp::Element* subtitle = 0;
-
- for (list<shared_ptr<Subtitle> >::iterator i = sorted.begin(); i != sorted.end(); ++i) {
-
- /* We will start a new <Font>...</Font> whenever some font property changes.
- I suppose we should really make an optimal hierarchy of <Font> tags, but
- that seems hard.
- */
-
- bool const font_changed =
- italic != (*i)->italic() ||
- color != (*i)->color() ||
- size != (*i)->size() ||
- effect != (*i)->effect() ||
- effect_color != (*i)->effect_color();
-
- if (font_changed) {
- italic = (*i)->italic ();
- color = (*i)->color ();
- size = (*i)->size ();
- effect = (*i)->effect ();
- effect_color = (*i)->effect_color ();
- }
-
- 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<string> (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 || font_changed ||
- (last_in != (*i)->in() ||
- last_out != (*i)->out() ||
- last_fade_up_time != (*i)->fade_up_time() ||
- last_fade_down_time != (*i)->fade_down_time()
- )) {
-
- subtitle = font->add_child ("Subtitle");
- subtitle->set_attribute ("SpotNumber", lexical_cast<string> (spot_number++));
- subtitle->set_attribute ("TimeIn", (*i)->in().to_string());
- subtitle->set_attribute ("TimeOut", (*i)->out().to_string());
- subtitle->set_attribute ("FadeUpTime", lexical_cast<string> ((*i)->fade_up_time().to_ticks()));
- subtitle->set_attribute ("FadeDownTime", lexical_cast<string> ((*i)->fade_down_time().to_ticks()));
-
- last_in = (*i)->in ();
- last_out = (*i)->out ();
- last_fade_up_time = (*i)->fade_up_time ();
- last_fade_down_time = (*i)->fade_down_time ();
- }
-
- xmlpp::Element* text = subtitle->add_child ("Text");
- text->set_attribute ("VAlign", valign_to_string ((*i)->v_align()));
- text->set_attribute ("VPosition", lexical_cast<string> ((*i)->v_position()));
- text->add_child_text ((*i)->text());
- }
-
- return doc.write_to_string_formatted ("UTF-8");
-}
-
+++ /dev/null
-/*
- Copyright (C) 2012 Carl Hetherington <cth@carlh.net>
-
- 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_SUBTITLE_ASSET_H
-#define LIBDCP_SUBTITLE_ASSET_H
-
-#include <libcxml/cxml.h>
-#include "asset.h"
-#include "dcp_time.h"
-
-namespace libdcp
-{
-
-namespace parse
-{
- class Font;
- class Text;
- class Subtitle;
- class LoadFont;
-}
-
-class Subtitle
-{
-public:
- Subtitle (
- std::string font,
- bool italic,
- Color color,
- int size,
- Time in,
- Time out,
- float v_position,
- VAlign v_align,
- std::string text,
- Effect effect,
- Color effect_color,
- Time fade_up_time,
- Time fade_down_time
- );
-
- std::string font () const {
- return _font;
- }
-
- bool italic () const {
- return _italic;
- }
-
- Color color () const {
- return _color;
- }
-
- Time in () const {
- return _in;
- }
-
- Time out () const {
- return _out;
- }
-
- std::string text () const {
- return _text;
- }
-
- float v_position () const {
- return _v_position;
- }
-
- VAlign v_align () const {
- return _v_align;
- }
-
- Effect effect () const {
- return _effect;
- }
-
- Color effect_color () const {
- return _effect_color;
- }
-
- Time fade_up_time () const {
- return _fade_up_time;
- }
-
- Time fade_down_time () const {
- return _fade_down_time;
- }
-
- int size () const {
- return _size;
- }
-
- int size_in_pixels (int screen_height) const;
-
-private:
- std::string _font;
- bool _italic;
- Color _color;
- /** Size in points as if the screen height is 11 inches, so a 72pt font
- * would be 1/11th of the screen height.
- */
- int _size;
- Time _in;
- Time _out;
- /** Vertical position as a proportion of the screen height from the top
- * (between 0 and 1)
- */
- float _v_position;
- VAlign _v_align;
- std::string _text;
- Effect _effect;
- Color _effect_color;
- Time _fade_up_time;
- Time _fade_down_time;
-};
-
-bool operator== (Subtitle const & a, Subtitle const & b);
-std::ostream& operator<< (std::ostream& s, Subtitle const & sub);
-
-class SubtitleAsset : public Asset
-{
-public:
- SubtitleAsset (std::string directory, std::string xml_file);
- SubtitleAsset (std::string directory, std::string movie_title, std::string language);
-
- void write_to_cpl (xmlpp::Element *) const;
- virtual bool equals (boost::shared_ptr<const Asset>, EqualityOptions, boost::function<void (NoteType, std::string)> note) const {
- /* XXX */
- note (ERROR, "subtitle assets not compared yet");
- return true;
- }
-
- std::string language () const {
- return _language;
- }
-
- std::list<boost::shared_ptr<Subtitle> > subtitles_at (Time t) const;
- std::list<boost::shared_ptr<Subtitle> > const & subtitles () const {
- return _subtitles;
- }
-
- void add (boost::shared_ptr<Subtitle>);
-
- void read_xml (std::string);
- void write_xml () const;
- Glib::ustring xml_as_string () const;
-
-protected:
-
- std::string asdcp_kind () const {
- return "Subtitle";
- }
-
-private:
- std::string font_id_to_name (std::string id) const;
- void read_mxf (std::string);
- void read_xml (boost::shared_ptr<cxml::Document>);
-
- struct ParseState {
- std::list<boost::shared_ptr<parse::Font> > font_nodes;
- std::list<boost::shared_ptr<parse::Text> > text_nodes;
- std::list<boost::shared_ptr<parse::Subtitle> > subtitle_nodes;
- };
-
- void maybe_add_subtitle (std::string text, ParseState const & parse_state);
-
- void examine_font_nodes (
- boost::shared_ptr<const cxml::Node> xml,
- std::list<boost::shared_ptr<parse::Font> > const & font_nodes,
- ParseState& parse_state
- );
-
- void examine_text_nodes (
- boost::shared_ptr<const cxml::Node> xml,
- std::list<boost::shared_ptr<parse::Text> > const & text_nodes,
- ParseState& parse_state
- );
-
- boost::optional<std::string> _movie_title;
- /* strangely, this is sometimes a string */
- std::string _reel_number;
- std::string _language;
- std::list<boost::shared_ptr<parse::LoadFont> > _load_font_nodes;
-
- std::list<boost::shared_ptr<Subtitle> > _subtitles;
- bool _need_sort;
-};
-
-}
-
-#endif
--- /dev/null
+/*
+ Copyright (C) 2012-2014 Carl Hetherington <cth@carlh.net>
+
+ 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 "subtitle_content.h"
+#include "util.h"
+#include "xml.h"
+#include "font.h"
+#include "text.h"
+#include "load_font.h"
+#include "subtitle_string.h"
+#include <libxml++/nodes/element.h>
+#include <boost/lexical_cast.hpp>
+#include <boost/algorithm/string.hpp>
+#include <fstream>
+
+using std::string;
+using std::list;
+using std::ostream;
+using std::ofstream;
+using std::stringstream;
+using std::cout;
+using boost::shared_ptr;
+using boost::lexical_cast;
+using boost::optional;
+using namespace dcp;
+
+SubtitleContent::SubtitleContent (boost::filesystem::path file)
+ : Content (file)
+ , _need_sort (false)
+{
+ shared_ptr<cxml::Document> xml (new cxml::Document ("DCSubtitle"));
+ xml->read_file (file);
+
+ _id = xml->string_child ("SubtitleID");
+ _movie_title = xml->string_child ("MovieTitle");
+ _reel_number = xml->string_child ("ReelNumber");
+ _language = xml->string_child ("Language");
+
+ xml->ignore_child ("LoadFont");
+
+ list<shared_ptr<dcp::Font> > font_nodes = type_children<dcp::Font> (xml, "Font");
+ _load_font_nodes = type_children<dcp::LoadFont> (xml, "LoadFont");
+
+ /* Now make Subtitle objects to represent the raw XML nodes
+ in a sane way.
+ */
+
+ ParseState parse_state;
+ examine_font_nodes (xml, font_nodes, parse_state);
+}
+
+SubtitleContent::SubtitleContent (Fraction edit_rate, string movie_title, string language)
+ : Content (edit_rate)
+ , _movie_title (movie_title)
+ , _reel_number ("1")
+ , _language (language)
+ , _need_sort (false)
+{
+
+}
+
+void
+SubtitleContent::examine_font_nodes (
+ shared_ptr<const cxml::Node> xml,
+ list<shared_ptr<dcp::Font> > const & font_nodes,
+ ParseState& parse_state
+ )
+{
+ for (list<shared_ptr<dcp::Font> >::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<shared_ptr<dcp::Subtitle> >::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);
+ parse_state.subtitle_nodes.pop_back ();
+ }
+
+ examine_font_nodes (xml, (*i)->font_nodes, parse_state);
+ examine_text_nodes (xml, (*i)->text_nodes, parse_state);
+
+ parse_state.font_nodes.pop_back ();
+ }
+}
+
+void
+SubtitleContent::examine_text_nodes (
+ shared_ptr<const cxml::Node> xml,
+ list<shared_ptr<dcp::Text> > const & text_nodes,
+ ParseState& parse_state
+ )
+{
+ for (list<shared_ptr<dcp::Text> >::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);
+ parse_state.text_nodes.pop_back ();
+ }
+}
+
+void
+SubtitleContent::maybe_add_subtitle (string text, ParseState const & parse_state)
+{
+ if (empty_or_white_space (text)) {
+ return;
+ }
+
+ if (parse_state.text_nodes.empty() || parse_state.subtitle_nodes.empty ()) {
+ return;
+ }
+
+ assert (!parse_state.text_nodes.empty ());
+ assert (!parse_state.subtitle_nodes.empty ());
+
+ dcp::Font effective_font (parse_state.font_nodes);
+ dcp::Text effective_text (*parse_state.text_nodes.back ());
+ dcp::Subtitle effective_subtitle (*parse_state.subtitle_nodes.back ());
+
+ _subtitles.push_back (
+ shared_ptr<SubtitleString> (
+ new SubtitleString (
+ font_id_to_name (effective_font.id),
+ effective_font.italic.get(),
+ effective_font.color.get(),
+ effective_font.size,
+ effective_subtitle.in,
+ effective_subtitle.out,
+ effective_text.v_position,
+ effective_text.v_align,
+ text,
+ effective_font.effect ? effective_font.effect.get() : NONE,
+ effective_font.effect_color.get(),
+ effective_subtitle.fade_up_time,
+ effective_subtitle.fade_down_time
+ )
+ )
+ );
+}
+
+list<shared_ptr<SubtitleString> >
+SubtitleContent::subtitles_at (Time t) const
+{
+ list<shared_ptr<SubtitleString> > s;
+ for (list<shared_ptr<SubtitleString> >::const_iterator i = _subtitles.begin(); i != _subtitles.end(); ++i) {
+ if ((*i)->in() <= t && t <= (*i)->out ()) {
+ s.push_back (*i);
+ }
+ }
+
+ return s;
+}
+
+std::string
+SubtitleContent::font_id_to_name (string id) const
+{
+ list<shared_ptr<dcp::LoadFont> >::const_iterator i = _load_font_nodes.begin();
+ while (i != _load_font_nodes.end() && (*i)->id != id) {
+ ++i;
+ }
+
+ if (i == _load_font_nodes.end ()) {
+ return "";
+ }
+
+ if ((*i)->uri == "arial.ttf") {
+ return "Arial";
+ }
+
+ return "";
+}
+
+void
+SubtitleContent::add (shared_ptr<SubtitleString> s)
+{
+ _subtitles.push_back (s);
+ _need_sort = true;
+}
+
+struct SubtitleSorter {
+ bool operator() (shared_ptr<SubtitleString> a, shared_ptr<SubtitleString> b) {
+ if (a->in() != b->in()) {
+ return a->in() < b->in();
+ }
+ return a->v_position() < b->v_position();
+ }
+};
+
+void
+SubtitleContent::write_xml () const
+{
+ FILE* f = fopen_boost (file (), "r");
+ Glib::ustring const s = xml_as_string ();
+ fwrite (s.c_str(), 1, s.length(), f);
+ fclose (f);
+}
+
+Glib::ustring
+SubtitleContent::xml_as_string () const
+{
+ xmlpp::Document doc;
+ xmlpp::Element* root = doc.create_root_node ("DCSubtitle");
+ root->set_attribute ("Version", "1.0");
+
+ root->add_child("SubtitleID")->add_child_text (_id);
+ root->add_child("MovieTitle")->add_child_text (_movie_title);
+ root->add_child("ReelNumber")->add_child_text (lexical_cast<string> (_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 ()) {
+ 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<shared_ptr<SubtitleString> > sorted = _subtitles;
+ if (_need_sort) {
+ sorted.sort (SubtitleSorter ());
+ }
+
+ /* XXX: multiple fonts not supported */
+ /* XXX: script, underlined, weight not supported */
+
+ bool italic = false;
+ Color color;
+ int size = 0;
+ Effect effect = NONE;
+ Color effect_color;
+ int spot_number = 1;
+ Time last_in;
+ Time last_out;
+ Time last_fade_up_time;
+ Time last_fade_down_time;
+
+ xmlpp::Element* font = 0;
+ xmlpp::Element* subtitle = 0;
+
+ for (list<shared_ptr<SubtitleString> >::iterator i = sorted.begin(); i != sorted.end(); ++i) {
+
+ /* We will start a new <Font>...</Font> whenever some font property changes.
+ I suppose we should really make an optimal hierarchy of <Font> tags, but
+ that seems hard.
+ */
+
+ bool const font_changed =
+ italic != (*i)->italic() ||
+ color != (*i)->color() ||
+ size != (*i)->size() ||
+ effect != (*i)->effect() ||
+ effect_color != (*i)->effect_color();
+
+ if (font_changed) {
+ italic = (*i)->italic ();
+ color = (*i)->color ();
+ size = (*i)->size ();
+ effect = (*i)->effect ();
+ effect_color = (*i)->effect_color ();
+ }
+
+ 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<string> (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 || font_changed ||
+ (last_in != (*i)->in() ||
+ last_out != (*i)->out() ||
+ last_fade_up_time != (*i)->fade_up_time() ||
+ last_fade_down_time != (*i)->fade_down_time()
+ )) {
+
+ subtitle = font->add_child ("Subtitle");
+ subtitle->set_attribute ("SpotNumber", lexical_cast<string> (spot_number++));
+ subtitle->set_attribute ("TimeIn", (*i)->in().to_string());
+ subtitle->set_attribute ("TimeOut", (*i)->out().to_string());
+ subtitle->set_attribute ("FadeUpTime", lexical_cast<string> ((*i)->fade_up_time().to_ticks()));
+ subtitle->set_attribute ("FadeDownTime", lexical_cast<string> ((*i)->fade_down_time().to_ticks()));
+
+ last_in = (*i)->in ();
+ last_out = (*i)->out ();
+ last_fade_up_time = (*i)->fade_up_time ();
+ last_fade_down_time = (*i)->fade_down_time ();
+ }
+
+ xmlpp::Element* text = subtitle->add_child ("Text");
+ text->set_attribute ("VAlign", valign_to_string ((*i)->v_align()));
+ text->set_attribute ("VPosition", lexical_cast<string> ((*i)->v_position()));
+ text->add_child_text ((*i)->text());
+ }
+
+ return doc.write_to_string_formatted ("UTF-8");
+}
+
--- /dev/null
+/*
+ Copyright (C) 2012-2014 Carl Hetherington <cth@carlh.net>
+
+ 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_SUBTITLE_CONTENT_H
+#define LIBDCP_SUBTITLE_CONTENT_H
+
+#include "content.h"
+#include "dcp_time.h"
+#include <libcxml/cxml.h>
+
+namespace dcp
+{
+
+class SubtitleString;
+class Font;
+class Text;
+class Subtitle;
+class LoadFont;
+
+/** @class SubtitleContent
+ * @brief A representation of an XML file containing subtitles.
+ */
+class SubtitleContent : public Content
+{
+public:
+ SubtitleContent (boost::filesystem::path file);
+ SubtitleContent (Fraction edit_rate, std::string movie_title, std::string language);
+
+ bool equals (
+ boost::shared_ptr<const Content>,
+ EqualityOptions,
+ boost::function<void (NoteType, std::string)> note
+ ) const {
+ /* XXX */
+ note (ERROR, "subtitle content not compared yet");
+ return true;
+ }
+
+ std::string language () const {
+ return _language;
+ }
+
+ std::list<boost::shared_ptr<SubtitleString> > subtitles_at (Time t) const;
+ std::list<boost::shared_ptr<SubtitleString> > const & subtitles () const {
+ return _subtitles;
+ }
+
+ void add (boost::shared_ptr<SubtitleString>);
+
+ void write_xml () const;
+ Glib::ustring xml_as_string () const;
+
+protected:
+ std::string pkl_type (Standard) const {
+ return "text/xml";
+ }
+
+ std::string asdcp_kind () const {
+ return "Subtitle";
+ }
+
+private:
+ std::string font_id_to_name (std::string id) const;
+
+ struct ParseState {
+ std::list<boost::shared_ptr<Font> > font_nodes;
+ std::list<boost::shared_ptr<Text> > text_nodes;
+ std::list<boost::shared_ptr<Subtitle> > subtitle_nodes;
+ };
+
+ void maybe_add_subtitle (std::string text, ParseState const & parse_state);
+
+ void examine_font_nodes (
+ boost::shared_ptr<const cxml::Node> xml,
+ std::list<boost::shared_ptr<Font> > const & font_nodes,
+ ParseState& parse_state
+ );
+
+ void examine_text_nodes (
+ boost::shared_ptr<const cxml::Node> xml,
+ std::list<boost::shared_ptr<Text> > const & text_nodes,
+ ParseState& parse_state
+ );
+
+ std::string _movie_title;
+ /* strangely, this is sometimes a string */
+ std::string _reel_number;
+ std::string _language;
+ std::list<boost::shared_ptr<LoadFont> > _load_font_nodes;
+
+ std::list<boost::shared_ptr<SubtitleString> > _subtitles;
+ bool _need_sort;
+};
+
+}
+
+#endif
--- /dev/null
+/*
+ Copyright (C) 2012-2014 Carl Hetherington <cth@carlh.net>
+
+ 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 "subtitle_string.h"
+#include "xml.h"
+
+using std::string;
+using std::ostream;
+using namespace dcp;
+
+SubtitleString::SubtitleString (
+ string font,
+ bool italic,
+ Color color,
+ int size,
+ Time in,
+ Time out,
+ float v_position,
+ VAlign v_align,
+ string text,
+ Effect effect,
+ Color effect_color,
+ Time fade_up_time,
+ Time fade_down_time
+ )
+ : _font (font)
+ , _italic (italic)
+ , _color (color)
+ , _size (size)
+ , _in (in)
+ , _out (out)
+ , _v_position (v_position)
+ , _v_align (v_align)
+ , _text (text)
+ , _effect (effect)
+ , _effect_color (effect_color)
+ , _fade_up_time (fade_up_time)
+ , _fade_down_time (fade_down_time)
+{
+
+}
+
+int
+SubtitleString::size_in_pixels (int screen_height) const
+{
+ /* Size in the subtitle file is given in points as if the screen
+ height is 11 inches, so a 72pt font would be 1/11th of the screen
+ height.
+ */
+
+ return _size * screen_height / (11 * 72);
+}
+
+bool
+dcp::operator== (SubtitleString const & a, SubtitleString const & b)
+{
+ return (
+ a.font() == b.font() &&
+ a.italic() == b.italic() &&
+ a.color() == b.color() &&
+ a.size() == b.size() &&
+ a.in() == b.in() &&
+ a.out() == b.out() &&
+ a.v_position() == b.v_position() &&
+ a.v_align() == b.v_align() &&
+ a.text() == b.text() &&
+ a.effect() == b.effect() &&
+ a.effect_color() == b.effect_color() &&
+ a.fade_up_time() == b.fade_up_time() &&
+ a.fade_down_time() == b.fade_down_time()
+ );
+}
+
+ostream&
+dcp::operator<< (ostream& s, SubtitleString const & sub)
+{
+ s << "\n`" << sub.text() << "' from " << sub.in() << " to " << sub.out() << ";\n"
+ << "fade up " << sub.fade_up_time() << ", fade down " << sub.fade_down_time() << ";\n"
+ << "font " << sub.font() << ", ";
+
+ if (sub.italic()) {
+ s << "italic";
+ } else {
+ s << "non-italic";
+ }
+
+ s << ", size " << sub.size() << ", color " << sub.color() << ", vpos " << sub.v_position() << ", valign " << ((int) sub.v_align()) << ";\n"
+ << "effect " << ((int) sub.effect()) << ", effect color " << sub.effect_color();
+
+ return s;
+}
--- /dev/null
+/*
+ Copyright (C) 2012-2014 Carl Hetherington <cth@carlh.net>
+
+ 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_SUBTITLE_STRING_H
+#define LIBDCP_SUBTITLE_STRING_H
+
+#include "types.h"
+#include "dcp_time.h"
+#include <string>
+
+namespace dcp {
+
+class SubtitleString
+{
+public:
+ SubtitleString (
+ std::string font,
+ bool italic,
+ Color color,
+ int size,
+ Time in,
+ Time out,
+ float v_position,
+ VAlign v_align,
+ std::string text,
+ Effect effect,
+ Color effect_color,
+ Time fade_up_time,
+ Time fade_down_time
+ );
+
+ std::string font () const {
+ return _font;
+ }
+
+ bool italic () const {
+ return _italic;
+ }
+
+ Color color () const {
+ return _color;
+ }
+
+ Time in () const {
+ return _in;
+ }
+
+ Time out () const {
+ return _out;
+ }
+
+ std::string text () const {
+ return _text;
+ }
+
+ float v_position () const {
+ return _v_position;
+ }
+
+ VAlign v_align () const {
+ return _v_align;
+ }
+
+ Effect effect () const {
+ return _effect;
+ }
+
+ Color effect_color () const {
+ return _effect_color;
+ }
+
+ Time fade_up_time () const {
+ return _fade_up_time;
+ }
+
+ Time fade_down_time () const {
+ return _fade_down_time;
+ }
+
+ int size () const {
+ return _size;
+ }
+
+ int size_in_pixels (int screen_height) const;
+
+private:
+ std::string _font;
+ bool _italic;
+ Color _color;
+ /** Size in points as if the screen height is 11 inches, so a 72pt font
+ * would be 1/11th of the screen height.
+ */
+ int _size;
+ Time _in;
+ Time _out;
+ /** Vertical position as a proportion of the screen height from the top
+ * (between 0 and 1)
+ */
+ float _v_position;
+ VAlign _v_align;
+ std::string _text;
+ Effect _effect;
+ Color _effect_color;
+ Time _fade_up_time;
+ Time _fade_down_time;
+};
+
+bool operator== (SubtitleString const & a, SubtitleString const & b);
+std::ostream& operator<< (std::ostream& s, SubtitleString const & sub);
+
+}
+
+#endif
--- /dev/null
+/*
+ Copyright (C) 2012-2014 Carl Hetherington <cth@carlh.net>
+
+ 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/text.cc
+ * @brief Text class for parsing subtitle XML.
+ */
+
+#include "text.h"
+#include "xml.h"
+#include "font.h"
+#include <libcxml/cxml.h>
+
+using std::string;
+using boost::shared_ptr;
+using boost::optional;
+using namespace dcp;
+
+/** Read a <Text> node from a subtitle XML file, noting its contents
+ * in this object's member variables.
+ * @param node Node to read.
+ */
+Text::Text (boost::shared_ptr<const cxml::Node> node)
+ : v_align (CENTER)
+{
+ text = node->content ();
+ v_position = node->number_attribute<float> ("VPosition");
+ optional<string> v = node->optional_string_attribute ("VAlign");
+ if (v) {
+ v_align = string_to_valign (v.get ());
+ }
+
+ font_nodes = type_children<Font> (node, "Font");
+}
--- /dev/null
+/*
+ Copyright (C) 2012-2014 Carl Hetherington <cth@carlh.net>
+
+ 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/text.h
+ * @brief Text class for parsing subtitle XML.
+ */
+
+#include "types.h"
+#include <boost/shared_ptr.hpp>
+#include <list>
+
+namespace cxml {
+ class Node;
+}
+
+namespace dcp {
+
+class Font;
+
+/** @class Text
+ * @brief Parser for Text nodes from subtitle XML.
+ */
+class Text
+{
+public:
+ /** Construct a default text node */
+ Text ()
+ : v_position (0)
+ , v_align (TOP)
+ {}
+
+ Text (boost::shared_ptr<const cxml::Node> node);
+
+ float v_position;
+ VAlign v_align;
+ std::string text;
+ std::list<boost::shared_ptr<Font> > font_nodes;
+};
+
+}
+/*
+ Copyright (C) 2012-2014 Carl Hetherington <cth@carlh.net>
+
+ 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 "types.h"
+#include "exceptions.h"
+#include <boost/lexical_cast.hpp>
+#include <boost/algorithm/string.hpp>
#include <vector>
#include <cstdio>
#include <iomanip>
-#include <boost/lexical_cast.hpp>
-#include <boost/algorithm/string.hpp>
-#include "types.h"
-#include "exceptions.h"
using namespace std;
-using namespace libdcp;
+using namespace dcp;
using namespace boost;
+/** Construct a Fraction from a string of the form <numerator> <denominator>
+ * e.g. "1 3".
+ */
Fraction::Fraction (string s)
{
vector<string> b;
}
bool
-libdcp::operator== (Fraction const & a, Fraction const & b)
+dcp::operator== (Fraction const & a, Fraction const & b)
{
return (a.numerator == b.numerator && a.denominator == b.denominator);
}
bool
-libdcp::operator!= (Fraction const & a, Fraction const & b)
+dcp::operator!= (Fraction const & a, Fraction const & b)
{
return (a.numerator != b.numerator || a.denominator != b.denominator);
}
+/** Construct a Color, initialising it to black. */
Color::Color ()
: r (0)
, g (0)
}
+/** Construct a Color from R, G and B. The values run between
+ * 0 and 255.
+ */
Color::Color (int r_, int g_, int b_)
: r (r_)
, g (g_)
* @param b Second color to compare.
*/
bool
-libdcp::operator== (Color const & a, Color const & b)
+dcp::operator== (Color const & a, Color const & b)
{
return (a.r == b.r && a.g == b.g && a.b == b.b);
}
* @param b Second color to compare.
*/
bool
-libdcp::operator!= (Color const & a, Color const & b)
+dcp::operator!= (Color const & a, Color const & b)
{
return !(a == b);
}
ostream &
-libdcp::operator<< (ostream& s, Color const & c)
+dcp::operator<< (ostream& s, Color const & c)
{
s << "(" << c.r << ", " << c.g << ", " << c.b << ")";
return s;
}
string
-libdcp::effect_to_string (Effect e)
+dcp::effect_to_string (Effect e)
{
switch (e) {
case NONE:
}
Effect
-libdcp::string_to_effect (string s)
+dcp::string_to_effect (string s)
{
if (s == "none") {
return NONE;
}
string
-libdcp::valign_to_string (VAlign v)
+dcp::valign_to_string (VAlign v)
{
switch (v) {
case TOP:
}
VAlign
-libdcp::string_to_valign (string s)
+dcp::string_to_valign (string s)
{
if (s == "top") {
return TOP;
/*
- Copyright (C) 2012 Carl Hetherington <cth@carlh.net>
+ Copyright (C) 2012-2014 Carl Hetherington <cth@carlh.net>
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
#ifndef LIBDCP_TYPES_H
#define LIBDCP_TYPES_H
-#include <string>
#include <boost/shared_ptr.hpp>
+#include <string>
-namespace libdcp
+namespace dcp
{
namespace parse {
EYE_LEFT,
EYE_RIGHT
};
-
+
+/** @class Fraction
+ * @brief A fraction (i.e. a thing with an integer numerator and an integer denominator).
+ */
class Fraction
{
public:
+ /** Construct a fraction of 0/0 */
Fraction () : numerator (0), denominator (0) {}
Fraction (std::string s);
+ /** Construct a fraction with a specified numerator and denominator.
+ * @param n Numerator.
+ * @param d Denominator.
+ */
Fraction (int n, int d) : numerator (n), denominator (d) {}
int numerator;
extern bool operator== (Fraction const & a, Fraction const & b);
extern bool operator!= (Fraction const & a, Fraction const & b);
-
-struct EqualityOptions {
+
+/** @struct EqualityOptions
+ * @brief A class to describe what "equality" means for a particular test.
+ *
+ * When comparing things, we want to be able to ignore some differences;
+ * this class expresses those differences.
+ */
+struct EqualityOptions
+{
+ /** Construct an EqualityOptions where nothing at all can differ */
EqualityOptions ()
: max_mean_pixel_error (0)
, max_std_dev_pixel_error (0)
, max_audio_sample_error (0)
- , cpl_names_can_differ (false)
+ , cpl_annotation_texts_can_differ (false)
, mxf_names_can_differ (false)
{}
+ /** The maximum allowable mean difference in pixel value between two images */
double max_mean_pixel_error;
+ /** The maximum standard deviation of the differences in pixel value between two images */
double max_std_dev_pixel_error;
+ /** The maximum difference in audio sample value between two soundtracks */
int max_audio_sample_error;
- bool cpl_names_can_differ;
+ /** true if the <AnnotationText> nodes of CPLs are allowed to differ */
+ bool cpl_annotation_texts_can_differ;
+ /** true if MXF filenames are allowed to differ */
bool mxf_names_can_differ;
};
NOTE
};
+enum Standard {
+ INTEROP,
+ SMPTE
+};
+
/** @class Color
* @brief An RGB color (aka colour).
*/
/*
- Copyright (C) 2012 Carl Hetherington <cth@carlh.net>
+ Copyright (C) 2012-2014 Carl Hetherington <cth@carlh.net>
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
* @brief Utility methods.
*/
-#include <stdexcept>
-#include <sstream>
-#include <iostream>
-#include <iomanip>
-#include <boost/filesystem.hpp>
-#include <boost/lexical_cast.hpp>
-#include <openssl/sha.h>
-#include <libxml++/nodes/element.h>
-#include <libxml++/document.h>
-#include <xmlsec/xmldsig.h>
-#include <xmlsec/dl.h>
-#include <xmlsec/app.h>
-#include <xmlsec/crypto.h>
-#include "KM_util.h"
-#include "KM_fileio.h"
-#include "AS_DCP.h"
#include "util.h"
#include "exceptions.h"
#include "types.h"
#include "certificates.h"
#include "gamma_lut.h"
#include "xyz_frame.h"
+#include "compose.hpp"
+#include "KM_util.h"
+#include "KM_fileio.h"
+#include "AS_DCP.h"
+#include <xmlsec/xmldsig.h>
+#include <xmlsec/dl.h>
+#include <xmlsec/app.h>
+#include <xmlsec/crypto.h>
+#include <libxml++/nodes/element.h>
+#include <libxml++/document.h>
+#include <openssl/sha.h>
+#include <boost/filesystem.hpp>
+#include <stdexcept>
+#include <sstream>
+#include <iostream>
+#include <iomanip>
using std::string;
using std::wstring;
using std::list;
using std::setw;
using std::setfill;
+using std::ostream;
using boost::shared_ptr;
-using boost::lexical_cast;
-using namespace libdcp;
+using boost::optional;
+using boost::function;
+using namespace dcp;
/** Create a UUID.
* @return UUID.
*/
string
-libdcp::make_uuid ()
+dcp::make_uuid ()
{
char buffer[64];
Kumu::UUID id;
/** Create a digest for a file.
* @param filename File name.
- * @param progress Pointer to a progress reporting function, or 0. The function will be called
+ * @param progress Optional progress reporting function. The function will be called
* with a progress value between 0 and 1.
* @return Digest.
*/
string
-libdcp::make_digest (string filename, boost::function<void (float)>* progress)
+dcp::make_digest (boost::filesystem::path filename, function<void (float)> progress)
{
Kumu::FileReader reader;
- Kumu::Result_t r = reader.OpenRead (filename.c_str ());
+ Kumu::Result_t r = reader.OpenRead (filename.string().c_str ());
if (ASDCP_FAILURE (r)) {
boost::throw_exception (FileError ("could not open file to compute digest", filename, r));
}
SHA1_Update (&sha, read_buffer.Data(), read);
if (progress) {
- (*progress) (float (done) / size);
+ progress (float (done) / size);
done += read;
}
}
}
/** Convert a content kind to a string which can be used in a
- * <ContentKind> node.
+ * <ContentKind> node.
* @param kind ContentKind.
* @return string.
*/
string
-libdcp::content_kind_to_string (ContentKind kind)
+dcp::content_kind_to_string (ContentKind kind)
{
switch (kind) {
case FEATURE:
assert (false);
}
-/** Convert a string from a <ContentKind> node to a libdcp ContentKind.
+/** Convert a string from a <ContentKind> node to a libdcp ContentKind.
* Reasonably tolerant about varying case.
- * @param type Content kind string.
+ * @param kind Content kind string.
* @return libdcp ContentKind.
*/
-libdcp::ContentKind
-libdcp::content_kind_from_string (string type)
+dcp::ContentKind
+dcp::content_kind_from_string (string kind)
{
- transform (type.begin(), type.end(), type.begin(), ::tolower);
+ transform (kind.begin(), kind.end(), kind.begin(), ::tolower);
- if (type == "feature") {
+ if (kind == "feature") {
return FEATURE;
- } else if (type == "short") {
+ } else if (kind == "short") {
return SHORT;
- } else if (type == "trailer") {
+ } else if (kind == "trailer") {
return TRAILER;
- } else if (type == "test") {
+ } else if (kind == "test") {
return TEST;
- } else if (type == "transitional") {
+ } else if (kind == "transitional") {
return TRANSITIONAL;
- } else if (type == "rating") {
+ } else if (kind == "rating") {
return RATING;
- } else if (type == "teaser") {
+ } else if (kind == "teaser") {
return TEASER;
- } else if (type == "policy") {
+ } else if (kind == "policy") {
return POLICY;
- } else if (type == "psa") {
+ } else if (kind == "psa") {
return PUBLIC_SERVICE_ANNOUNCEMENT;
- } else if (type == "advertisement") {
+ } else if (kind == "advertisement") {
return ADVERTISEMENT;
}
* This is useful for scaling 4K DCP images down to 2K.
* @return XYZ image.
*/
-shared_ptr<libdcp::XYZFrame>
-libdcp::decompress_j2k (uint8_t* data, int64_t size, int reduce)
+shared_ptr<dcp::XYZFrame>
+dcp::decompress_j2k (uint8_t* data, int64_t size, int reduce)
{
opj_dinfo_t* decoder = opj_create_decompress (CODEC_J2K);
opj_dparameters_t parameters;
if (!image) {
opj_destroy_decompress (decoder);
opj_cio_close (cio);
- boost::throw_exception (DCPReadError ("could not decode JPEG2000 codestream of " + lexical_cast<string> (size) + " bytes."));
+ boost::throw_exception (DCPReadError (String::compose ("could not decode JPEG2000 codestream of %1 bytes.", size)));
}
opj_destroy_decompress (decoder);
* @return true if the string contains only space, newline or tab characters, or is empty.
*/
bool
-libdcp::empty_or_white_space (string s)
+dcp::empty_or_white_space (string s)
{
for (size_t i = 0; i < s.length(); ++i) {
if (s[i] != ' ' && s[i] != '\n' && s[i] != '\t') {
return true;
}
+/** Set up various bits that the library needs. Should be called one
+ * by client applications.
+ */
void
-libdcp::init ()
+dcp::init ()
{
if (xmlSecInit() < 0) {
throw MiscError ("could not initialise xmlsec");
}
}
-bool libdcp::operator== (libdcp::Size const & a, libdcp::Size const & b)
+bool dcp::operator== (dcp::Size const & a, dcp::Size const & b)
{
return (a.width == b.width && a.height == b.height);
}
-bool libdcp::operator!= (libdcp::Size const & a, libdcp::Size const & b)
+bool dcp::operator!= (dcp::Size const & a, dcp::Size const & b)
{
return !(a == b);
}
-/** The base64 decode routine in KM_util.cpp gives different values to both
- * this and the command-line base64 for some inputs. Not sure why.
+ostream& dcp::operator<< (ostream& s, dcp::Size const & a)
+{
+ s << a.width << "x" << a.height;
+ return s;
+}
+
+/** Decode a base64 string. The base64 decode routine in KM_util.cpp
+ * gives different values to both this and the command-line base64
+ * for some inputs. Not sure why.
+ *
+ * @param in base64-encoded string.
+ * @param out Output buffer.
+ * @param out_length Length of output buffer.
+ * @return Number of characters written to the output buffer.
*/
int
-libdcp::base64_decode (string const & in, unsigned char* out, int out_length)
+dcp::base64_decode (string const & in, unsigned char* out, int out_length)
{
BIO* b64 = BIO_new (BIO_f_base64 ());
return N;
}
+/** Convert a struct tm to a string of the form
+ * 2014-01-26T21:39:00+01:00
+ * @param tm struct tm.
+ * @return Time as a string.
+ */
string
-libdcp::tm_to_string (struct tm* tm)
+dcp::tm_to_string (struct tm* tm)
{
char buffer[64];
strftime (buffer, 64, "%Y-%m-%dT%H:%M:%S", tm);
* @return string of the form e.g. -01:00.
*/
string
-libdcp::utc_offset_to_string (int b)
+dcp::utc_offset_to_string (int b)
{
bool const negative = (b < 0);
b = negative ? -b : b;
return o.str ();
}
+/** Convert a boost::posix_time::ptime to a string of the form
+ * 2014-01-26T21:39:00+01:00.
+ * @param t boost::posix_time::ptime.
+ * @return Time as a string.
+ */
string
-libdcp::ptime_to_string (boost::posix_time::ptime t)
+dcp::ptime_to_string (boost::posix_time::ptime t)
{
struct tm t_tm = boost::posix_time::to_tm (t);
return tm_to_string (&t_tm);
}
-/* Apparently there is no way to create an ofstream using a UTF-8
- filename under Windows. We are hence reduced to using fopen
- with this wrapper.
-*/
+/** @param p Path to open.
+ * @param t mode flags, as for fopen(3).
+ * @return FILE pointer or 0 on error.
+ *
+ * Apparently there is no way to create an ofstream using a UTF-8
+ * filename under Windows. We are hence reduced to using fopen
+ * with this wrapper.
+ */
FILE *
-libdcp::fopen_boost (boost::filesystem::path p, string t)
+dcp::fopen_boost (boost::filesystem::path p, string t)
{
#ifdef LIBDCP_WINDOWS
wstring w (t.begin(), t.end());
return fopen (p.c_str(), t.c_str ());
#endif
}
+
+optional<boost::filesystem::path>
+dcp::relative_to_root (boost::filesystem::path root, boost::filesystem::path file)
+{
+ boost::filesystem::path::const_iterator i = root.begin ();
+ boost::filesystem::path::const_iterator j = file.begin ();
+
+ while (i != root.end() && j != file.end() && *i == *j) {
+ ++i;
+ ++j;
+ }
+
+ if (i != root.end ()) {
+ return optional<boost::filesystem::path> ();
+ }
+
+ boost::filesystem::path rel;
+ while (j != file.end ()) {
+ rel /= *j++;
+ }
+
+ return rel;
+}
/*
- Copyright (C) 2012 Carl Hetherington <cth@carlh.net>
+ Copyright (C) 2012-2014 Carl Hetherington <cth@carlh.net>
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
* @brief Utility methods.
*/
-#include <string>
-#include <stdint.h>
+#include "types.h"
#include <boost/shared_ptr.hpp>
#include <boost/function.hpp>
#include <boost/date_time/posix_time/posix_time.hpp>
#include <boost/filesystem.hpp>
+#include <boost/optional.hpp>
#include <openjpeg.h>
-#include "types.h"
+#include <string>
+#include <stdint.h>
namespace xmlpp {
class Element;
}
-namespace libdcp {
+namespace dcp {
class ARGBFrame;
class CertificateChain;
class GammaLUT;
class XYZFrame;
-struct Size {
+/** @struct Size
+ * @brief The integer, two-dimensional size of something.
+ */
+struct Size
+{
Size ()
: width (0)
, height (0)
extern bool operator== (Size const & a, Size const & b);
extern bool operator!= (Size const & a, Size const & b);
+extern std::ostream& operator<< (std::ostream& s, Size const & a);
extern std::string make_uuid ();
-extern std::string make_digest (std::string filename, boost::function<void (float)> *);
+extern std::string make_digest (boost::filesystem::path filename, boost::function<void (float)>);
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 void init ();
-extern void sign (xmlpp::Element* parent, CertificateChain const & certificates, boost::filesystem::path signer_key, bool interop);
+extern void sign (xmlpp::Element* parent, CertificateChain const & certificates, boost::filesystem::path signer_key, Standard standard);
extern void add_signature_value (xmlpp::Element* parent, CertificateChain const & certificates, boost::filesystem::path signer_key, std::string const & ns);
extern void add_signer (xmlpp::Element* parent, CertificateChain const & certificates, std::string const & ns);
extern int base64_decode (std::string const & in, unsigned char* out, int out_length);
-
+extern boost::optional<boost::filesystem::path> relative_to_root (boost::filesystem::path root, boost::filesystem::path file);
extern std::string tm_to_string (struct tm *);
extern std::string utc_offset_to_string (int);
extern std::string ptime_to_string (boost::posix_time::ptime);
extern FILE * fopen_boost (boost::filesystem::path, std::string);
+
+template <class F, class T>
+std::list<boost::shared_ptr<T> >
+list_of_type (std::list<boost::shared_ptr<F> > const & from)
+{
+ std::list<boost::shared_ptr<T> > out;
+ for (typename std::list<boost::shared_ptr<F> >::const_iterator i = from.begin(); i != from.end(); ++i) {
+ boost::shared_ptr<T> check = boost::dynamic_pointer_cast<T> (*i);
+ if (check) {
+ out.push_back (check);
+ }
+ }
+
+ return out;
+}
}
-namespace libdcp {
+namespace dcp {
extern char const * version;
extern char const * git_commit;
else:
obj = bld(features = 'cxx cxxshlib')
- obj.name = 'libdcp'
- obj.target = 'dcp'
+ obj.name = 'libdcp%s' % bld.env.API_VERSION
+ obj.target = 'dcp%s' % bld.env.API_VERSION
obj.export_includes = ['.']
obj.uselib = 'BOOST_FILESYSTEM BOOST_SIGNALS2 BOOST_DATETIME OPENSSL SIGC++ LIBXML++ OPENJPEG CXML XMLSEC1'
- obj.use = 'libkumu-libdcp libasdcp-libdcp'
+ obj.use = 'libkumu-libdcp%s libasdcp-libdcp%s' % (bld.env.API_VERSION, bld.env.API_VERSION)
obj.source = """
argb_frame.cc
asset.cc
certificates.cc
colour_matrix.cc
+ content.cc
cpl.cc
dcp.cc
dcp_time.cc
exceptions.cc
+ file.cc
+ font.cc
gamma_lut.cc
image.cc
kdm.cc
key.cc
+ load_font.cc
metadata.cc
- mono_picture_asset.cc
- mono_picture_asset_writer.cc
+ mono_picture_mxf.cc
+ mono_picture_mxf_writer.cc
mono_picture_frame.cc
- mxf_asset.cc
- picture_asset.cc
- picture_asset_writer.cc
- rec709_linearised_gamma_lut.cc
+ mxf.cc
+ mxf_writer.cc
+ object.cc
+ picture_mxf.cc
+ picture_mxf_writer.cc
reel.cc
+ reel_asset.cc
+ reel_mono_picture_asset.cc
+ reel_picture_asset.cc
+ reel_sound_asset.cc
+ reel_stereo_picture_asset.cc
+ reel_subtitle_asset.cc
rgb_xyz.cc
signer.cc
signer_chain.cc
- sound_asset.cc
+ sound_mxf.cc
+ sound_mxf_writer.cc
sound_frame.cc
- srgb_linearised_gamma_lut.cc
- stereo_picture_asset.cc
- stereo_picture_asset_writer.cc
+ stereo_picture_mxf.cc
+ stereo_picture_mxf_writer.cc
stereo_picture_frame.cc
- subtitle_asset.cc
+ subtitle.cc
+ subtitle_content.cc
+ subtitle_string.cc
+ text.cc
types.cc
util.cc
version.cc
xyz_frame.cc
- parse/asset_map.cc
- parse/cpl.cc
- parse/pkl.cc
- parse/subtitle.cc
"""
headers = """
certificates.h
colour_matrix.h
cpl.h
+ content.h
dcp.h
dcp_time.h
exceptions.h
image.h
kdm.h
key.h
- lut.h
lut_cache.h
metadata.h
- mono_picture_asset.h
+ mono_picture_mxf.h
mono_picture_frame.h
- mxf_asset.h
- picture_asset.h
- picture_asset_writer.h
+ mxf.h
+ mxf_writer.h
+ object.h
+ picture_mxf.h
+ picture_mxf_writer.h
rgb_xyz.h
- rec709_linearised_gamma_lut.h
reel.h
+ reel_asset.h
+ reel_mono_picture_asset.h
+ reel_picture_asset.h
+ reel_sound_asset.h
+ reel_stereo_picture_asset.h
+ ref.h
argb_frame.h
signer.h
signer_chain.h
- sound_asset.h
sound_frame.h
- srgb_linearised_gamma_lut.h
- stereo_picture_asset.h
+ sound_mxf.h
+ sound_mxf_writer.h
+ stereo_picture_mxf.h
stereo_picture_frame.h
- subtitle_asset.h
+ subtitle.h
+ subtitle_content.h
+ subtitle_string.h
types.h
util.h
version.h
xyz_frame.h
"""
- bld.install_files('${PREFIX}/include/libdcp', headers)
+ bld.install_files('${PREFIX}/include/libdcp%s/dcp' % bld.env.API_VERSION, headers)
if bld.env.STATIC:
- bld.install_files('${PREFIX}/lib', 'libdcp.a')
+ bld.install_files('${PREFIX}/lib', 'libdcp%s.a' % bld.env.API_VERSION)
/*
- Copyright (C) 2013 Carl Hetherington <cth@carlh.net>
+ Copyright (C) 2013-2014 Carl Hetherington <cth@carlh.net>
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
#ifndef LIBDCP_XML_H
#define LIBDCP_XML_H
-#include <libcxml/cxml.h>
#include "exceptions.h"
+#include <libcxml/cxml.h>
-namespace libdcp
+namespace dcp
{
template <class T>
+++ /dev/null
-/*
- Copyright (C) 2013 Carl Hetherington <cth@carlh.net>
-
- 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/xml/kdm_smpte.h
- * @brief 1:1ish C++ representations of the XML schema for a SMPTE KDM.
- *
- * This file contains classes which map pretty-much 1:1 to the elements in a SMPTE KDM
- * (Key Delivery Message). The `main' KDM class contains a pointer to a DCinemaSecurityMessage
- * from this file.
- *
- * This should probably have been automatically generated from the XSD,
- * but I think it's too much trouble considering that the XSD does not
- * change very often.
- */
-
-#ifndef LIBDCP_XML_KDM_SMPTE_H
-#define LIBDCP_XML_KDM_SMPTE_H
-
-#include <string>
-#include <list>
-#include <boost/optional.hpp>
-#include <boost/filesystem.hpp>
-#include <libxml/parser.h>
-#include <libxml++/libxml++.h>
-#include <libcxml/cxml.h>
-#include "../exceptions.h"
-
-namespace libdcp {
-namespace xml {
-
-class Writer
-{
-public:
- Writer ()
- : document (new xmlpp::Document)
- {}
-
- boost::shared_ptr<xmlpp::Document> document;
- std::map<std::string, xmlpp::Attribute *> references;
-};
-
-class Signer
-{
-public:
- Signer () {}
- Signer (boost::shared_ptr<const cxml::Node> node)
- : x509_issuer_name (node->string_child ("X509IssuerName"))
- , x509_serial_number (node->string_child ("X509SerialNumber"))
- {
- node->done ();
- }
-
- void as_xml (xmlpp::Element* node) const
- {
- node->add_child("X509IssuerName", "ds")->add_child_text (x509_issuer_name);
- node->add_child("X509SerialNumber", "ds")->add_child_text (x509_serial_number);
- }
-
- std::string x509_issuer_name;
- std::string x509_serial_number;
-};
-
-class Recipient
-{
-public:
- Recipient () {}
- Recipient (boost::shared_ptr<const cxml::Node> node)
- : x509_issuer_serial (node->node_child ("X509IssuerSerial"))
- , x509_subject_name (node->string_child ("X509SubjectName"))
- {
- node->done ();
- }
-
- void as_xml (xmlpp::Element* node) const
- {
- x509_issuer_serial.as_xml (node->add_child ("X509IssuerSerial"));
- node->add_child("X509SubjectName")->add_child_text (x509_subject_name);
- }
-
- Signer x509_issuer_serial;
- std::string x509_subject_name;
-};
-
-class AuthorizedDeviceInfo
-{
-public:
- AuthorizedDeviceInfo () {}
- AuthorizedDeviceInfo (boost::shared_ptr<const cxml::Node> node)
- : device_list_identifier (node->string_child ("DeviceListIdentifier"))
- , device_list_description (node->string_child ("DeviceListDescription"))
- {
- std::list<boost::shared_ptr<cxml::Node> > ct = node->node_child("DeviceList")->node_children("CertificateThumbprint");
- for (std::list<boost::shared_ptr<cxml::Node> >::const_iterator i = ct.begin(); i != ct.end(); ++i) {
- device_list.push_back ((*i)->content ());
- }
-
- node->done ();
- }
-
- void as_xml (xmlpp::Element* node) const
- {
- node->add_child ("DeviceListIdentifier")->add_child_text (device_list_identifier);
- node->add_child ("DeviceListDescription")->add_child_text (device_list_description);
- xmlpp::Element* dl = node->add_child ("DeviceList");
- for (std::list<std::string>::const_iterator i = device_list.begin(); i != device_list.end(); ++i) {
- dl->add_child("CertificateThumbprint")->add_child_text (*i);
- }
- }
-
- std::string device_list_identifier;
- std::string device_list_description;
- std::list<std::string> device_list;
-};
-
-class TypedKeyId
-{
-public:
- TypedKeyId () {}
-
- TypedKeyId (std::string t, std::string i)
- : key_type (t)
- , key_id (i)
- {}
-
- TypedKeyId (boost::shared_ptr<const cxml::Node> node)
- : key_type (node->string_child ("KeyType"))
- , key_id (node->string_child ("KeyId"))
- {
- node->done ();
- }
-
- void as_xml (xmlpp::Element* node) const
- {
- node->add_child("KeyType")->add_child_text (key_type);
- node->add_child("KeyId")->add_child_text (key_id);
- }
-
- std::string key_type;
- std::string key_id;
-};
-
-class AuthenticatedPublic
-{
-public:
- AuthenticatedPublic () {}
- AuthenticatedPublic (boost::shared_ptr<const cxml::Node> node)
- : message_id (node->string_child ("MessageId"))
- , message_type (node->string_child ("MessageType"))
- , annotation_text (node->optional_string_child ("AnnotationText"))
- , issue_date (node->string_child ("IssueDate"))
- , signer (node->node_child ("Signer"))
- {
- boost::shared_ptr<const cxml::Node> c = node->node_child ("RequiredExtensions");
- c = c->node_child ("KDMRequiredExtensions");
- recipient = Recipient (c->node_child ("Recipient"));
- composition_playlist_id = c->string_child ("CompositionPlaylistId");
- content_authenticator = c->optional_string_child ("ContentAuthenticator");
- content_title_text = c->string_child ("ContentTitleText");
- content_keys_not_valid_before = c->string_child ("ContentKeysNotValidBefore");
- content_keys_not_valid_after = c->string_child ("ContentKeysNotValidAfter");
- authorized_device_info = AuthorizedDeviceInfo (c->node_child ("AuthorizedDeviceInfo"));
-
- std::list<boost::shared_ptr<cxml::Node> > kil = c->node_child("KeyIdList")->node_children("TypedKeyId");
- for (std::list<boost::shared_ptr<cxml::Node> >::iterator i = kil.begin(); i != kil.end(); ++i) {
- key_id_list.push_back (TypedKeyId (*i));
- }
-
- boost::shared_ptr<cxml::Node> fmfl = c->optional_node_child("ForensicMarkFlagList");
- if (fmfl) {
- std::list<boost::shared_ptr<cxml::Node> > fmf = fmfl->node_children("ForensicMarkFlag");
- for (std::list<boost::shared_ptr<cxml::Node> >::iterator i = fmf.begin(); i != fmf.end(); ++i) {
- forensic_mark_flag_list.push_back ((*i)->content ());
- }
- }
-
- node->ignore_child ("NonCriticalExtensions");
- node->done ();
- }
-
- void as_xml (Writer& writer, xmlpp::Element* node) const
- {
- writer.references["ID_AuthenticatedPublic"] = node->set_attribute ("Id", "ID_AuthenticatedPublic");
-
- node->add_child("MessageId")->add_child_text (message_id);
- node->add_child("MessageType")->add_child_text (message_type);
- if (annotation_text) {
- node->add_child("AnnotationText")->add_child_text (annotation_text.get ());
- }
- node->add_child("IssueDate")->add_child_text (issue_date);
- signer.as_xml (node->add_child("Signer"));
-
- xmlpp::Element* kdm_required_extensions = node->add_child("RequiredExtensions")->add_child("KDMRequiredExtensions");
- kdm_required_extensions->set_attribute ("xmlns", "http://www.smpte-ra.org/schemas/430-1/2006/KDM");
- recipient.as_xml (kdm_required_extensions->add_child ("Recipient"));
-
- kdm_required_extensions->add_child("CompositionPlaylistId")->add_child_text (composition_playlist_id);
- if (content_authenticator) {
- kdm_required_extensions->add_child("ContentAuthenticator")->add_child_text (content_authenticator.get ());
- }
- kdm_required_extensions->add_child("ContentTitleText")->add_child_text (content_title_text);
- kdm_required_extensions->add_child("ContentKeysNotValidBefore")->add_child_text (content_keys_not_valid_before);
- kdm_required_extensions->add_child("ContentKeysNotValidAfter")->add_child_text (content_keys_not_valid_after);
- authorized_device_info.as_xml (kdm_required_extensions->add_child("AuthorizedDeviceInfo"));
-
- xmlpp::Element* kil = kdm_required_extensions->add_child("KeyIdList");
- for (std::list<TypedKeyId>::const_iterator i = key_id_list.begin(); i != key_id_list.end(); ++i) {
- i->as_xml (kil->add_child ("TypedKeyId"));
- }
-
- xmlpp::Element* fmfl = kdm_required_extensions->add_child ("ForensicMarkFlagList");
- for (std::list<std::string>::const_iterator i = forensic_mark_flag_list.begin(); i != forensic_mark_flag_list.end(); ++i) {
- fmfl->add_child("ForensicMarkFlag")->add_child_text (*i);
- }
-
- node->add_child ("NonCriticalExtensions");
- }
-
- std::string message_id;
- std::string message_type;
- boost::optional<std::string> annotation_text;
- std::string issue_date;
- Signer signer;
- Recipient recipient;
- std::string composition_playlist_id;
- boost::optional<std::string> content_authenticator;
- std::string content_title_text;
- std::string content_keys_not_valid_before;
- std::string content_keys_not_valid_after;
- AuthorizedDeviceInfo authorized_device_info;
- std::list<TypedKeyId> key_id_list;
- std::list<std::string> forensic_mark_flag_list;
-};
-
-class AuthenticatedPrivate
-{
-public:
- AuthenticatedPrivate () {}
-
- AuthenticatedPrivate (boost::shared_ptr<const cxml::Node> node)
- {
- std::list<boost::shared_ptr<cxml::Node> > ek = node->node_children ("EncryptedKey");
- for (std::list<boost::shared_ptr<cxml::Node> >::const_iterator i = ek.begin(); i != ek.end(); ++i) {
- encrypted_keys.push_back ((*i)->node_child("CipherData")->string_child("CipherValue"));
- }
-
- node->done ();
- }
-
- void as_xml (Writer& writer, xmlpp::Element* node) const
- {
- writer.references["ID_AuthenticatedPrivate"] = node->set_attribute ("Id", "ID_AuthenticatedPrivate");
-
- for (std::list<std::string>::const_iterator i = encrypted_keys.begin(); i != encrypted_keys.end(); ++i) {
- xmlpp::Element* encrypted_key = node->add_child ("EncryptedKey", "enc");
- xmlpp::Element* encryption_method = encrypted_key->add_child ("EncryptionMethod", "enc");
- encryption_method->set_attribute ("Algorithm", "http://www.w3.org/2001/04/xmlenc#rsa-oaep-mgf1p");
- xmlpp::Element* digest_method = encryption_method->add_child ("DigestMethod", "ds");
- digest_method->set_attribute ("Algorithm", "http://www.w3.org/2000/09/xmldsig#sha1");
- xmlpp::Element* cipher_data = encrypted_key->add_child ("CipherData", "enc");
- cipher_data->add_child("CipherValue", "enc")->add_child_text (*i);
- }
- }
-
- std::list<std::string> encrypted_keys;
-};
-
-class X509Data
-{
-public:
- X509Data () {}
- X509Data (boost::shared_ptr<const cxml::Node> node)
- : x509_issuer_serial (Signer (node->node_child ("X509IssuerSerial")))
- , x509_certificate (node->string_child ("X509Certificate"))
- {
- node->done ();
- }
-
- void as_xml (xmlpp::Element* node) const
- {
- x509_issuer_serial.as_xml (node->add_child ("X509IssuerSerial", "ds"));
- node->add_child("X509Certificate", "ds")->add_child_text (x509_certificate);
- }
-
- Signer x509_issuer_serial;
- std::string x509_certificate;
-};
-
-class Reference
-{
-public:
- Reference () {}
- Reference (std::string u)
- : uri (u)
- {}
-
- Reference (boost::shared_ptr<const cxml::Node> node)
- : uri (node->string_attribute ("URI"))
- , digest_value (node->string_child ("DigestValue"))
- {
- node->ignore_child ("DigestMethod");
- node->done ();
- }
-
- void as_xml (xmlpp::Element* node) const
- {
- xmlpp::Element* reference = node->add_child ("Reference", "ds");
- reference->set_attribute ("URI", uri);
- reference->add_child("DigestMethod", "ds")->set_attribute ("Algorithm", "http://www.w3.org/2001/04/xmlenc#sha256");
- reference->add_child("DigestValue", "ds")->add_child_text (digest_value);
- }
-
- std::string uri;
- std::string digest_value;
-};
-
-class Signature
-{
-public:
- Signature ()
- : authenticated_public ("#ID_AuthenticatedPublic")
- , authenticated_private ("#ID_AuthenticatedPrivate")
- {}
-
- Signature (boost::shared_ptr<const cxml::Node> node)
- {
- std::list<boost::shared_ptr<cxml::Node> > refs = node->node_child("SignedInfo")->node_children ("Reference");
- for (std::list<boost::shared_ptr<cxml::Node> >::const_iterator i = refs.begin(); i != refs.end(); ++i) {
- if ((*i)->string_attribute("URI") == "#ID_AuthenticatedPublic") {
- authenticated_public = Reference (*i);
- } else if ((*i)->string_attribute("URI") == "#ID_AuthenticatedPrivate") {
- authenticated_private = Reference (*i);
- } else {
- throw XMLError ("unrecognised reference URI");
- }
- }
-
- std::list<boost::shared_ptr<cxml::Node> > data = node->node_child("KeyInfo")->node_children ("X509Data");
- for (std::list<boost::shared_ptr<cxml::Node> >::const_iterator i = data.begin(); i != data.end(); ++i) {
- key_info.push_back (X509Data (*i));
- }
-
- signature_value = node->string_child ("SignatureValue");
-
- node->done ();
- }
-
- void as_xml (xmlpp::Element* node) const
- {
- xmlpp::Element* si = node->add_child ("SignedInfo", "ds");
- si->add_child ("CanonicalizationMethod", "ds")->set_attribute ("Algorithm", "http://www.w3.org/TR/2001/REC-xml-c14n-20010315#WithComments");
- si->add_child ("SignatureMethod", "ds")->set_attribute ("Algorithm", "http://www.w3.org/2001/04/xmldsig-more#rsa-sha256");
-
- authenticated_public.as_xml (si);
- authenticated_private.as_xml (si);
-
- node->add_child("SignatureValue", "ds")->add_child_text (signature_value);
-
- xmlpp::Element* ki = node->add_child ("KeyInfo", "ds");
- for (std::list<X509Data>::const_iterator i = key_info.begin(); i != key_info.end(); ++i) {
- i->as_xml (ki->add_child ("X509Data", "ds"));
- }
- }
-
- Reference authenticated_public;
- Reference authenticated_private;
- std::string signature_value;
- std::list<X509Data> key_info;
-};
-
-class DCinemaSecurityMessage
-{
-public:
- DCinemaSecurityMessage () {}
- DCinemaSecurityMessage (boost::filesystem::path file)
- {
- cxml::Document f ("DCinemaSecurityMessage");
- f.read_file (file.string ());
-
- authenticated_public = AuthenticatedPublic (f.node_child ("AuthenticatedPublic"));
- authenticated_private = AuthenticatedPrivate (f.node_child ("AuthenticatedPrivate"));
- signature = Signature (f.node_child ("Signature"));
-
- f.done ();
- }
-
- boost::shared_ptr<xmlpp::Document> as_xml () const
- {
- Writer writer;
-
- xmlpp::Element* root = writer.document->create_root_node ("DCinemaSecurityMessage", "http://www.smpte-ra.org/schemas/430-3/2006/ETM");
- root->set_namespace_declaration ("http://www.w3.org/2000/09/xmldsig#", "ds");
- root->set_namespace_declaration ("http://www.w3.org/2001/04/xmlenc#", "enc");
-
- authenticated_public.as_xml (writer, root->add_child ("AuthenticatedPublic"));
- authenticated_private.as_xml (writer, root->add_child ("AuthenticatedPrivate"));
- signature.as_xml (root->add_child ("Signature", "ds"));
-
- for (std::map<std::string, xmlpp::Attribute*>::const_iterator i = writer.references.begin(); i != writer.references.end(); ++i) {
- xmlAddID (0, writer.document->cobj(), (const xmlChar *) i->first.c_str(), i->second->cobj ());
- }
-
- return writer.document;
- }
-
- AuthenticatedPublic authenticated_public;
- AuthenticatedPrivate authenticated_private;
- Signature signature;
-};
-
-}
-}
-
-#endif
-
/*
- Copyright (C) 2012-2013 Carl Hetherington <cth@carlh.net>
+ Copyright (C) 2012-2014 Carl Hetherington <cth@carlh.net>
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
*/
+/** @file src/xyz_frame.cc
+ * @brief XZYFrame class.
+ */
+
+#include "xyz_frame.h"
#include <cassert>
#include <stdexcept>
-#include "xyz_frame.h"
-using namespace libdcp;
+using namespace dcp;
/** Construct an XYZFrame, taking ownership of the opj_image_t */
XYZFrame::XYZFrame (opj_image_t* image)
assert (_opj_image->numcomps == 3);
}
+/** Construct a new XYZFrame with undefined contents.
+ * @param size Size for the frame in pixels.
+ */
XYZFrame::XYZFrame (Size size)
{
opj_image_cmptparm_t cmptparm[3];
_opj_image->y1 = size.height;
}
+/** XYZFrame destructor */
XYZFrame::~XYZFrame ()
{
opj_image_destroy (_opj_image);
}
+/** @param c Component index (0, 1 or 2)
+ * @return Pointer to the data for component c.
+ */
int *
XYZFrame::data (int c) const
{
return _opj_image->comps[c].data;
}
-libdcp::Size
+/** @return Size of the image in pixels */
+dcp::Size
XYZFrame::size () const
{
/* XXX: this may not be right; x0 and y0 can presumably be non-zero */
- return libdcp::Size (_opj_image->x1, _opj_image->y1);
+ return dcp::Size (_opj_image->x1, _opj_image->y1);
}
/*
- Copyright (C) 2012-2013 Carl Hetherington <cth@carlh.net>
+ Copyright (C) 2012-2014 Carl Hetherington <cth@carlh.net>
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
*/
-#include <openjpeg.h>
+/** @file src/xyz_frame.h
+ * @brief XZYFrame class.
+ */
+
#include "util.h"
+#include <openjpeg.h>
-namespace libdcp {
+namespace dcp {
-class XYZFrame
+/** @class XYZFrame
+ * @brief An image in XYZ colour.
+ *
+ * This class is a thin wrapper of libopenjpeg's opj_image_t.
+ */
+class XYZFrame : public boost::noncopyable
{
public:
XYZFrame (opj_image_t *);
~XYZFrame ();
int* data (int) const;
- libdcp::Size size () const;
+ dcp::Size size () const;
+ /** @return Pointer to opj_image_t struct. The caller
+ * must not delete this.
+ */
opj_image_t* opj_image () const {
return _opj_image;
}
private:
- opj_image_t* _opj_image;
+ opj_image_t* _opj_image; ///< opj_image_t that we are managing
};
}
BOOST_AUTO_TEST_CASE (certificates)
{
- libdcp::CertificateChain c;
+ dcp::CertificateChain c;
- c.add (shared_ptr<libdcp::Certificate> (new libdcp::Certificate (boost::filesystem::path ("test/ref/crypt/ca.self-signed.pem"))));
- c.add (shared_ptr<libdcp::Certificate> (new libdcp::Certificate (boost::filesystem::path ("test/ref/crypt/intermediate.signed.pem"))));
- c.add (shared_ptr<libdcp::Certificate> (new libdcp::Certificate (boost::filesystem::path ("test/ref/crypt/leaf.signed.pem"))));
+ c.add (shared_ptr<dcp::Certificate> (new dcp::Certificate (boost::filesystem::path ("test/ref/crypt/ca.self-signed.pem"))));
+ c.add (shared_ptr<dcp::Certificate> (new dcp::Certificate (boost::filesystem::path ("test/ref/crypt/intermediate.signed.pem"))));
+ c.add (shared_ptr<dcp::Certificate> (new dcp::Certificate (boost::filesystem::path ("test/ref/crypt/leaf.signed.pem"))));
- list<shared_ptr<libdcp::Certificate> > leaf_to_root = c.leaf_to_root ();
+ list<shared_ptr<dcp::Certificate> > leaf_to_root = c.leaf_to_root ();
- list<shared_ptr<libdcp::Certificate> >::iterator i = leaf_to_root.begin ();
+ list<shared_ptr<dcp::Certificate> >::iterator i = leaf_to_root.begin ();
/* Leaf */
BOOST_CHECK_EQUAL (*i, c.leaf ());
);
/* Check that reconstruction from a string works */
- libdcp::Certificate test (c.root()->certificate (true));
+ dcp::Certificate test (c.root()->certificate (true));
BOOST_CHECK_EQUAL (test.certificate(), c.root()->certificate());
}
#include "util.h"
-/* Check that libdcp::Color works */
+/* Check that dcp::Color works */
BOOST_AUTO_TEST_CASE (color)
{
- libdcp::Color c ("FFFF0000");
+ dcp::Color c ("FFFF0000");
BOOST_CHECK_EQUAL (c.r, 255);
BOOST_CHECK_EQUAL (c.g, 0);
BOOST_CHECK_EQUAL (c.b, 0);
BOOST_CHECK_EQUAL (c.to_argb_string(), "FFFF0000");
- c = libdcp::Color ("FF00FF00");
+ c = dcp::Color ("FF00FF00");
BOOST_CHECK_EQUAL (c.r, 0);
BOOST_CHECK_EQUAL (c.g, 255);
BOOST_CHECK_EQUAL (c.b, 0);
BOOST_CHECK_EQUAL (c.to_argb_string(), "FF00FF00");
- c = libdcp::Color ("FF0000FF");
+ c = dcp::Color ("FF0000FF");
BOOST_CHECK_EQUAL (c.r, 0);
BOOST_CHECK_EQUAL (c.g, 0);
+++ /dev/null
-/*
- Copyright (C) 2014 Carl Hetherington <cth@carlh.net>
-
- 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 <boost/test/unit_test.hpp>
-#include <libcxml/cxml.h>
-#include "cpl.h"
-#include "mono_picture_asset.h"
-
-using boost::shared_ptr;
-
-/* Test for a reported bug where <ScreenAspectRatio> in Interop files uses
- excessive decimal places and (sometimes) the wrong decimal point character.
-*/
-BOOST_AUTO_TEST_CASE (cpl_sar)
-{
- shared_ptr<libdcp::MonoPictureAsset> mp (new libdcp::MonoPictureAsset ("build/test/foo", "video.mxf"));
- mp->set_interop (true);
-
- {
- mp->set_size (libdcp::Size (1998, 1080));
- xmlpp::Document doc;
- xmlpp::Element* el = doc.create_root_node ("Test");
- mp->write_to_cpl (el);
-
- cxml::Node node (el);
- BOOST_CHECK_EQUAL (node.node_child("MainPicture")->string_child ("ScreenAspectRatio"), "1.85");
- }
-
- {
- mp->set_size (libdcp::Size (2048, 858));
- xmlpp::Document doc;
- xmlpp::Element* el = doc.create_root_node ("Test");
- mp->write_to_cpl (el);
-
- cxml::Node node (el);
- BOOST_CHECK_EQUAL (node.node_child("MainPicture")->string_child ("ScreenAspectRatio"), "2.39");
- }
-}
--- /dev/null
+/*
+ Copyright (C) 2014 Carl Hetherington <cth@carlh.net>
+
+ 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 "cpl.h"
+#include "reel_mono_picture_asset.h"
+#include "mono_picture_mxf.h"
+#include <libcxml/cxml.h>
+#include <boost/test/unit_test.hpp>
+
+using boost::shared_ptr;
+
+/* Test for a reported bug where <ScreenAspectRatio> in Interop files uses
+ excessive decimal places and (sometimes) the wrong decimal point character.
+*/
+BOOST_AUTO_TEST_CASE (cpl_sar)
+{
+ shared_ptr<dcp::ReelMonoPictureAsset> pa (new dcp::ReelMonoPictureAsset ());
+
+ {
+ pa->set_screen_aspect_ratio (dcp::Fraction (1998, 1080));
+ xmlpp::Document doc;
+ xmlpp::Element* el = doc.create_root_node ("Test");
+ pa->write_to_cpl (el, dcp::INTEROP);
+
+ cxml::Node node (el);
+ BOOST_CHECK_EQUAL (node.node_child("MainPicture")->string_child ("ScreenAspectRatio"), "1.85");
+ }
+
+ {
+ pa->set_screen_aspect_ratio (dcp::Fraction (2048, 858));
+ xmlpp::Document doc;
+ xmlpp::Element* el = doc.create_root_node ("Test");
+ pa->write_to_cpl (el, dcp::INTEROP);
+
+ cxml::Node node (el);
+ BOOST_CHECK_EQUAL (node.node_child("MainPicture")->string_child ("ScreenAspectRatio"), "2.39");
+ }
+}
/*
- Copyright (C) 2013 Carl Hetherington <cth@carlh.net>
+ Copyright (C) 2013-2014 Carl Hetherington <cth@carlh.net>
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
*/
-#include <boost/test/unit_test.hpp>
#include "dcp.h"
#include "metadata.h"
#include "cpl.h"
-#include "mono_picture_asset.h"
-#include "sound_asset.h"
+#include "mono_picture_mxf.h"
+#include "picture_mxf_writer.h"
+#include "sound_mxf_writer.h"
+#include "sound_mxf.h"
+#include "subtitle_content.h"
#include "reel.h"
#include "test.h"
+#include "file.h"
+#include "reel_mono_picture_asset.h"
+#include "reel_sound_asset.h"
#include "KM_util.h"
+#include <sndfile.h>
+#include <boost/test/unit_test.hpp>
using boost::shared_ptr;
Kumu::libdcp_test = true;
/* Some known metadata */
- libdcp::XMLMetadata xml_meta;
+ dcp::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;
+ dcp::MXFMetadata mxf_meta;
mxf_meta.company_name = "OpenDCP";
mxf_meta.product_name = "OpenDCP";
mxf_meta.product_version = "0.0.25";
- /* We're making build/test/DCP/foo */
+ /* We're making build/test/foo */
boost::filesystem::remove_all ("build/test/DCP/foo");
boost::filesystem::create_directories ("build/test/DCP/foo");
- libdcp::DCP d ("build/test/DCP/foo");
- shared_ptr<libdcp::CPL> cpl (new libdcp::CPL ("build/test/DCP/foo", "A Test DCP", libdcp::FEATURE, 24, 24));
+ dcp::DCP d ("build/test/DCP/foo");
+ shared_ptr<dcp::CPL> cpl (new dcp::CPL ("A Test DCP", dcp::FEATURE));
+ cpl->set_content_version_id ("urn:uri:81fb54df-e1bf-4647-8788-ea7ba154375b_2012-07-17T04:45:18+00:00");
+ cpl->set_content_version_label_text ("81fb54df-e1bf-4647-8788-ea7ba154375b_2012-07-17T04:45:18+00:00");
- shared_ptr<libdcp::MonoPictureAsset> mp (new libdcp::MonoPictureAsset ("build/test/DCP/foo", "video.mxf"));
- mp->set_progress (&d.Progress);
- mp->set_edit_rate (24);
- mp->set_intrinsic_duration (24);
- mp->set_duration (24);
- mp->set_size (libdcp::Size (32, 32));
+ shared_ptr<dcp::MonoPictureMXF> mp (new dcp::MonoPictureMXF (dcp::Fraction (24, 1)));
mp->set_metadata (mxf_meta);
- mp->create (j2c);
+ shared_ptr<dcp::PictureMXFWriter> picture_writer = mp->start_write ("build/test/DCP/foo/video.mxf", dcp::SMPTE, false);
+ dcp::File j2c ("test/data/32x32_red_square.j2c");
+ for (int i = 0; i < 24; ++i) {
+ picture_writer->write (j2c.data (), j2c.size ());
+ }
+ picture_writer->finalize ();
- shared_ptr<libdcp::SoundAsset> ms (new libdcp::SoundAsset ("build/test/DCP/foo", "audio.mxf"));
- ms->set_progress (&d.Progress);
- ms->set_edit_rate (24);
- ms->set_intrinsic_duration (24);
- ms->set_duration (24);
- ms->set_channels (2);
+ shared_ptr<dcp::SoundMXF> ms (new dcp::SoundMXF (dcp::Fraction (24, 1), 48000, 1));
ms->set_metadata (mxf_meta);
- ms->create (wav);
+ shared_ptr<dcp::SoundMXFWriter> sound_writer = ms->start_write ("build/test/DCP/foo/audio.mxf", dcp::SMPTE);
+
+ SF_INFO info;
+ info.format = 0;
+ SNDFILE* sndfile = sf_open ("test/data/1s_24-bit_48k_silence.wav", SFM_READ, &info);
+ BOOST_CHECK (sndfile);
+ float buffer[4096*6];
+ float* channels[1];
+ channels[0] = buffer;
+ while (1) {
+ sf_count_t N = sf_readf_float (sndfile, buffer, 4096);
+ sound_writer->write (channels, N);
+ if (N < 4096) {
+ break;
+ }
+ }
+
+ sound_writer->finalize ();
- cpl->add_reel (shared_ptr<libdcp::Reel> (new libdcp::Reel (mp, ms, shared_ptr<libdcp::SubtitleAsset> ())));
- d.add_cpl (cpl);
+ cpl->add (shared_ptr<dcp::Reel> (
+ new dcp::Reel (
+ shared_ptr<dcp::ReelMonoPictureAsset> (new dcp::ReelMonoPictureAsset (mp, 0)),
+ shared_ptr<dcp::ReelSoundAsset> (new dcp::ReelSoundAsset (ms, 0)),
+ shared_ptr<dcp::ReelSubtitleAsset> ()
+ )
+ ));
+
+ d.add (cpl);
+ d.add (mp);
+ d.add (ms);
- d.write_xml (false, xml_meta);
+ d.write_xml (dcp::SMPTE, xml_meta);
/* build/test/DCP/foo is checked against test/ref/DCP/foo by run-tests.sh */
}
#include <boost/test/unit_test.hpp>
#include "dcp_time.h"
-/** Check that libdcp::Time works */
+/** Check that dcp::Time works */
BOOST_AUTO_TEST_CASE (dcp_time)
{
- libdcp::Time t (977143, 24);
+ dcp::Time t (977143, 24);
BOOST_CHECK_EQUAL (t.t, 73);
BOOST_CHECK_EQUAL (t.s, 34);
BOOST_CHECK_EQUAL (t.to_string(), "11:18:34:73");
BOOST_CHECK_EQUAL (t.to_ticks(), 10178573);
- libdcp::Time a (3, 2, 3, 4);
- libdcp::Time b (2, 3, 4, 5);
+ dcp::Time a (3, 2, 3, 4);
+ dcp::Time b (2, 3, 4, 5);
- libdcp::Time r = a - b;
+ dcp::Time r = a - b;
BOOST_CHECK_EQUAL (r.h, 0);
BOOST_CHECK_EQUAL (r.m, 58);
BOOST_CHECK_EQUAL (r.s, 58);
BOOST_CHECK_EQUAL (r.to_string(), "0:58:58:249");
BOOST_CHECK_EQUAL (r.to_ticks(), 884749);
- a = libdcp::Time (1, 58, 56, 240);
- b = libdcp::Time (1, 7, 12, 120);
+ a = dcp::Time (1, 58, 56, 240);
+ b = dcp::Time (1, 7, 12, 120);
r = a + b;
BOOST_CHECK_EQUAL (r.h, 3);
BOOST_CHECK_EQUAL (r.m, 6);
BOOST_CHECK_EQUAL (r.to_string(), "3:6:9:110");
BOOST_CHECK_EQUAL (r.to_ticks(), 2792360);
- a = libdcp::Time (24, 12, 6, 3);
- b = libdcp::Time (16, 8, 4, 2);
+ a = dcp::Time (24, 12, 6, 3);
+ b = dcp::Time (16, 8, 4, 2);
BOOST_CHECK_CLOSE (a / b, 1.5, 1e-5);
- BOOST_CHECK_EQUAL (libdcp::Time (4128391203LL).to_ticks(), 4128391203LL);
- BOOST_CHECK_EQUAL (libdcp::Time (60000).to_ticks(), 60000);
+ BOOST_CHECK_EQUAL (dcp::Time (4128391203LL).to_ticks(), 4128391203LL);
+ BOOST_CHECK_EQUAL (dcp::Time (60000).to_ticks(), 60000);
}
#include "mono_picture_frame.h"
#include "cpl.h"
#include "argb_frame.h"
-#include "mono_picture_asset.h"
+#include "mono_picture_mxf.h"
+#include "reel_picture_asset.h"
#include "reel.h"
#include "test.h"
using boost::dynamic_pointer_cast;
using boost::shared_ptr;
-static shared_ptr<const libdcp::ARGBFrame>
-get_frame (libdcp::DCP const & dcp)
+static shared_ptr<const dcp::ARGBFrame>
+get_frame (dcp::DCP const & dcp)
{
- shared_ptr<const libdcp::Reel> reel = dcp.cpls().front()->reels().front ();
- shared_ptr<const libdcp::PictureAsset> picture = reel->main_picture ();
+ shared_ptr<const dcp::Reel> reel = dcp.cpls().front()->reels().front ();
+ shared_ptr<dcp::PictureMXF> picture = reel->main_picture()->mxf ();
BOOST_CHECK (picture);
- shared_ptr<const libdcp::MonoPictureAsset> mono_picture = dynamic_pointer_cast<const libdcp::MonoPictureAsset> (picture);
- shared_ptr<const libdcp::MonoPictureFrame> j2k_frame = mono_picture->get_frame (0);
+ shared_ptr<const dcp::MonoPictureMXF> mono_picture = dynamic_pointer_cast<const dcp::MonoPictureMXF> (picture);
+ shared_ptr<const dcp::MonoPictureFrame> j2k_frame = mono_picture->get_frame (0);
return j2k_frame->argb_frame ();
}
{
boost::filesystem::path plaintext_path = private_test;
plaintext_path /= "TONEPLATES-SMPTE-PLAINTEXT_TST_F_XX-XX_ITL-TD_51-XX_2K_WOE_20111001_WOE_OV";
- libdcp::DCP plaintext (plaintext_path.string ());
+ dcp::DCP plaintext (plaintext_path.string ());
plaintext.read ();
BOOST_CHECK_EQUAL (plaintext.encrypted (), false);
boost::filesystem::path encrypted_path = private_test;
encrypted_path /= "TONEPLATES-SMPTE-ENCRYPTED_TST_F_XX-XX_ITL-TD_51-XX_2K_WOE_20111001_WOE_OV";
- libdcp::DCP encrypted (encrypted_path.string ());
+ dcp::DCP encrypted (encrypted_path.string ());
encrypted.read ();
BOOST_CHECK_EQUAL (encrypted.encrypted (), true);
- libdcp::KDM kdm (
+ dcp::KDM kdm (
"test/data/kdm_TONEPLATES-SMPTE-ENC_.smpte-430-2.ROOT.NOT_FOR_PRODUCTION_20130706_20230702_CAR_OV_t1_8971c838.xml",
"test/data/private.key"
);
- encrypted.add_kdm (kdm);
+ encrypted.add (kdm);
- shared_ptr<const libdcp::ARGBFrame> plaintext_frame = get_frame (plaintext);
- shared_ptr<const libdcp::ARGBFrame> encrypted_frame = get_frame (encrypted);
+ shared_ptr<const dcp::ARGBFrame> plaintext_frame = get_frame (plaintext);
+ shared_ptr<const dcp::ARGBFrame> encrypted_frame = get_frame (encrypted);
/* Check that plaintext and encrypted are the same */
BOOST_CHECK_EQUAL (plaintext_frame->stride(), encrypted_frame->stride());
/** Load in a KDM that didn't work at first */
BOOST_AUTO_TEST_CASE (failing_kdm_test)
{
- libdcp::KDM kdm (
+ dcp::KDM kdm (
"test/data/target.pem.crt.de5d4eba-e683-41ca-bdda-aa4ad96af3f4.kdm.xml",
"test/data/private.key"
);
/*
- Copyright (C) 2013 Carl Hetherington <cth@carlh.net>
+ Copyright (C) 2013-2014 Carl Hetherington <cth@carlh.net>
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
*/
-#include <boost/test/unit_test.hpp>
#include "kdm.h"
#include "KM_util.h"
#include "metadata.h"
#include "dcp.h"
#include "signer.h"
#include "cpl.h"
-#include "mono_picture_asset.h"
-#include "sound_asset.h"
+#include "mono_picture_mxf.h"
+#include "picture_mxf_writer.h"
+#include "sound_mxf.h"
#include "reel.h"
#include "test.h"
+#include "file.h"
#include "signer_chain.h"
+#include "subtitle_content.h"
+#include "reel_mono_picture_asset.h"
+#include "reel_sound_asset.h"
+#include <boost/test/unit_test.hpp>
+#include <boost/shared_ptr.hpp>
using boost::shared_ptr;
/* Load a certificate chain from build/test/data/ *.pem and then build
an encrypted DCP and a KDM using it.
*/
-BOOST_AUTO_TEST_CASE (encryption)
+BOOST_AUTO_TEST_CASE (encryption_test)
{
boost::filesystem::remove_all ("build/test/signer");
boost::filesystem::create_directory ("build/test/signer");
- libdcp::make_signer_chain ("build/test/signer", "openssl");
+ dcp::make_signer_chain ("build/test/signer", "openssl");
Kumu::libdcp_test = true;
- libdcp::MXFMetadata mxf_metadata;
+ dcp::MXFMetadata mxf_metadata;
mxf_metadata.company_name = "OpenDCP";
mxf_metadata.product_name = "OpenDCP";
mxf_metadata.product_version = "0.0.25";
- libdcp::XMLMetadata xml_metadata;
+ dcp::XMLMetadata xml_metadata;
xml_metadata.issuer = "OpenDCP 0.0.25";
xml_metadata.creator = "OpenDCP 0.0.25";
xml_metadata.issue_date = "2012-07-17T04:45:18+00:00";
boost::filesystem::remove_all ("build/test/DCP/bar");
boost::filesystem::create_directories ("build/test/DCP/bar");
- libdcp::DCP d ("build/test/DCP/bar");
+ dcp::DCP d ("build/test/DCP/bar");
/* Use test/ref/crypt so this test is repeatable */
- libdcp::CertificateChain chain;
- chain.add (shared_ptr<libdcp::Certificate> (new libdcp::Certificate (boost::filesystem::path ("test/ref/crypt/ca.self-signed.pem"))));
- chain.add (shared_ptr<libdcp::Certificate> (new libdcp::Certificate (boost::filesystem::path ("test/ref/crypt/intermediate.signed.pem"))));
- chain.add (shared_ptr<libdcp::Certificate> (new libdcp::Certificate (boost::filesystem::path ("test/ref/crypt/leaf.signed.pem"))));
+ dcp::CertificateChain chain;
+ chain.add (shared_ptr<dcp::Certificate> (new dcp::Certificate (boost::filesystem::path ("test/ref/crypt/ca.self-signed.pem"))));
+ chain.add (shared_ptr<dcp::Certificate> (new dcp::Certificate (boost::filesystem::path ("test/ref/crypt/intermediate.signed.pem"))));
+ chain.add (shared_ptr<dcp::Certificate> (new dcp::Certificate (boost::filesystem::path ("test/ref/crypt/leaf.signed.pem"))));
- shared_ptr<libdcp::Signer> signer (
- new libdcp::Signer (
+ shared_ptr<dcp::Signer> signer (
+ new dcp::Signer (
chain,
"test/ref/crypt/leaf.key"
)
);
- shared_ptr<libdcp::CPL> cpl (new libdcp::CPL ("build/test/DCP/bar", "A Test DCP", libdcp::FEATURE, 24, 24));
+ shared_ptr<dcp::CPL> cpl (new dcp::CPL ("A Test DCP", dcp::FEATURE));
- libdcp::Key key;
+ dcp::Key key;
- shared_ptr<libdcp::MonoPictureAsset> mp (new libdcp::MonoPictureAsset ("build/test/DCP/bar", "video.mxf"));
- mp->set_progress (&d.Progress);
- mp->set_edit_rate (24);
- mp->set_intrinsic_duration (24);
- mp->set_duration (24);
- mp->set_size (libdcp::Size (32, 32));
+ shared_ptr<dcp::MonoPictureMXF> mp (new dcp::MonoPictureMXF (dcp::Fraction (24, 1)));
mp->set_metadata (mxf_metadata);
mp->set_key (key);
- mp->create (j2c);
-
- shared_ptr<libdcp::SoundAsset> ms (new libdcp::SoundAsset ("build/test/DCP/bar", "audio.mxf"));
- ms->set_progress (&d.Progress);
- ms->set_edit_rate (24);
- ms->set_intrinsic_duration (24);
- mp->set_duration (24);
- ms->set_channels (2);
- ms->set_metadata (mxf_metadata);
- ms->set_key (key);
- ms->create (wav);
-
- cpl->add_reel (shared_ptr<libdcp::Reel> (new libdcp::Reel (mp, ms, shared_ptr<libdcp::SubtitleAsset> ())));
- d.add_cpl (cpl);
-
- d.write_xml (false, xml_metadata, signer);
- libdcp::KDM kdm (
+ shared_ptr<dcp::PictureMXFWriter> writer = mp->start_write ("build/test/DCP/bar/video.mxf", dcp::SMPTE, false);
+ dcp::File j2c ("test/data/32x32_red_square.j2c");
+ for (int i = 0; i < 24; ++i) {
+ writer->write (j2c.data (), j2c.size ());
+ }
+ writer->finalize ();
+
+ cpl->add (shared_ptr<dcp::Reel> (new dcp::Reel (
+ shared_ptr<dcp::ReelMonoPictureAsset> (new dcp::ReelMonoPictureAsset (mp, 0)),
+ shared_ptr<dcp::ReelSoundAsset> (),
+ shared_ptr<dcp::ReelSubtitleAsset> ()
+ )));
+ d.add (cpl);
+ d.write_xml (dcp::SMPTE, xml_metadata, signer);
+
+ dcp::KDM kdm (
cpl,
signer,
signer->certificates().leaf(),
+++ /dev/null
-/*
- Copyright (C) 2013 Carl Hetherington <cth@carlh.net>
-
- 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 <boost/test/unit_test.hpp>
-#include "dcp.h"
-#include "mono_picture_asset.h"
-#include "sound_asset.h"
-#include "util.h"
-#include "exceptions.h"
-
-using std::vector;
-using std::string;
-
-/* Check that an exception is thrown when trying to create MXFs from non-existant sources */
-BOOST_AUTO_TEST_CASE (error_test)
-{
- /* Create an empty DCP */
- libdcp::DCP d ("build/test/fred");
-
- /* Random filename that does not exist */
- vector<boost::filesystem::path> p;
- p.push_back ("frobozz");
-
- /* Trying to create video/audio MXFs using a non-existant file should throw an exception */
- libdcp::MonoPictureAsset pa ("build/test/fred", "video.mxf");
- BOOST_CHECK_THROW (pa.create (p), libdcp::FileError);
-
- libdcp::SoundAsset sa ("build/test/fred", "audio.mxf");
- sa.set_channels (1);
- BOOST_CHECK_THROW (sa.create (p), libdcp::FileError);
-}
#include <fstream>
#include <boost/test/unit_test.hpp>
-#include "picture_asset_writer.h"
+#include "picture_mxf.h"
+#include "picture_mxf_writer.h"
using namespace std;
/* Test writing and reading of frame_info_test with fstream and stdio */
BOOST_AUTO_TEST_CASE (frame_info_test)
{
- libdcp::FrameInfo a (8589934592LL, 17179869184LL, "thisisahash");
+ dcp::FrameInfo a (8589934592LL, 17179869184LL, "thisisahash");
ofstream o1 ("build/test/frame_info1");
a.write (o1);
BOOST_CHECK_EQUAL (s1, s2);
ifstream l1 ("build/test/frame_info1");
- libdcp::FrameInfo b1 (l1);
+ dcp::FrameInfo b1 (l1);
FILE* l2 = fopen ("build/test/frame_info2", "r");
BOOST_CHECK (l2);
- libdcp::FrameInfo b2 (l2);
+ dcp::FrameInfo b2 (l2);
BOOST_CHECK_EQUAL (b1.offset, b2.offset);
BOOST_CHECK_EQUAL (b1.size, b2.size);
{
uint8_t foo[138];
memset (foo, 0, 138);
- libdcp::KDMKey kkey (foo, 138);
+ dcp::KDMKey kkey (foo, 138);
uint8_t* raw = new uint8_t[16];
uint8_t* p = raw;
#include <boost/test/unit_test.hpp>
#include "kdm.h"
-#include "xml/kdm_smpte.h"
+#include "kdm_smpte_xml.h"
using std::list;
using boost::shared_ptr;
BOOST_AUTO_TEST_CASE (kdm_test)
{
- libdcp::KDM kdm (
+ dcp::KDM kdm (
"test/data/kdm_TONEPLATES-SMPTE-ENC_.smpte-430-2.ROOT.NOT_FOR_PRODUCTION_20130706_20230702_CAR_OV_t1_8971c838.xml",
"test/data/private.key"
);
- list<libdcp::KDMKey> keys = kdm.keys ();
+ list<dcp::KDMKey> keys = kdm.keys ();
BOOST_CHECK_EQUAL (keys.size(), 2);
/* Check that we can read in a KDM and then write it back out again the same */
BOOST_AUTO_TEST_CASE (kdm_passthrough_test)
{
- libdcp::xml::DCinemaSecurityMessage kdm (
+ dcp::xml::DCinemaSecurityMessage kdm (
"test/data/kdm_TONEPLATES-SMPTE-ENC_.smpte-430-2.ROOT.NOT_FOR_PRODUCTION_20130706_20230702_CAR_OV_t1_8971c838.xml"
);
+++ /dev/null
-/*
- Copyright (C) 2013 Carl Hetherington <cth@carlh.net>
-
- 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 <boost/test/unit_test.hpp>
-#include "opendcp_lut.h"
-#include "opendcp_lut.cc"
-#include "srgb_linearised_gamma_lut.h"
-#include "rec709_linearised_gamma_lut.h"
-#include "gamma_lut.h"
-
-/* Check that some of our LUTs match the ones from OpenDCP that
- DVD-o-matic uses / once used.
-*/
-BOOST_AUTO_TEST_CASE (lut_test)
-{
- libdcp::SRGBLinearisedGammaLUT lut_in_srgb (12, 2.4);
- for (int i = 0; i < 4096; ++i) {
- /* Hmm; 1% isn't exactly great... */
- BOOST_CHECK_CLOSE (opendcp::lut_in[0][i], lut_in_srgb.lut()[i], 1);
- }
-
- libdcp::Rec709LinearisedGammaLUT lut_in_rec709 (12, 1 / 0.45);
- for (int i = 0; i < 4096; ++i) {
- /* Hmm; 1% isn't exactly great... */
- BOOST_CHECK_CLOSE (opendcp::lut_in[1][i], lut_in_rec709.lut()[i], 1);
- }
-
- libdcp::GammaLUT lut_out (16, 1 / 2.6);
- for (int i = 0; i < 65536; ++i) {
- BOOST_CHECK_CLOSE (opendcp::lut_out[0][i], lut_out.lut()[i] * 4096, 1);
- }
-}
/* Read DCP that is in git and make sure that basic stuff is read in correctly */
BOOST_AUTO_TEST_CASE (read_dcp)
{
- libdcp::DCP d ("test/ref/DCP/foo");
+ dcp::DCP d ("test/ref/DCP/foo");
d.read ();
- list<shared_ptr<libdcp::CPL> > cpls = d.cpls ();
+ list<shared_ptr<dcp::CPL> > cpls = d.cpls ();
BOOST_CHECK_EQUAL (cpls.size(), 1);
- BOOST_CHECK_EQUAL (cpls.front()->name(), "A Test DCP");
- BOOST_CHECK_EQUAL (cpls.front()->content_kind(), libdcp::FEATURE);
- BOOST_CHECK_EQUAL (cpls.front()->frames_per_second(), 24);
- BOOST_CHECK_EQUAL (cpls.front()->length(), 24);
+ BOOST_CHECK_EQUAL (cpls.front()->annotation_text(), "A Test DCP");
+ BOOST_CHECK_EQUAL (cpls.front()->content_kind(), dcp::FEATURE);
}
#include <boost/test/unit_test.hpp>
#include <boost/filesystem.hpp>
-#include "mono_picture_asset_writer.h"
-#include "mono_picture_asset.h"
+#include "mono_picture_mxf_writer.h"
+#include "mono_picture_mxf.h"
#include "KM_util.h"
using std::string;
boost::filesystem::remove_all ("build/test/baz");
boost::filesystem::create_directories ("build/test/baz");
- shared_ptr<libdcp::MonoPictureAsset> mp (new libdcp::MonoPictureAsset ("build/test/baz", "video1.mxf"));
- mp->set_edit_rate (24);
- mp->set_size (libdcp::Size (32, 32));
- shared_ptr<libdcp::PictureAssetWriter> writer = mp->start_write (false);
+ shared_ptr<dcp::MonoPictureMXF> mp (new dcp::MonoPictureMXF (dcp::Fraction (24, 1)));
+ shared_ptr<dcp::PictureMXFWriter> writer = mp->start_write ("build/test/baz/video1.mxf", dcp::SMPTE, false);
int written_size = 0;
for (int i = 0; i < 24; ++i) {
- libdcp::FrameInfo info = writer->write (data, size);
+ dcp::FrameInfo info = writer->write (data, size);
written_size = info.size;
}
Kumu::ResetTestRNG ();
#endif
- mp.reset (new libdcp::MonoPictureAsset ("build/test/baz", "video2.mxf"));
- mp->set_edit_rate (24);
- mp->set_size (libdcp::Size (32, 32));
- writer = mp->start_write (true);
+ mp.reset (new dcp::MonoPictureMXF (dcp::Fraction (24, 1)));
+ writer = mp->start_write ("build/test/baz/video2.mxf", dcp::SMPTE, true);
writer->write (data, size);
+/*
+ Copyright (C) 2012-2014 Carl Hetherington <cth@carlh.net>
+
+ 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 <iostream>
#include "dcp.h"
#include "cpl.h"
#include "reel.h"
-#include "subtitle_asset.h"
+#include "subtitle_content.h"
+#include "reel_subtitle_asset.h"
#include "exceptions.h"
using std::cout;
using std::cerr;
using std::list;
using boost::shared_ptr;
-using namespace libdcp;
+using namespace dcp;
int
main (int argc, char* argv[])
}
DCP* dcp = new DCP (argv[1]);
- dcp->read (false);
+ dcp->read ();
list<shared_ptr<CPL> > cpls = dcp->cpls ();
for (list<boost::shared_ptr<CPL> >::iterator i = cpls.begin(); i != cpls.end(); ++i) {
for (list<shared_ptr<Reel> >::iterator j = reels.begin(); j != reels.end(); ++j) {
if ((*j)->main_subtitle()) {
- (*j)->main_subtitle()->write_xml ();
+ (*j)->main_subtitle()->subtitle_content()->write_xml ();
}
}
}
*/
-#include <iostream>
-#include <boost/test/unit_test.hpp>
#include "certificates.h"
#include "kdm.h"
#include "signer.h"
-#include "mono_picture_asset.h"
-#include "sound_asset.h"
+#include "mono_picture_mxf.h"
+#include "sound_mxf.h"
#include "reel.h"
#include "test.h"
#include "cpl.h"
#include "mono_picture_frame.h"
#include "argb_frame.h"
#include "signer_chain.h"
+#include "mono_picture_mxf_writer.h"
+#include "reel_picture_asset.h"
+#include "reel_mono_picture_asset.h"
+#include "file.h"
+#include <boost/test/unit_test.hpp>
+#include <iostream>
using std::list;
using boost::shared_ptr;
{
boost::filesystem::remove_all ("build/test/signer");
boost::filesystem::create_directory ("build/test/signer");
- libdcp::make_signer_chain ("build/test/signer", "openssl");
+ dcp::make_signer_chain ("build/test/signer", "openssl");
- libdcp::CertificateChain chain;
- chain.add (shared_ptr<libdcp::Certificate> (new libdcp::Certificate (boost::filesystem::path ("build/test/signer/ca.self-signed.pem"))));
- chain.add (shared_ptr<libdcp::Certificate> (new libdcp::Certificate (boost::filesystem::path ("build/test/signer/intermediate.signed.pem"))));
- chain.add (shared_ptr<libdcp::Certificate> (new libdcp::Certificate (boost::filesystem::path ("build/test/signer/leaf.signed.pem"))));
+ dcp::CertificateChain chain;
+ chain.add (shared_ptr<dcp::Certificate> (new dcp::Certificate (boost::filesystem::path ("build/test/signer/ca.self-signed.pem"))));
+ chain.add (shared_ptr<dcp::Certificate> (new dcp::Certificate (boost::filesystem::path ("build/test/signer/intermediate.signed.pem"))));
+ chain.add (shared_ptr<dcp::Certificate> (new dcp::Certificate (boost::filesystem::path ("build/test/signer/leaf.signed.pem"))));
- shared_ptr<libdcp::Signer> signer (
- new libdcp::Signer (
+ shared_ptr<dcp::Signer> signer (
+ new dcp::Signer (
chain,
"test/data/signer.key"
)
boost::filesystem::path work_dir = "build/test/round_trip_test";
boost::filesystem::create_directory (work_dir);
- shared_ptr<libdcp::MonoPictureAsset> asset_A (new libdcp::MonoPictureAsset (work_dir, "video.mxf"));
- asset_A->set_edit_rate (24);
- asset_A->set_intrinsic_duration (24);
- asset_A->set_size (libdcp::Size (32, 32));
- asset_A->create (j2c);
+ shared_ptr<dcp::MonoPictureMXF> mxf_A (new dcp::MonoPictureMXF (dcp::Fraction (24, 1)));
+ shared_ptr<dcp::PictureMXFWriter> writer = mxf_A->start_write (work_dir / "video.mxf", dcp::SMPTE, false);
+ dcp::File j2c ("test/data/32x32_red_square.j2c");
+ for (int i = 0; i < 24; ++i) {
+ writer->write (j2c.data (), j2c.size ());
+ }
+ writer->finalize ();
- libdcp::Key key;
+ dcp::Key key;
- asset_A->set_key (key);
+ mxf_A->set_key (key);
- shared_ptr<libdcp::CPL> cpl (new libdcp::CPL (work_dir, "A Test DCP", libdcp::FEATURE, 24, 24));
- cpl->add_reel (shared_ptr<libdcp::Reel> (new libdcp::Reel (asset_A, shared_ptr<libdcp::SoundAsset> (), shared_ptr<libdcp::SubtitleAsset> ())));
+ shared_ptr<dcp::CPL> cpl (new dcp::CPL ("A Test DCP", dcp::FEATURE));
+ shared_ptr<dcp::Reel> reel (new dcp::Reel ());
+ reel->add (shared_ptr<dcp::ReelMonoPictureAsset> (new dcp::ReelMonoPictureAsset (mxf_A, 0)));
+ cpl->add (reel);
/* A KDM using our certificate chain's leaf key pair */
- libdcp::KDM kdm_A (
+ dcp::KDM kdm_A (
cpl,
signer,
signer->certificates().leaf(),
kdm_A.as_xml (kdm_file);
/* Reload the KDM, using our private key to decrypt it */
- libdcp::KDM kdm_B (kdm_file, "build/test/signer/leaf.key");
+ dcp::KDM kdm_B (kdm_file, "build/test/signer/leaf.key");
/* Check that the decrypted KDMKeys are the same as the ones we started with */
BOOST_CHECK_EQUAL (kdm_A.keys().size(), kdm_B.keys().size());
- list<libdcp::KDMKey> keys_A = kdm_A.keys ();
- list<libdcp::KDMKey> keys_B = kdm_B.keys ();
- list<libdcp::KDMKey>::const_iterator i = keys_A.begin();
- list<libdcp::KDMKey>::const_iterator j = keys_B.begin();
+ list<dcp::KDMKey> keys_A = kdm_A.keys ();
+ list<dcp::KDMKey> keys_B = kdm_B.keys ();
+ list<dcp::KDMKey>::const_iterator i = keys_A.begin();
+ list<dcp::KDMKey>::const_iterator j = keys_B.begin();
while (i != keys_A.end ()) {
BOOST_CHECK (*i == *j);
++i;
}
/* Reload the picture MXF */
- shared_ptr<libdcp::MonoPictureAsset> asset_B (
- new libdcp::MonoPictureAsset (work_dir, "video.mxf")
+ shared_ptr<dcp::MonoPictureMXF> mxf_B (
+ new dcp::MonoPictureMXF (work_dir / "video.mxf")
);
- asset_B->set_key (kdm_B.keys().front().key());
+ BOOST_CHECK (!kdm_B.keys().empty ());
+ mxf_B->set_key (kdm_B.keys().front().key());
- shared_ptr<libdcp::ARGBFrame> frame_A = asset_A->get_frame(0)->argb_frame ();
- shared_ptr<libdcp::ARGBFrame> frame_B = asset_B->get_frame(0)->argb_frame ();
+ shared_ptr<dcp::ARGBFrame> frame_A = mxf_A->get_frame(0)->argb_frame ();
+ shared_ptr<dcp::ARGBFrame> frame_B = mxf_B->get_frame(0)->argb_frame ();
BOOST_CHECK_EQUAL (frame_A->size().width, frame_B->size().width);
BOOST_CHECK_EQUAL (frame_A->size().height, frame_B->size().height);
BOOST_CHECK_EQUAL (memcmp (frame_A->data(), frame_B->data(), frame_A->size().width * frame_A->size().height), 0);
#include <iostream>
-#include "subtitle_asset.h"
+#include "subtitle_content.h"
using namespace std;
exit (EXIT_FAILURE);
}
- libdcp::SubtitleAsset s ("foo", "bar", "baz");
- s.read_xml (argv[1]);
+ dcp::SubtitleContent s (argv[1]);
cout << s.xml_as_string ();
return 0;
}
/*
- Copyright (C) 2012-2013 Carl Hetherington <cth@carlh.net>
+ Copyright (C) 2012-2014 Carl Hetherington <cth@carlh.net>
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
*/
+#include "subtitle_content.h"
+#include "subtitle_string.h"
#include <boost/test/unit_test.hpp>
-#include "subtitle_asset.h"
using std::list;
using boost::shared_ptr;
-/* Load a subtitle asset from XML and check that it is read correctly */
+/* Load some subtitle content from XML and check that it is read correctly */
BOOST_AUTO_TEST_CASE (subtitles1)
{
- libdcp::SubtitleAsset subs ("test/data", "subs1.xml");
+ dcp::SubtitleContent subs ("test/data/subs1.xml");
BOOST_CHECK_EQUAL (subs.language(), "French");
- list<shared_ptr<libdcp::Subtitle> > s = subs.subtitles_at (libdcp::Time (0, 0, 6, 1));
+ list<shared_ptr<dcp::SubtitleString> > s = subs.subtitles_at (dcp::Time (0, 0, 6, 1));
BOOST_CHECK_EQUAL (s.size(), 1);
- BOOST_CHECK_EQUAL (*(s.front().get()), libdcp::Subtitle (
+ BOOST_CHECK_EQUAL (*(s.front().get()), dcp::SubtitleString (
"Arial",
false,
- libdcp::Color (255, 255, 255),
+ dcp::Color (255, 255, 255),
39,
- libdcp::Time (0, 0, 5, 198),
- libdcp::Time (0, 0, 7, 115),
+ dcp::Time (0, 0, 5, 198),
+ dcp::Time (0, 0, 7, 115),
15,
- libdcp::BOTTOM,
+ dcp::BOTTOM,
"My jacket was Idi Amin's",
- libdcp::BORDER,
- libdcp::Color (0, 0, 0),
- libdcp::Time (0, 0, 0, 1),
- libdcp::Time (0, 0, 0, 1)
+ dcp::BORDER,
+ dcp::Color (0, 0, 0),
+ dcp::Time (0, 0, 0, 1),
+ dcp::Time (0, 0, 0, 1)
));
- s = subs.subtitles_at (libdcp::Time (0, 0, 7, 190));
+ s = subs.subtitles_at (dcp::Time (0, 0, 7, 190));
BOOST_CHECK_EQUAL (s.size(), 2);
- BOOST_CHECK_EQUAL (*(s.front().get()), libdcp::Subtitle (
+ BOOST_CHECK_EQUAL (*(s.front().get()), dcp::SubtitleString (
"Arial",
true,
- libdcp::Color (255, 255, 255),
+ dcp::Color (255, 255, 255),
39,
- libdcp::Time (0, 0, 7, 177),
- libdcp::Time (0, 0, 11, 31),
+ dcp::Time (0, 0, 7, 177),
+ dcp::Time (0, 0, 11, 31),
21,
- libdcp::BOTTOM,
+ dcp::BOTTOM,
"My corset was H.M. The Queen's",
- libdcp::BORDER,
- libdcp::Color (0, 0, 0),
- libdcp::Time (0, 0, 0, 1),
- libdcp::Time (0, 0, 0, 1)
+ dcp::BORDER,
+ dcp::Color (0, 0, 0),
+ dcp::Time (0, 0, 0, 1),
+ dcp::Time (0, 0, 0, 1)
));
- BOOST_CHECK_EQUAL (*(s.back().get()), libdcp::Subtitle (
+ BOOST_CHECK_EQUAL (*(s.back().get()), dcp::SubtitleString (
"Arial",
false,
- libdcp::Color (255, 255, 255),
+ dcp::Color (255, 255, 255),
39,
- libdcp::Time (0, 0, 7, 177),
- libdcp::Time (0, 0, 11, 31),
+ dcp::Time (0, 0, 7, 177),
+ dcp::Time (0, 0, 11, 31),
15,
- libdcp::BOTTOM,
+ dcp::BOTTOM,
"My large wonderbra",
- libdcp::BORDER,
- libdcp::Color (0, 0, 0),
- libdcp::Time (0, 0, 0, 1),
- libdcp::Time (0, 0, 0, 1)
+ dcp::BORDER,
+ dcp::Color (0, 0, 0),
+ dcp::Time (0, 0, 0, 1),
+ dcp::Time (0, 0, 0, 1)
));
- s = subs.subtitles_at (libdcp::Time (0, 0, 11, 95));
+ s = subs.subtitles_at (dcp::Time (0, 0, 11, 95));
BOOST_CHECK_EQUAL (s.size(), 1);
- BOOST_CHECK_EQUAL (*(s.back().get()), libdcp::Subtitle (
+ BOOST_CHECK_EQUAL (*(s.back().get()), dcp::SubtitleString (
"Arial",
false,
- libdcp::Color (255, 255, 255),
+ dcp::Color (255, 255, 255),
39,
- libdcp::Time (0, 0, 11, 94),
- libdcp::Time (0, 0, 13, 63),
+ dcp::Time (0, 0, 11, 94),
+ dcp::Time (0, 0, 13, 63),
15,
- libdcp::BOTTOM,
+ dcp::BOTTOM,
"Once belonged to the Shah",
- libdcp::BORDER,
- libdcp::Color (0, 0, 0),
- libdcp::Time (0, 0, 0, 1),
- libdcp::Time (0, 0, 0, 1)
+ dcp::BORDER,
+ dcp::Color (0, 0, 0),
+ dcp::Time (0, 0, 0, 1),
+ dcp::Time (0, 0, 0, 1)
));
- s = subs.subtitles_at (libdcp::Time (0, 0, 14, 42));
+ s = subs.subtitles_at (dcp::Time (0, 0, 14, 42));
BOOST_CHECK_EQUAL (s.size(), 1);
- BOOST_CHECK_EQUAL (*(s.back().get()), libdcp::Subtitle (
+ BOOST_CHECK_EQUAL (*(s.back().get()), dcp::SubtitleString (
"Arial",
false,
- libdcp::Color (255, 255, 255),
+ dcp::Color (255, 255, 255),
39,
- libdcp::Time (0, 0, 13, 104),
- libdcp::Time (0, 0, 15, 177),
+ dcp::Time (0, 0, 13, 104),
+ dcp::Time (0, 0, 15, 177),
15,
- libdcp::BOTTOM,
+ dcp::BOTTOM,
"And these are Roy Hattersley's jeans",
- libdcp::BORDER,
- libdcp::Color (0, 0, 0),
- libdcp::Time (0, 0, 0, 1),
- libdcp::Time (0, 0, 0, 1)
+ dcp::BORDER,
+ dcp::Color (0, 0, 0),
+ dcp::Time (0, 0, 0, 1),
+ dcp::Time (0, 0, 0, 1)
));
}
/** And similarly for another one */
BOOST_AUTO_TEST_CASE (subtitles2)
{
- libdcp::SubtitleAsset subs ("test/data", "subs2.xml");
+ dcp::SubtitleContent subs ("test/data/subs2.xml");
- list<shared_ptr<libdcp::Subtitle> > s = subs.subtitles_at (libdcp::Time (0, 0, 42, 100));
+ list<shared_ptr<dcp::SubtitleString> > s = subs.subtitles_at (dcp::Time (0, 0, 42, 100));
BOOST_CHECK_EQUAL (s.size(), 2);
- BOOST_CHECK_EQUAL (*(s.front().get()), libdcp::Subtitle (
+ BOOST_CHECK_EQUAL (*(s.front().get()), dcp::SubtitleString (
"Arial",
true,
- libdcp::Color (255, 255, 255),
+ dcp::Color (255, 255, 255),
42,
- libdcp::Time (0, 0, 41, 62),
- libdcp::Time (0, 0, 43, 52),
+ dcp::Time (0, 0, 41, 62),
+ dcp::Time (0, 0, 43, 52),
89,
- libdcp::TOP,
+ dcp::TOP,
"At afternoon tea with John Peel",
- libdcp::BORDER,
- libdcp::Color (0, 0, 0),
- libdcp::Time (0, 0, 0, 0),
- libdcp::Time (0, 0, 0, 0)
+ dcp::BORDER,
+ dcp::Color (0, 0, 0),
+ dcp::Time (0, 0, 0, 0),
+ dcp::Time (0, 0, 0, 0)
));
- BOOST_CHECK_EQUAL (*(s.back().get()), libdcp::Subtitle (
+ BOOST_CHECK_EQUAL (*(s.back().get()), dcp::SubtitleString (
"Arial",
true,
- libdcp::Color (255, 255, 255),
+ dcp::Color (255, 255, 255),
42,
- libdcp::Time (0, 0, 41, 62),
- libdcp::Time (0, 0, 43, 52),
+ dcp::Time (0, 0, 41, 62),
+ dcp::Time (0, 0, 43, 52),
95,
- libdcp::TOP,
+ dcp::TOP,
"I enquired if his accent was real",
- libdcp::BORDER,
- libdcp::Color (0, 0, 0),
- libdcp::Time (0, 0, 0, 0),
- libdcp::Time (0, 0, 0, 0)
+ dcp::BORDER,
+ dcp::Color (0, 0, 0),
+ dcp::Time (0, 0, 0, 0),
+ dcp::Time (0, 0, 0, 0)
));
- s = subs.subtitles_at (libdcp::Time (0, 0, 50, 50));
+ s = subs.subtitles_at (dcp::Time (0, 0, 50, 50));
BOOST_CHECK_EQUAL (s.size(), 2);
- BOOST_CHECK_EQUAL (*(s.front().get()), libdcp::Subtitle (
+ BOOST_CHECK_EQUAL (*(s.front().get()), dcp::SubtitleString (
"Arial",
true,
- libdcp::Color (255, 255, 255),
+ dcp::Color (255, 255, 255),
42,
- libdcp::Time (0, 0, 50, 42),
- libdcp::Time (0, 0, 52, 21),
+ dcp::Time (0, 0, 50, 42),
+ dcp::Time (0, 0, 52, 21),
89,
- libdcp::TOP,
+ dcp::TOP,
"He said \"out of the house",
- libdcp::BORDER,
- libdcp::Color (0, 0, 0),
- libdcp::Time (0, 0, 0, 0),
- libdcp::Time (0, 0, 0, 0)
+ dcp::BORDER,
+ dcp::Color (0, 0, 0),
+ dcp::Time (0, 0, 0, 0),
+ dcp::Time (0, 0, 0, 0)
));
- BOOST_CHECK_EQUAL (*(s.back().get()), libdcp::Subtitle (
+ BOOST_CHECK_EQUAL (*(s.back().get()), dcp::SubtitleString (
"Arial",
true,
- libdcp::Color (255, 255, 255),
+ dcp::Color (255, 255, 255),
42,
- libdcp::Time (0, 0, 50, 42),
- libdcp::Time (0, 0, 52, 21),
+ dcp::Time (0, 0, 50, 42),
+ dcp::Time (0, 0, 52, 21),
95,
- libdcp::TOP,
+ dcp::TOP,
"I'm incredibly scouse",
- libdcp::BORDER,
- libdcp::Color (0, 0, 0),
- libdcp::Time (0, 0, 0, 0),
- libdcp::Time (0, 0, 0, 0)
+ dcp::BORDER,
+ dcp::Color (0, 0, 0),
+ dcp::Time (0, 0, 0, 0),
+ dcp::Time (0, 0, 0, 0)
));
- s = subs.subtitles_at (libdcp::Time (0, 1, 2, 300));
+ s = subs.subtitles_at (dcp::Time (0, 1, 2, 300));
BOOST_CHECK_EQUAL (s.size(), 2);
- BOOST_CHECK_EQUAL (*(s.front().get()), libdcp::Subtitle (
+ BOOST_CHECK_EQUAL (*(s.front().get()), dcp::SubtitleString (
"Arial",
true,
- libdcp::Color (255, 255, 255),
+ dcp::Color (255, 255, 255),
42,
- libdcp::Time (0, 1, 2, 208),
- libdcp::Time (0, 1, 4, 10),
+ dcp::Time (0, 1, 2, 208),
+ dcp::Time (0, 1, 4, 10),
89,
- libdcp::TOP,
+ dcp::TOP,
"At home it depends how I feel.\"",
- libdcp::BORDER,
- libdcp::Color (0, 0, 0),
- libdcp::Time (0, 0, 0, 0),
- libdcp::Time (0, 0, 0, 0)
+ dcp::BORDER,
+ dcp::Color (0, 0, 0),
+ dcp::Time (0, 0, 0, 0),
+ dcp::Time (0, 0, 0, 0)
));
- BOOST_CHECK_EQUAL (*(s.back().get()), libdcp::Subtitle (
+ BOOST_CHECK_EQUAL (*(s.back().get()), dcp::SubtitleString (
"Arial",
true,
- libdcp::Color (255, 255, 255),
+ dcp::Color (255, 255, 255),
42,
- libdcp::Time (0, 1, 2, 208),
- libdcp::Time (0, 1, 4, 10),
+ dcp::Time (0, 1, 2, 208),
+ dcp::Time (0, 1, 4, 10),
95,
- libdcp::TOP,
+ dcp::TOP,
"I spent a long weekend in Brighton",
- libdcp::BORDER,
- libdcp::Color (0, 0, 0),
- libdcp::Time (0, 0, 0, 0),
- libdcp::Time (0, 0, 0, 0)
+ dcp::BORDER,
+ dcp::Color (0, 0, 0),
+ dcp::Time (0, 0, 0, 0),
+ dcp::Time (0, 0, 0, 0)
));
- s = subs.subtitles_at (libdcp::Time (0, 1, 15, 50));
+ s = subs.subtitles_at (dcp::Time (0, 1, 15, 50));
BOOST_CHECK_EQUAL (s.size(), 2);
- BOOST_CHECK_EQUAL (*(s.front().get()), libdcp::Subtitle (
+ BOOST_CHECK_EQUAL (*(s.front().get()), dcp::SubtitleString (
"Arial",
true,
- libdcp::Color (255, 255, 255),
+ dcp::Color (255, 255, 255),
42,
- libdcp::Time (0, 1, 15, 42),
- libdcp::Time (0, 1, 16, 42),
+ dcp::Time (0, 1, 15, 42),
+ dcp::Time (0, 1, 16, 42),
89,
- libdcp::TOP,
+ dcp::TOP,
"With the legendary Miss Enid Blyton",
- libdcp::BORDER,
- libdcp::Color (0, 0, 0),
- libdcp::Time (0, 0, 0, 0),
- libdcp::Time (0, 0, 0, 0)
+ dcp::BORDER,
+ dcp::Color (0, 0, 0),
+ dcp::Time (0, 0, 0, 0),
+ dcp::Time (0, 0, 0, 0)
));
- BOOST_CHECK_EQUAL (*(s.back().get()), libdcp::Subtitle (
+ BOOST_CHECK_EQUAL (*(s.back().get()), dcp::SubtitleString (
"Arial",
true,
- libdcp::Color (255, 255, 255),
+ dcp::Color (255, 255, 255),
42,
- libdcp::Time (0, 1, 15, 42),
- libdcp::Time (0, 1, 16, 42),
+ dcp::Time (0, 1, 15, 42),
+ dcp::Time (0, 1, 16, 42),
95,
- libdcp::TOP,
+ dcp::TOP,
"She said \"you be Noddy",
- libdcp::BORDER,
- libdcp::Color (0, 0, 0),
- libdcp::Time (0, 0, 0, 0),
- libdcp::Time (0, 0, 0, 0)
+ dcp::BORDER,
+ dcp::Color (0, 0, 0),
+ dcp::Time (0, 0, 0, 0),
+ dcp::Time (0, 0, 0, 0)
));
- s = subs.subtitles_at (libdcp::Time (0, 1, 27, 200));
+ s = subs.subtitles_at (dcp::Time (0, 1, 27, 200));
BOOST_CHECK_EQUAL (s.size(), 2);
- BOOST_CHECK_EQUAL (*(s.front().get()), libdcp::Subtitle (
+ BOOST_CHECK_EQUAL (*(s.front().get()), dcp::SubtitleString (
"Arial",
true,
- libdcp::Color (255, 255, 255),
+ dcp::Color (255, 255, 255),
42,
- libdcp::Time (0, 1, 27, 115),
- libdcp::Time (0, 1, 28, 208),
+ dcp::Time (0, 1, 27, 115),
+ dcp::Time (0, 1, 28, 208),
89,
- libdcp::TOP,
+ dcp::TOP,
"That curious creature the Sphinx",
- libdcp::BORDER,
- libdcp::Color (0, 0, 0),
- libdcp::Time (0, 0, 0, 0),
- libdcp::Time (0, 0, 0, 0)
+ dcp::BORDER,
+ dcp::Color (0, 0, 0),
+ dcp::Time (0, 0, 0, 0),
+ dcp::Time (0, 0, 0, 0)
));
- BOOST_CHECK_EQUAL (*(s.back().get()), libdcp::Subtitle (
+ BOOST_CHECK_EQUAL (*(s.back().get()), dcp::SubtitleString (
"Arial",
true,
- libdcp::Color (255, 255, 255),
+ dcp::Color (255, 255, 255),
42,
- libdcp::Time (0, 1, 27, 115),
- libdcp::Time (0, 1, 28, 208),
+ dcp::Time (0, 1, 27, 115),
+ dcp::Time (0, 1, 28, 208),
95,
- libdcp::TOP,
+ dcp::TOP,
"Is smarter than anyone thinks",
- libdcp::BORDER,
- libdcp::Color (0, 0, 0),
- libdcp::Time (0, 0, 0, 0),
- libdcp::Time (0, 0, 0, 0)
+ dcp::BORDER,
+ dcp::Color (0, 0, 0),
+ dcp::Time (0, 0, 0, 0),
+ dcp::Time (0, 0, 0, 0)
));
- s = subs.subtitles_at (libdcp::Time (0, 1, 42, 300));
+ s = subs.subtitles_at (dcp::Time (0, 1, 42, 300));
BOOST_CHECK_EQUAL (s.size(), 2);
- BOOST_CHECK_EQUAL (*(s.front().get()), libdcp::Subtitle (
+ BOOST_CHECK_EQUAL (*(s.front().get()), dcp::SubtitleString (
"Arial",
false,
- libdcp::Color (255, 255, 255),
+ dcp::Color (255, 255, 255),
42,
- libdcp::Time (0, 1, 42, 229),
- libdcp::Time (0, 1, 45, 62),
+ dcp::Time (0, 1, 42, 229),
+ dcp::Time (0, 1, 45, 62),
89,
- libdcp::TOP,
+ dcp::TOP,
"It sits there and smirks",
- libdcp::BORDER,
- libdcp::Color (0, 0, 0),
- libdcp::Time (0, 0, 0, 0),
- libdcp::Time (0, 0, 0, 0)
+ dcp::BORDER,
+ dcp::Color (0, 0, 0),
+ dcp::Time (0, 0, 0, 0),
+ dcp::Time (0, 0, 0, 0)
));
- BOOST_CHECK_EQUAL (*(s.back().get()), libdcp::Subtitle (
+ BOOST_CHECK_EQUAL (*(s.back().get()), dcp::SubtitleString (
"Arial",
false,
- libdcp::Color (255, 255, 255),
+ dcp::Color (255, 255, 255),
42,
- libdcp::Time (0, 1, 42, 229),
- libdcp::Time (0, 1, 45, 62),
+ dcp::Time (0, 1, 42, 229),
+ dcp::Time (0, 1, 45, 62),
95,
- libdcp::TOP,
+ dcp::TOP,
"And you don't think it works",
- libdcp::BORDER,
- libdcp::Color (0, 0, 0),
- libdcp::Time (0, 0, 0, 0),
- libdcp::Time (0, 0, 0, 0)
+ dcp::BORDER,
+ dcp::Color (0, 0, 0),
+ dcp::Time (0, 0, 0, 0),
+ dcp::Time (0, 0, 0, 0)
));
- s = subs.subtitles_at (libdcp::Time (0, 1, 45, 200));
+ s = subs.subtitles_at (dcp::Time (0, 1, 45, 200));
BOOST_CHECK_EQUAL (s.size(), 2);
- BOOST_CHECK_EQUAL (*(s.front().get()), libdcp::Subtitle (
+ BOOST_CHECK_EQUAL (*(s.front().get()), dcp::SubtitleString (
"Arial",
false,
- libdcp::Color (255, 255, 255),
+ dcp::Color (255, 255, 255),
42,
- libdcp::Time (0, 1, 45, 146),
- libdcp::Time (0, 1, 47, 94),
+ dcp::Time (0, 1, 45, 146),
+ dcp::Time (0, 1, 47, 94),
89,
- libdcp::TOP,
+ dcp::TOP,
"Then when you're not looking, it winks.",
- libdcp::BORDER,
- libdcp::Color (0, 0, 0),
- libdcp::Time (0, 0, 0, 0),
- libdcp::Time (0, 0, 0, 0)
+ dcp::BORDER,
+ dcp::Color (0, 0, 0),
+ dcp::Time (0, 0, 0, 0),
+ dcp::Time (0, 0, 0, 0)
));
- BOOST_CHECK_EQUAL (*(s.back().get()), libdcp::Subtitle (
+ BOOST_CHECK_EQUAL (*(s.back().get()), dcp::SubtitleString (
"Arial",
false,
- libdcp::Color (255, 255, 255),
+ dcp::Color (255, 255, 255),
42,
- libdcp::Time (0, 1, 45, 146),
- libdcp::Time (0, 1, 47, 94),
+ dcp::Time (0, 1, 45, 146),
+ dcp::Time (0, 1, 47, 94),
95,
- libdcp::TOP,
+ dcp::TOP,
"When it snows you will find Sister Sledge",
- libdcp::BORDER,
- libdcp::Color (0, 0, 0),
- libdcp::Time (0, 0, 0, 0),
- libdcp::Time (0, 0, 0, 0)
+ dcp::BORDER,
+ dcp::Color (0, 0, 0),
+ dcp::Time (0, 0, 0, 0),
+ dcp::Time (0, 0, 0, 0)
));
- s = subs.subtitles_at (libdcp::Time (0, 1, 47, 249));
+ s = subs.subtitles_at (dcp::Time (0, 1, 47, 249));
BOOST_CHECK_EQUAL (s.size(), 2);
- BOOST_CHECK_EQUAL (*(s.front().get()), libdcp::Subtitle (
+ BOOST_CHECK_EQUAL (*(s.front().get()), dcp::SubtitleString (
"Arial",
false,
- libdcp::Color (255, 255, 255),
+ dcp::Color (255, 255, 255),
42,
- libdcp::Time (0, 1, 47, 146),
- libdcp::Time (0, 1, 48, 167),
+ dcp::Time (0, 1, 47, 146),
+ dcp::Time (0, 1, 48, 167),
89,
- libdcp::TOP,
+ dcp::TOP,
"Out mooning, at night, on the ledge",
- libdcp::BORDER,
- libdcp::Color (0, 0, 0),
- libdcp::Time (0, 0, 0, 0),
- libdcp::Time (0, 0, 0, 0)
+ dcp::BORDER,
+ dcp::Color (0, 0, 0),
+ dcp::Time (0, 0, 0, 0),
+ dcp::Time (0, 0, 0, 0)
));
- BOOST_CHECK_EQUAL (*(s.back().get()), libdcp::Subtitle (
+ BOOST_CHECK_EQUAL (*(s.back().get()), dcp::SubtitleString (
"Arial",
false,
- libdcp::Color (255, 255, 255),
+ dcp::Color (255, 255, 255),
42,
- libdcp::Time (0, 1, 47, 146),
- libdcp::Time (0, 1, 48, 167),
+ dcp::Time (0, 1, 47, 146),
+ dcp::Time (0, 1, 48, 167),
95,
- libdcp::TOP,
+ dcp::TOP,
"One storey down",
- libdcp::BORDER,
- libdcp::Color (0, 0, 0),
- libdcp::Time (0, 0, 0, 0),
- libdcp::Time (0, 0, 0, 0)
+ dcp::BORDER,
+ dcp::Color (0, 0, 0),
+ dcp::Time (0, 0, 0, 0),
+ dcp::Time (0, 0, 0, 0)
));
- s = subs.subtitles_at (libdcp::Time (0, 2, 6, 210));
+ s = subs.subtitles_at (dcp::Time (0, 2, 6, 210));
BOOST_CHECK_EQUAL (s.size(), 2);
- BOOST_CHECK_EQUAL (*(s.front().get()), libdcp::Subtitle (
+ BOOST_CHECK_EQUAL (*(s.front().get()), dcp::SubtitleString (
"Arial",
true,
- libdcp::Color (255, 255, 255),
+ dcp::Color (255, 255, 255),
42,
- libdcp::Time (0, 2, 5, 208),
- libdcp::Time (0, 2, 7, 31),
+ dcp::Time (0, 2, 5, 208),
+ dcp::Time (0, 2, 7, 31),
89,
- libdcp::TOP,
+ dcp::TOP,
"HELLO",
- libdcp::BORDER,
- libdcp::Color (0, 0, 0),
- libdcp::Time (0, 0, 0, 0),
- libdcp::Time (0, 0, 0, 0)
+ dcp::BORDER,
+ dcp::Color (0, 0, 0),
+ dcp::Time (0, 0, 0, 0),
+ dcp::Time (0, 0, 0, 0)
));
- BOOST_CHECK_EQUAL (*(s.back().get()), libdcp::Subtitle (
+ BOOST_CHECK_EQUAL (*(s.back().get()), dcp::SubtitleString (
"Arial",
true,
- libdcp::Color (255, 255, 255),
+ dcp::Color (255, 255, 255),
42,
- libdcp::Time (0, 2, 5, 208),
- libdcp::Time (0, 2, 7, 31),
+ dcp::Time (0, 2, 5, 208),
+ dcp::Time (0, 2, 7, 31),
95,
- libdcp::TOP,
+ dcp::TOP,
"WORLD",
- libdcp::BORDER,
- libdcp::Color (0, 0, 0),
- libdcp::Time (0, 0, 0, 0),
- libdcp::Time (0, 0, 0, 0)
+ dcp::BORDER,
+ dcp::Color (0, 0, 0),
+ dcp::Time (0, 0, 0, 0),
+ dcp::Time (0, 0, 0, 0)
));
#define BOOST_TEST_MODULE libdcp_test
#include <boost/test/unit_test.hpp>
#include "util.h"
+#include "test.h"
using std::string;
{
TestConfig()
{
- libdcp::init ();
+ dcp::init ();
}
};
}
boost::filesystem::path
-wav (libdcp::Channel)
+wav (dcp::Channel)
{
return "test/data/1s_24-bit_48k_silence.wav";
}
*/
-extern boost::filesystem::path j2c (int);
-extern boost::filesystem::path wav (libdcp::Channel);
extern std::string private_test;
#include "metadata.h"
#include "util.h"
-/** Test libdcp::utc_offset_to_string */
+/** Test dcp::utc_offset_to_string */
BOOST_AUTO_TEST_CASE (utc_offset_to_string_test)
{
- BOOST_CHECK_EQUAL (libdcp::utc_offset_to_string (30), "+00:30");
- BOOST_CHECK_EQUAL (libdcp::utc_offset_to_string (60), "+01:00");
- BOOST_CHECK_EQUAL (libdcp::utc_offset_to_string (61), "+01:01");
- BOOST_CHECK_EQUAL (libdcp::utc_offset_to_string (7 * 60), "+07:00");
- BOOST_CHECK_EQUAL (libdcp::utc_offset_to_string (-11 * 60), "-11:00");
+ BOOST_CHECK_EQUAL (dcp::utc_offset_to_string (30), "+00:30");
+ BOOST_CHECK_EQUAL (dcp::utc_offset_to_string (60), "+01:00");
+ BOOST_CHECK_EQUAL (dcp::utc_offset_to_string (61), "+01:01");
+ BOOST_CHECK_EQUAL (dcp::utc_offset_to_string (7 * 60), "+07:00");
+ BOOST_CHECK_EQUAL (dcp::utc_offset_to_string (-11 * 60), "-11:00");
}
}
unsigned char decoded[N];
- int const r = libdcp::base64_decode (s, decoded, N);
+ int const r = dcp::base64_decode (s, decoded, N);
BOOST_CHECK_EQUAL (r, N);
for (int i = 0; i < N; ++i) {
BOOST_AUTO_TEST_CASE (content_kind_test)
{
- BOOST_CHECK_EQUAL (libdcp::content_kind_from_string ("feature"), libdcp::FEATURE);
- BOOST_CHECK_EQUAL (libdcp::content_kind_from_string ("Feature"), libdcp::FEATURE);
- BOOST_CHECK_EQUAL (libdcp::content_kind_from_string ("FeaturE"), libdcp::FEATURE);
- BOOST_CHECK_EQUAL (libdcp::content_kind_from_string ("Short"), libdcp::SHORT);
- BOOST_CHECK_EQUAL (libdcp::content_kind_from_string ("trailer"), libdcp::TRAILER);
- BOOST_CHECK_EQUAL (libdcp::content_kind_from_string ("test"), libdcp::TEST);
- BOOST_CHECK_EQUAL (libdcp::content_kind_from_string ("transitional"), libdcp::TRANSITIONAL);
- BOOST_CHECK_EQUAL (libdcp::content_kind_from_string ("rating"), libdcp::RATING);
- BOOST_CHECK_EQUAL (libdcp::content_kind_from_string ("teaser"), libdcp::TEASER);
- BOOST_CHECK_EQUAL (libdcp::content_kind_from_string ("policy"), libdcp::POLICY);
- BOOST_CHECK_EQUAL (libdcp::content_kind_from_string ("psa"), libdcp::PUBLIC_SERVICE_ANNOUNCEMENT);
- BOOST_CHECK_EQUAL (libdcp::content_kind_from_string ("advertisement"), libdcp::ADVERTISEMENT);
+ BOOST_CHECK_EQUAL (dcp::content_kind_from_string ("feature"), dcp::FEATURE);
+ BOOST_CHECK_EQUAL (dcp::content_kind_from_string ("Feature"), dcp::FEATURE);
+ BOOST_CHECK_EQUAL (dcp::content_kind_from_string ("FeaturE"), dcp::FEATURE);
+ BOOST_CHECK_EQUAL (dcp::content_kind_from_string ("Short"), dcp::SHORT);
+ BOOST_CHECK_EQUAL (dcp::content_kind_from_string ("trailer"), dcp::TRAILER);
+ BOOST_CHECK_EQUAL (dcp::content_kind_from_string ("test"), dcp::TEST);
+ BOOST_CHECK_EQUAL (dcp::content_kind_from_string ("transitional"), dcp::TRANSITIONAL);
+ BOOST_CHECK_EQUAL (dcp::content_kind_from_string ("rating"), dcp::RATING);
+ BOOST_CHECK_EQUAL (dcp::content_kind_from_string ("teaser"), dcp::TEASER);
+ BOOST_CHECK_EQUAL (dcp::content_kind_from_string ("policy"), dcp::POLICY);
+ BOOST_CHECK_EQUAL (dcp::content_kind_from_string ("psa"), dcp::PUBLIC_SERVICE_ANNOUNCEMENT);
+ BOOST_CHECK_EQUAL (dcp::content_kind_from_string ("advertisement"), dcp::ADVERTISEMENT);
+}
+
+BOOST_AUTO_TEST_CASE (relative_to_root_test)
+{
+ {
+ boost::filesystem::path root = "a";
+ root /= "b";
+
+ boost::filesystem::path file = "a";
+ file /= "b";
+ file /= "c";
+
+ boost::optional<boost::filesystem::path> rel = dcp::relative_to_root (root, file);
+ BOOST_CHECK (rel);
+ BOOST_CHECK_EQUAL (rel.get(), boost::filesystem::path ("c"));
+ }
+
+ {
+ boost::filesystem::path root = "a";
+ root /= "b";
+ root /= "c";
+
+ boost::filesystem::path file = "a";
+ file /= "b";
+
+ boost::optional<boost::filesystem::path> rel = dcp::relative_to_root (root, file);
+ BOOST_CHECK (!rel);
+ }
+
+ {
+ boost::filesystem::path root = "a";
+
+ boost::filesystem::path file = "a";
+ file /= "b";
+ file /= "c";
+
+ boost::optional<boost::filesystem::path> rel = dcp::relative_to_root (root, file);
+ BOOST_CHECK (rel);
+
+ boost::filesystem::path check = "b";
+ check /= "c";
+ BOOST_CHECK_EQUAL (rel.get(), check);
+ }
}
else:
boost_lib_suffix = ''
- conf.check_cxx(fragment = """
- #define BOOST_TEST_MODULE Config test\n
- #include <boost/test/unit_test.hpp>\n
- int main() {}
- """,
- msg = 'Checking for boost unit testing library',
- lib = 'boost_unit_test_framework%s' % boost_lib_suffix,
- uselib_store = 'BOOST_TEST')
+ conf.check_cxx(fragment="""
+ #define BOOST_TEST_MODULE Config test\n
+ #include <boost/test/unit_test.hpp>\n
+ int main() {}
+ """,
+ msg='Checking for boost unit testing library',
+ lib='boost_unit_test_framework%s' % boost_lib_suffix,
+ uselib_store='BOOST_TEST')
conf.env.prepend_value('LINKFLAGS', '-Lsrc')
def build(bld):
- obj = bld(features = 'cxx cxxprogram')
+ obj = bld(features='cxx cxxprogram')
obj.name = 'tests'
- obj.uselib = 'BOOST_TEST OPENJPEG CXML XMLSEC1'
- obj.use = 'libdcp'
+ obj.uselib = 'BOOST_TEST OPENJPEG CXML XMLSEC1 SNDFILE'
+ obj.use = 'libdcp%s' % bld.env.API_VERSION
obj.source = """
certificates_test.cc
color_test.cc
- cpl_sar.cc
+ cpl_sar_test.cc
dcp_test.cc
dcp_time_test.cc
decryption_test.cc
encryption_test.cc
- error_test.cc
frame_info_test.cc
kdm_key_test.cc
kdm_test.cc
- lut_test.cc
read_dcp_test.cc
recovery_test.cc
round_trip_test.cc
obj.target = 'tests'
obj.install_path = ''
- obj = bld(features = 'cxx cxxprogram')
+ obj = bld(features='cxx cxxprogram')
obj.name = 'subs_in_out'
obj.uselib = 'BOOST_TEST OPENJPEG CXML'
- obj.use = 'libdcp'
+ obj.use = 'libdcp%s' % bld.env.API_VERSION
obj.source = 'subs_in_out.cc'
obj.target = 'subs_in_out'
obj.install_path = ''
- obj = bld(features = 'cxx cxxprogram')
+ obj = bld(features='cxx cxxprogram')
obj.name = 'rewrite_subs'
obj.uselib = 'BOOST_TEST OPENJPEG CXML'
- obj.use = 'libdcp'
+ obj.use = 'libdcp%s' % bld.env.API_VERSION
obj.source = 'rewrite_subs.cc'
obj.target = 'rewrite_subs'
obj.install_path = ''
using namespace std;
using namespace boost;
-using namespace libdcp;
+using namespace dcp;
static bool verbose = false;
+/*
+ Copyright (C) 2012-2014 Carl Hetherington <cth@carlh.net>
+
+ 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 <iostream>
#include <cstdlib>
#include <boost/filesystem.hpp>
#include "dcp.h"
#include "exceptions.h"
#include "reel.h"
-#include "sound_asset.h"
-#include "picture_asset.h"
-#include "subtitle_asset.h"
+#include "sound_mxf.h"
+#include "picture_mxf.h"
+#include "subtitle_content.h"
+#include "reel_picture_asset.h"
+#include "reel_sound_asset.h"
+#include "reel_subtitle_asset.h"
+#include "subtitle_string.h"
#include "cpl.h"
using std::string;
using std::cout;
using std::list;
using boost::shared_ptr;
-using namespace libdcp;
+using namespace dcp;
static void
help (string n)
DCP* dcp = 0;
try {
dcp = new DCP (argv[optind]);
- dcp->read (false);
+ dcp->read ();
} catch (FileError& e) {
cerr << "Could not read DCP " << argv[optind] << "; " << e.what() << " " << e.filename() << "\n";
exit (EXIT_FAILURE);
list<shared_ptr<CPL> > cpls = dcp->cpls ();
for (list<shared_ptr<CPL> >::iterator i = cpls.begin(); i != cpls.end(); ++i) {
- cout << " CPL: " << (*i)->name() << "\n"
- << " Length: " << (*i)->length() << "\n"
- << " Frames per second: " << (*i)->frames_per_second() << "\n";
+ cout << " CPL: " << (*i)->annotation_text() << "\n";
list<shared_ptr<Reel> > reels = (*i)->reels ();
cout << " Reel " << R << "\n";
if ((*j)->main_picture()) {
- cout << " Picture: " << (*j)->main_picture()->size().width << "x" << (*j)->main_picture()->size().height << "\n";
+ cout << " Picture: "
+ << (*j)->main_picture()->mxf()->size().width
+ << "x"
+ << (*j)->main_picture()->mxf()->size().height << "\n";
}
if ((*j)->main_sound()) {
- cout << " Sound: " << (*j)->main_sound()->channels() << " channels at " << (*j)->main_sound()->sampling_rate() << "Hz\n";
+ cout << " Sound: "
+ << (*j)->main_sound()->mxf()->channels()
+ << " channels at "
+ << (*j)->main_sound()->mxf()->sampling_rate() << "Hz\n";
}
if ((*j)->main_subtitle()) {
- list<shared_ptr<Subtitle> > subs = (*j)->main_subtitle()->subtitles ();
- cout << " Subtitle: " << subs.size() << " subtitles in " << (*j)->main_subtitle()->language() << "\n";
+ list<shared_ptr<SubtitleString> > subs = (*j)->main_subtitle()->subtitle_content()->subtitles ();
+ cout << " Subtitle: " << subs.size() << " subtitles in " << (*j)->main_subtitle()->subtitle_content()->language() << "\n";
if (subtitles) {
- for (list<shared_ptr<Subtitle> >::const_iterator k = subs.begin(); k != subs.end(); ++k) {
+ for (list<shared_ptr<SubtitleString> >::const_iterator k = subs.begin(); k != subs.end(); ++k) {
cout << " " << (*k)->text() << "\n";
cout << " "
<< "font:" << (*k)->font() << "; "
def build(bld):
obj = bld(features = 'cxx cxxprogram')
- obj.use = ['libdcp']
+ obj.use = ['libdcp%s' % bld.env.API_VERSION]
obj.uselib = 'OPENJPEG CXML'
obj.source = 'dcpdiff.cc'
obj.target = 'dcpdiff'
obj = bld(features = 'cxx cxxprogram')
- obj.use = ['libdcp']
+ obj.use = ['libdcp%s' % bld.env.API_VERSION]
obj.uselib = 'OPENJPEG CXML'
obj.source = 'dcpinfo.cc'
obj.target = 'dcpinfo'
import os
APPNAME = 'libdcp'
-VERSION = '0.93pre'
+VERSION = '1.00.0devel'
+API_VERSION = '-1.0'
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', action='store_true', default = False, help = 'build libdcp and in-tree dependencies statically, and link statically to openjpeg and cxml')
+ opt.add_option('--target-windows', action='store_true', default=False, help='set up to do a cross-compile to Windows')
+ opt.add_option('--target-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', 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')
conf.env.append_value('CXXFLAGS', ['-DLIBDCP_VERSION="%s"' % VERSION])
conf.env.TARGET_WINDOWS = conf.options.target_windows
- conf.env.STATIC = conf.options.static
- conf.env.OSX = conf.options.osx
+ conf.env.TARGET_OSX = conf.options.target_osx
conf.env.ENABLE_DEBUG = conf.options.enable_debug
+ conf.env.STATIC = conf.options.static
+ conf.env.API_VERSION = API_VERSION
if conf.options.target_windows:
conf.env.append_value('CXXFLAGS', '-DLIBDCP_WINDOWS')
else:
conf.env.append_value('CXXFLAGS', '-DLIBDCP_POSIX')
- if not conf.options.osx:
+ if not conf.options.target_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)
- conf.check_cfg(package = 'xmlsec1', args = '--cflags --libs', uselib_store = 'XMLSEC1', mandatory = True)
+ 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)
+ conf.check_cfg(package='xmlsec1', args='--cflags --libs', uselib_store='XMLSEC1', mandatory=True)
# Remove erroneous escaping of quotes from xmlsec1 defines
conf.env.DEFINES_XMLSEC1 = [f.replace('\\', '') for f in conf.env.DEFINES_XMLSEC1]
+ conf.check_cfg(package='', path='Magick++-config', args='--cppflags --cxxflags --libs', uselib_store='MAGICK', mandatory=False)
+ conf.check_cfg(package='sndfile', args='--cflags --libs', uselib_store='SNDFILE', mandatory=False)
if conf.options.static:
- conf.check_cc(fragment = """
- #include <stdio.h>\n
- #include <openjpeg.h>\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)
+ conf.check_cc(fragment="""
+ #include <stdio.h>\n
+ #include <openjpeg.h>\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)
conf.env.HAVE_CXML = 1
conf.env.STLIB_CXML = ['cxml']
# Windows builds are any more reliable
conf.env.append_value('CXXFLAGS', '-O2')
- conf.check_cxx(fragment = """
- #include <boost/version.hpp>\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 = 'yes',
- errmsg = 'too old\nPlease install boost version 1.45 or higher.')
-
- conf.check_cxx(fragment = """
- #include <boost/filesystem.hpp>\n
- int main() { boost::filesystem::copy_file ("a", "b"); }\n
- """,
- msg = 'Checking for boost filesystem library',
- libpath = '/usr/local/lib',
- lib = ['boost_filesystem%s' % boost_lib_suffix, 'boost_system%s' % boost_lib_suffix],
- uselib_store = 'BOOST_FILESYSTEM')
-
- conf.check_cxx(fragment = """
- #include <boost/signals2.hpp>\n
- int main() { boost::signals2::signal<void (int)> x; }\n
- """,
- msg = 'Checking for boost signals2 library',
- uselib_store = 'BOOST_SIGNALS2')
-
- conf.check_cxx(fragment = """
- #include <boost/date_time.hpp>\n
- int main() { boost::gregorian::day_clock::local_day(); }\n
- """,
- msg = 'Checking for boost datetime library',
- libpath = '/usr/local/lib',
- lib = ['boost_date_time%s' % boost_lib_suffix, 'boost_system%s' % boost_lib_suffix],
- uselib_store = 'BOOST_DATETIME')
+ conf.check_cxx(fragment="""
+ #include <boost/version.hpp>\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='yes',
+ errmsg='too old\nPlease install boost version 1.45 or higher.')
+
+ conf.check_cxx(fragment="""
+ #include <boost/filesystem.hpp>\n
+ int main() { boost::filesystem::copy_file ("a", "b"); }\n
+ """,
+ msg='Checking for boost filesystem library',
+ libpath='/usr/local/lib',
+ lib=['boost_filesystem%s' % boost_lib_suffix, 'boost_system%s' % boost_lib_suffix],
+ uselib_store='BOOST_FILESYSTEM')
+
+ conf.check_cxx(fragment="""
+ #include <boost/signals2.hpp>\n
+ int main() { boost::signals2::signal<void (int)> x; }\n
+ """,
+ msg='Checking for boost signals2 library',
+ uselib_store='BOOST_SIGNALS2')
+
+ conf.check_cxx(fragment="""
+ #include <boost/date_time.hpp>\n
+ int main() { boost::gregorian::day_clock::local_day(); }\n
+ """,
+ msg='Checking for boost datetime library',
+ libpath='/usr/local/lib',
+ lib=['boost_date_time%s' % boost_lib_suffix, 'boost_system%s' % boost_lib_suffix],
+ uselib_store='BOOST_DATETIME')
conf.recurse('test')
conf.recurse('asdcplib')
else:
boost_lib_suffix = ''
- bld(source = 'libdcp.pc.in',
- version = VERSION,
- includedir = '%s/include' % bld.env.PREFIX,
- libs = "-L${libdir} -ldcp -lasdcp-libdcp -lkumu-libdcp -lcxml -lboost_system%s" % boost_lib_suffix,
- install_path = '${LIBDIR}/pkgconfig')
+ bld(source='libdcp%s.pc.in' % bld.env.API_VERSION,
+ version=VERSION,
+ includedir='%s/include/libdcp%s' % (bld.env.PREFIX, bld.env.API_VERSION),
+ libs="-L${libdir} -ldcp%s -lasdcp-libdcp%s -lkumu-libdcp%s -lcxml -lboost_system%s" % (API_VERSION, API_VERSION, API_VERSION, boost_lib_suffix),
+ install_path='${LIBDIR}/pkgconfig')
bld.recurse('src')
bld.recurse('tools')
try:
text = '#include "version.h"\n'
- text += 'char const * libdcp::git_commit = \"%s\";\n' % commit
- text += 'char const * libdcp::version = \"%s\";\n' % version
+ text += 'char const * dcp::git_commit = \"%s\";\n' % commit
+ text += 'char const * dcp::version = \"%s\";\n' % version
if bld.env.ENABLE_DEBUG:
debug_string = 'true'
else: