X-Git-Url: https://git.carlh.net/gitweb/?a=blobdiff_plain;f=src%2Flib%2Fffmpeg_content.cc;h=6681a4f0a897aa6c6c9de3c192c1cad434d69a8c;hb=1671e097a24cd169f1ad4ea89b0cb3ae105b1e70;hp=7f1c75a936915d3ea440cd24ccb4b6c2ffde2e75;hpb=8fedaaa75c4586a4cc7ffb393bd71d1fdb091dc8;p=dcpomatic.git diff --git a/src/lib/ffmpeg_content.cc b/src/lib/ffmpeg_content.cc index 7f1c75a93..6681a4f0a 100644 --- a/src/lib/ffmpeg_content.cc +++ b/src/lib/ffmpeg_content.cc @@ -16,24 +16,25 @@ You should have received a copy of the GNU General Public License along with DCP-o-matic. If not, see . + */ -#include "ffmpeg_content.h" -#include "video_content.h" #include "audio_content.h" -#include "ffmpeg_examiner.h" -#include "ffmpeg_subtitle_stream.h" -#include "ffmpeg_audio_stream.h" #include "compose.hpp" -#include "job.h" -#include "util.h" -#include "filter.h" -#include "film.h" -#include "log.h" #include "config.h" +#include "constants.h" #include "exceptions.h" +#include "ffmpeg_audio_stream.h" +#include "ffmpeg_content.h" +#include "ffmpeg_examiner.h" +#include "ffmpeg_subtitle_stream.h" +#include "film.h" +#include "filter.h" #include "frame_rate_change.h" +#include "job.h" +#include "log.h" #include "text_content.h" +#include "video_content.h" #include #include extern "C" { @@ -45,6 +46,7 @@ extern "C" { #include "i18n.h" + using std::string; using std::vector; using std::list; @@ -59,17 +61,20 @@ using boost::optional; using dcp::raw_convert; using namespace dcpomatic; + int const FFmpegContentProperty::SUBTITLE_STREAMS = 100; int const FFmpegContentProperty::SUBTITLE_STREAM = 101; int const FFmpegContentProperty::FILTERS = 102; int const FFmpegContentProperty::KDM = 103; + FFmpegContent::FFmpegContent (boost::filesystem::path p) : Content (p) { } + template optional get_optional_enum (cxml::ConstNodePtr node, string name) @@ -81,12 +86,17 @@ get_optional_enum (cxml::ConstNodePtr node, string name) return static_cast(*v); } + FFmpegContent::FFmpegContent (cxml::ConstNodePtr node, int version, list& notes) : Content (node) { - video = VideoContent::from_xml (this, node, version); + _color_range = get_optional_enum(node, "ColorRange"); + + VideoRange const video_range_hint = (_color_range && *_color_range == AVCOL_RANGE_JPEG) ? VideoRange::FULL : VideoRange::VIDEO; + + video = VideoContent::from_xml (this, node, version, video_range_hint); audio = AudioContent::from_xml (this, node, version); - text = TextContent::from_xml (this, node, version); + text = TextContent::from_xml (this, node, version, notes); for (auto i: node->node_children("SubtitleStream")) { _subtitle_streams.push_back (make_shared(i, version)); @@ -118,14 +128,14 @@ FFmpegContent::FFmpegContent (cxml::ConstNodePtr node, int version, list _first_video = ContentTime (f.get ()); } - _color_range = get_optional_enum(node, "ColorRange"); _color_primaries = get_optional_enum(node, "ColorPrimaries"); _color_trc = get_optional_enum(node, "ColorTransferCharacteristic"); _colorspace = get_optional_enum(node, "Colorspace"); _bits_per_pixel = node->optional_number_child ("BitsPerPixel"); } -FFmpegContent::FFmpegContent (vector > c) + +FFmpegContent::FFmpegContent (vector> c) : Content (c) { auto i = c.begin (); @@ -186,10 +196,11 @@ FFmpegContent::FFmpegContent (vector > c) _bits_per_pixel = ref->_bits_per_pixel; } + void FFmpegContent::as_xml (xmlpp::Node* node, bool with_paths) const { - node->add_child("Type")->add_child_text ("FFmpeg"); + node->add_child("Type")->add_child_text("FFmpeg"); Content::as_xml (node, with_paths); if (video) { @@ -199,7 +210,7 @@ FFmpegContent::as_xml (xmlpp::Node* node, bool with_paths) const if (audio) { audio->as_xml (node); - for (auto i: audio->streams ()) { + for (auto i: audio->streams()) { auto f = dynamic_pointer_cast (i); DCPOMATIC_ASSERT (f); f->as_xml (node->add_child("AudioStream")); @@ -225,31 +236,32 @@ FFmpegContent::as_xml (xmlpp::Node* node, bool with_paths) const } if (_first_video) { - node->add_child("FirstVideo")->add_child_text (raw_convert (_first_video.get().get())); + node->add_child("FirstVideo")->add_child_text(raw_convert(_first_video.get().get())); } if (_color_range) { - node->add_child("ColorRange")->add_child_text (raw_convert (static_cast (*_color_range))); + node->add_child("ColorRange")->add_child_text(raw_convert(static_cast(*_color_range))); } if (_color_primaries) { - node->add_child("ColorPrimaries")->add_child_text (raw_convert (static_cast (*_color_primaries))); + node->add_child("ColorPrimaries")->add_child_text(raw_convert(static_cast(*_color_primaries))); } if (_color_trc) { - node->add_child("ColorTransferCharacteristic")->add_child_text (raw_convert (static_cast (*_color_trc))); + node->add_child("ColorTransferCharacteristic")->add_child_text(raw_convert(static_cast(*_color_trc))); } if (_colorspace) { - node->add_child("Colorspace")->add_child_text (raw_convert (static_cast (*_colorspace))); + node->add_child("Colorspace")->add_child_text(raw_convert(static_cast(*_colorspace))); } if (_bits_per_pixel) { - node->add_child("BitsPerPixel")->add_child_text (raw_convert (*_bits_per_pixel)); + node->add_child("BitsPerPixel")->add_child_text(raw_convert(*_bits_per_pixel)); } } + void FFmpegContent::examine (shared_ptr film, shared_ptr job) { - ChangeSignaller cc1 (this, FFmpegContentProperty::SUBTITLE_STREAMS); - ChangeSignaller cc2 (this, FFmpegContentProperty::SUBTITLE_STREAM); + ContentChangeSignaller cc1 (this, FFmpegContentProperty::SUBTITLE_STREAMS); + ContentChangeSignaller cc2 (this, FFmpegContentProperty::SUBTITLE_STREAM); if (job) { job->set_progress_unknown (); @@ -261,7 +273,7 @@ FFmpegContent::examine (shared_ptr film, shared_ptr job) if (examiner->has_video ()) { video.reset (new VideoContent (this)); - video->take_from_examiner (examiner); + video->take_from_examiner(film, examiner); } auto first_path = path (0); @@ -290,7 +302,7 @@ FFmpegContent::examine (shared_ptr film, shared_ptr job) } } - if (!examiner->audio_streams().empty ()) { + if (!examiner->audio_streams().empty()) { audio = make_shared(this); for (auto i: examiner->audio_streams()) { @@ -308,6 +320,7 @@ FFmpegContent::examine (shared_ptr film, shared_ptr job) text.clear (); text.push_back (make_shared(this, TextType::OPEN_SUBTITLE, TextType::UNKNOWN)); _subtitle_stream = _subtitle_streams.front (); + text.front()->add_font(make_shared("")); } } @@ -319,25 +332,27 @@ FFmpegContent::examine (shared_ptr film, shared_ptr job) /* FFmpeg has detected this file as 29.97 and the examiner thinks it is using "soft" 2:3 pulldown (telecine). * This means we can treat it as a 23.976fps file. */ - set_video_frame_rate (24000.0 / 1001); + set_video_frame_rate(film, 24000.0 / 1001); video->set_length (video->length() * 24.0 / 30); } } + string FFmpegContent::summary () const { if (video && audio) { - return String::compose (_("%1 [movie]"), path_summary ()); + return String::compose (_("%1 [movie]"), path_summary()); } else if (video) { - return String::compose (_("%1 [video]"), path_summary ()); + return String::compose (_("%1 [video]"), path_summary()); } else if (audio) { - return String::compose (_("%1 [audio]"), path_summary ()); + return String::compose (_("%1 [audio]"), path_summary()); } return path_summary (); } + string FFmpegContent::technical_summary () const { @@ -372,10 +387,11 @@ FFmpegContent::technical_summary () const ); } + void FFmpegContent::set_subtitle_stream (shared_ptr s) { - ChangeSignaller cc (this, FFmpegContentProperty::SUBTITLE_STREAM); + ContentChangeSignaller cc (this, FFmpegContentProperty::SUBTITLE_STREAM); { boost::mutex::scoped_lock lm (_mutex); @@ -383,18 +399,21 @@ FFmpegContent::set_subtitle_stream (shared_ptr s) } } + bool operator== (FFmpegStream const & a, FFmpegStream const & b) { return a._id == b._id; } + bool operator!= (FFmpegStream const & a, FFmpegStream const & b) { return a._id != b._id; } + DCPTime FFmpegContent::full_length (shared_ptr film) const { @@ -413,9 +432,10 @@ FFmpegContent::full_length (shared_ptr film) const /* XXX: subtitle content? */ - return DCPTime(); + return {}; } + DCPTime FFmpegContent::approximate_length () const { @@ -433,10 +453,11 @@ FFmpegContent::approximate_length () const return DCPTime::from_frames (longest, 24); } + void FFmpegContent::set_filters (vector const & filters) { - ChangeSignaller cc (this, FFmpegContentProperty::FILTERS); + ContentChangeSignaller cc (this, FFmpegContentProperty::FILTERS); { boost::mutex::scoped_lock lm (_mutex); @@ -444,6 +465,7 @@ FFmpegContent::set_filters (vector const & filters) } } + string FFmpegContent::identifier () const { @@ -470,6 +492,7 @@ FFmpegContent::identifier () const return s; } + void FFmpegContent::set_default_colour_conversion () { @@ -505,6 +528,7 @@ FFmpegContent::set_default_colour_conversion () } } + void FFmpegContent::add_properties (shared_ptr film, list& p) const { @@ -514,10 +538,12 @@ FFmpegContent::add_properties (shared_ptr film, list& video->add_properties (p); if (_bits_per_pixel) { - /* Assuming there's three components, so bits per pixel component is _bits_per_pixel / 3 */ - int const lim_start = pow(2, _bits_per_pixel.get() / 3 - 4); - int const lim_end = 235 * pow(2, _bits_per_pixel.get() / 3 - 8); - int const total = pow(2, _bits_per_pixel.get() / 3); + auto pixel_quanta_product = video->pixel_quanta().x * video->pixel_quanta().y; + auto bits_per_main_pixel = pixel_quanta_product * _bits_per_pixel.get() / (pixel_quanta_product + 2); + + int const lim_start = pow(2, bits_per_main_pixel - 4); + int const lim_end = 235 * pow(2, bits_per_main_pixel - 8); + int const total = pow(2, bits_per_main_pixel); switch (_color_range.get_value_or(AVCOL_RANGE_UNSPECIFIED)) { case AVCOL_RANGE_UNSPECIFIED: @@ -530,14 +556,14 @@ FFmpegContent::add_properties (shared_ptr film, list& /// file is limited, so that not all possible values are valid. p.push_back ( UserProperty ( - UserProperty::VIDEO, _("Colour range"), String::compose(_("Limited (%1-%2)"), lim_start, lim_end) + UserProperty::VIDEO, _("Colour range"), String::compose(_("Limited / video (%1-%2)"), lim_start, lim_end) ) ); break; case AVCOL_RANGE_JPEG: /// 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 (UserProperty::VIDEO, _("Colour range"), String::compose (_("Full (0-%1)"), total))); + p.push_back(UserProperty(UserProperty::VIDEO, _("Colour range"), String::compose(_("Full (0-%1)"), total - 1))); break; default: DCPOMATIC_ASSERT (false); @@ -649,6 +675,7 @@ FFmpegContent::add_properties (shared_ptr film, list& } } + /** 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 @@ -658,23 +685,25 @@ void FFmpegContent::signal_subtitle_stream_changed () { /* XXX: this is too late; really it should be before the change */ - ChangeSignaller cc (this, FFmpegContentProperty::SUBTITLE_STREAM); + ContentChangeSignaller cc (this, FFmpegContentProperty::SUBTITLE_STREAM); } -vector > + +vector> FFmpegContent::ffmpeg_audio_streams () const { - vector > fa; + vector> fa; if (audio) { for (auto i: audio->streams()) { - fa.push_back (dynamic_pointer_cast (i)); + fa.push_back (dynamic_pointer_cast(i)); } } return fa; } + void FFmpegContent::take_settings_from (shared_ptr c) {