Make sure we use limited ("video") range data when exporting.
authorCarl Hetherington <cth@carlh.net>
Sun, 15 Nov 2020 19:47:42 +0000 (20:47 +0100)
committerCarl Hetherington <cth@carlh.net>
Mon, 16 Nov 2020 00:40:36 +0000 (01:40 +0100)
Our export formats all currently use limited range but we weren't
making sure data fed to the encoders was limited range.

Should fix #1832.

16 files changed:
src/lib/butler.cc
src/lib/butler.h
src/lib/dcp_video.cc
src/lib/ffmpeg_encoder.cc
src/lib/ffmpeg_file_encoder.cc
src/lib/image.cc
src/lib/image.h
src/lib/player_video.cc
src/lib/player_video.h
src/wx/film_viewer.cc
src/wx/gl_video_view.cc
src/wx/simple_video_view.cc
test/butler_test.cc
test/dcp_playback_test.cc
test/image_test.cc
test/player_test.cc

index 39da0bd5c10434a04449eaf782098cff29cfe13e..d27778b70b0a909b1d8aae0626dece75d8d41108 100644 (file)
@@ -62,6 +62,7 @@ Butler::Butler (
        AudioMapping audio_mapping,
        int audio_channels,
        function<AVPixelFormat (AVPixelFormat)> pixel_format,
+       VideoRange video_range,
        bool aligned,
        bool fast
        )
@@ -76,6 +77,7 @@ Butler::Butler (
        , _audio_channels (audio_channels)
        , _disable_audio (false)
        , _pixel_format (pixel_format)
+       , _video_range (video_range)
        , _aligned (aligned)
        , _fast (fast)
 {
@@ -305,7 +307,7 @@ try
        /* If the weak_ptr cannot be locked the video obviously no longer requires any work */
        if (video) {
                LOG_TIMING("start-prepare in %1", thread_id());
-               video->prepare (_pixel_format, _aligned, _fast);
+               video->prepare (_pixel_format, _video_range, _aligned, _fast);
                LOG_TIMING("finish-prepare in %1", thread_id());
        }
 }
index e13843c90e9c14833704cde408e65de072e8e5c9..6b933be4b85a4e98814297e4d4cf6bcdbd9ec14a 100644 (file)
@@ -41,6 +41,7 @@ public:
                AudioMapping map,
                int audio_channels,
                boost::function<AVPixelFormat (AVPixelFormat)> pixel_format,
+               VideoRange video_range,
                bool aligned,
                bool fast
                );
@@ -115,6 +116,7 @@ private:
        bool _disable_audio;
 
        boost::function<AVPixelFormat (AVPixelFormat)> _pixel_format;
+       VideoRange _video_range;
        bool _aligned;
        bool _fast;
 
