X-Git-Url: https://git.carlh.net/gitweb/?a=blobdiff_plain;f=src%2Flib%2Fffmpeg_content.cc;h=64da0b1af0b71d2f8e8d6909655a8ed08a896e41;hb=249ae25148213a2ab5d76980133182e7f2521524;hp=ebe11748a036ac9152bbd7f6c06e37d564a197a8;hpb=3828baf56467224f5d44049bf1e7a7ed11f43a05;p=dcpomatic.git diff --git a/src/lib/ffmpeg_content.cc b/src/lib/ffmpeg_content.cc index ebe11748a..64da0b1af 100644 --- a/src/lib/ffmpeg_content.cc +++ b/src/lib/ffmpeg_content.cc @@ -32,9 +32,8 @@ #include "log.h" #include "exceptions.h" #include "frame_rate_change.h" -#include "safe_stringstream.h" -#include "raw_convert.h" #include "subtitle_content.h" +#include #include extern "C" { #include @@ -54,9 +53,11 @@ using std::list; using std::cout; using std::pair; using std::make_pair; +using std::max; using boost::shared_ptr; using boost::dynamic_pointer_cast; using boost::optional; +using dcp::raw_convert; int const FFmpegContentProperty::SUBTITLE_STREAMS = 100; int const FFmpegContentProperty::SUBTITLE_STREAM = 101; @@ -72,7 +73,7 @@ FFmpegContent::FFmpegContent (shared_ptr film, cxml::ConstNodePtr no : Content (film, node) { video = VideoContent::from_xml (this, node, version); - audio = AudioContent::from_xml (this, node); + audio = AudioContent::from_xml (this, node, version); subtitle = SubtitleContent::from_xml (this, node, version); list c = node->node_children ("SubtitleStream"); @@ -118,19 +119,50 @@ FFmpegContent::FFmpegContent (shared_ptr film, cxml::ConstNodePtr no } -FFmpegContent::FFmpegContent (shared_ptr film, vector > c) +FFmpegContent::FFmpegContent (shared_ptr film, vector > c) : Content (film, c) { - video.reset (new VideoContent (this, c)); - audio.reset (new AudioContent (this, c)); - subtitle.reset (new SubtitleContent (this, c)); + vector >::const_iterator i = c.begin (); + + bool need_video = false; + bool need_audio = false; + bool need_subtitle = false; + + if (i != c.end ()) { + need_video = static_cast ((*i)->video); + need_audio = static_cast ((*i)->audio); + need_subtitle = static_cast ((*i)->subtitle); + } + + while (i != c.end ()) { + if (need_video != static_cast ((*i)->video)) { + throw JoinError (_("Content to be joined must all have or not have video")); + } + if (need_audio != static_cast ((*i)->audio)) { + throw JoinError (_("Content to be joined must all have or not have audio")); + } + if (need_subtitle != static_cast ((*i)->subtitle)) { + throw JoinError (_("Content to be joined must all have or not have subtitles")); + } + ++i; + } + + if (need_video) { + video.reset (new VideoContent (this, c)); + } + if (need_audio) { + audio.reset (new AudioContent (this, c)); + } + if (need_subtitle) { + subtitle.reset (new SubtitleContent (this, c)); + } shared_ptr ref = dynamic_pointer_cast (c[0]); DCPOMATIC_ASSERT (ref); for (size_t i = 0; i < c.size(); ++i) { shared_ptr fc = dynamic_pointer_cast (c[i]); - if (fc->subtitle->use() && *(fc->_subtitle_stream.get()) != *(ref->_subtitle_stream.get())) { + if (fc->subtitle && fc->subtitle->use() && *(fc->_subtitle_stream.get()) != *(ref->_subtitle_stream.get())) { throw JoinError (_("Content to be joined must use the same subtitle stream.")); } } @@ -149,10 +181,10 @@ FFmpegContent::FFmpegContent (shared_ptr film, vectoradd_child("Type")->add_child_text ("FFmpeg"); - Content::as_xml (node); + Content::as_xml (node, with_paths); if (video) { video->as_xml (node); @@ -190,10 +222,10 @@ FFmpegContent::as_xml (xmlpp::Node* node) const node->add_child("FirstVideo")->add_child_text (raw_convert (_first_video.get().get())); } - node->add_child("ColorRange")->add_child_text (raw_convert (_color_range)); - node->add_child("ColorPrimaries")->add_child_text (raw_convert (_color_primaries)); - node->add_child("ColorTransferCharacteristic")->add_child_text (raw_convert (_color_trc)); - node->add_child("Colorspace")->add_child_text (raw_convert (_colorspace)); + node->add_child("ColorRange")->add_child_text (raw_convert (static_cast (_color_range))); + node->add_child("ColorPrimaries")->add_child_text (raw_convert (static_cast (_color_primaries))); + node->add_child("ColorTransferCharacteristic")->add_child_text (raw_convert (static_cast (_color_trc))); + 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.get ())); } @@ -211,9 +243,10 @@ FFmpegContent::examine (shared_ptr job) if (examiner->has_video ()) { video.reset (new VideoContent (this)); video->take_from_examiner (examiner); - set_default_colour_conversion (); } + boost::filesystem::path first_path = path (0); + { boost::mutex::scoped_lock lm (_mutex); @@ -235,7 +268,7 @@ FFmpegContent::examine (shared_ptr job) AudioStreamPtr as = audio->streams().front(); AudioMapping m = as->mapping (); - film()->make_audio_mapping_default (m); + film()->make_audio_mapping_default (m, first_path); as->set_mapping (m); } @@ -247,6 +280,10 @@ FFmpegContent::examine (shared_ptr job) } + if (examiner->has_video ()) { + set_default_colour_conversion (); + } + signal_changed (FFmpegContentProperty::SUBTITLE_STREAMS); signal_changed (FFmpegContentProperty::SUBTITLE_STREAM); } @@ -331,7 +368,13 @@ FFmpegContent::full_length () const } DCPOMATIC_ASSERT (audio); - return DCPTime::from_frames (llrint (audio->stream()->length() / frc.speed_up), audio->stream()->frame_rate()); + + DCPTime longest; + BOOST_FOREACH (AudioStreamPtr i, audio->streams ()) { + longest = max (longest, DCPTime::from_frames (llrint (i->length() / frc.speed_up), i->frame_rate())); + } + + return longest; } void @@ -348,64 +391,61 @@ FFmpegContent::set_filters (vector const & filters) string FFmpegContent::identifier () const { - SafeStringStream s; - - s << Content::identifier(); + string s = Content::identifier(); if (video) { - s << "_" << video->identifier(); + s += "_" + video->identifier(); } - if (subtitle) { - s << "_" << subtitle->identifier(); + if (subtitle && subtitle->use() && subtitle->burn()) { + s += "_" + subtitle->identifier(); } boost::mutex::scoped_lock lm (_mutex); if (_subtitle_stream) { - s << "_" << _subtitle_stream->identifier (); + s += "_" + _subtitle_stream->identifier (); } for (vector::const_iterator i = _filters.begin(); i != _filters.end(); ++i) { - s << "_" << (*i)->id (); - } - - return s.str (); -} - -list -FFmpegContent::image_subtitles_during (ContentTimePeriod period, bool starting) const -{ - shared_ptr stream = subtitle_stream (); - if (!stream) { - return list (); - } - - return stream->image_subtitles_during (period, starting); -} - -list -FFmpegContent::text_subtitles_during (ContentTimePeriod period, bool starting) const -{ - shared_ptr stream = subtitle_stream (); - if (!stream) { - return list (); + s += "_" + (*i)->id (); } - return stream->text_subtitles_during (period, starting); + return s; } void FFmpegContent::set_default_colour_conversion () { + DCPOMATIC_ASSERT (video); + dcp::Size const s = video->size (); boost::mutex::scoped_lock lm (_mutex); - if (s.width < 1080) { - video->set_colour_conversion (PresetColourConversion::from_id ("rec601").conversion); - } else { + switch (_colorspace) { + case AVCOL_SPC_RGB: + video->set_colour_conversion (PresetColourConversion::from_id ("srgb").conversion); + break; + case AVCOL_SPC_BT709: video->set_colour_conversion (PresetColourConversion::from_id ("rec709").conversion); + break; + case AVCOL_SPC_BT470BG: + case AVCOL_SPC_SMPTE170M: + case AVCOL_SPC_SMPTE240M: + video->set_colour_conversion (PresetColourConversion::from_id ("rec601").conversion); + break; + case AVCOL_SPC_BT2020_CL: + case AVCOL_SPC_BT2020_NCL: + video->set_colour_conversion (PresetColourConversion::from_id ("rec2020").conversion); + break; + default: + if (s.width < 1080) { + video->set_colour_conversion (PresetColourConversion::from_id ("rec601").conversion); + } else { + video->set_colour_conversion (PresetColourConversion::from_id ("rec709").conversion); + } + break; } } @@ -413,118 +453,128 @@ void FFmpegContent::add_properties (list& p) const { Content::add_properties (p); - video->add_properties (p); - audio->add_properties (p); - if (_bits_per_pixel) { - int const sub = 219 * pow (2, _bits_per_pixel.get() - 8); - int const total = pow (2, _bits_per_pixel.get()); - - switch (_color_range) { - case AVCOL_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: - /// 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: - /// 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); + if (video) { + video->add_properties (p); + + if (_bits_per_pixel) { + int const sub = 219 * pow (2, _bits_per_pixel.get() - 8); + int const total = pow (2, _bits_per_pixel.get()); + + switch (_color_range) { + case AVCOL_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 (UserProperty::VIDEO, _("Colour range"), _("Unspecified"))); + break; + case AVCOL_RANGE_MPEG: + /// 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 ( + UserProperty::VIDEO, _("Colour range"), String::compose (_("Limited (%1-%2)"), (total - sub) / 2, (total + sub) / 2) + ) + ); + 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))); + break; + default: + DCPOMATIC_ASSERT (false); + } + } else { + switch (_color_range) { + case AVCOL_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 (UserProperty::VIDEO, _("Colour range"), _("Unspecified"))); + break; + case AVCOL_RANGE_MPEG: + /// 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 (UserProperty::VIDEO, _("Colour range"), _("Limited"))); + 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"), _("Full"))); + break; + default: + DCPOMATIC_ASSERT (false); + } } - } else { - switch (_color_range) { - case AVCOL_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: - /// 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: - /// 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); + + char const * primaries[] = { + _("Unspecified"), + _("BT709"), + _("Unspecified"), + _("Unspecified"), + _("BT470M"), + _("BT470BG"), + _("SMPTE 170M (BT601)"), + _("SMPTE 240M"), + _("Film"), + _("BT2020"), + _("SMPTE ST 428-1 (CIE 1931 XYZ)"), + _("SMPTE ST 431-2 (2011)"), + _("SMPTE ST 432-1 D65 (2010)") + }; + + DCPOMATIC_ASSERT (AVCOL_PRI_NB <= 13); + p.push_back (UserProperty (UserProperty::VIDEO, _("Colour primaries"), primaries[_color_primaries])); + + char const * transfers[] = { + _("Unspecified"), + _("BT709"), + _("Unspecified"), + _("Unspecified"), + _("Gamma 22 (BT470M)"), + _("Gamma 28 (BT470BG)"), + _("SMPTE 170M (BT601)"), + _("SMPTE 240M"), + _("Linear"), + _("Logarithmic (100:1 range)"), + _("Logarithmic (316:1 range)"), + _("IEC61966-2-4"), + _("BT1361 extended colour gamut"), + _("IEC61966-2-1 (sRGB or sYCC)"), + _("BT2020 for a 10-bit system"), + _("BT2020 for a 12-bit system"), + _("SMPTE ST 2084 for 10, 12, 14 and 16 bit systems"), + _("SMPTE ST 428-1"), + _("ARIB STD-B67 ('Hybrid log-gamma')") + }; + + DCPOMATIC_ASSERT (AVCOL_TRC_NB <= 19); + p.push_back (UserProperty (UserProperty::VIDEO, _("Colour transfer characteristic"), transfers[_color_trc])); + + char const * spaces[] = { + _("RGB / sRGB (IEC61966-2-1)"), + _("BT709"), + _("Unspecified"), + _("Unspecified"), + _("FCC"), + _("BT470BG (BT601-6)"), + _("SMPTE 170M (BT601-6)"), + _("SMPTE 240M"), + _("YCOCG"), + _("BT2020 non-constant luminance"), + _("BT2020 constant luminance"), + _("SMPTE 2085, Y'D'zD'x"), + }; + + DCPOMATIC_ASSERT (AVCOL_SPC_NB == 12); + p.push_back (UserProperty (UserProperty::VIDEO, _("Colourspace"), spaces[_colorspace])); + + if (_bits_per_pixel) { + p.push_back (UserProperty (UserProperty::VIDEO, _("Bits per pixel"), _bits_per_pixel.get ())); } } - char const * primaries[] = { - _("Unspecified"), - _("BT709"), - _("Unspecified"), - _("Unspecified"), - _("BT470M"), - _("BT470BG"), - _("SMPTE 170M (BT601)"), - _("SMPTE 240M"), - _("Film"), - _("BT2020"), - _("SMPTE ST 428-1 (CIE 1931 XYZ)") - }; - - DCPOMATIC_ASSERT (AVCOL_PRI_NB <= 11); - p.push_back (UserProperty (_("Video"), _("Colour primaries"), primaries[_color_primaries])); - - char const * transfers[] = { - _("Unspecified"), - _("BT709"), - _("Unspecified"), - _("Unspecified"), - _("Gamma 22 (BT470M)"), - _("Gamma 28 (BT470BG)"), - _("SMPTE 170M (BT601)"), - _("SMPTE 240M"), - _("Linear"), - _("Logarithmic (100:1 range)"), - _("Logarithmic (316:1 range)"), - _("IEC61966-2-4"), - _("BT1361 extended colour gamut"), - _("IEC61966-2-1 (sRGB or sYCC)"), - _("BT2020 for a 10-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 <= 18); - p.push_back (UserProperty (_("Video"), _("Colour transfer characteristic"), transfers[_color_trc])); - - char const * spaces[] = { - _("RGB / sRGB (IEC61966-2-1)"), - _("BT709"), - _("Unspecified"), - _("Unspecified"), - _("FCC"), - _("BT470BG (BT601-6)"), - _("SMPTE 170M (BT601-6)"), - _("SMPTE 240M"), - _("YCOCG"), - _("BT2020 non-constant luminance"), - _("BT2020 constant luminance"), - }; - - DCPOMATIC_ASSERT (AVCOL_SPC_NB == 11); - p.push_back (UserProperty (_("Video"), _("Colourspace"), spaces[_colorspace])); - - if (_bits_per_pixel) { - p.push_back (UserProperty (_("Video"), _("Bits per pixel"), raw_convert (_bits_per_pixel.get ()))); + if (audio) { + audio->add_properties (p); } } @@ -552,3 +602,12 @@ FFmpegContent::ffmpeg_audio_streams () const return fa; } + +void +FFmpegContent::take_settings_from (shared_ptr c) +{ + Content::take_settings_from (c); + + shared_ptr fc = dynamic_pointer_cast (c); + _filters = fc->_filters; +}