diff options
Diffstat (limited to 'src')
| -rw-r--r-- | src/asset.cc | 81 | ||||
| -rw-r--r-- | src/asset.h | 56 | ||||
| -rw-r--r-- | src/dcp.cc | 270 | ||||
| -rw-r--r-- | src/dcp.h | 72 | ||||
| -rw-r--r-- | src/picture_asset.cc | 92 | ||||
| -rw-r--r-- | src/picture_asset.h | 37 | ||||
| -rw-r--r-- | src/sound_asset.cc | 131 | ||||
| -rw-r--r-- | src/sound_asset.h | 33 | ||||
| -rw-r--r-- | src/tags.cc | 46 | ||||
| -rw-r--r-- | src/tags.h | 42 | ||||
| -rw-r--r-- | src/util.cc | 95 | ||||
| -rw-r--r-- | src/util.h | 28 | ||||
| -rw-r--r-- | src/wscript | 14 |
13 files changed, 997 insertions, 0 deletions
diff --git a/src/asset.cc b/src/asset.cc new file mode 100644 index 00000000..2101e4bb --- /dev/null +++ b/src/asset.cc @@ -0,0 +1,81 @@ +/* + 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 <boost/filesystem.hpp> +#include <AS_DCP.h> +#include <KM_util.h> +#include "asset.h" +#include "util.h" +#include "tags.h" + +using namespace std; +using namespace boost; +using namespace libdcp; + +/** Construct an Asset. + * @param p Pathname of MXF file. + * @param fps Frames per second. + * @param len Length in frames. + */ + +Asset::Asset (string p, int fps, int len) + : _mxf_path (p) + , _fps (fps) + , _length (len) + , _uuid (make_uuid ()) +{ + +} + +void +Asset::write_to_pkl (ostream& s) const +{ + s << " <Id>urn:uuid:" << _uuid << "</Id>\n" + << " <AnnotationText>" << filesystem::path(_mxf_path).filename() << "</AnnotationText>\n" + << " <Hash>" << _digest << "</Hash>\n" + << " <Size>" << filesystem::file_size(_mxf_path) << "</Size>\n" + << " <Type>application/mxf</Type>\n"; +} + +void +Asset::write_to_assetmap (ostream& s) const +{ + s << " <Asset>\n" + << " <Id>urn:uuid:" << _uuid << "</Id>\n" + << " <ChunkList>\n" + << " <Chunk>\n" + << " <Path>" << filesystem::path(_mxf_path).filename() << "</Path>\n" + << " <VolumeIndex>1</VolumeIndex>\n" + << " <Offset>0</Offset>\n" + << " <Length>" << filesystem::file_size(_mxf_path) << "</Length>\n" + << " </Chunk>\n" + << " </ChunkList>\n" + << " </Asset>\n"; +} + +void +Asset::fill_writer_info (ASDCP::WriterInfo* writer_info) const +{ + writer_info->ProductVersion = Tags::instance()->product_version; + writer_info->CompanyName = Tags::instance()->company_name; + writer_info->ProductName = Tags::instance()->product_name.c_str(); + + writer_info->LabelSetType = ASDCP::LS_MXF_SMPTE; + Kumu::GenRandomUUID (writer_info->AssetUUID); +} diff --git a/src/asset.h b/src/asset.h new file mode 100644 index 00000000..ce742d11 --- /dev/null +++ b/src/asset.h @@ -0,0 +1,56 @@ +/* + 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_ASSET_H +#define LIBDCP_ASSET_H + +#include <string> +#include <sigc++/sigc++.h> + +namespace ASDCP { + class WriterInfo; +} + +namespace libdcp +{ + +class Asset +{ +public: + Asset (std::string, int, int); + + virtual void write_to_cpl (std::ostream &) const = 0; + void write_to_pkl (std::ostream &) const; + void write_to_assetmap (std::ostream &) const; + + sigc::signal1<void, float> Progress; + +protected: + void fill_writer_info (ASDCP::WriterInfo *) const; + + std::string _mxf_path; + int _fps; + int _length; + std::string _uuid; + std::string _digest; +}; + +} + +#endif diff --git a/src/dcp.cc b/src/dcp.cc new file mode 100644 index 00000000..0ba4ed72 --- /dev/null +++ b/src/dcp.cc @@ -0,0 +1,270 @@ +/* + 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 <sstream> +#include <fstream> +#include <iomanip> +#include <cassert> +#include <boost/filesystem.hpp> +#include "dcp.h" +#include "asset.h" +#include "sound_asset.h" +#include "picture_asset.h" +#include "util.h" +#include "tags.h" + +using namespace std; +using namespace boost; +using namespace libdcp; + +/** Construct a DCP. + * @param d Directory to write files to. + */ +DCP::DCP (string d, string n, ContentType c, int fps, int length) + : _directory (d) + , _name (n) + , _content_type (c) + , _fps (fps) + , _length (length) +{ + char buffer[64]; + time_t now; + time (&now); + struct tm* tm = localtime (&now); + strftime (buffer, 64, "%Y-%m-%dT%I:%M:%S+00:00", tm); + _date = string (buffer); +} + +void +DCP::add_sound_asset (list<string> const & files) +{ + filesystem::path p; + p /= _directory; + p /= "audio.mxf"; + _assets.push_back (shared_ptr<SoundAsset> (new SoundAsset (files, p.string(), _fps, _length))); +} + +void +DCP::add_picture_asset (list<string> const & files, int w, int h) +{ + filesystem::path p; + p /= _directory; + p /= "video.mxf"; + _assets.push_back (shared_ptr<PictureAsset> (new PictureAsset (files, p.string(), _fps, _length, w, h))); +} + +/** Write the required XML files to the directory that was + * passed into the constructor. + */ +void +DCP::write_xml () const +{ + string cpl_uuid = make_uuid (); + string cpl_path = write_cpl (cpl_uuid); + int cpl_length = filesystem::file_size (cpl_path); + string cpl_digest = make_digest (cpl_path); + + string pkl_uuid = make_uuid (); + string pkl_path = write_pkl (pkl_uuid, cpl_uuid, cpl_digest, cpl_length); + + write_volindex (); + write_assetmap (cpl_uuid, cpl_length, pkl_uuid, filesystem::file_size (pkl_path)); +} + +/** Write the CPL file. + * @param cpl_uuid UUID to use. + * @return CPL pathname. + */ +string +DCP::write_cpl (string cpl_uuid) const +{ + filesystem::path p; + p /= _directory; + stringstream s; + s << cpl_uuid << "_cpl.xml"; + p /= s.str(); + ofstream cpl (p.string().c_str()); + + cpl << "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n" + << "<CompositionPlaylist xmlns=\"http://www.smpte-ra.org/schemas/429-7/2006/CPL\">\n" + << " <Id>urn:uuid:" << cpl_uuid << "</Id>\n" + << " <AnnotationText>" << _name << "</AnnotationText>\n" + << " <IssueDate>" << _date << "</IssueDate>\n" + << " <Creator>libdcp " << Tags::instance()->creator << "</Creator>\n" + << " <ContentTitleText>" << _name << "</ContentTitleText>\n" + << " <ContentKind>" << _content_type << "</ContentKind>\n" + << " <ContentVersion>\n" + << " <Id>urn:uri:" << cpl_uuid << "_" << _date << "</Id>\n" + << " <LabelText>" << cpl_uuid << "_" << _date << "</LabelText>\n" + << " </ContentVersion>\n" + << " <RatingList/>\n" + << " <ReelList>\n"; + + cpl << " <Reel>\n" + << " <Id>urn:uuid:" << make_uuid() << "</Id>\n" + << " <AssetList>\n"; + + for (list<shared_ptr<Asset> >::const_iterator i = _assets.begin(); i != _assets.end(); ++i) { + (*i)->write_to_cpl (cpl); + } + + cpl << " </AssetList>\n" + << " </Reel>\n" + << " </ReelList>\n" + << "</CompositionPlaylist>\n"; + + return p.string (); +} + +/** Write the PKL file. + * @param pkl_uuid UUID to use. + * @param cpl_uuid UUID of the CPL file. + * @param cpl_digest SHA digest of the CPL file. + * @param cpl_length Length of the CPL file in bytes. + */ +std::string +DCP::write_pkl (string pkl_uuid, string cpl_uuid, string cpl_digest, int cpl_length) const +{ + filesystem::path p; + p /= _directory; + stringstream s; + s << pkl_uuid << "_pkl.xml"; + p /= s.str(); + ofstream pkl (p.string().c_str()); + + pkl << "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n" + << "<PackingList xmlns=\"http://www.smpte-ra.org/schemas/429-8/2007/PKL\">\n" + << " <Id>urn:uuid:" << pkl_uuid << "</Id>\n" + << " <AnnotationText>" << _name << "</AnnotationText>\n" + << " <IssueDate>" << _date << "</IssueDate>\n" + << " <Issuer>" << Tags::instance()->issuer << "</Issuer>\n" + << " <Creator>" << Tags::instance()->creator << "</Creator>\n" + << " <AssetList>\n"; + + for (list<shared_ptr<Asset> >::const_iterator i = _assets.begin(); i != _assets.end(); ++i) { + (*i)->write_to_pkl (pkl); + } + + pkl << " <Asset>\n" + << " <Id>urn:uuid" << cpl_uuid << "</Id>\n" + << " <Hash>" << cpl_digest << "</Hash>\n" + << " <Size>" << cpl_length << "</Size>\n" + << " <Type>text/xml</Type>\n" + << " </Asset>\n"; + + pkl << " </AssetList>\n" + << "</PackingList>\n"; + + return p.string (); +} + +void +DCP::write_volindex () const +{ + filesystem::path p; + p /= _directory; + p /= "VOLINDEX.xml"; + ofstream vi (p.string().c_str()); + + vi << "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n" + << "<VolumeIndex xmlns=\"http://www.smpte-ra.org/schemas/429-9/2007/AM\">\n" + << " <Index>1</Index>\n" + << "</VolumeIndex>\n"; +} + +void +DCP::write_assetmap (string cpl_uuid, int cpl_length, string pkl_uuid, int pkl_length) const +{ + filesystem::path p; + p /= _directory; + p /= "ASSETMAP.xml"; + ofstream am (p.string().c_str()); + + am << "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n" + << "<AssetMap xmlns=\"http://www.smpte-ra.org/schemas/429-9/2007/AM\">\n" + << " <Id>urn:uuid:" << make_uuid() << "</Id>\n" + << " <Creator>" << Tags::instance()->creator << "</Creator>\n" + << " <VolumeCount>1</VolumeCount>\n" + << " <IssueDate>" << _date << "</IssueDate>\n" + << " <Issuer>" << Tags::instance()->issuer << "</Issuer>\n" + << " <AssetList>\n"; + + am << " <Asset>\n" + << " <Id>urn:uuid:" << pkl_uuid << "</Id>\n" + << " <PackingList>true</PackingList>\n" + << " <ChunkList>\n" + << " <Chunk>\n" + << " <Path>" << pkl_uuid << "_pkl.xml</Path>\n" + << " <VolumeIndex>1</VolumeIndex>\n" + << " <Offset>0</Offset>\n" + << " <Length>" << pkl_length << "</Length>\n" + << " </Chunk>\n" + << " </ChunkList>\n" + << " </Asset>\n"; + + am << " <Asset>\n" + << " <Id>urn:uuid:" << cpl_uuid << "</Id>\n" + << " <ChunkList>\n" + << " <Chunk>\n" + << " <Path>" << cpl_uuid << "_cpl.xml</Path>\n" + << " <VolumeIndex>1</VolumeIndex>\n" + << " <Offset>0</Offset>\n" + << " <Length>" << cpl_length << "</Length>\n" + << " </Chunk>\n" + << " </ChunkList>\n" + << " </Asset>\n"; + + for (list<shared_ptr<Asset> >::const_iterator i = _assets.begin(); i != _assets.end(); ++i) { + (*i)->write_to_assetmap (am); + } + + am << " </AssetList>\n" + << "</AssetMap>\n"; +} + + +string +DCP::content_type_string (ContentType t) +{ + switch (t) { + case FEATURE: + return "feature"; + case SHORT: + return "short"; + case TRAILER: + return "trailer"; + case TEST: + return "test"; + case TRANSITIONAL: + return "transitional"; + case RATING: + return "rating"; + case TEASER: + return "teaser"; + case POLICY: + return "policy"; + case PUBLIC_SERVICE_ANNOUNCEMENT: + return "psa"; + case ADVERTISEMENT: + return "advertisement"; + } + + assert (false); +} + diff --git a/src/dcp.h b/src/dcp.h new file mode 100644 index 00000000..27be9ec6 --- /dev/null +++ b/src/dcp.h @@ -0,0 +1,72 @@ +/* + 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 <string> +#include <list> +#include <boost/shared_ptr.hpp> + +namespace libdcp +{ + +class Asset; + +class DCP +{ +public: + enum ContentType + { + FEATURE, + SHORT, + TRAILER, + TEST, + TRANSITIONAL, + RATING, + TEASER, + POLICY, + PUBLIC_SERVICE_ANNOUNCEMENT, + ADVERTISEMENT + }; + + DCP (std::string, std::string, ContentType, int, int); + + void add_sound_asset (std::list<std::string> const &); + void add_picture_asset (std::list<std::string> const &, int, int); + + void write_xml () const; + +private: + + std::string write_cpl (std::string) const; + std::string write_pkl (std::string, std::string, std::string, int) const; + void write_volindex () const; + void write_assetmap (std::string, int, std::string, int) const; + + static std::string content_type_string (ContentType); + + std::string _directory; + std::string _name; + ContentType _content_type; + int _fps; + int _length; + std::list<boost::shared_ptr<Asset> > _assets; + + std::string _date; +}; + +} diff --git a/src/picture_asset.cc b/src/picture_asset.cc new file mode 100644 index 00000000..4e3b0227 --- /dev/null +++ b/src/picture_asset.cc @@ -0,0 +1,92 @@ +/* + 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 <list> +#include <stdexcept> +#include <iostream> +#include <boost/filesystem.hpp> +#include <AS_DCP.h> +#include <KM_fileio.h> +#include "picture_asset.h" +#include "util.h" + +using namespace std; +using namespace boost; +using namespace libdcp; + +PictureAsset::PictureAsset (list<string> const & files, string p, int fps, int len, int w, int h) + : Asset (p, fps, len) + , _width (w) + , _height (h) +{ + ASDCP::JP2K::CodestreamParser j2k_parser; + ASDCP::JP2K::FrameBuffer frame_buffer (4 * Kumu::Megabyte); + if (ASDCP_FAILURE (j2k_parser.OpenReadFrame (files.front().c_str(), frame_buffer))) { + throw runtime_error ("could not open J2K file for reading"); + } + + ASDCP::JP2K::PictureDescriptor picture_desc; + j2k_parser.FillPictureDescriptor (picture_desc); + /* XXX: we round for DCP: not sure if this is right */ + picture_desc.EditRate = ASDCP::Rational (_fps, 1); + + ASDCP::WriterInfo writer_info; + fill_writer_info (&writer_info); + + ASDCP::JP2K::MXFWriter mxf_writer; + if (ASDCP_FAILURE (mxf_writer.OpenWrite (_mxf_path.c_str(), writer_info, picture_desc))) { + throw runtime_error ("could not open MXF for writing"); + } + + int j = 0; + for (list<string>::const_iterator i = files.begin(); i != files.end(); ++i) { + if (ASDCP_FAILURE (j2k_parser.OpenReadFrame (i->c_str(), frame_buffer))) { + throw runtime_error ("could not open J2K file for reading"); + } + + /* XXX: passing 0 to WriteFrame ok? */ + if (ASDCP_FAILURE (mxf_writer.WriteFrame (frame_buffer, 0, 0))) { + throw runtime_error ("error in writing video MXF"); + } + + ++j; + Progress (float (j) / files.size ()); + } + + if (ASDCP_FAILURE (mxf_writer.Finalize())) { + throw runtime_error ("error in finalising video MXF"); + } + + _digest = make_digest (_mxf_path); +} + +void +PictureAsset::write_to_cpl (ostream& s) const +{ + s << " <MainPicture>\n" + << " <Id>" << _uuid << "</Id>\n" + << " <AnnotationText>" << filesystem::path(_mxf_path).filename() << "</AnnotationText>\n" + << " <EditRate>" << _fps << "</EditRate>\n" + << " <IntrinsicDuration>" << _length << "</IntrinsicDuration>\n" + << " <EntryPoint>0</EntryPoint>\n" + << " <Duration>" << _length << "</Duration>\n" + << " <FrameRate>" << _fps << "</FrameRate>\n" + << " <ScreenAspectRatio>" << _width << " " << _height << "</ScreenAspectRatio>\n" + << " </MainPicture>\n"; +} diff --git a/src/picture_asset.h b/src/picture_asset.h new file mode 100644 index 00000000..cef5367b --- /dev/null +++ b/src/picture_asset.h @@ -0,0 +1,37 @@ +/* + 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 "asset.h" + +namespace libdcp +{ + +class PictureAsset : public Asset +{ +public: + PictureAsset (std::list<std::string> const &, std::string, int, int, int, int); + + void write_to_cpl (std::ostream &) const; + +private: + int _width; + int _height; +}; + +} diff --git a/src/sound_asset.cc b/src/sound_asset.cc new file mode 100644 index 00000000..30083719 --- /dev/null +++ b/src/sound_asset.cc @@ -0,0 +1,131 @@ +/* + 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 <iostream> +#include <stdexcept> +#include <boost/filesystem.hpp> +#include <AS_DCP.h> +#include "sound_asset.h" +#include "util.h" + +using namespace std; +using namespace boost; +using namespace libdcp; + +SoundAsset::SoundAsset (list<string> const & files, string p, int fps, int len) + : Asset (p, fps, len) +{ + ASDCP::Rational asdcp_fps (_fps, 1); + + ASDCP::PCM::WAVParser pcm_parser_channel[files.size()]; + if (pcm_parser_channel[0].OpenRead (files.front().c_str(), asdcp_fps)) { + throw runtime_error ("could not open WAV file for reading"); + } + + ASDCP::PCM::AudioDescriptor audio_desc; + pcm_parser_channel[0].FillAudioDescriptor (audio_desc); + audio_desc.ChannelCount = 0; + audio_desc.BlockAlign = 0; + audio_desc.EditRate = asdcp_fps; + audio_desc.AvgBps = audio_desc.AvgBps * files.size (); + + ASDCP::PCM::FrameBuffer frame_buffer_channel[files.size()]; + ASDCP::PCM::AudioDescriptor audio_desc_channel[files.size()]; + + int j = 0; + for (list<string>::const_iterator i = files.begin(); i != files.end(); ++i) { + + if (ASDCP_FAILURE (pcm_parser_channel[j].OpenRead (i->c_str(), asdcp_fps))) { + throw runtime_error ("could not open WAV file for reading"); + } + + pcm_parser_channel[j].FillAudioDescriptor (audio_desc_channel[j]); + frame_buffer_channel[j].Capacity (ASDCP::PCM::CalcFrameBufferSize (audio_desc_channel[j])); + + audio_desc.ChannelCount += audio_desc_channel[j].ChannelCount; + audio_desc.BlockAlign += audio_desc_channel[j].BlockAlign; + ++j; + } + + 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; + fill_writer_info (&writer_info); + + ASDCP::PCM::MXFWriter mxf_writer; + if (ASDCP_FAILURE (mxf_writer.OpenWrite (_mxf_path.c_str(), writer_info, audio_desc))) { + throw runtime_error ("could not open audio MXF for writing"); + } + + for (int i = 0; i < _length; ++i) { + + 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; + + for (list<string>::size_type j = 0; j < files.size(); ++j) { + memset (frame_buffer_channel[j].Data(), 0, frame_buffer_channel[j].Capacity()); + if (ASDCP_FAILURE (pcm_parser_channel[j].ReadFrame (frame_buffer_channel[j]))) { + throw runtime_error ("could not read audio frame"); + } + + if (frame_buffer_channel[j].Size() != frame_buffer_channel[j].Capacity()) { + throw runtime_error ("short audio frame"); + } + } + + while (data_s < data_e) { + for (list<string>::size_type j = 0; j < files.size(); ++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, 0, 0))) { + throw runtime_error ("could not write audio MXF frame"); + } + + Progress (float (i) / _length); + } + + if (ASDCP_FAILURE (mxf_writer.Finalize())) { + throw runtime_error ("could not finalise audio MXF"); + } + + _digest = make_digest (_mxf_path); +} + +void +SoundAsset::write_to_cpl (ostream& s) const +{ + s << " <MainSound>\n" + << " <Id>" << _uuid << "</Id>\n" + << " <AnnotationText>" << filesystem::path(_mxf_path).filename() << "</AnnotationText>\n" + << " <EditRate>" << _fps << "</EditRate>\n" + << " <IntrinsicDuration>" << _length << "</IntrinsicDuration>\n" + << " <EntryPoint>0</EntryPoint>\n" + << " <Duration>" << _length << "</Duration>\n" + << " </MainSound>\n"; +} + diff --git a/src/sound_asset.h b/src/sound_asset.h new file mode 100644 index 00000000..8c63b530 --- /dev/null +++ b/src/sound_asset.h @@ -0,0 +1,33 @@ +/* + 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 "asset.h" + +namespace libdcp +{ + +class SoundAsset : public Asset +{ +public: + SoundAsset (std::list<std::string> const &, std::string, int, int); + + void write_to_cpl (std::ostream &) const; +}; + +} diff --git a/src/tags.cc b/src/tags.cc new file mode 100644 index 00000000..40aeeea3 --- /dev/null +++ b/src/tags.cc @@ -0,0 +1,46 @@ +/* + 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 "tags.h" + +using namespace std; +using namespace libdcp; + +Tags* Tags::_instance = 0; + +Tags::Tags () + : company_name ("libdcp") + , product_name ("libdcp") + , product_version (LIBDCP_VERSION) + , issuer ("libdcp" LIBDCP_VERSION) + , creator ("libdcp" LIBDCP_VERSION) +{ + +} + +Tags * +Tags::instance () +{ + if (_instance == 0) { + _instance = new Tags; + } + + return _instance; +} + diff --git a/src/tags.h b/src/tags.h new file mode 100644 index 00000000..036bd4e6 --- /dev/null +++ b/src/tags.h @@ -0,0 +1,42 @@ +/* + 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 <string> + +namespace libdcp +{ + +class Tags +{ +public: + static Tags* instance (); + + std::string company_name; + std::string product_name; + std::string product_version; + std::string issuer; + std::string creator; + +private: + Tags (); + + static Tags* _instance; +}; + +} diff --git a/src/util.cc b/src/util.cc new file mode 100644 index 00000000..aab2e184 --- /dev/null +++ b/src/util.cc @@ -0,0 +1,95 @@ +/* + 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 <stdexcept> +#include <sstream> +#include <iomanip> +#include <openssl/sha.h> +#include "KM_util.h" +#include "KM_fileio.h" +#include "AS_DCP.h" +#include "util.h" + +using namespace std; + +bool libdcp::libdcp_test = false; + +/** Create a UUID. + * @return UUID. + */ +string +libdcp::make_uuid () +{ + char buffer[64]; + Kumu::UUID id; + + if (libdcp_test) { + static int N = 0; + byte_t t[16]; + for (int i = 0; i < 16; ++i) { + t[i] = N; + } + ++N; + + id = Kumu::UUID (t); + } else { + Kumu::GenRandomValue (id); + } + + id.EncodeHex (buffer, 64); + return string (buffer); +} + +/** Create a digest for a file. + * @param filename File name. + * @return Digest. + */ +string +libdcp::make_digest (string filename) +{ + Kumu::FileReader reader; + if (ASDCP_FAILURE (reader.OpenRead (filename.c_str ()))) { + throw runtime_error ("could not open file to compute digest"); + } + + SHA_CTX sha; + SHA1_Init (&sha); + + Kumu::ByteString read_buffer (65536); + while (1) { + ui32_t read = 0; + Kumu::Result_t r = reader.Read (read_buffer.Data(), read_buffer.Capacity(), &read); + + if (r == Kumu::RESULT_ENDOFFILE) { + break; + } else if (ASDCP_FAILURE (r)) { + throw runtime_error ("could not read file to compute digest"); + } + + SHA1_Update (&sha, read_buffer.Data(), read); + } + + byte_t byte_buffer[20]; + SHA1_Final (byte_buffer, &sha); + + stringstream s; + char digest[64]; + s << setfill('0') << setw(36) << Kumu::base64encode (byte_buffer, 20, digest, 64); + return s.str (); +} diff --git a/src/util.h b/src/util.h new file mode 100644 index 00000000..fcb6d739 --- /dev/null +++ b/src/util.h @@ -0,0 +1,28 @@ +/* + 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 <string> + +namespace libdcp { + +extern std::string make_uuid (); +extern std::string make_digest (std::string); +extern bool libdcp_test; + +} diff --git a/src/wscript b/src/wscript new file mode 100644 index 00000000..22b75b97 --- /dev/null +++ b/src/wscript @@ -0,0 +1,14 @@ +def build(bld): + obj = bld(features = 'cxx cxxshlib') + obj.name = 'libdcp' + obj.export_includes = ['.'] + obj.uselib = 'ASDCP KUMU BOOST_FILESYSTEM OPENSSL SIGC++' + obj.source = """ + dcp.cc + asset.cc + sound_asset.cc + picture_asset.cc + util.cc + tags.cc + """ + obj.target = 'libdcp' |