index b3461e56908fa015ab38255d41f209647e508c21..ffeb23a466f78be64a0f95f28a9ddc9b69415ed7 100644 (file)
@@ -99,7 +99,7 @@ DCPVideo::convert_to_xyz (shared_ptr<const PlayerVideo> frame, dcp::NoteHandler
 {
        shared_ptr<dcp::OpenJPEGImage> xyz;
 
-       shared_ptr<Image> image = frame->image (bind (&PlayerVideo::keep_xyz_or_rgb, _1), true, false);
+       shared_ptr<Image> image = frame->image (bind (&PlayerVideo::keep_xyz_or_rgb, _1), VIDEO_RANGE_FULL, true, false);
        if (frame->colour_conversion()) {
                xyz = dcp::rgb_to_xyz (
                        image->data()[0],
index 8f9b3defc676af3f81494c2b7796649a1e53fe16..2c76a38c3973405d2733f3046361eb008bb93bf9 100644 (file)
@@ -110,7 +110,9 @@ FFmpegEncoder::FFmpegEncoder (
                }
        }
 
-       _butler.reset (new Butler(_player, map, _output_audio_channels, bind(&PlayerVideo::force, _1, FFmpegFileEncoder::pixel_format(format)), true, false));
+       _butler.reset (
+               new Butler(_player, map, _output_audio_channels, bind(&PlayerVideo::force, _1, FFmpegFileEncoder::pixel_format(format)), VIDEO_RANGE_VIDEO, true, false)
+               );
 }
 
 
index 511730185716ddba8368b828f76228f775d5eeba..05b6b7fe51aaee8923b5deda1124b3e4d9a994d6 100644 (file)
@@ -420,8 +420,10 @@ DCPOMATIC_ENABLE_WARNINGS
 void
 FFmpegFileEncoder::video (shared_ptr<PlayerVideo> video, DCPTime time)
 {
+       /* All our output formats are video range at the moment */
        shared_ptr<Image> image = video->image (
                bind (&PlayerVideo::force, _1, _pixel_format),
+               VIDEO_RANGE_VIDEO,
                true,
                false
                );
index 57c152f137a396b471ce71b8bbaa842ccd9dce86..9dae94f7ce2f3f6fa1f7f5ac7d64a396931a9d0d 100644 (file)
@@ -122,14 +122,24 @@ Image::planes () const
  *  @param inter_size Size to scale the cropped image to.
  *  @param out_size Size of output frame; if this is larger than inter_size there will be black padding.
  *  @param yuv_to_rgb YUV to RGB transformation to use, if required.
+ *  @param video_range Video range of the image.
  *  @param out_format Output pixel format.
  *  @param out_aligned true to make the output image aligned.
+ *  @param out_video_range Video range to use for the output image.
  *  @param fast Try to be fast at the possible expense of quality; at present this means using
  *  fast bilinear rather than bicubic scaling.
  */
 shared_ptr<Image>
 Image::crop_scale_window (
-       Crop crop, dcp::Size inter_size, dcp::Size out_size, dcp::YUVToRGB yuv_to_rgb, VideoRange video_range, AVPixelFormat out_format, bool out_aligned, bool fast
+       Crop crop,
+       dcp::Size inter_size,
+       dcp::Size out_size,
+       dcp::YUVToRGB yuv_to_rgb,
+       VideoRange video_range,
+       AVPixelFormat out_format,
+       VideoRange out_video_range,
+       bool out_aligned,
+       bool fast
        ) const
 {
        /* Empirical testing suggests that sws_scale() will crash if
@@ -171,13 +181,13 @@ Image::crop_scale_window (
           1 -> destination range JPEG (i.e. "full", 0-255)
 
           But remember: sws_setColorspaceDetails ignores these
-          parameters unless the corresponding image isYUV or isGray.
-          (If it's neither, it uses video range).
+          parameters unless the both source and destination images
+          are isYUV or isGray.  (If either is not, it uses video range).
        */
        sws_setColorspaceDetails (
                scale_context,
                sws_getCoefficients (lut[yuv_to_rgb]), video_range == VIDEO_RANGE_VIDEO ? 0 : 1,
-               sws_getCoefficients (lut[yuv_to_rgb]), 1,
+               sws_getCoefficients (lut[yuv_to_rgb]), out_video_range == VIDEO_RANGE_VIDEO ? 0 : 1,
                0, 1 << 16, 1 << 16
                );
 
index c648fda1b8f0598bb6d4a0738c1292b72f10e41a..7dd633f617c8a7166c4e2baa6d4119e62fe1cc20 100644 (file)
@@ -66,7 +66,15 @@ public:
        boost::shared_ptr<Image> convert_pixel_format (dcp::YUVToRGB yuv_to_rgb, AVPixelFormat out_format, bool aligned, bool fast) const;
        boost::shared_ptr<Image> scale (dcp::Size out_size, dcp::YUVToRGB yuv_to_rgb, AVPixelFormat out_format, bool aligned, bool fast) const;
        boost::shared_ptr<Image> crop_scale_window (
-               Crop crop, dcp::Size inter_size, dcp::Size out_size, dcp::YUVToRGB yuv_to_rgb, VideoRange video_range, AVPixelFormat out_format, bool aligned, bool fast
+               Crop crop,
+               dcp::Size inter_size,
+               dcp::Size out_size,
+               dcp::YUVToRGB yuv_to_rgb,
+               VideoRange video_range,
+               AVPixelFormat out_format,
+               VideoRange out_video_range,
+               bool aligned,
+               bool fast
                ) const;
 
        void make_black ();
index 620245781afa3374e062cd018119b7c5b23ce677..8c1b95bba37917422d0b89a0ad04c84673ccd48f 100644 (file)
@@ -109,13 +109,13 @@ PlayerVideo::set_text (PositionImage image)
 }
 
 shared_ptr<Image>
-PlayerVideo::image (function<AVPixelFormat (AVPixelFormat)> pixel_format, bool aligned, bool fast) const
+PlayerVideo::image (function<AVPixelFormat (AVPixelFormat)> pixel_format, VideoRange video_range, bool aligned, bool fast) const
 {
        /* XXX: this assumes that image() and prepare() are only ever called with the same parameters (except crop, inter size, out size, fade) */
 
        boost::mutex::scoped_lock lm (_mutex);
        if (!_image || _crop != _image_crop || _inter_size != _image_inter_size || _out_size != _image_out_size || _fade != _image_fade) {
-               make_image (pixel_format, aligned, fast);
+               make_image (pixel_format, video_range, aligned, fast);
        }
        return _image;
 }
@@ -128,7 +128,7 @@ PlayerVideo::image (function<AVPixelFormat (AVPixelFormat)> pixel_format, bool a
  *  @param fast true to be fast at the expense of quality.
  */
 void
-PlayerVideo::make_image (function<AVPixelFormat (AVPixelFormat)> pixel_format, bool aligned, bool fast) const
+PlayerVideo::make_image (function<AVPixelFormat (AVPixelFormat)> pixel_format, VideoRange video_range, bool aligned, bool fast) const
 {
        _image_crop = _crop;
        _image_inter_size = _inter_size;
@@ -171,7 +171,7 @@ PlayerVideo::make_image (function<AVPixelFormat (AVPixelFormat)> pixel_format, b
        }
 
        _image = prox.image->crop_scale_window (
-               total_crop, _inter_size, _out_size, yuv_to_rgb, _video_range, pixel_format (prox.image->pixel_format()), aligned, fast
+               total_crop, _inter_size, _out_size, yuv_to_rgb, _video_range, pixel_format (prox.image->pixel_format()), video_range, aligned, fast
                );
 
        if (_text) {
@@ -289,12 +289,12 @@ PlayerVideo::keep_xyz_or_rgb (AVPixelFormat p)
 }
 
 void
-PlayerVideo::prepare (function<AVPixelFormat (AVPixelFormat)> pixel_format, bool aligned, bool fast)
+PlayerVideo::prepare (function<AVPixelFormat (AVPixelFormat)> pixel_format, VideoRange video_range, bool aligned, bool fast)
 {
        _in->prepare (_inter_size);
        boost::mutex::scoped_lock lm (_mutex);
        if (!_image) {
-               make_image (pixel_format, aligned, fast);
+               make_image (pixel_format, video_range, aligned, fast);
        }
 }
 
index 6043632c29000d45943e735ffb992810e12b0f9a..0456457db6594544d6508f98a725a293862df00a 100644 (file)
@@ -67,8 +67,8 @@ public:
 
        void set_text (PositionImage);
 
-       void prepare (boost::function<AVPixelFormat (AVPixelFormat)> pixel_format, bool aligned, bool fast);
-       boost::shared_ptr<Image> image (boost::function<AVPixelFormat (AVPixelFormat)> pixel_format, bool aligned, bool fast) const;
+       void prepare (boost::function<AVPixelFormat (AVPixelFormat)> pixel_format, VideoRange video_range, bool aligned, bool fast);
+       boost::shared_ptr<Image> image (boost::function<AVPixelFormat (AVPixelFormat)> pixel_format, VideoRange video_range, bool aligned, bool fast) const;
 
        static AVPixelFormat force (AVPixelFormat, AVPixelFormat);
        static AVPixelFormat keep_xyz_or_rgb (AVPixelFormat);
@@ -114,7 +114,7 @@ public:
        }
 
 private:
-       void make_image (boost::function<AVPixelFormat (AVPixelFormat)> pixel_format, bool aligned, bool fast) const;
+       void make_image (boost::function<AVPixelFormat (AVPixelFormat)> pixel_format, VideoRange video_range, bool aligned, bool fast) const;
 
        boost::shared_ptr<const ImageProxy> _in;
        Crop _crop;
index 20cbb434c009471e5c182c4c150841f86fc7af0d..9561c32b5197ce1551db7f4e6383c4a313d871f4 100644 (file)
@@ -219,6 +219,7 @@ FilmViewer::recreate_butler ()
                        Config::instance()->audio_mapping(_audio_channels),
                        _audio_channels,
                        bind(&PlayerVideo::force, _1, AV_PIX_FMT_RGB24),
+                       VIDEO_RANGE_FULL,
                        false,
                        true
                        )
index 38270a7b7ba1fc42c6ca2fa7e99d493bc702ba74..08b62dee4cf73f7b8afe1d89ac16bd9d97b48d35 100644 (file)
@@ -325,7 +325,7 @@ GLVideoView::set_image_and_draw ()
 {
        shared_ptr<PlayerVideo> pv = player_video().first;
        if (pv) {
-               set_image (pv->image(bind(&PlayerVideo::force, _1, AV_PIX_FMT_RGB24), false, true));
+               set_image (pv->image(bind(&PlayerVideo::force, _1, AV_PIX_FMT_RGB24), VIDEO_RANGE_FULL, false, true));
                draw (pv->inter_position(), pv->inter_size());
                _viewer->image_changed (pv);
        }
index 2e79deee8c1f689f571bc8bf4cb6b471a6a3bcfd..dd1296ed6a8b4030eb279115e663e5660b433d72 100644 (file)
@@ -254,7 +254,7 @@ SimpleVideoView::update ()
        _state_timer.set ("get image");
 
        set_image (
-               player_video().first->image(bind(&PlayerVideo::force, _1, AV_PIX_FMT_RGB24), false, true)
+               player_video().first->image(bind(&PlayerVideo::force, _1, AV_PIX_FMT_RGB24), VIDEO_RANGE_FULL, false, true)
                );
 
        _state_timer.set ("ImageChanged");
index 9f87662fcfcc0b664e2d04fc638c996472083c57..8e3e7222f0aac0695b3e6a1d6a7210d652aeb9d2 100644 (file)
@@ -55,7 +55,7 @@ BOOST_AUTO_TEST_CASE (butler_test1)
                map.set (i, i, 1);
        }
 
-       Butler butler (shared_ptr<Player>(new Player(film)), map, 6, bind(&PlayerVideo::force, _1, AV_PIX_FMT_RGB24), false, false);
+       Butler butler (shared_ptr<Player>(new Player(film)), map, 6, bind(&PlayerVideo::force, _1, AV_PIX_FMT_RGB24), VIDEO_RANGE_FULL, false, false);
 
        BOOST_CHECK (butler.get_video(true, 0).second == DCPTime());
        BOOST_CHECK (butler.get_video(true, 0).second == DCPTime::from_frames(1, 24));
index 120fecede9b17ab4dbfca8b3f43a7b63428f6c1a..a2cf37866d18805bb7e404d8bdc2cbb9788329ba 100644 (file)
@@ -47,6 +47,7 @@ BOOST_AUTO_TEST_CASE (dcp_playback_test)
                        AudioMapping(6, 6),
                        6,
                        bind(&PlayerVideo::force, _1, AV_PIX_FMT_RGB24),
+                       VIDEO_RANGE_FULL,
                        false,
                        true)
                );
@@ -58,7 +59,7 @@ BOOST_AUTO_TEST_CASE (dcp_playback_test)
                }
                /* assuming DCP is 24fps/48kHz */
                butler->get_audio (audio_buffer, 2000);
