X-Git-Url: https://git.carlh.net/gitweb/?a=blobdiff_plain;f=src%2Flib%2Fffmpeg_content.cc;h=b34fdf6aa811bd48fbfecf8a69b25c80ae51eafa;hb=a8a0dfd1b21de6c0facf965ab119833ff6f790bf;hp=a0bf88c2513a077870d9c7e84b42b29940f7b253;hpb=90becb40eb48467b6d31d6939bcfcf39c3c9652c;p=dcpomatic.git diff --git a/src/lib/ffmpeg_content.cc b/src/lib/ffmpeg_content.cc index a0bf88c25..b34fdf6aa 100644 --- a/src/lib/ffmpeg_content.cc +++ b/src/lib/ffmpeg_content.cc @@ -1,19 +1,20 @@ /* Copyright (C) 2013-2016 Carl Hetherington - This program is free software; you can redistribute it and/or modify + 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. - This program is distributed in the hope that it will be useful, + 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 this program; if not, write to the Free Software - Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + along with DCP-o-matic. If not, see . */ @@ -53,6 +54,7 @@ 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; @@ -64,19 +66,15 @@ int const FFmpegContentProperty::FILTERS = 102; FFmpegContent::FFmpegContent (shared_ptr film, boost::filesystem::path p) : Content (film, p) { - video.reset (new VideoContent (this, film)); - audio.reset (new AudioContent (this, film)); - subtitle.reset (new SubtitleContent (this, film)); - set_default_colour_conversion (); } FFmpegContent::FFmpegContent (shared_ptr film, cxml::ConstNodePtr node, int version, list& notes) : Content (film, node) { - video = VideoContent::from_xml (this, film, node, version); - audio = AudioContent::from_xml (this, film, node); - subtitle = SubtitleContent::from_xml (this, film, node, version); + video = VideoContent::from_xml (this, node, version); + audio = AudioContent::from_xml (this, node, version); + subtitle = SubtitleContent::from_xml (this, node, version); list c = node->node_children ("SubtitleStream"); for (list::const_iterator i = c.begin(); i != c.end(); ++i) { @@ -124,9 +122,12 @@ FFmpegContent::FFmpegContent (shared_ptr film, cxml::ConstNodePtr no FFmpegContent::FFmpegContent (shared_ptr film, vector > c) : Content (film, c) { - video.reset (new VideoContent (this, film, c)); - audio.reset (new AudioContent (this, film, c)); - subtitle.reset (new SubtitleContent (this, film, c)); + /* XXX: this should look at c to decide which of video/audio/subtitle + get created. + */ + video.reset (new VideoContent (this, c)); + audio.reset (new AudioContent (this, c)); + subtitle.reset (new SubtitleContent (this, c)); shared_ptr ref = dynamic_pointer_cast (c[0]); DCPOMATIC_ASSERT (ref); @@ -163,6 +164,12 @@ FFmpegContent::as_xml (xmlpp::Node* node) const if (audio) { audio->as_xml (node); + + BOOST_FOREACH (AudioStreamPtr i, audio->streams ()) { + shared_ptr f = dynamic_pointer_cast (i); + DCPOMATIC_ASSERT (f); + f->as_xml (node->add_child("AudioStream")); + } } if (subtitle) { @@ -179,12 +186,6 @@ FFmpegContent::as_xml (xmlpp::Node* node) const (*i)->as_xml (t); } - BOOST_FOREACH (AudioStreamPtr i, audio->streams ()) { - shared_ptr f = dynamic_pointer_cast (i); - DCPOMATIC_ASSERT (f); - f->as_xml (node->add_child("AudioStream")); - } - for (vector::const_iterator i = _filters.begin(); i != _filters.end(); ++i) { node->add_child("Filter")->add_child_text ((*i)->id ()); } @@ -210,35 +211,46 @@ FFmpegContent::examine (shared_ptr job) Content::examine (job); shared_ptr examiner (new FFmpegExaminer (shared_from_this (), job)); - video->take_from_examiner (examiner); - set_default_colour_conversion (); + + 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); - _subtitle_streams = examiner->subtitle_streams (); - if (!_subtitle_streams.empty ()) { - _subtitle_stream = _subtitle_streams.front (); + if (examiner->has_video ()) { + _first_video = examiner->first_video (); + _color_range = examiner->color_range (); + _color_primaries = examiner->color_primaries (); + _color_trc = examiner->color_trc (); + _colorspace = examiner->colorspace (); + _bits_per_pixel = examiner->bits_per_pixel (); } - BOOST_FOREACH (shared_ptr i, examiner->audio_streams ()) { - audio->add_stream (i); - } + if (!examiner->audio_streams().empty ()) { + audio.reset (new AudioContent (this)); + + BOOST_FOREACH (shared_ptr i, examiner->audio_streams ()) { + audio->add_stream (i); + } - if (!audio->streams().empty ()) { 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); } - _first_video = examiner->first_video (); + _subtitle_streams = examiner->subtitle_streams (); + if (!_subtitle_streams.empty ()) { + subtitle.reset (new SubtitleContent (this)); + _subtitle_stream = _subtitle_streams.front (); + } - _color_range = examiner->color_range (); - _color_primaries = examiner->color_primaries (); - _color_trc = examiner->color_trc (); - _colorspace = examiner->colorspace (); - _bits_per_pixel = examiner->bits_per_pixel (); } signal_changed (FFmpegContentProperty::SUBTITLE_STREAMS); @@ -248,8 +260,15 @@ FFmpegContent::examine (shared_ptr job) string FFmpegContent::summary () const { - /* Get the string() here so that the name does not have quotes around it */ - return String::compose (_("%1 [movie]"), path_summary ()); + if (video && audio) { + return String::compose (_("%1 [movie]"), path_summary ()); + } else if (video) { + return String::compose (_("%1 [video]"), path_summary ()); + } else if (audio) { + return String::compose (_("%1 [audio]"), path_summary ()); + } + + return path_summary (); } string @@ -271,12 +290,19 @@ FFmpegContent::technical_summary () const string filt = Filter::ffmpeg_string (_filters); - return Content::technical_summary() + " - " - + video->technical_summary() + " - " - + audio->technical_summary() + " - " - + String::compose ( - "ffmpeg: audio %1 subtitle %2 filters %3", as, ss, filt - ); + string s = Content::technical_summary (); + + if (video) { + s += " - " + video->technical_summary (); + } + + if (audio) { + s += " - " + audio->technical_summary (); + } + + return s + String::compose ( + "ffmpeg: audio %1 subtitle %2 filters %3", as, ss, filt + ); } void @@ -306,7 +332,18 @@ DCPTime FFmpegContent::full_length () const { FrameRateChange const frc (active_video_frame_rate (), film()->video_frame_rate ()); - return DCPTime::from_frames (llrint (video->length_after_3d_combine() * frc.factor()), film()->video_frame_rate()); + if (video) { + return DCPTime::from_frames (llrint (video->length_after_3d_combine() * frc.factor()), film()->video_frame_rate()); + } + + DCPOMATIC_ASSERT (audio); + + 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 @@ -325,9 +362,15 @@ FFmpegContent::identifier () const { SafeStringStream s; - s << Content::identifier() << "_" - << video->identifier() << "_" - << subtitle->identifier(); + s << Content::identifier(); + + if (video) { + s << "_" << video->identifier(); + } + + if (subtitle) { + s << "_" << subtitle->identifier(); + } boost::mutex::scoped_lock lm (_mutex); @@ -367,6 +410,8 @@ FFmpegContent::text_subtitles_during (ContentTimePeriod period, bool starting) c void FFmpegContent::set_default_colour_conversion () { + DCPOMATIC_ASSERT (video); + dcp::Size const s = video->size (); boost::mutex::scoped_lock lm (_mutex); @@ -382,118 +427,124 @@ 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)") + }; + + DCPOMATIC_ASSERT (AVCOL_PRI_NB <= 11); + 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") + }; + + DCPOMATIC_ASSERT (AVCOL_TRC_NB <= 18); + 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"), + }; + + DCPOMATIC_ASSERT (AVCOL_SPC_NB == 11); + p.push_back (UserProperty (UserProperty::VIDEO, _("Colourspace"), spaces[_colorspace])); + + if (_bits_per_pixel) { + p.push_back (UserProperty (UserProperty::VIDEO, _("Bits per pixel"), raw_convert (_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); } } @@ -512,8 +563,12 @@ vector > FFmpegContent::ffmpeg_audio_streams () const { vector > fa; - BOOST_FOREACH (AudioStreamPtr i, audio->streams()) { - fa.push_back (dynamic_pointer_cast (i)); + + if (audio) { + BOOST_FOREACH (AudioStreamPtr i, audio->streams()) { + fa.push_back (dynamic_pointer_cast (i)); + } } + return fa; }