Don't scale chroma subsampled images to sizes that don't align with the subsampling... v2.15.166
authorCarl Hetherington <cth@carlh.net>
Sun, 3 Oct 2021 19:22:14 +0000 (21:22 +0200)
committerCarl Hetherington <cth@carlh.net>
Sun, 3 Oct 2021 21:41:02 +0000 (23:41 +0200)
There's a slightly odd effect when scaling e.g. YVU420 images to
odd and then even widths - there's a small but visible luminance
shift.  I don't know why this happens, but keeping the scaling
sizes locked to the subsampling seems to help.

src/lib/pixel_quanta.cc
src/lib/pixel_quanta.h
src/lib/player.cc
src/lib/player_video.cc
src/lib/util.cc
src/lib/util.h
src/lib/video_content.cc
src/lib/video_content.h

index 09e6840645cf7d967a05b9dddbbbb92aaf2f84e1..7c1d285cffd3d0c1b55b0384f73cc582b10cd135 100644 (file)
@@ -53,6 +53,13 @@ PixelQuanta::round_y (int y_) const
 }
 
 
+dcp::Size
+PixelQuanta::round (dcp::Size size) const
+{
+       return dcp::Size (round_x(size.width), round_y(size.height));
+}
+
+
 PixelQuanta
 max (PixelQuanta const& a, PixelQuanta const& b)
 {
index c37ba189bb34895696d5a3a8b8656619f363678b..018ce334638f1819ac56eddb541283303049144d 100644 (file)
@@ -26,6 +26,7 @@
 #include "warnings.h"
 
 #include <libcxml/cxml.h>
+#include <dcp/types.h>
 DCPOMATIC_DISABLE_WARNINGS
 #include <libxml++/libxml++.h>
 DCPOMATIC_ENABLE_WARNINGS
@@ -54,6 +55,7 @@ public:
 
        int round_x (int x_) const;
        int round_y (int y_) const;
+       dcp::Size round (dcp::Size size) const;
 
        int x;
        int y;
index 285126ced266a71f70575a7502c1d865407563f3..b93bf3f4a7c2756643e47b4cc8e8f0d2a9bcc6b1 100644 (file)
@@ -920,16 +920,23 @@ Player::video (weak_ptr<Piece> wp, ContentVideo video)
                }
        }
 
+       auto const content_video = piece->content->video;
+
        _last_video[wp] = std::make_shared<PlayerVideo>(
                video.image,
-               piece->content->video->actual_crop(),
-               piece->content->video->fade (_film, video.frame),
-               scale_for_display(piece->content->video->scaled_size(_film->frame_size()), _video_container_size, _film->frame_size()),
+               content_video->actual_crop(),
+               content_video->fade (_film, video.frame),
+               scale_for_display(
+                       content_video->scaled_size(_film->frame_size()),
+                       _video_container_size,
+                       _film->frame_size(),
+                       content_video->pixel_quanta()
+                       ),
                _video_container_size,
                video.eyes,
                video.part,
-               piece->content->video->colour_conversion(),
-               piece->content->video->range(),
+               content_video->colour_conversion(),
+               content_video->range(),
                piece->content,
                video.frame,
                false
index c9bc2dcde9b9e6f48f414cadcaae269cc6d1248b..4cc536bb7530583639e14e3ff7c6270549daf947 100644 (file)
@@ -345,7 +345,12 @@ PlayerVideo::reset_metadata (shared_ptr<const Film> film, dcp::Size player_video
 
        _crop = content->video->actual_crop();
        _fade = content->video->fade(film, _video_frame.get());
-       _inter_size = scale_for_display(content->video->scaled_size(film->frame_size()), player_video_container_size, film->frame_size());
+       _inter_size = scale_for_display(
+               content->video->scaled_size(film->frame_size()),
+               player_video_container_size,
+               film->frame_size(),
+               content->video->pixel_quanta()
+               );
        _out_size = player_video_container_size;
        _colour_conversion = content->video->colour_conversion();
        _video_range = content->video->range();
index d3af74376a3cd2349eeceafa9ab3ab35f5dc9423..78ed8da99f9e1a2e0ddfe3ea416c4d8296fd6702 100644 (file)
@@ -1111,7 +1111,7 @@ linear_to_db (double linear)
 
 
 dcp::Size
-scale_for_display (dcp::Size s, dcp::Size display_container, dcp::Size film_container)
+scale_for_display (dcp::Size s, dcp::Size display_container, dcp::Size film_container, PixelQuanta quanta)
 {
        /* Now scale it down if the display container is smaller than the film container */
        if (display_container != film_container) {
@@ -1122,6 +1122,7 @@ scale_for_display (dcp::Size s, dcp::Size display_container, dcp::Size film_cont
 
                s.width = lrintf (s.width * scale);
                s.height = lrintf (s.height * scale);
+               s = quanta.round (s);
        }
 
        return s;
index 013eabe120678c415f28e176a115ed729a12eae3..10c5678ffd37f72c4b0e37c0d450f18ad950efa3 100644 (file)
 
 */
 
+
 /** @file src/util.h
  *  @brief Some utility functions and classes.
  */
 
+
 #ifndef DCPOMATIC_UTIL_H
 #define DCPOMATIC_UTIL_H
 
-#include "types.h"
-#include "dcpomatic_time.h"
+
 #include "audio_mapping.h"
+#include "dcpomatic_time.h"
+#include "pixel_quanta.h"
+#include "types.h"
 #include <dcp/atmos_asset.h>
 #include <dcp/decrypted_kdm.h>
 #include <dcp/util.h>
@@ -41,6 +45,7 @@
 
 #undef check
 
+
 namespace dcp {
        class PictureAsset;
        class SoundAsset;
@@ -119,7 +124,7 @@ extern std::string day_of_week_to_string (boost::gregorian::greg_weekday d);
 extern void emit_subtitle_image (dcpomatic::ContentTimePeriod period, dcp::SubtitleImage sub, dcp::Size size, std::shared_ptr<TextDecoder> decoder);
 extern bool show_jobs_on_console (bool progress);
 extern void copy_in_bits (boost::filesystem::path from, boost::filesystem::path to, std::function<void (float)>);
-extern dcp::Size scale_for_display (dcp::Size s, dcp::Size display_container, dcp::Size film_container);
+extern dcp::Size scale_for_display (dcp::Size s, dcp::Size display_container, dcp::Size film_container, PixelQuanta quanta);
 extern dcp::DecryptedKDM decrypt_kdm_with_helpful_error (dcp::EncryptedKDM kdm);
 extern boost::filesystem::path default_font_file ();
 extern std::string to_upper (std::string s);
index 0ef1021161d7a69004494d733da1b83bc02ca046..9ff35ffdf891c783b9efa2fffc6e332aea04e3cf 100644 (file)
@@ -655,7 +655,7 @@ VideoContent::scaled_size (dcp::Size film_container)
                _legacy_ratio = boost::optional<float>();
        }
 
-       return auto_size;
+       return _pixel_quanta.round (auto_size);
 }
 
 
index ce645bb41fd714c8c6ad5c0b1c734827bbbee9a6..2adf941d97cc3cd4a26a5b0e0c13ca33abd95464 100644 (file)
@@ -183,6 +183,11 @@ public:
                return _range;
        }
 
+       PixelQuanta pixel_quanta () const {
+               boost::mutex::scoped_lock lm (_mutex);
+               return _pixel_quanta;
+       }
+
        bool use () const {
                boost::mutex::scoped_lock lm (_mutex);
                return _use;