-               p.first->image(bind(&PlayerVideo::force, _1, AV_PIX_FMT_RGB24), false, true);
+               p.first->image(bind(&PlayerVideo::force, _1, AV_PIX_FMT_RGB24), VIDEO_RANGE_FULL, false, true);
        }
        delete[] audio_buffer;
 }
index e2b1d71c7d0899a8a7e60b4a242e0632f7706e62..6401db8514e353abe63c23cf2bb3ca8da28aa7fc 100644 (file)
@@ -261,7 +261,9 @@ BOOST_AUTO_TEST_CASE (crop_scale_window_test)
 {
        shared_ptr<FFmpegImageProxy> proxy(new FFmpegImageProxy("test/data/flat_red.png", VIDEO_RANGE_FULL));
        shared_ptr<Image> raw = proxy->image().image;
-       shared_ptr<Image> out = raw->crop_scale_window(Crop(), dcp::Size(1998, 836), dcp::Size(1998, 1080), dcp::YUV_TO_RGB_REC709, VIDEO_RANGE_FULL, AV_PIX_FMT_YUV420P, true, false);
+       shared_ptr<Image> out = raw->crop_scale_window(
+               Crop(), dcp::Size(1998, 836), dcp::Size(1998, 1080), dcp::YUV_TO_RGB_REC709, VIDEO_RANGE_FULL, AV_PIX_FMT_YUV420P, VIDEO_RANGE_FULL, true, false
+               );
        shared_ptr<Image> save = out->scale(dcp::Size(1998, 1080), dcp::YUV_TO_RGB_REC709, AV_PIX_FMT_RGB24, false, false);
        write_image(save, "build/test/crop_scale_window_test.png");
        check_image("test/data/crop_scale_window_test.png", "build/test/crop_scale_window_test.png");
@@ -271,15 +273,21 @@ BOOST_AUTO_TEST_CASE (crop_scale_window_test)
 BOOST_AUTO_TEST_CASE (crop_scale_window_test2)
 {
        shared_ptr<Image> image (new Image(AV_PIX_FMT_XYZ12LE, dcp::Size(2048, 858), true));
-       image->crop_scale_window (Crop(279, 0, 0, 0), dcp::Size(1069, 448), dcp::Size(1069, 578), dcp::YUV_TO_RGB_REC709, VIDEO_RANGE_FULL, AV_PIX_FMT_RGB24, false, false);
-       image->crop_scale_window (Crop(2048, 0, 0, 0), dcp::Size(1069, 448), dcp::Size(1069, 578), dcp::YUV_TO_RGB_REC709, VIDEO_RANGE_FULL, AV_PIX_FMT_RGB24, false, false);
+       image->crop_scale_window (
+               Crop(279, 0, 0, 0), dcp::Size(1069, 448), dcp::Size(1069, 578), dcp::YUV_TO_RGB_REC709, VIDEO_RANGE_FULL, AV_PIX_FMT_RGB24, VIDEO_RANGE_FULL, false, false
+               );
+       image->crop_scale_window (
+               Crop(2048, 0, 0, 0), dcp::Size(1069, 448), dcp::Size(1069, 578), dcp::YUV_TO_RGB_REC709, VIDEO_RANGE_FULL, AV_PIX_FMT_RGB24, VIDEO_RANGE_FULL, false, false
+               );
 }
 
 BOOST_AUTO_TEST_CASE (crop_scale_window_test3)
 {
        shared_ptr<FFmpegImageProxy> proxy(new FFmpegImageProxy("test/data/player_seek_test_0.png", VIDEO_RANGE_FULL));
        shared_ptr<Image> xyz = proxy->image().image->convert_pixel_format(dcp::YUV_TO_RGB_REC709, AV_PIX_FMT_RGB24, true, false);
-       shared_ptr<Image> cropped = xyz->crop_scale_window(Crop(512, 0, 0, 0), dcp::Size(1486, 1080), dcp::Size(1998, 1080), dcp::YUV_TO_RGB_REC709, VIDEO_RANGE_FULL, AV_PIX_FMT_RGB24, false, false);
+       shared_ptr<Image> cropped = xyz->crop_scale_window(
+               Crop(512, 0, 0, 0), dcp::Size(1486, 1080), dcp::Size(1998, 1080), dcp::YUV_TO_RGB_REC709, VIDEO_RANGE_FULL, AV_PIX_FMT_RGB24, VIDEO_RANGE_FULL, false, false
+               );
        write_image(cropped, "build/test/crop_scale_window_test3.png");
        check_image("test/data/crop_scale_window_test3.png", "build/test/crop_scale_window_test3.png");
 }
@@ -288,7 +296,9 @@ BOOST_AUTO_TEST_CASE (crop_scale_window_test4)
 {
        shared_ptr<FFmpegImageProxy> proxy(new FFmpegImageProxy("test/data/player_seek_test_0.png", VIDEO_RANGE_FULL));
        shared_ptr<Image> xyz = proxy->image().image->convert_pixel_format(dcp::YUV_TO_RGB_REC709, AV_PIX_FMT_RGB24, true, false);
-       shared_ptr<Image> cropped = xyz->crop_scale_window(Crop(512, 0, 0, 0), dcp::Size(1486, 1080), dcp::Size(1998, 1080), dcp::YUV_TO_RGB_REC709, VIDEO_RANGE_FULL, AV_PIX_FMT_XYZ12LE, false, false);
+       shared_ptr<Image> cropped = xyz->crop_scale_window(
+               Crop(512, 0, 0, 0), dcp::Size(1486, 1080), dcp::Size(1998, 1080), dcp::YUV_TO_RGB_REC709, VIDEO_RANGE_FULL, AV_PIX_FMT_XYZ12LE, VIDEO_RANGE_FULL, false, false
+               );
        write_image(cropped, "build/test/crop_scale_window_test4.png");
        check_image("test/data/crop_scale_window_test4.png", "build/test/crop_scale_window_test4.png", 35000);
 }
@@ -297,7 +307,9 @@ BOOST_AUTO_TEST_CASE (crop_scale_window_test5)
 {
        shared_ptr<FFmpegImageProxy> proxy(new FFmpegImageProxy("test/data/player_seek_test_0.png", VIDEO_RANGE_FULL));
        shared_ptr<Image> xyz = proxy->image().image->convert_pixel_format(dcp::YUV_TO_RGB_REC709, AV_PIX_FMT_XYZ12LE, true, false);
-       shared_ptr<Image> cropped = xyz->crop_scale_window(Crop(512, 0, 0, 0), dcp::Size(1486, 1080), dcp::Size(1998, 1080), dcp::YUV_TO_RGB_REC709, VIDEO_RANGE_FULL, AV_PIX_FMT_RGB24, false, false);
+       shared_ptr<Image> cropped = xyz->crop_scale_window(
+               Crop(512, 0, 0, 0), dcp::Size(1486, 1080), dcp::Size(1998, 1080), dcp::YUV_TO_RGB_REC709, VIDEO_RANGE_FULL, AV_PIX_FMT_RGB24, VIDEO_RANGE_FULL, false, false
+               );
        write_image(cropped, "build/test/crop_scale_window_test5.png");
        check_image("test/data/crop_scale_window_test5.png", "build/test/crop_scale_window_test5.png");
 }
@@ -306,7 +318,9 @@ BOOST_AUTO_TEST_CASE (crop_scale_window_test6)
 {
        shared_ptr<FFmpegImageProxy> proxy(new FFmpegImageProxy("test/data/player_seek_test_0.png", VIDEO_RANGE_FULL));
        shared_ptr<Image> xyz = proxy->image().image->convert_pixel_format(dcp::YUV_TO_RGB_REC709, AV_PIX_FMT_XYZ12LE, true, false);
-       shared_ptr<Image> cropped = xyz->crop_scale_window(Crop(512, 0, 0, 0), dcp::Size(1486, 1080), dcp::Size(1998, 1080), dcp::YUV_TO_RGB_REC709, VIDEO_RANGE_FULL, AV_PIX_FMT_XYZ12LE, false, false);
+       shared_ptr<Image> cropped = xyz->crop_scale_window(
+               Crop(512, 0, 0, 0), dcp::Size(1486, 1080), dcp::Size(1998, 1080), dcp::YUV_TO_RGB_REC709, VIDEO_RANGE_FULL, AV_PIX_FMT_XYZ12LE, VIDEO_RANGE_FULL, false, false
+               );
        write_image(cropped, "build/test/crop_scale_window_test6.png");
        check_image("test/data/crop_scale_window_test6.png", "build/test/crop_scale_window_test6.png", 35000);
 }
index 2dc79d3f7d132c8b43157d561ae21edbad28f3eb..f44806d68e673ed9f501897d0e84761162039b99 100644 (file)
@@ -218,7 +218,7 @@ BOOST_AUTO_TEST_CASE (player_seek_test)
        player->set_always_burn_open_subtitles ();
        player->set_play_referenced ();
 
-       shared_ptr<Butler> butler (new Butler (player, AudioMapping(), 2, bind(PlayerVideo::force, _1, AV_PIX_FMT_RGB24), false, true));
+       shared_ptr<Butler> butler (new Butler (player, AudioMapping(), 2, bind(PlayerVideo::force, _1, AV_PIX_FMT_RGB24), VIDEO_RANGE_FULL, false, true));
        butler->disable_audio();
 
        for (int i = 0; i < 10; ++i) {
@@ -226,7 +226,7 @@ BOOST_AUTO_TEST_CASE (player_seek_test)
                butler->seek (t, true);
                pair<shared_ptr<PlayerVideo>, DCPTime> video = butler->get_video(true, 0);
                BOOST_CHECK_EQUAL(video.second.get(), t.get());
-               write_image(video.first->image(bind(PlayerVideo::force, _1, AV_PIX_FMT_RGB24), false, true), String::compose("build/test/player_seek_test_%1.png", i));
+               write_image(video.first->image(bind(PlayerVideo::force, _1, AV_PIX_FMT_RGB24), VIDEO_RANGE_FULL, false, true), String::compose("build/test/player_seek_test_%1.png", i));
                /* This 14.08 is empirically chosen (hopefully) to accept changes in rendering between the reference and a test machine
                   (17.10 and 16.04 seem to anti-alias a little differently) but to reject gross errors e.g. missing fonts or missing
                   text altogether.
@@ -249,7 +249,7 @@ BOOST_AUTO_TEST_CASE (player_seek_test2)
        player->set_always_burn_open_subtitles ();
        player->set_play_referenced ();
 
-       shared_ptr<Butler> butler (new Butler(player, AudioMapping(), 2, bind(PlayerVideo::force, _1, AV_PIX_FMT_RGB24), false, true));
+       shared_ptr<Butler> butler (new Butler(player, AudioMapping(), 2, bind(PlayerVideo::force, _1, AV_PIX_FMT_RGB24), VIDEO_RANGE_FULL, false, true));
        butler->disable_audio();
 
        butler->seek(DCPTime::from_seconds(5), true);
@@ -259,7 +259,9 @@ BOOST_AUTO_TEST_CASE (player_seek_test2)
                butler->seek (t, true);
                pair<shared_ptr<PlayerVideo>, DCPTime> video = butler->get_video(true, 0);
                BOOST_CHECK_EQUAL(video.second.get(), t.get());
-               write_image(video.first->image(bind(PlayerVideo::force, _1, AV_PIX_FMT_RGB24), false, true), String::compose("build/test/player_seek_test2_%1.png", i));
+               write_image(
+                       video.first->image(bind(PlayerVideo::force, _1, AV_PIX_FMT_RGB24), VIDEO_RANGE_FULL, false, true), String::compose("build/test/player_seek_test2_%1.png", i)
+                       );
                check_image(String::compose("test/data/player_seek_test2_%1.png", i), String::compose("build/test/player_seek_test2_%1.png", i), 14.08);
        }
 }
@@ -334,7 +336,7 @@ BOOST_AUTO_TEST_CASE (player_trim_crash)
 
        shared_ptr<Player> player (new Player(film));
        player->set_fast ();
-       shared_ptr<Butler> butler (new Butler(player, AudioMapping(), 6, bind(&PlayerVideo::force, _1, AV_PIX_FMT_RGB24), false, true));
+       shared_ptr<Butler> butler (new Butler(player, AudioMapping(), 6, bind(&PlayerVideo::force, _1, AV_PIX_FMT_RGB24), VIDEO_RANGE_FULL, false, true));
 
        /* Wait for the butler to fill */
        dcpomatic_sleep_seconds (5);