Actually use YUV->RGB setting when converting.
authorCarl Hetherington <cth@carlh.net>
Wed, 22 Apr 2015 14:35:34 +0000 (15:35 +0100)
committerCarl Hetherington <cth@carlh.net>
Wed, 22 Apr 2015 14:35:34 +0000 (15:35 +0100)
src/lib/image.cc
src/lib/image.h
src/lib/player.cc
src/lib/player_video.cc
src/wx/film_viewer.cc
test/image_test.cc
test/make_black_test.cc

index 177219813131cb0b387eec74efdf441917fe57e8..bba5eeda1a0241d213dae5b30c804022f98de7ba 100644 (file)
@@ -87,7 +87,9 @@ Image::components () const
 
 /** Crop this image, scale it to `inter_size' and then place it in a black frame of `out_size' */
 shared_ptr<Image>
-Image::crop_scale_window (Crop crop, dcp::Size inter_size, dcp::Size out_size, AVPixelFormat out_format, bool out_aligned) const
+Image::crop_scale_window (
+       Crop crop, dcp::Size inter_size, dcp::Size out_size, dcp::YUVToRGB yuv_to_rgb, AVPixelFormat out_format, bool out_aligned
+       ) const
 {
        /* Empirical testing suggests that sws_scale() will crash if
           the input image is not aligned.
@@ -115,6 +117,19 @@ Image::crop_scale_window (Crop crop, dcp::Size inter_size, dcp::Size out_size, A
                throw StringError (N_("Could not allocate SwsContext"));
        }
 
+       DCPOMATIC_ASSERT (yuv_to_rgb < dcp::YUV_TO_RGB_COUNT);
+       int const lut[dcp::YUV_TO_RGB_COUNT] = {
+               SWS_CS_ITU601,
+               SWS_CS_ITU709
+       };
+
+       sws_setColorspaceDetails (
+               scale_context,
+               sws_getCoefficients (lut[yuv_to_rgb]), 0,
+               sws_getCoefficients (lut[yuv_to_rgb]), 0,
+               0, 1 << 16, 1 << 16
+               );
+       
        /* Prepare input data pointers with crop */
        uint8_t* scale_in_data[components()];
        for (int c = 0; c < components(); ++c) {
@@ -142,7 +157,7 @@ Image::crop_scale_window (Crop crop, dcp::Size inter_size, dcp::Size out_size, A
 }
 
 shared_ptr<Image>
-Image::scale (dcp::Size out_size, AVPixelFormat out_format, bool out_aligned) const
+Image::scale (dcp::Size out_size, dcp::YUVToRGB yuv_to_rgb, AVPixelFormat out_format, bool out_aligned) const
 {
        /* Empirical testing suggests that sws_scale() will crash if
           the input image is not aligned.
@@ -157,6 +172,19 @@ Image::scale (dcp::Size out_size, AVPixelFormat out_format, bool out_aligned) co
                SWS_BICUBIC, 0, 0, 0
                );
 
+       DCPOMATIC_ASSERT (yuv_to_rgb < dcp::YUV_TO_RGB_COUNT);
+       int const lut[dcp::YUV_TO_RGB_COUNT] = {
+               SWS_CS_ITU601,
+               SWS_CS_ITU709
+       };
+
+       sws_setColorspaceDetails (
+               scale_context,
+               sws_getCoefficients (lut[yuv_to_rgb]), 0,
+               sws_getCoefficients (lut[yuv_to_rgb]), 0,
+               0, 1 << 16, 1 << 16
+               );
+       
        sws_scale (
                scale_context,
                data(), stride(),
index 2e90a89e92ed9701b19c3c4a80c0e67e10687297..5c3931102af776c259965bf7fb9487a02370d193 100644 (file)
@@ -27,6 +27,7 @@
 #include "position.h"
 #include "position_image.h"
 #include "types.h"
+#include <dcp/colour_conversion.h>
 extern "C" {
 #include <libavcodec/avcodec.h>
 #include <libavfilter/avfilter.h>
@@ -57,10 +58,9 @@ public:
        int line_factor (int) const;
        int lines (int) const;
 
-       boost::shared_ptr<Image> scale (dcp::Size, AVPixelFormat, bool aligned) const;
+       boost::shared_ptr<Image> scale (dcp::Size, dcp::YUVToRGB yuv_to_rgb, AVPixelFormat, bool aligned) const;
        boost::shared_ptr<Image> crop (Crop c, bool aligned) const;
-
-       boost::shared_ptr<Image> crop_scale_window (Crop c, dcp::Size, dcp::Size, AVPixelFormat, bool aligned) const;
+       boost::shared_ptr<Image> crop_scale_window (Crop c, dcp::Size, dcp::Size, dcp::YUVToRGB yuv_to_rgb, AVPixelFormat, bool aligned) const;
        
        void make_black ();
        void make_transparent ();
index e3c85ee56ef40ef6f1ae0cb370656bc96697a53d..495d20533b3eb15947f8a199b34901700d07b5f3 100644 (file)
@@ -280,6 +280,7 @@ Player::transform_image_subtitles (list<ImageSubtitle> subs) const
                        PositionImage (
                                i->image->scale (
                                        scaled_size,
+                                       dcp::YUV_TO_RGB_REC601,
                                        i->image->pixel_format (),
                                        true
                                        ),
index aad75889fc6a4a4e9f0dedf339f4db88d9dfc012..81e01329a5b641ac1869d2f158b645375d364bd1 100644 (file)
@@ -110,8 +110,13 @@ PlayerVideo::image (AVPixelFormat pixel_format, bool burn_subtitle, dcp::NoteHan
        default:
                break;
        }
+
+       dcp::YUVToRGB yuv_to_rgb = dcp::YUV_TO_RGB_REC601;
+       if (_colour_conversion) {
+               yuv_to_rgb = _colour_conversion.get().yuv_to_rgb();
+       }
                
-       shared_ptr<Image> out = im->crop_scale_window (total_crop, _inter_size, _out_size, pixel_format, true);
+       shared_ptr<Image> out = im->crop_scale_window (total_crop, _inter_size, _out_size, yuv_to_rgb, pixel_format, true);
 
        if (burn_subtitle && _subtitle.image) {
                out->alpha_blend (_subtitle.image, _subtitle.position);
index 26f135d48eed0b480e4736a6c01feda55b874132..a1cc5dfc4bd37dd1751523895291005069975909 100644 (file)
@@ -180,7 +180,13 @@ FilmViewer::get (DCPTime p, bool accurate)
        if (!pvf.empty ()) {
                try {
                        _frame = pvf.front()->image (PIX_FMT_RGB24, true, boost::bind (&Log::dcp_log, _film->log().get(), _1, _2));
-                       _frame = _frame->scale (_frame->size(), PIX_FMT_RGB24, false);
+
+                       dcp::YUVToRGB yuv_to_rgb = dcp::YUV_TO_RGB_REC601;
+                       if (pvf.front()->colour_conversion()) {
+                               yuv_to_rgb = pvf.front()->colour_conversion().get().yuv_to_rgb();
+                       }
+                       
+                       _frame = _frame->scale (_frame->size(), yuv_to_rgb, PIX_FMT_RGB24, false);
                        _position = pvf.front()->time ();
                        _inter_position = pvf.front()->inter_position ();
                        _inter_size = pvf.front()->inter_size ();
index b622b250db50eb6f6ff9ac82d8090dc3caa82991..9aca9878d813277c03785159b5a296e48112c9b3 100644 (file)
@@ -156,7 +156,7 @@ BOOST_AUTO_TEST_CASE (crop_image_test2)
        image = image->crop (crop, true);
 
        /* Convert it back to RGB to make comparison to black easier */
-       image = image->scale (image->size(), PIX_FMT_RGB24, true);
+       image = image->scale (image->size(), dcp::YUV_TO_RGB_REC601, PIX_FMT_RGB24, true);
 
        /* Check that its still black after the crop */
        uint8_t* p = image->data()[0];
@@ -250,13 +250,13 @@ crop_scale_window_single (AVPixelFormat in_format, dcp::Size in_size, Crop crop,
                                
        /* Convert using separate methods */
        boost::shared_ptr<Image> sep = test->crop (crop, true);
-       sep = sep->scale (inter_size, PIX_FMT_RGB24, true);
+       sep = sep->scale (inter_size, dcp::YUV_TO_RGB_REC601, PIX_FMT_RGB24, true);
        boost::shared_ptr<Image> sep_container (new Image (PIX_FMT_RGB24, out_size, true));
        sep_container->make_black ();
        sep_container->copy (sep, Position<int> ((out_size.width - inter_size.width) / 2, (out_size.height - inter_size.height) / 2));
 
        /* Convert using the all-in-one method */
-       shared_ptr<Image> all = test->crop_scale_window (crop, inter_size, out_size, PIX_FMT_RGB24, true);
+       shared_ptr<Image> all = test->crop_scale_window (crop, inter_size, out_size, dcp::YUV_TO_RGB_REC601, PIX_FMT_RGB24, true);
 
        /* Compare */
        BOOST_CHECK_EQUAL (sep_container->size().width, all->size().width);
index 913b6da10857ba1de2e4d2586899a5a2e7c2079c..b0243310bbacd2b9bfd9a23809195eab2763d212 100644 (file)
@@ -80,7 +80,7 @@ BOOST_AUTO_TEST_CASE (make_black_test)
        for (list<AVPixelFormat>::const_iterator i = pix_fmts.begin(); i != pix_fmts.end(); ++i) {
                boost::shared_ptr<Image> foo (new Image (*i, in_size, true));
                foo->make_black ();
-               boost::shared_ptr<Image> bar = foo->scale (out_size, PIX_FMT_RGB24, true);
+               boost::shared_ptr<Image> bar = foo->scale (out_size, dcp::YUV_TO_RGB_REC601, PIX_FMT_RGB24, true);
                
                uint8_t* p = bar->data()[0];
                for (int y = 0; y < bar->size().height; ++y) {