Logging improvements to allow prettier displays in the server GUI.
[dcpomatic.git] / src / lib / ffmpeg_content.cc
index c4fc363578f6c32ea23c3dec56b6f0a3bc39b0fb..2c2d36a986c6eb3b725b40c9222e38d5f9e043d6 100644 (file)
 #include <libcxml/cxml.h>
 extern "C" {
 #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;
 using std::list;
 using std::cout;
 using std::pair;
+using std::make_pair;
 using boost::shared_ptr;
 using boost::dynamic_pointer_cast;
+using boost::optional;
 
 int const FFmpegContentProperty::SUBTITLE_STREAMS = 100;
 int const FFmpegContentProperty::SUBTITLE_STREAM = 101;
@@ -95,7 +100,19 @@ FFmpegContent::FFmpegContent (shared_ptr<const Film> film, cxml::ConstNodePtr no
                }
        }
 
-       _first_video = node->optional_number_child<double> ("FirstVideo");
+       optional<ContentTime::Type> const f = node->optional_number_child<ContentTime::Type> ("FirstVideo");
+       if (f) {
+               _first_video = ContentTime (f.get ());
+       }
+
+       _color_range = static_cast<AVColorRange> (node->optional_number_child<int>("ColorRange").get_value_or (AVCOL_RANGE_UNSPECIFIED));
+       _color_primaries = static_cast<AVColorPrimaries> (node->optional_number_child<int>("ColorPrimaries").get_value_or (AVCOL_PRI_UNSPECIFIED));
+       _color_trc = static_cast<AVColorTransferCharacteristic> (
+               node->optional_number_child<int>("ColorTransferCharacteristic").get_value_or (AVCOL_TRC_UNSPECIFIED)
+               );
+       _colorspace = static_cast<AVColorSpace> (node->optional_number_child<int>("Colorspace").get_value_or (AVCOL_SPC_UNSPECIFIED));
+       _bits_per_pixel = node->optional_number_child<int> ("BitsPerPixel");
+
 }
 
 FFmpegContent::FFmpegContent (shared_ptr<const Film> film, vector<boost::shared_ptr<Content> > c)
@@ -150,6 +167,14 @@ FFmpegContent::as_xml (xmlpp::Node* node) const
        if (_first_video) {
                node->add_child("FirstVideo")->add_child_text (raw_convert<string> (_first_video.get().get()));
        }
+
+       node->add_child("ColorRange")->add_child_text (raw_convert<string> (_color_range));
+       node->add_child("ColorPrimaries")->add_child_text (raw_convert<string> (_color_primaries));
+       node->add_child("ColorTransferCharacteristic")->add_child_text (raw_convert<string> (_color_trc));
+       node->add_child("Colorspace")->add_child_text (raw_convert<string> (_colorspace));
+       if (_bits_per_pixel) {
+               node->add_child("BitsPerPixel")->add_child_text (raw_convert<string> (_bits_per_pixel.get ()));
+       }
 }
 
 void
@@ -182,6 +207,12 @@ FFmpegContent::examine (shared_ptr<Job> job)
                }
 
                _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 ();
        }
 
        signal_changed (FFmpegContentProperty::SUBTITLE_STREAMS);
@@ -252,7 +283,7 @@ 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());
+       return DCPTime::from_frames (llrint (video_length_after_3d_combine() * frc.factor()), film->video_frame_rate());
 }
 
 void
@@ -271,7 +302,8 @@ FFmpegContent::identifier () const
 {
        SafeStringStream s;
 
-       s << VideoContent::identifier();
+       s << VideoContent::identifier() << "_"
+         << SubtitleContent::identifier();
 
        boost::mutex::scoped_lock lm (_mutex);
 
@@ -298,7 +330,13 @@ FFmpegContent::subtitles_during (ContentTimePeriod period, bool starting) const
 }
 
 bool
-FFmpegContent::has_subtitles () const
+FFmpegContent::has_text_subtitles () const
+{
+       return false;
+}
+
+bool
+FFmpegContent::has_image_subtitles () const
 {
        return !subtitle_streams().empty ();
 }
@@ -326,3 +364,101 @@ FFmpegContent::audio_streams () const
        copy (_audio_streams.begin(), _audio_streams.end(), back_inserter (s));
        return s;
 }
+
+void
+FFmpegContent::add_properties (list<pair<string, string> >& p) const
+{
+       VideoContent::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:
+                       p.push_back (make_pair (_("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)));
+                       break;
+               case AVCOL_RANGE_JPEG:
+                       p.push_back (make_pair (_("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")));
+                       break;
+               case AVCOL_RANGE_MPEG:
+                       p.push_back (make_pair (_("Colour range"), _("Limited")));
+                       break;
+               case AVCOL_RANGE_JPEG:
+                       p.push_back (make_pair (_("Colour range"), _("Full")));
+                       break;
+               default:
+                       DCPOMATIC_ASSERT (false);
+               }
+       }
+
+       char const * primaries[] = {
+               _("Unspecified"),
+               _("BT709"),
+               _("Unspecified"),
+               _("Unspecified"),
+               _("BT470M"),
+               _("BT470BG"),
+               _("SMPTE 170M (BT601)"),
+               _("SMPTE 240M"),
+               _("Film"),
+               _("BT2020")
+       };
+
+       DCPOMATIC_ASSERT (AVCOL_PRI_NB == 10);
+       p.push_back (make_pair (_("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")
+       };
+
+       DCPOMATIC_ASSERT (AVCOL_TRC_NB == 16);
+       p.push_back (make_pair (_("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 (make_pair (_("Colourspace"), spaces[_colorspace]));
+
+       if (_bits_per_pixel) {
+               p.push_back (make_pair (_("Bits per pixel"), raw_convert<string> (_bits_per_pixel.get ())));
+       }
+}