are re-written, meaning that they can be encrypted.
This commit is mostly just for the backend. We also need a fair
few checks/restrictions in the UI:
- any present atmos content dictates the project frame rate
- no mixed edit rates of atmos content
- probably some other things I haven't thought of
(target.platform == 'osx' and target.bits == 64) or
(target.platform == 'windows')) else {}
- deps.append(('libdcp', 'cdb664d', cpp_lib_options))
- deps.append(('libsub', 'dec1726', cpp_lib_options))
+ deps.append(('libdcp', '2667081', cpp_lib_options))
+ deps.append(('libsub', 'fc5ce01', cpp_lib_options))
deps.append(('leqm-nrt', 'carl'))
deps.append(('rtaudio', 'carl'))
# We get our OpenSSL libraries from the environment, but we
--- /dev/null
+/*
+ Copyright (C) 2020 Carl Hetherington <cth@carlh.net>
+
+ This file is part of DCP-o-matic.
+
+ DCP-o-matic 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.
+
+ DCP-o-matic 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 DCP-o-matic. If not, see <http://www.gnu.org/licenses/>.
+
+*/
+
+
+#include "atmos_content.h"
+#include <dcp/raw_convert.h>
+#include <libxml++/libxml++.h>
+
+
+using std::string;
+using boost::shared_ptr;
+
+
+int const AtmosContentProperty::EDIT_RATE = 700;
+
+
+AtmosContent::AtmosContent (Content* parent)
+ : ContentPart (parent)
+ , _length (0)
+{
+
+}
+
+
+AtmosContent::AtmosContent (Content* parent, cxml::ConstNodePtr node)
+ : ContentPart (parent)
+{
+ _length = node->number_child<Frame>("Length");
+ _edit_rate = dcp::Fraction (node->string_child("EditRate"));
+}
+
+
+shared_ptr<AtmosContent>
+AtmosContent::from_xml (Content* parent, cxml::ConstNodePtr node)
+{
+ return shared_ptr<AtmosContent> (new AtmosContent(parent, node));
+}
+
+
+void
+AtmosContent::as_xml (xmlpp::Node* node) const
+{
+ node->add_child("Length")->add_child_text(dcp::raw_convert<string>(_length));
+ node->add_child("EditRate")->add_child_text(_edit_rate.as_string());
+}
+
+
+void
+AtmosContent::set_length (Frame len)
+{
+ maybe_set (_length, len, ContentProperty::LENGTH);
+}
+
+
+void
+AtmosContent::set_edit_rate (dcp::Fraction rate)
+{
+ maybe_set (_edit_rate, rate, AtmosContentProperty::EDIT_RATE);
+}
+
--- /dev/null
+/*
+ Copyright (C) 2020 Carl Hetherington <cth@carlh.net>
+
+ This file is part of DCP-o-matic.
+
+ DCP-o-matic 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.
+
+ DCP-o-matic 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 DCP-o-matic. If not, see <http://www.gnu.org/licenses/>.
+
+*/
+
+
+#include "content_part.h"
+
+
+class Content;
+
+
+class AtmosContentProperty
+{
+public:
+ static int const EDIT_RATE;
+};
+
+
+class AtmosContent : public ContentPart
+{
+public:
+ AtmosContent (Content* parent);
+
+ static boost::shared_ptr<AtmosContent> from_xml (Content* parent, cxml::ConstNodePtr node);
+
+ void as_xml (xmlpp::Node* node) const;
+
+ void set_length (Frame len);
+
+ Frame length () const {
+ return _length;
+ }
+
+ void set_edit_rate (dcp::Fraction rate);
+
+ dcp::Fraction rate () const {
+ return _edit_rate;
+ }
+
+private:
+ AtmosContent (Content* parent, cxml::ConstNodePtr node);
+
+ Frame _length;
+ dcp::Fraction _edit_rate;
+};
+
--- /dev/null
+/*
+ Copyright (C) 2020 Carl Hetherington <cth@carlh.net>
+
+ This file is part of DCP-o-matic.
+
+ DCP-o-matic 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.
+
+ DCP-o-matic 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 DCP-o-matic. If not, see <http://www.gnu.org/licenses/>.
+
+*/
+
+
+#include "atmos_decoder.h"
+#include "content.h"
+#include "dcpomatic_assert.h"
+#include "dcpomatic_time.h"
+#include "decoder.h"
+#include "film.h"
+
+
+using boost::shared_ptr;
+
+
+AtmosDecoder::AtmosDecoder (Decoder* parent, shared_ptr<const Content> content)
+ : DecoderPart (parent)
+ , _content (content)
+{
+
+}
+
+
+void
+AtmosDecoder::seek ()
+{
+ _position = boost::none;
+}
+
+
+void
+AtmosDecoder::emit (shared_ptr<const Film> film, shared_ptr<const dcp::AtmosFrame> data, Frame frame, AtmosMetadata metadata)
+{
+ Data (ContentAtmos(data, frame, metadata));
+ /* There's no fiddling with frame rates when we are using Atmos; the DCP rate must be the same as the Atmos one */
+ _position = dcpomatic::ContentTime::from_frames (frame, film->video_frame_rate());
+}
--- /dev/null
+/*
+ Copyright (C) 2020 Carl Hetherington <cth@carlh.net>
+
+ This file is part of DCP-o-matic.
+
+ DCP-o-matic 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.
+
+ DCP-o-matic 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 DCP-o-matic. If not, see <http://www.gnu.org/licenses/>.
+
+*/
+
+
+#include "atmos_metadata.h"
+#include "content_atmos.h"
+#include "decoder_part.h"
+#include <boost/signals2.hpp>
+
+
+class AtmosDecoder : public DecoderPart
+{
+public:
+ AtmosDecoder (Decoder* parent, boost::shared_ptr<const Content> content);
+
+ boost::optional<dcpomatic::ContentTime> position (boost::shared_ptr<const Film>) const {
+ return _position;
+ }
+
+ void seek ();
+
+ void emit (boost::shared_ptr<const Film> film, boost::shared_ptr<const dcp::AtmosFrame> data, Frame frame, AtmosMetadata metadata);
+
+ boost::signals2::signal<void (ContentAtmos)> Data;
+
+private:
+ boost::shared_ptr<const Content> _content;
+ boost::optional<dcpomatic::ContentTime> _position;
+};
--- /dev/null
+/*
+ Copyright (C) 2012-2020 Carl Hetherington <cth@carlh.net>
+
+ This file is part of DCP-o-matic.
+
+ DCP-o-matic 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.
+
+ DCP-o-matic 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 DCP-o-matic. If not, see <http://www.gnu.org/licenses/>.
+
+*/
+
+
+#include "atmos_metadata.h"
+#include <dcp/atmos_asset.h>
+
+
+using boost::shared_ptr;
+
+
+AtmosMetadata::AtmosMetadata (shared_ptr<const dcp::AtmosAsset> asset)
+ : _first_frame (asset->first_frame())
+ , _max_channel_count (asset->max_channel_count())
+ , _max_object_count (asset->max_object_count())
+ , _atmos_version (asset->atmos_version())
+{
+
+}
+
+
+shared_ptr<dcp::AtmosAsset>
+AtmosMetadata::create (dcp::Fraction edit_rate) const
+{
+ return shared_ptr<dcp::AtmosAsset> (new dcp::AtmosAsset(edit_rate, _first_frame, _max_channel_count, _max_object_count, _atmos_version));
+}
--- /dev/null
+/*
+ Copyright (C) 2012-2020 Carl Hetherington <cth@carlh.net>
+
+ This file is part of DCP-o-matic.
+
+ DCP-o-matic 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.
+
+ DCP-o-matic 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 DCP-o-matic. If not, see <http://www.gnu.org/licenses/>.
+
+*/
+
+#ifndef DCPOMATIC_ATMOS_METADATA_H
+#define DCPOMATIC_ATMOS_METADATA_H
+
+#include <dcp/atmos_asset.h>
+#include <boost/shared_ptr.hpp>
+
+class AtmosMetadata
+{
+public:
+ AtmosMetadata (boost::shared_ptr<const dcp::AtmosAsset> asset);
+ boost::shared_ptr<dcp::AtmosAsset> create (dcp::Fraction edit_rate) const;
+
+private:
+ int _first_frame;
+ int _max_channel_count;
+ int _max_object_count;
+ int _atmos_version;
+};
+
+#endif
+
*/
+#include "atmos_content.h"
#include "atmos_mxf_content.h"
#include "job.h"
#include "film.h"
AtmosMXFContent::AtmosMXFContent (cxml::ConstNodePtr node, int)
: Content (node)
{
- /* This was mistakenly left out for a while, so make sure we at least don't
- * crash if an old Film is loaded.
- */
- _length = node->optional_number_child<Frame>("Length").get_value_or(0);
+ atmos = AtmosContent::from_xml (this, node);
}
bool
{
boost::mutex::scoped_lock lm (_mutex);
- _length = a->intrinsic_duration ();
+ atmos.reset (new AtmosContent(this));
+ atmos->set_length (a->intrinsic_duration());
+ atmos->set_edit_rate (a->edit_rate());
}
}
{
node->add_child("Type")->add_child_text ("AtmosMXF");
Content::as_xml (node, with_paths);
- node->add_child("Length")->add_child_text(dcp::raw_convert<string>(_length));
+ atmos->as_xml (node);
}
DCPTime
AtmosMXFContent::full_length (shared_ptr<const Film> film) const
{
FrameRateChange const frc (film, shared_from_this());
- return DCPTime::from_frames (llrint (_length * frc.factor()), film->video_frame_rate());
+ return DCPTime::from_frames (llrint (atmos->length() * frc.factor()), film->video_frame_rate());
}
DCPTime
AtmosMXFContent::approximate_length () const
{
- return DCPTime::from_frames (_length, 24);
+ return DCPTime::from_frames (atmos->length(), 24);
}
dcpomatic::DCPTime approximate_length () const;
static bool valid_mxf (boost::filesystem::path path);
-
-private:
- Frame _length;
};
--- /dev/null
+/*
+ Copyright (C) 2020 Carl Hetherington <cth@carlh.net>
+
+ This file is part of DCP-o-matic.
+
+ DCP-o-matic 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.
+
+ DCP-o-matic 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 DCP-o-matic. If not, see <http://www.gnu.org/licenses/>.
+
+*/
+
+#include "atmos_content.h"
+#include "atmos_decoder.h"
+#include "atmos_mxf_content.h"
+#include "atmos_mxf_decoder.h"
+#include "dcpomatic_time.h"
+#include <dcp/atmos_asset.h>
+#include <dcp/atmos_asset_reader.h>
+
+using boost::shared_ptr;
+
+AtmosMXFDecoder::AtmosMXFDecoder (boost::shared_ptr<const Film> film, boost::shared_ptr<const AtmosMXFContent> content)
+ : Decoder (film)
+ , _content (content)
+{
+ atmos.reset (new AtmosDecoder(this, content));
+
+ shared_ptr<dcp::AtmosAsset> asset (new dcp::AtmosAsset(_content->path(0)));
+ _reader = asset->start_read ();
+ _metadata = AtmosMetadata (asset);
+}
+
+
+bool
+AtmosMXFDecoder::pass ()
+{
+ double const vfr = _content->active_video_frame_rate (film());
+ int64_t const frame = _next.frames_round (vfr);
+
+ if (frame >= _content->atmos->length()) {
+ return true;
+ }
+
+ atmos->emit (film(), _reader->get_frame(frame), frame, *_metadata);
+ _next += dcpomatic::ContentTime::from_frames (1, vfr);
+ return false;
+}
+
+
+void
+AtmosMXFDecoder::seek (dcpomatic::ContentTime t, bool accurate)
+{
+ Decoder::seek (t, accurate);
+ _next = t;
+}
+
--- /dev/null
+/*
+ Copyright (C) 2020 Carl Hetherington <cth@carlh.net>
+
+ This file is part of DCP-o-matic.
+
+ DCP-o-matic 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.
+
+ DCP-o-matic 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 DCP-o-matic. If not, see <http://www.gnu.org/licenses/>.
+
+*/
+
+#include "atmos_metadata.h"
+#include "dcpomatic_time.h"
+#include "decoder.h"
+#include <dcp/atmos_asset_reader.h>
+
+class AtmosMXFContent;
+
+class AtmosMXFDecoder : public Decoder
+{
+public:
+ AtmosMXFDecoder (boost::shared_ptr<const Film> film, boost::shared_ptr<const AtmosMXFContent>);
+
+ bool pass ();
+ void seek (dcpomatic::ContentTime t, bool accurate);
+
+private:
+ boost::shared_ptr<const AtmosMXFContent> _content;
+ dcpomatic::ContentTime _next;
+ boost::shared_ptr<dcp::AtmosAssetReader> _reader;
+ boost::optional<AtmosMetadata> _metadata;
+};
+
class Job;
class Film;
+class AtmosContent;
class ContentProperty
{
boost::shared_ptr<VideoContent> video;
boost::shared_ptr<AudioContent> audio;
std::list<boost::shared_ptr<TextContent> > text;
+ boost::shared_ptr<AtmosContent> atmos;
boost::shared_ptr<TextContent> only_text () const;
boost::shared_ptr<TextContent> text_of_original_type (TextType type) const;
--- /dev/null
+/*
+ Copyright (C) 2020 Carl Hetherington <cth@carlh.net>
+
+ This file is part of DCP-o-matic.
+
+ DCP-o-matic 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.
+
+ DCP-o-matic 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 DCP-o-matic. If not, see <http://www.gnu.org/licenses/>.
+
+*/
+
+#ifndef DCPOMATIC_CONTENT_ATMOS_H
+#define DCPOMATIC_CONTENT_ATMOS_H
+
+#include "atmos_metadata.h"
+#include "types.h"
+#include <dcp/atmos_asset_reader.h>
+#include <boost/shared_ptr.hpp>
+
+/** @class ContentAtmos
+ * @brief Some Atmos data that has come out of a decoder.
+ */
+class ContentAtmos
+{
+public:
+ ContentAtmos (boost::shared_ptr<const dcp::AtmosFrame> data_, Frame frame_, AtmosMetadata metadata_)
+ : data (data_)
+ , frame (frame_)
+ , metadata (metadata_)
+ {}
+
+ boost::shared_ptr<const dcp::AtmosFrame> data;
+ Frame frame;
+ AtmosMetadata metadata;
+};
+
+#endif
*/
+#include "atmos_content.h"
#include "dcp_content.h"
#include "video_content.h"
#include "audio_content.h"
as->set_mapping (m);
}
+ if (examiner->has_atmos()) {
+ boost::mutex::scoped_lock lm (_mutex);
+ atmos.reset (new AtmosContent(this));
+ }
+
int texts = 0;
{
boost::mutex::scoped_lock lm (_mutex);
/*
- Copyright (C) 2014-2019 Carl Hetherington <cth@carlh.net>
+ Copyright (C) 2014-2020 Carl Hetherington <cth@carlh.net>
This file is part of DCP-o-matic.
*/
+#include "atmos_decoder.h"
#include "dcp_decoder.h"
#include "dcp_content.h"
#include "audio_content.h"
#include <dcp/sound_asset_reader.h>
#include <dcp/subtitle_image.h>
#include <dcp/decrypted_kdm.h>
+#include <dcp/reel_atmos_asset.h>
#include <boost/foreach.hpp>
#include <iostream>
/* XXX: this time here should be the time of the first subtitle, not 0 */
text.push_back (shared_ptr<TextDecoder> (new TextDecoder (this, i, ContentTime())));
}
+ if (c->atmos) {
+ atmos.reset (new AtmosDecoder (this, c));
+ }
}
/* We try to avoid re-scanning the DCP's files every time we make a new DCPDecoder; we do this
audio->emit (film(), _dcp_content->audio->stream(), data, ContentTime::from_frames (_offset, vfr) + _next);
}
+ if (_atmos_reader) {
+ DCPOMATIC_ASSERT (_atmos_metadata);
+ atmos->emit (film(), _atmos_reader->get_frame(frame), frame, *_atmos_metadata);
+ }
+
_next += ContentTime::from_frames (1, vfr);
if ((*_reel)->main_picture ()) {
_mono_reader.reset ();
_stereo_reader.reset ();
_sound_reader.reset ();
+ _atmos_reader.reset ();
return;
}
} else {
_sound_reader.reset ();
}
+
+ if ((*_reel)->atmos()) {
+ shared_ptr<dcp::AtmosAsset> asset = (*_reel)->atmos()->asset();
+ _atmos_reader = asset->start_read();
+ _atmos_metadata = AtmosMetadata (asset);
+ } else {
+ _atmos_reader.reset ();
+ _atmos_metadata = boost::none;
+ }
}
void
/*
- Copyright (C) 2014-2016 Carl Hetherington <cth@carlh.net>
+ Copyright (C) 2014-2020 Carl Hetherington <cth@carlh.net>
This file is part of DCP-o-matic.
* @brief A decoder of existing DCPs.
*/
+#include "atmos_metadata.h"
#include "decoder.h"
#include "dcp.h"
#include <dcp/mono_picture_asset_reader.h>
boost::shared_ptr<dcp::StereoPictureAssetReader> _stereo_reader;
/** Reader for current sound asset, if applicable */
boost::shared_ptr<dcp::SoundAssetReader> _sound_reader;
+ boost::shared_ptr<dcp::AtmosAssetReader> _atmos_reader;
+ boost::optional<AtmosMetadata> _atmos_metadata;
bool _decode_referenced;
boost::optional<int> _forced_reduction;
_player_video_connection = _player->Video.connect (bind (&DCPEncoder::video, this, _1, _2));
_player_audio_connection = _player->Audio.connect (bind (&DCPEncoder::audio, this, _1, _2));
_player_text_connection = _player->Text.connect (bind (&DCPEncoder::text, this, _1, _2, _3, _4));
+ _player_atmos_connection = _player->Atmos.connect (bind (&DCPEncoder::atmos, this, _1, _2, _3));
BOOST_FOREACH (shared_ptr<const Content> c, film->content ()) {
BOOST_FOREACH (shared_ptr<TextContent> i, c->text) {
_player_video_connection.release ();
_player_audio_connection.release ();
_player_text_connection.release ();
+ _player_atmos_connection.release ();
}
void
}
}
+
+void
+DCPEncoder::atmos (shared_ptr<const dcp::AtmosFrame> data, DCPTime time, AtmosMetadata metadata)
+{
+ _writer->write (data, time, metadata);
+}
+
+
optional<float>
DCPEncoder::current_rate () const
{
/*
- Copyright (C) 2012-2018 Carl Hetherington <cth@carlh.net>
+ Copyright (C) 2012-2020 Carl Hetherington <cth@carlh.net>
This file is part of DCP-o-matic.
*/
+#include "atmos_metadata.h"
#include "types.h"
#include "player_text.h"
#include "dcp_text_track.h"
#include "encoder.h"
+#include <dcp/atmos_frame.h>
#include <boost/weak_ptr.hpp>
class Film;
void video (boost::shared_ptr<PlayerVideo>, dcpomatic::DCPTime);
void audio (boost::shared_ptr<AudioBuffers>, dcpomatic::DCPTime);
void text (PlayerText, TextType, boost::optional<DCPTextTrack>, dcpomatic::DCPTimePeriod);
+ void atmos (boost::shared_ptr<const dcp::AtmosFrame>, dcpomatic::DCPTime, AtmosMetadata metadata);
boost::shared_ptr<Writer> _writer;
boost::shared_ptr<J2KEncoder> _j2k_encoder;
boost::signals2::scoped_connection _player_video_connection;
boost::signals2::scoped_connection _player_audio_connection;
boost::signals2::scoped_connection _player_text_connection;
+ boost::signals2::scoped_connection _player_atmos_connection;
};
#include <dcp/sound_asset.h>
#include <dcp/sound_asset_reader.h>
#include <dcp/subtitle_asset.h>
+#include <dcp/reel_atmos_asset.h>
#include <dcp/reel_subtitle_asset.h>
#include <dcp/reel_closed_caption_asset.h>
#include <dcp/reel_markers_asset.h>
, _needs_assets (false)
, _kdm_valid (false)
, _three_d (false)
+ , _has_atmos (false)
{
shared_ptr<dcp::CPL> cpl;
if (j->main_subtitle() && !j->main_subtitle()->asset_ref().resolved()) {
++unsatisfied;
}
+ if (j->atmos() && !j->atmos()->asset_ref().resolved()) {
+ ++unsatisfied;
+ }
}
if (unsatisfied < least_unsatisfied) {
_markers.insert (rm.begin(), rm.end());
}
+ if (i->atmos()) {
+ _has_atmos = true;
+ }
+
if (i->main_picture()) {
_reel_lengths.push_back (i->main_picture()->actual_duration());
} else if (i->main_sound()) {
_reel_lengths.push_back (i->main_subtitle()->actual_duration());
} else if (!i->closed_captions().empty()) {
_reel_lengths.push_back (i->closed_captions().front()->actual_duration());
+ } else if (!i->atmos()) {
+ _reel_lengths.push_back (i->atmos()->actual_duration());
}
}
if (i->main_subtitle()) {
i->main_subtitle()->asset()->subtitles ();
}
+
+ if (i->atmos()) {
+ i->atmos()->asset()->start_read()->get_frame(0);
+ }
}
} catch (dcp::ReadError& e) {
_kdm_valid = false;
return _content_version;
}
+ bool has_atmos () const {
+ return _has_atmos;
+ }
+
private:
boost::optional<double> _video_frame_rate;
boost::optional<dcp::Size> _video_size;
std::map<dcp::Marker, dcp::Time> _markers;
std::vector<dcp::Rating> _ratings;
std::string _content_version;
+ bool _has_atmos;
};
/*
- Copyright (C) 2012-2018 Carl Hetherington <cth@carlh.net>
+ Copyright (C) 2012-2020 Carl Hetherington <cth@carlh.net>
This file is part of DCP-o-matic.
class VideoDecoder;
class AudioDecoder;
class TextDecoder;
+class AtmosDecoder;
class DecoderPart;
/** @class Decoder.
boost::shared_ptr<VideoDecoder> video;
boost::shared_ptr<AudioDecoder> audio;
std::list<boost::shared_ptr<TextDecoder> > text;
+ boost::shared_ptr<AtmosDecoder> atmos;
boost::shared_ptr<TextDecoder> only_text () const;
/*
- Copyright (C) 2016-2019 Carl Hetherington <cth@carlh.net>
+ Copyright (C) 2016-2020 Carl Hetherington <cth@carlh.net>
This file is part of DCP-o-matic.
*/
+#include "atmos_mxf_content.h"
+#include "atmos_mxf_decoder.h"
#include "ffmpeg_content.h"
#include "ffmpeg_decoder.h"
#include "dcp_content.h"
return shared_ptr<Decoder> (new VideoMXFDecoder(film, vmc));
}
+ shared_ptr<const AtmosMXFContent> amc = dynamic_pointer_cast<const AtmosMXFContent> (content);
+ if (amc) {
+ return shared_ptr<Decoder> (new AtmosMXFDecoder(film, amc));
+ }
+
return shared_ptr<Decoder> ();
}
class Film;
struct isdcf_name_test;
struct recover_test_2d_encrypted;
+struct atmos_encrypted_passthrough_test;
class InfoFileHandle
{
friend struct ::isdcf_name_test;
friend struct ::recover_test_2d_encrypted;
+ friend struct ::atmos_encrypted_passthrough_test;
template <typename> friend class ChangeSignaller;
boost::filesystem::path info_file (dcpomatic::DCPTimePeriod p) const;
*/
+#include "atmos_decoder.h"
#include "player.h"
#include "film.h"
#include "audio_buffers.h"
}
shared_ptr<Decoder> decoder = decoder_factory (_film, i, _fast, _tolerant, old_decoder);
- FrameRateChange frc (_film, i);
+ DCPOMATIC_ASSERT (decoder);
- if (!decoder) {
- /* Not something that we can decode; e.g. Atmos content */
- continue;
- }
+ FrameRateChange frc (_film, i);
if (decoder->video && _ignore_video) {
decoder->video->set_ignore (true);
++j;
}
+
+ if (decoder->atmos) {
+ decoder->atmos->Data.connect (bind(&Player::atmos, this, weak_ptr<Piece>(piece), _1));
+ }
}
_stream_states.clear ();
return _playlist ? _playlist : _film->playlist();
}
+
+void
+Player::atmos (weak_ptr<Piece>, ContentAtmos data)
+{
+ Atmos (data.data, DCPTime::from_frames(data.frame, _film->video_frame_rate()), data.metadata);
+}
+
/*
- Copyright (C) 2013-2019 Carl Hetherington <cth@carlh.net>
+ Copyright (C) 2013-2020 Carl Hetherington <cth@carlh.net>
This file is part of DCP-o-matic.
#ifndef DCPOMATIC_PLAYER_H
#define DCPOMATIC_PLAYER_H
+#include "atmos_metadata.h"
#include "player_text.h"
#include "active_text.h"
#include "content_text.h"
#include "film.h"
#include "content.h"
+#include "content_atmos.h"
#include "position_image.h"
#include "piece.h"
#include "content_video.h"
class Font;
}
+class AtmosContent;
class PlayerVideo;
class Playlist;
class AudioBuffers;
* after the corresponding Video.
*/
boost::signals2::signal<void (PlayerText, TextType, boost::optional<DCPTextTrack>, dcpomatic::DCPTimePeriod)> Text;
+ boost::signals2::signal<void (boost::shared_ptr<const dcp::AtmosFrame>, dcpomatic::DCPTime, AtmosMetadata)> Atmos;
private:
friend class PlayerWrapper;
dcpomatic::ContentTime dcp_to_content_time (boost::shared_ptr<const Piece> piece, dcpomatic::DCPTime t) const;
dcpomatic::DCPTime content_time_to_dcp (boost::shared_ptr<const Piece> piece, dcpomatic::ContentTime t) const;
boost::shared_ptr<PlayerVideo> black_player_video_frame (Eyes eyes) const;
+
void video (boost::weak_ptr<Piece>, ContentVideo);
void audio (boost::weak_ptr<Piece>, AudioStreamPtr, ContentAudio);
void bitmap_text_start (boost::weak_ptr<Piece>, boost::weak_ptr<const TextContent>, ContentBitmapText);
void plain_text_start (boost::weak_ptr<Piece>, boost::weak_ptr<const TextContent>, ContentStringText);
void subtitle_stop (boost::weak_ptr<Piece>, boost::weak_ptr<const TextContent>, dcpomatic::ContentTime);
+ void atmos (boost::weak_ptr<Piece>, ContentAtmos);
+
dcpomatic::DCPTime one_video_frame () const;
void fill_audio (dcpomatic::DCPTimePeriod period);
std::pair<boost::shared_ptr<AudioBuffers>, dcpomatic::DCPTime> discard_audio (
#include "config.h"
#include "audio_buffers.h"
#include "image.h"
+#include <dcp/atmos_asset.h>
+#include <dcp/atmos_asset_writer.h>
#include <dcp/mono_picture_asset.h>
#include <dcp/stereo_picture_asset.h>
#include <dcp/sound_asset.h>
#include <dcp/sound_asset_writer.h>
#include <dcp/reel.h>
+#include <dcp/reel_atmos_asset.h>
#include <dcp/reel_mono_picture_asset.h>
#include <dcp/reel_stereo_picture_asset.h>
#include <dcp/reel_sound_asset.h>
_last_written[eyes] = encoded;
}
+
+void
+ReelWriter::write (shared_ptr<const dcp::AtmosFrame> atmos, AtmosMetadata metadata)
+{
+ if (!_atmos_asset) {
+ _atmos_asset = metadata.create (dcp::Fraction(_film->video_frame_rate(), 1));
+ if (_film->encrypted()) {
+ _atmos_asset->set_key(_film->key());
+ }
+ _atmos_asset_writer = _atmos_asset->start_write (
+ _film->directory().get() / atmos_asset_filename (_atmos_asset, _reel_index, _reel_count, _content_summary)
+ );
+ }
+ _atmos_asset_writer->write (atmos);
+}
+
+
void
ReelWriter::fake_write (int size)
{
_sound_asset->set_file (audio_to);
}
+
+ if (_atmos_asset) {
+ _atmos_asset_writer->finalize ();
+ boost::filesystem::path atmos_to;
+ atmos_to /= _film->dir (_film->dcp_name());
+ string const aaf = atmos_asset_filename (_atmos_asset, _reel_index, _reel_count, _content_summary);
+ atmos_to /= aaf;
+
+ boost::system::error_code ec;
+ boost::filesystem::rename (_film->file(aaf), atmos_to, ec);
+ if (ec) {
+ throw FileError (
+ String::compose (_("could not move atmos asset into the DCP (%1)"), ec.value ()), aaf
+ );
+ }
+
+ _atmos_asset->set_file (atmos_to);
+ }
}
template <class T>
reel->add (ma);
}
+ if (_atmos_asset) {
+ reel->add (shared_ptr<dcp::ReelAtmosAsset>(new dcp::ReelAtmosAsset(_atmos_asset, 0)));
+ }
+
return reel;
}
if (_sound_asset) {
_sound_asset->hash (set_progress);
}
+
+ if (_atmos_asset) {
+ _atmos_asset->hash (set_progress);
+ }
}
Frame
/*
- Copyright (C) 2012-2019 Carl Hetherington <cth@carlh.net>
+ Copyright (C) 2012-2020 Carl Hetherington <cth@carlh.net>
This file is part of DCP-o-matic.
*/
+#include "atmos_metadata.h"
#include "types.h"
#include "dcpomatic_time.h"
#include "referenced_reel_asset.h"
#include "player_text.h"
#include "dcp_text_track.h"
#include <dcp/picture_asset_writer.h>
+#include <dcp/atmos_asset_writer.h>
#include <boost/shared_ptr.hpp>
#include <boost/weak_ptr.hpp>
class SoundAsset;
class SoundAssetWriter;
class SubtitleAsset;
+ class AtmosAsset;
class ReelAsset;
class Reel;
}
void repeat_write (Frame frame, Eyes eyes);
void write (boost::shared_ptr<const AudioBuffers> audio);
void write (PlayerText text, TextType type, boost::optional<DCPTextTrack> track, dcpomatic::DCPTimePeriod period);
+ void write (boost::shared_ptr<const dcp::AtmosFrame> atmos, AtmosMetadata metadata);
void finish ();
boost::shared_ptr<dcp::Reel> create_reel (std::list<ReferencedReelAsset> const & refs, std::list<boost::shared_ptr<dcpomatic::Font> > const & fonts);
boost::shared_ptr<dcp::SoundAssetWriter> _sound_asset_writer;
boost::shared_ptr<dcp::SubtitleAsset> _subtitle_asset;
std::map<DCPTextTrack, boost::shared_ptr<dcp::SubtitleAsset> > _closed_caption_assets;
+ boost::shared_ptr<dcp::AtmosAsset> _atmos_asset;
+ boost::shared_ptr<dcp::AtmosAssetWriter> _atmos_asset_writer;
static int const _info_size;
};
#include <dcp/picture_asset.h>
#include <dcp/sound_asset.h>
#include <dcp/subtitle_asset.h>
+#include <dcp/atmos_asset.h>
extern "C" {
#include <libavfilter/avfilter.h>
#include <libavformat/avformat.h>
return Config::instance()->dcp_asset_filename_format().get(values, "_" + asset->id() + ".mxf");
}
+
+string
+atmos_asset_filename (shared_ptr<dcp::AtmosAsset> asset, int reel_index, int reel_count, optional<string> summary)
+{
+ dcp::NameFormat::Map values;
+ values['t'] = "atmos";
+ values['r'] = raw_convert<string> (reel_index + 1);
+ values['n'] = raw_convert<string> (reel_count);
+ if (summary) {
+ values['c'] = careful_string_filter (summary.get());
+ }
+ return Config::instance()->dcp_asset_filename_format().get(values, "_" + asset->id() + ".mxf");
+}
+
+
float
relaxed_string_to_float (string s)
{
#include "types.h"
#include "dcpomatic_time.h"
#include "audio_mapping.h"
+#include <dcp/atmos_asset.h>
#include <dcp/decrypted_kdm.h>
#include <dcp/util.h>
#include <dcp/subtitle_image.h>
extern std::map<std::string, std::string> split_get_request (std::string url);
extern std::string video_asset_filename (boost::shared_ptr<dcp::PictureAsset> asset, int reel_index, int reel_count, boost::optional<std::string> content_summary);
extern std::string audio_asset_filename (boost::shared_ptr<dcp::SoundAsset> asset, int reel_index, int reel_count, boost::optional<std::string> content_summary);
+extern std::string atmos_asset_filename (boost::shared_ptr<dcp::AtmosAsset> asset, int reel_index, int reel_count, boost::optional<std::string> content_summary);
extern float relaxed_string_to_float (std::string);
extern std::string careful_string_filter (std::string);
extern std::pair<int, int> audio_channel_types (std::list<int> mapped, int channels);
double const vfr = _content->active_video_frame_rate (film());
int64_t const frame = _next.frames_round (vfr);
-
if (frame >= _content->video->length()) {
return true;
}
BOOST_FOREACH (DCPTextTrack i, _film->closed_caption_tracks()) {
_caption_reels[i] = _reels.begin ();
}
+ _atmos_reel = _reels.begin ();
/* Check that the signer is OK */
string reason;
}
+void
+Writer::write (shared_ptr<const dcp::AtmosFrame> atmos, DCPTime time, AtmosMetadata metadata)
+{
+ if (_atmos_reel->period().to == time) {
+ ++_atmos_reel;
+ DCPOMATIC_ASSERT (_atmos_reel != _reels.end());
+ }
+
+ /* We assume that we get a video frame's worth of data here */
+ _atmos_reel->write (atmos, metadata);
+}
+
+
/** Caller must hold a lock on _state_mutex */
bool
Writer::have_sequenced_image_at_queue_head ()
/*
- Copyright (C) 2012-2019 Carl Hetherington <cth@carlh.net>
+ Copyright (C) 2012-2020 Carl Hetherington <cth@carlh.net>
This file is part of DCP-o-matic.
* @brief Writer class.
*/
+#include "atmos_metadata.h"
#include "types.h"
#include "player_text.h"
#include "exception_store.h"
#include "dcp_text_track.h"
+#include <dcp/atmos_frame.h>
#include <boost/shared_ptr.hpp>
#include <boost/weak_ptr.hpp>
#include <boost/thread.hpp>
void write (PlayerText text, TextType type, boost::optional<DCPTextTrack>, dcpomatic::DCPTimePeriod period);
void write (std::list<boost::shared_ptr<dcpomatic::Font> > fonts);
void write (ReferencedReelAsset asset);
+ void write (boost::shared_ptr<const dcp::AtmosFrame> atmos, dcpomatic::DCPTime time, AtmosMetadata metadata);
void finish ();
void set_encoder_threads (int threads);
std::vector<ReelWriter>::iterator _audio_reel;
std::vector<ReelWriter>::iterator _subtitle_reel;
std::map<DCPTextTrack, std::vector<ReelWriter>::iterator> _caption_reels;
+ std::vector<ReelWriter>::iterator _atmos_reel;
/** our thread */
boost::thread _thread;
analyse_audio_job.cc
analyse_subtitles_job.cc
analytics.cc
+ atmos_content.cc
atmos_mxf_content.cc
+ atmos_decoder.cc
+ atmos_metadata.cc
+ atmos_mxf_decoder.cc
audio_analysis.cc
audio_buffers.cc
audio_content.cc
--- /dev/null
+/*
+ Copyright (C) 2020 Carl Hetherington <cth@carlh.net>
+
+ This file is part of DCP-o-matic.
+
+ DCP-o-matic 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.
+
+ DCP-o-matic 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 DCP-o-matic. If not, see <http://www.gnu.org/licenses/>.
+
+*/
+
+
+#include "lib/config.h"
+#include "lib/content.h"
+#include "lib/content_factory.h"
+#include "lib/dcp_content.h"
+#include "lib/film.h"
+#include "test.h"
+#include <boost/test/unit_test.hpp>
+#include <iostream>
+
+
+using std::string;
+using std::vector;
+using boost::optional;
+using boost::shared_ptr;
+
+
+BOOST_AUTO_TEST_CASE (atmos_passthrough_test)
+{
+ shared_ptr<Film> film = new_test_film2 ("atmos_passthrough_test");
+ boost::filesystem::path ref = TestPaths::private_data / "atmos_asset.mxf";
+ shared_ptr<Content> content = content_factory (TestPaths::private_data / "atmos_asset.mxf").front();
+ film->examine_and_add_content (content);
+ BOOST_REQUIRE (!wait_for_jobs());
+
+ film->make_dcp ();
+ BOOST_REQUIRE (!wait_for_jobs());
+
+ BOOST_REQUIRE (mxf_atmos_files_same(ref, dcp_file(film, "atmos"), true));
+}
+
+
+BOOST_AUTO_TEST_CASE (atmos_encrypted_passthrough_test)
+{
+ shared_ptr<Film> film = new_test_film2 ("atmos_encrypted_passthrough_test");
+ boost::filesystem::path ref = TestPaths::private_data / "atmos_asset.mxf";
+ shared_ptr<Content> content = content_factory (TestPaths::private_data / "atmos_asset.mxf").front();
+ film->examine_and_add_content (content);
+ BOOST_REQUIRE (!wait_for_jobs());
+
+ film->set_encrypted (true);
+ film->_key = dcp::Key ("4fac12927eb122af1c2781aa91f3a4cc");
+ film->make_dcp ();
+ BOOST_REQUIRE (!wait_for_jobs());
+
+ BOOST_REQUIRE (!mxf_atmos_files_same(ref, dcp_file(film, "atmos")));
+
+ dcp::EncryptedKDM kdm = film->make_kdm (
+ Config::instance()->decryption_chain()->leaf(),
+ vector<string>(),
+ dcp_file(film, "cpl"),
+ dcp::LocalTime(),
+ dcp::LocalTime(),
+ dcp::MODIFIED_TRANSITIONAL_1,
+ false,
+ optional<int>()
+ );
+
+ shared_ptr<Film> film2 = new_test_film2 ("atmos_encrypted_passthrough_test2");
+ shared_ptr<DCPContent> content2 (new DCPContent(film->dir(film->dcp_name())));
+ content2->add_kdm (kdm);
+ film2->examine_and_add_content (content2);
+ BOOST_REQUIRE (!wait_for_jobs());
+
+ std::cout << "making 2nd dcp.\n";
+ film2->make_dcp ();
+ BOOST_REQUIRE (!wait_for_jobs());
+
+ BOOST_CHECK (mxf_atmos_files_same(ref, dcp_file(film2, "atmos"), true));
+}
+
}
}
+
+/** @return true if the files are the same, otherwise false */
+bool
+mxf_atmos_files_same (boost::filesystem::path ref, boost::filesystem::path check, bool verbose)
+{
+ ASDCP::ATMOS::MXFReader ref_reader;
+ BOOST_REQUIRE (!ASDCP_FAILURE(ref_reader.OpenRead(ref.string().c_str())));
+
+ ASDCP::ATMOS::AtmosDescriptor ref_desc;
+ BOOST_REQUIRE (!ASDCP_FAILURE(ref_reader.FillAtmosDescriptor(ref_desc)));
+
+ ASDCP::ATMOS::MXFReader check_reader;
+ BOOST_REQUIRE (!ASDCP_FAILURE(check_reader.OpenRead(check.string().c_str())));
+
+ ASDCP::ATMOS::AtmosDescriptor check_desc;
+ BOOST_REQUIRE (!ASDCP_FAILURE(check_reader.FillAtmosDescriptor(check_desc)));
+
+ if (ref_desc.EditRate.Numerator != check_desc.EditRate.Numerator) {
+ if (verbose) {
+ std::cout << "EditRate.Numerator differs.\n";
+ }
+ return false;
+ }
+ if (ref_desc.EditRate.Denominator != check_desc.EditRate.Denominator) {
+ if (verbose) {
+ std::cout << "EditRate.Denominator differs.\n";
+ }
+ return false;
+ }
+ if (ref_desc.ContainerDuration != check_desc.ContainerDuration) {
+ if (verbose) {
+ std::cout << "EditRate.ContainerDuration differs.\n";
+ }
+ return false;
+ }
+ if (ref_desc.FirstFrame != check_desc.FirstFrame) {
+ if (verbose) {
+ std::cout << "EditRate.FirstFrame differs.\n";
+ }
+ return false;
+ }
+ if (ref_desc.MaxChannelCount != check_desc.MaxChannelCount) {
+ if (verbose) {
+ std::cout << "EditRate.MaxChannelCount differs.\n";
+ }
+ return false;
+ }
+ if (ref_desc.MaxObjectCount != check_desc.MaxObjectCount) {
+ if (verbose) {
+ std::cout << "EditRate.MaxObjectCount differs.\n";
+ }
+ return false;
+ }
+ if (ref_desc.AtmosVersion != check_desc.AtmosVersion) {
+ if (verbose) {
+ std::cout << "EditRate.AtmosVersion differs.\n";
+ }
+ return false;
+ }
+
+ ASDCP::DCData::FrameBuffer ref_buffer (Kumu::Megabyte);
+ ASDCP::DCData::FrameBuffer check_buffer (Kumu::Megabyte);
+ for (size_t i = 0; i < ref_desc.ContainerDuration; ++i) {
+ ref_reader.ReadFrame (i, ref_buffer, 0);
+ check_reader.ReadFrame (i, check_buffer, 0);
+ if (memcmp(ref_buffer.RoData(), check_buffer.RoData(), ref_buffer.Size())) {
+ if (verbose) {
+ std::cout << "data differs.\n";
+ }
+ return false;
+ }
+ }
+
+ return true;
+}
+
+
void
check_image (boost::filesystem::path ref, boost::filesystem::path check, double threshold)
{
extern void check_file (boost::filesystem::path ref, boost::filesystem::path check);
extern void check_wav_file (boost::filesystem::path ref, boost::filesystem::path check);
extern void check_mxf_audio_file (boost::filesystem::path ref, boost::filesystem::path check);
+extern bool mxf_atmos_files_same (boost::filesystem::path ref, boost::filesystem::path check, bool verbose = false);
extern void check_xml (boost::filesystem::path, boost::filesystem::path, std::list<std::string>);
extern void check_file (boost::filesystem::path, boost::filesystem::path);
extern void check_ffmpeg (boost::filesystem::path, boost::filesystem::path, int audio_tolerance);
obj.use = 'libdcpomatic2'
obj.source = """
4k_test.cc
+ atmos_test.cc
audio_analysis_test.cc
audio_buffers_test.cc
audio_delay_test.cc