uses it.
2018-07-20 Carl Hetherington <cth@carlh.net>
+ * Remove Join function.
+
* Advanced configuration option to allow any container ratio.
* Support closed-caption creation (#725).
}
}
-AudioContent::AudioContent (Content* parent, vector<shared_ptr<Content> > c)
- : ContentPart (parent)
-{
- shared_ptr<AudioContent> ref = c[0]->audio;
- DCPOMATIC_ASSERT (ref);
-
- for (size_t i = 1; i < c.size(); ++i) {
- if (c[i]->audio->gain() != ref->gain()) {
- throw JoinError (_("Content to be joined must have the same audio gain."));
- }
-
- if (c[i]->audio->delay() != ref->delay()) {
- throw JoinError (_("Content to be joined must have the same audio delay."));
- }
- }
-
- _gain = ref->gain ();
- _delay = ref->delay ();
- _streams = ref->streams ();
-}
-
void
AudioContent::as_xml (xmlpp::Node* node) const
{
{
public:
explicit AudioContent (Content* parent);
- AudioContent (Content* parent, std::vector<boost::shared_ptr<Content> >);
void as_xml (xmlpp::Node *) const;
std::string technical_summary () const;
_type = string_to_caption_type (node->optional_string_child("CaptionType").get_value_or("open"));
}
-CaptionContent::CaptionContent (Content* parent, vector<shared_ptr<Content> > c)
- : ContentPart (parent)
-{
- shared_ptr<CaptionContent> ref = c[0]->caption;
- DCPOMATIC_ASSERT (ref);
- list<shared_ptr<Font> > ref_fonts = ref->fonts ();
-
- for (size_t i = 1; i < c.size(); ++i) {
-
- if (c[i]->caption->use() != ref->use()) {
- throw JoinError (_("Content to be joined must have the same 'use subtitles' setting."));
- }
-
- if (c[i]->caption->burn() != ref->burn()) {
- throw JoinError (_("Content to be joined must have the same 'burn subtitles' setting."));
- }
-
- if (c[i]->caption->x_offset() != ref->x_offset()) {
- throw JoinError (_("Content to be joined must have the same subtitle X offset."));
- }
-
- if (c[i]->caption->y_offset() != ref->y_offset()) {
- throw JoinError (_("Content to be joined must have the same subtitle Y offset."));
- }
-
- if (c[i]->caption->x_scale() != ref->x_scale()) {
- throw JoinError (_("Content to be joined must have the same subtitle X scale."));
- }
-
- if (c[i]->caption->y_scale() != ref->y_scale()) {
- throw JoinError (_("Content to be joined must have the same subtitle Y scale."));
- }
-
- if (c[i]->caption->line_spacing() != ref->line_spacing()) {
- throw JoinError (_("Content to be joined must have the same subtitle line spacing."));
- }
-
- if ((c[i]->caption->fade_in() != ref->fade_in()) || (c[i]->caption->fade_out() != ref->fade_out())) {
- throw JoinError (_("Content to be joined must have the same subtitle fades."));
- }
-
- if ((c[i]->caption->outline_width() != ref->outline_width())) {
- throw JoinError (_("Content to be joined must have the same outline width."));
- }
-
- list<shared_ptr<Font> > fonts = c[i]->caption->fonts ();
- if (fonts.size() != ref_fonts.size()) {
- throw JoinError (_("Content to be joined must use the same fonts."));
- }
-
- list<shared_ptr<Font> >::const_iterator j = ref_fonts.begin ();
- list<shared_ptr<Font> >::const_iterator k = fonts.begin ();
-
- while (j != ref_fonts.end ()) {
- if (**j != **k) {
- throw JoinError (_("Content to be joined must use the same fonts."));
- }
- ++j;
- ++k;
- }
- }
-
- _use = ref->use ();
- _burn = ref->burn ();
- _x_offset = ref->x_offset ();
- _y_offset = ref->y_offset ();
- _x_scale = ref->x_scale ();
- _y_scale = ref->y_scale ();
- _language = ref->language ();
- _fonts = ref_fonts;
- _line_spacing = ref->line_spacing ();
- _fade_in = ref->fade_in ();
- _fade_out = ref->fade_out ();
- _outline_width = ref->outline_width ();
-
- connect_to_fonts ();
-}
/** _mutex must not be held on entry */
void
{
public:
explicit CaptionContent (Content* parent);
- CaptionContent (Content* parent, std::vector<boost::shared_ptr<Content> >);
void as_xml (xmlpp::Node *) const;
std::string identifier () const;
_video_frame_rate = node->optional_number_child<double> ("VideoFrameRate");
}
-Content::Content (shared_ptr<const Film> film, vector<shared_ptr<Content> > c)
- : _film (film)
- , _position (c.front()->position ())
- , _trim_start (c.front()->trim_start ())
- , _trim_end (c.back()->trim_end ())
- , _video_frame_rate (c.front()->video_frame_rate())
- , _change_signals_frequent (false)
-{
- for (size_t i = 0; i < c.size(); ++i) {
- if (i > 0 && c[i]->trim_start() > ContentTime ()) {
- throw JoinError (_("Only the first piece of content to be joined can have a start trim."));
- }
-
- if (i < (c.size() - 1) && c[i]->trim_end () > ContentTime ()) {
- throw JoinError (_("Only the last piece of content to be joined can have an end trim."));
- }
-
- if (
- (_video_frame_rate && !c[i]->_video_frame_rate) ||
- (!_video_frame_rate && c[i]->_video_frame_rate)
- ) {
- throw JoinError (_("Content to be joined must have the same video frame rate"));
- }
-
- if (_video_frame_rate && fabs (_video_frame_rate.get() - c[i]->_video_frame_rate.get()) > VIDEO_FRAME_RATE_EPSILON) {
- throw JoinError (_("Content to be joined must have the same video frame rate"));
- }
-
- for (size_t j = 0; j < c[i]->number_of_paths(); ++j) {
- _paths.push_back (c[i]->path (j));
- }
- }
-}
-
void
Content::as_xml (xmlpp::Node* node, bool with_paths) const
{
Content (boost::shared_ptr<const Film>, DCPTime);
Content (boost::shared_ptr<const Film>, boost::filesystem::path);
Content (boost::shared_ptr<const Film>, cxml::ConstNodePtr);
- Content (boost::shared_ptr<const Film>, std::vector<boost::shared_ptr<Content> >);
virtual ~Content () {}
/** Examine the content to establish digest, frame rates and any other
boost::filesystem::path _file;
};
-class JoinError : public std::runtime_error
-{
-public:
- explicit JoinError (std::string s)
- : std::runtime_error (s)
- {}
-};
-
/** @class OpenFileError.
* @brief Indicates that some error occurred when trying to open a file.
*/
}
-FFmpegContent::FFmpegContent (shared_ptr<const Film> film, vector<shared_ptr<Content> > c)
- : Content (film, c)
-{
- vector<shared_ptr<Content> >::const_iterator i = c.begin ();
-
- bool need_video = false;
- bool need_audio = false;
- bool need_caption = false;
-
- if (i != c.end ()) {
- need_video = static_cast<bool> ((*i)->video);
- need_audio = static_cast<bool> ((*i)->audio);
- need_caption = static_cast<bool> ((*i)->caption);
- }
-
- while (i != c.end ()) {
- if (need_video != static_cast<bool> ((*i)->video)) {
- throw JoinError (_("Content to be joined must all have or not have video"));
- }
- if (need_audio != static_cast<bool> ((*i)->audio)) {
- throw JoinError (_("Content to be joined must all have or not have audio"));
- }
- if (need_caption != static_cast<bool> ((*i)->caption)) {
- throw JoinError (_("Content to be joined must all have or not have captions"));
- }
- ++i;
- }
-
- if (need_video) {
- video.reset (new VideoContent (this, c));
- }
- if (need_audio) {
- audio.reset (new AudioContent (this, c));
- }
- if (need_caption) {
- caption.reset (new CaptionContent (this, c));
- }
-
- shared_ptr<FFmpegContent> ref = dynamic_pointer_cast<FFmpegContent> (c[0]);
- DCPOMATIC_ASSERT (ref);
-
- for (size_t i = 0; i < c.size(); ++i) {
- shared_ptr<FFmpegContent> fc = dynamic_pointer_cast<FFmpegContent> (c[i]);
- if (fc->caption && fc->caption->use() && *(fc->_subtitle_stream.get()) != *(ref->_subtitle_stream.get())) {
- throw JoinError (_("Content to be joined must use the same subtitle stream."));
- }
- }
-
- /* XXX: should probably check that more of the stuff below is the same in *this and ref */
-
- _subtitle_streams = ref->subtitle_streams ();
- _subtitle_stream = ref->subtitle_stream ();
- _first_video = ref->_first_video;
- _filters = ref->_filters;
- _color_range = ref->_color_range;
- _color_primaries = ref->_color_primaries;
- _color_trc = ref->_color_trc;
- _colorspace = ref->_colorspace;
- _bits_per_pixel = ref->_bits_per_pixel;
-}
-
void
FFmpegContent::as_xml (xmlpp::Node* node, bool with_paths) const
{
public:
FFmpegContent (boost::shared_ptr<const Film>, boost::filesystem::path);
FFmpegContent (boost::shared_ptr<const Film>, cxml::ConstNodePtr, int version, std::list<std::string> &);
- FFmpegContent (boost::shared_ptr<const Film>, std::vector<boost::shared_ptr<Content> >);
boost::shared_ptr<FFmpegContent> shared_from_this () {
return boost::dynamic_pointer_cast<FFmpegContent> (Content::shared_from_this ());
/*
- Copyright (C) 2013-2016 Carl Hetherington <cth@carlh.net>
+ Copyright (C) 2013-2018 Carl Hetherington <cth@carlh.net>
This file is part of DCP-o-matic.
}
}
-VideoContent::VideoContent (Content* parent, vector<shared_ptr<Content> > c)
- : ContentPart (parent)
- , _length (0)
- , _yuv (false)
-{
- shared_ptr<VideoContent> ref = c[0]->video;
- DCPOMATIC_ASSERT (ref);
-
- for (size_t i = 1; i < c.size(); ++i) {
-
- if (c[i]->video->size() != ref->size()) {
- throw JoinError (_("Content to be joined must have the same picture size."));
- }
-
- if (c[i]->video->frame_type() != ref->frame_type()) {
- throw JoinError (_("Content to be joined must have the same video frame type."));
- }
-
- if (c[i]->video->crop() != ref->crop()) {
- throw JoinError (_("Content to be joined must have the same crop."));
- }
-
- if (c[i]->video->scale() != ref->scale()) {
- throw JoinError (_("Content to be joined must have the same scale setting."));
- }
-
- if (c[i]->video->colour_conversion() != ref->colour_conversion()) {
- throw JoinError (_("Content to be joined must have the same colour conversion."));
- }
-
- if (c[i]->video->fade_in() != ref->fade_in() || c[i]->video->fade_out() != ref->fade_out()) {
- throw JoinError (_("Content to be joined must have the same fades."));
- }
-
- _length += c[i]->video->length ();
-
- if (c[i]->video->yuv ()) {
- _yuv = true;
- }
- }
-
- _size = ref->size ();
- _frame_type = ref->frame_type ();
- _crop = ref->crop ();
- _scale = ref->scale ();
- _colour_conversion = ref->colour_conversion ();
- _fade_in = ref->fade_in ();
- _fade_out = ref->fade_out ();
-}
-
void
VideoContent::as_xml (xmlpp::Node* node) const
{
/*
- Copyright (C) 2013-2016 Carl Hetherington <cth@carlh.net>
+ Copyright (C) 2013-2018 Carl Hetherington <cth@carlh.net>
This file is part of DCP-o-matic.
{
public:
explicit VideoContent (Content* parent);
- VideoContent (Content* parent, std::vector<boost::shared_ptr<Content> >);
void as_xml (xmlpp::Node *) const;
std::string technical_summary () const;
enum {
/* Start at 256 so we can have IDs on _cpl_menu from 1 to 255 */
ID_repeat = 256,
- ID_join,
ID_find_missing,
ID_properties,
ID_re_examine,
, _pop_up_open (false)
{
_repeat = _menu->Append (ID_repeat, _("Repeat..."));
- _join = _menu->Append (ID_join, _("Join"));
_find_missing = _menu->Append (ID_find_missing, _("Find missing..."));
_properties = _menu->Append (ID_properties, _("Properties..."));
_re_examine = _menu->Append (ID_re_examine, _("Re-examine..."));
_remove = _menu->Append (ID_remove, _("Remove"));
_parent->Bind (wxEVT_MENU, boost::bind (&ContentMenu::repeat, this), ID_repeat);
- _parent->Bind (wxEVT_MENU, boost::bind (&ContentMenu::join, this), ID_join);
_parent->Bind (wxEVT_MENU, boost::bind (&ContentMenu::find_missing, this), ID_find_missing);
_parent->Bind (wxEVT_MENU, boost::bind (&ContentMenu::properties, this), ID_properties);
_parent->Bind (wxEVT_MENU, boost::bind (&ContentMenu::re_examine, this), ID_re_examine);
}
}
- _join->Enable (n > 1);
-
_find_missing->Enable (_content.size() == 1 && !_content.front()->paths_valid ());
_properties->Enable (_content.size() == 1);
_re_examine->Enable (!_content.empty ());
_views.clear ();
}
-void
-ContentMenu::join ()
-{
- vector<shared_ptr<Content> > fc;
- BOOST_FOREACH (shared_ptr<Content> i, _content) {
- shared_ptr<FFmpegContent> f = dynamic_pointer_cast<FFmpegContent> (i);
- if (f) {
- fc.push_back (f);
- }
- }
-
- DCPOMATIC_ASSERT (fc.size() > 1);
-
- shared_ptr<Film> film = _film.lock ();
- if (!film) {
- return;
- }
-
- try {
- shared_ptr<FFmpegContent> joined (new FFmpegContent (film, fc));
- film->remove_content (_content);
- film->examine_and_add_content (joined);
- } catch (JoinError& e) {
- error_dialog (_parent, std_to_wx (e.what ()));
- }
-}
-
void
ContentMenu::remove ()
{
private:
void repeat ();
- void join ();
void find_missing ();
void properties ();
void re_examine ();
ContentList _content;
TimelineContentViewList _views;
wxMenuItem* _repeat;
- wxMenuItem* _join;
wxMenuItem* _find_missing;
wxMenuItem* _properties;
wxMenuItem* _re_examine;