/*
- Copyright (C) 2013-2015 Carl Hetherington <cth@carlh.net>
+ Copyright (C) 2013-2016 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 "ffmpeg_content.h"
+#include "video_content.h"
#include "ffmpeg_examiner.h"
#include "ffmpeg_subtitle_stream.h"
#include "ffmpeg_audio_stream.h"
#include <libavformat/avformat.h>
#include <libavutil/pixdesc.h>
}
+#include <libxml++/libxml++.h>
#include <boost/foreach.hpp>
+#include <iostream>
#include "i18n.h"
-#define LOG_GENERAL(...) film->log()->log (String::compose (__VA_ARGS__), Log::TYPE_GENERAL);
+#define LOG_GENERAL(...) film->log()->log (String::compose (__VA_ARGS__), LogEntry::TYPE_GENERAL);
using std::string;
using std::vector;
FFmpegContent::FFmpegContent (shared_ptr<const Film> film, boost::filesystem::path p)
: Content (film, p)
- , VideoContent (film, p)
, AudioContent (film, p)
, SubtitleContent (film, p)
+ , video (new VideoContent (film))
{
-
+ set_default_colour_conversion ();
}
FFmpegContent::FFmpegContent (shared_ptr<const Film> film, cxml::ConstNodePtr node, int version, list<string>& notes)
: Content (film, node)
- , VideoContent (film, node, version)
, AudioContent (film, node)
, SubtitleContent (film, node, version)
+ , video (new VideoContent (film, node, version))
{
list<cxml::NodePtr> c = node->node_children ("SubtitleStream");
for (list<cxml::NodePtr>::const_iterator i = c.begin(); i != c.end(); ++i) {
- _subtitle_streams.push_back (shared_ptr<FFmpegSubtitleStream> (new FFmpegSubtitleStream (*i)));
+ _subtitle_streams.push_back (shared_ptr<FFmpegSubtitleStream> (new FFmpegSubtitleStream (*i, version)));
if ((*i)->optional_number_child<int> ("Selected")) {
_subtitle_stream = _subtitle_streams.back ();
}
FFmpegContent::FFmpegContent (shared_ptr<const Film> film, vector<boost::shared_ptr<Content> > c)
: Content (film, c)
- , VideoContent (film, c)
, AudioContent (film, c)
, SubtitleContent (film, c)
+ , video (new VideoContent (film, c))
{
shared_ptr<FFmpegContent> ref = dynamic_pointer_cast<FFmpegContent> (c[0]);
DCPOMATIC_ASSERT (ref);
}
}
+ /* 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 ();
_audio_streams = ref->ffmpeg_audio_streams ();
_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
{
node->add_child("Type")->add_child_text ("FFmpeg");
Content::as_xml (node);
- VideoContent::as_xml (node);
+ video->as_xml (node);
AudioContent::as_xml (node);
SubtitleContent::as_xml (node);
shared_ptr<FFmpegExaminer> examiner (new FFmpegExaminer (shared_from_this (), job));
take_from_video_examiner (examiner);
-
- shared_ptr<const Film> film = _film.lock ();
- DCPOMATIC_ASSERT (film);
+ set_default_colour_conversion ();
{
boost::mutex::scoped_lock lm (_mutex);
if (!_audio_streams.empty ()) {
AudioMapping m = _audio_streams.front()->mapping ();
- film->make_audio_mapping_default (m);
+ film()->make_audio_mapping_default (m);
_audio_streams.front()->set_mapping (m);
}
string filt = Filter::ffmpeg_string (_filters);
return Content::technical_summary() + " - "
- + VideoContent::technical_summary() + " - "
+ + video->technical_summary() + " - "
+ AudioContent::technical_summary() + " - "
+ String::compose (
"ffmpeg: audio %1 subtitle %2 filters %3", as, ss, filt
DCPTime
FFmpegContent::full_length () const
{
- shared_ptr<const Film> film = _film.lock ();
- DCPOMATIC_ASSERT (film);
- FrameRateChange const frc (video_frame_rate (), film->video_frame_rate ());
- return DCPTime::from_frames (rint (video_length_after_3d_combine() * frc.factor()), film->video_frame_rate());
+ FrameRateChange const frc (video_frame_rate (), film()->video_frame_rate ());
+ return DCPTime::from_frames (llrint (video_length_after_3d_combine() * frc.factor()), film()->video_frame_rate());
}
void
{
SafeStringStream s;
- s << VideoContent::identifier() << "_"
+ s << Content::identifier() << "_"
+ << video->identifier() << "_"
<< SubtitleContent::identifier();
boost::mutex::scoped_lock lm (_mutex);
}
list<ContentTimePeriod>
-FFmpegContent::subtitles_during (ContentTimePeriod period, bool starting) const
+FFmpegContent::image_subtitles_during (ContentTimePeriod period, bool starting) const
+{
+ shared_ptr<FFmpegSubtitleStream> stream = subtitle_stream ();
+ if (!stream) {
+ return list<ContentTimePeriod> ();
+ }
+
+ return stream->image_subtitles_during (period, starting);
+}
+
+list<ContentTimePeriod>
+FFmpegContent::text_subtitles_during (ContentTimePeriod period, bool starting) const
{
shared_ptr<FFmpegSubtitleStream> stream = subtitle_stream ();
if (!stream) {
return list<ContentTimePeriod> ();
}
- return stream->subtitles_during (period, starting);
+ return stream->text_subtitles_during (period, starting);
}
bool
-FFmpegContent::has_text_subtitles () const
+FFmpegContent::has_image_subtitles () const
{
+ BOOST_FOREACH (shared_ptr<FFmpegSubtitleStream> i, subtitle_streams()) {
+ if (i->has_image_subtitles()) {
+ return true;
+ }
+ }
+
return false;
}
bool
-FFmpegContent::has_image_subtitles () const
+FFmpegContent::has_text_subtitles () const
{
- return !subtitle_streams().empty ();
+ BOOST_FOREACH (shared_ptr<FFmpegSubtitleStream> i, subtitle_streams()) {
+ if (i->has_text_subtitles()) {
+ return true;
+ }
+ }
+
+ return false;
}
void
}
void
-FFmpegContent::add_properties (list<pair<string, string> >& p) const
+FFmpegContent::add_properties (list<UserProperty>& p) const
{
- VideoContent::add_properties (p);
+ Content::add_properties (p);
+ video->add_properties (p);
+ AudioContent::add_properties (p);
if (_bits_per_pixel) {
int const sub = 219 * pow (2, _bits_per_pixel.get() - 8);
switch (_color_range) {
case AVCOL_RANGE_UNSPECIFIED:
- p.push_back (make_pair (_("Colour range"), _("Unspecified")));
+ /// TRANSLATORS: this means that the range of pixel values used in this
+ /// file is unknown (not specified in the file).
+ p.push_back (UserProperty (_("Video"), _("Colour range"), _("Unspecified")));
break;
case AVCOL_RANGE_MPEG:
- p.push_back (make_pair (_("Colour range"), String::compose (_("Limited (%1-%2)"), (total - sub) / 2, (total + sub) / 2)));
+ /// TRANSLATORS: this means that the range of pixel values used in this
+ /// file is limited, so that not all possible values are valid.
+ p.push_back (
+ UserProperty (
+ _("Video"), _("Colour range"), String::compose (_("Limited (%1-%2)"), (total - sub) / 2, (total + sub) / 2)
+ )
+ );
break;
case AVCOL_RANGE_JPEG:
- p.push_back (make_pair (_("Colour range"), String::compose (_("Full (0-%1)"), total)));
+ /// TRANSLATORS: this means that the range of pixel values used in this
+ /// file is full, so that all possible pixel values are valid.
+ p.push_back (UserProperty (_("Video"), _("Colour range"), String::compose (_("Full (0-%1)"), total)));
break;
default:
DCPOMATIC_ASSERT (false);
} else {
switch (_color_range) {
case AVCOL_RANGE_UNSPECIFIED:
- p.push_back (make_pair (_("Colour range"), _("Unspecified")));
+ /// TRANSLATORS: this means that the range of pixel values used in this
+ /// file is unknown (not specified in the file).
+ p.push_back (UserProperty (_("Video"), _("Colour range"), _("Unspecified")));
break;
case AVCOL_RANGE_MPEG:
- p.push_back (make_pair (_("Colour range"), _("Limited")));
+ /// TRANSLATORS: this means that the range of pixel values used in this
+ /// file is limited, so that not all possible values are valid.
+ p.push_back (UserProperty (_("Video"), _("Colour range"), _("Limited")));
break;
case AVCOL_RANGE_JPEG:
- p.push_back (make_pair (_("Colour range"), _("Full")));
+ /// TRANSLATORS: this means that the range of pixel values used in this
+ /// file is full, so that all possible pixel values are valid.
+ p.push_back (UserProperty (_("Video"), _("Colour range"), _("Full")));
break;
default:
DCPOMATIC_ASSERT (false);
_("SMPTE 170M (BT601)"),
_("SMPTE 240M"),
_("Film"),
- _("BT2020")
+ _("BT2020"),
+ _("SMPTE ST 428-1 (CIE 1931 XYZ)")
};
- DCPOMATIC_ASSERT (AVCOL_PRI_NB == 10);
- p.push_back (make_pair (_("Colour primaries"), primaries[_color_primaries]));
+ DCPOMATIC_ASSERT (AVCOL_PRI_NB == 11);
+ p.push_back (UserProperty (_("Video"), _("Colour primaries"), primaries[_color_primaries]));
char const * transfers[] = {
_("Unspecified"),
_("BT1361 extended colour gamut"),
_("IEC61966-2-1 (sRGB or sYCC)"),
_("BT2020 for a 10-bit system"),
- _("BT2020 for a 12-bit system")
+ _("BT2020 for a 12-bit system"),
+ _("SMPTE ST 2084 for 10, 12, 14 and 16 bit systems"),
+ _("SMPTE ST 428-1")
};
- DCPOMATIC_ASSERT (AVCOL_TRC_NB == 16);
- p.push_back (make_pair (_("Colour transfer characteristic"), transfers[_color_trc]));
+ DCPOMATIC_ASSERT (AVCOL_TRC_NB == 18);
+ p.push_back (UserProperty (_("Video"), _("Colour transfer characteristic"), transfers[_color_trc]));
char const * spaces[] = {
_("RGB / sRGB (IEC61966-2-1)"),
};
DCPOMATIC_ASSERT (AVCOL_SPC_NB == 11);
- p.push_back (make_pair (_("Colourspace"), spaces[_colorspace]));
+ p.push_back (UserProperty (_("Video"), _("Colourspace"), spaces[_colorspace]));
if (_bits_per_pixel) {
- p.push_back (make_pair (_("Bits per pixel"), raw_convert<string> (_bits_per_pixel.get ())));
+ p.push_back (UserProperty (_("Video"), _("Bits per pixel"), raw_convert<string> (_bits_per_pixel.get ())));
}
}
+
+/** Our subtitle streams have colour maps, which can be changed, but
+ * they have no way of signalling that change. As a hack, we have this
+ * method which callers can use when they've modified one of our subtitle
+ * streams.
+ */
+void
+FFmpegContent::signal_subtitle_stream_changed ()
+{
+ signal_changed (FFmpegContentProperty::SUBTITLE_STREAM);
+}
+
+double
+FFmpegContent::subtitle_video_frame_rate () const
+{
+ return video->video_frame_rate ();
+}