wip: got stuck... because PlayerVideo is related to the render size adjust-sizing
authorCarl Hetherington <cth@carlh.net>
Thu, 4 Aug 2022 21:55:17 +0000 (23:55 +0200)
committerCarl Hetherington <cth@carlh.net>
Thu, 4 Aug 2022 21:55:17 +0000 (23:55 +0200)
because its subtitles are prepared for the _video_container_size that
the Player knows about.  I think the only way around this would be to
store the subs in PlayerVideo in some independent way and to scale/convert
to bitmap later.

17 files changed:
src/lib/butler.cc
src/lib/butler.h
src/lib/dcp_video.cc
src/lib/dcp_video.h
src/lib/ffmpeg_encoder.cc
src/lib/ffmpeg_file_encoder.cc
src/lib/j2k_encoder.cc
src/lib/pixel_quanta.cc
src/lib/pixel_quanta.h
src/lib/player.cc
src/lib/player_video.cc
src/lib/player_video.h
src/lib/video_ring_buffers.cc
src/lib/video_ring_buffers.h
src/wx/simple_video_view.cc
src/wx/video_waveform_plot.cc
test/player_video_test.cc [new file with mode: 0644]

index ce35b1f39aff61da043aa71e0a3d5fad0e963f11..ad3834deeba57af36903bee99c33139480a0cba0 100644 (file)
@@ -57,6 +57,8 @@ using namespace boost::placeholders;
 
 /** @param pixel_format Pixel format functor that will be used when calling ::image on PlayerVideos coming out of this
  *  butler.  This will be used (where possible) to prepare the PlayerVideos so that calling image() on them is quick.
+ *  @param display_container Same as above for the `display_container` value.
+ *  @param film_container Same as above for the `film_container` value.
  *  @param alignment Same as above for the `alignment' value.
  *  @param fast Same as above for the `fast' flag.
  */
@@ -66,6 +68,8 @@ Butler::Butler (
        AudioMapping audio_mapping,
        int audio_channels,
        function<AVPixelFormat (AVPixelFormat)> pixel_format,
+       dcp::Size display_container,
+       dcp::Size film_container,
        VideoRange video_range,
        Image::Alignment alignment,
        bool fast,
@@ -84,6 +88,8 @@ Butler::Butler (
        , _audio_channels (audio_channels)
        , _disable_audio (audio == Audio::DISABLED)
        , _pixel_format (pixel_format)
+       , _display_container(display_container)
+       , _film_container(film_container)
        , _video_range (video_range)
        , _alignment (alignment)
        , _fast (fast)
@@ -326,7 +332,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, _video_range, _alignment, _fast, _prepare_only_proxy);
+               video->prepare(_pixel_format, _display_container, _film_container, _video_range, _alignment, _fast, _prepare_only_proxy);
                LOG_TIMING("finish-prepare in %1", thread_id());
        }
 }
@@ -410,7 +416,7 @@ Butler::player_change (ChangeType type, int property)
                if (type == ChangeType::DONE) {
                        auto film = _film.lock();
                        if (film) {
-                               _video.reset_metadata (film, _player->video_container_size());
+                               _video.reset_metadata(film);
                        }
                }
                return;
index 87408646bc28e3e458e23f75757cc5a81b80da44..711c9100090789a581bbe4bd054170850b511dd0 100644 (file)
@@ -50,6 +50,8 @@ public:
                AudioMapping map,
                int audio_channels,
                std::function<AVPixelFormat (AVPixelFormat)> pixel_format,
+               dcp::Size display_container,
+               dcp::Size film_container,
                VideoRange video_range,
                Image::Alignment alignment,
                bool fast,
@@ -130,6 +132,8 @@ private:
        bool _disable_audio;
 
        std::function<AVPixelFormat (AVPixelFormat)> _pixel_format;
+       dcp::Size _display_container;
+       dcp::Size _film_container;
        VideoRange _video_range;
        Image::Alignment _alignment;
        bool _fast;
index 14f23bd3782e108e8a27c596a926880eccdfbecb..0e42f0a1217b987a4e750e9e177e34804538d11c 100644 (file)
@@ -80,9 +80,10 @@ using namespace boost::placeholders;
  *  @param bw J2K bandwidth to use (see Config::j2k_bandwidth ())
  */
 DCPVideo::DCPVideo (
-       shared_ptr<const PlayerVideo> frame, int index, int dcp_fps, int bw, Resolution r
+       shared_ptr<const PlayerVideo> frame, dcp::Size container, int index, int dcp_fps, int bw, Resolution r
        )
        : _frame (frame)
+       , _container(container)
        , _index (index)
        , _frames_per_second (dcp_fps)
        , _j2k_bandwidth (bw)
@@ -101,11 +102,18 @@ DCPVideo::DCPVideo (shared_ptr<const PlayerVideo> frame, shared_ptr<const cxml::
 }
 
 shared_ptr<dcp::OpenJPEGImage>
-DCPVideo::convert_to_xyz (shared_ptr<const PlayerVideo> frame, dcp::NoteHandler note)
+DCPVideo::convert_to_xyz (shared_ptr<const PlayerVideo> frame, dcp::Size container, dcp::NoteHandler note)
 {
        shared_ptr<dcp::OpenJPEGImage> xyz;
 
-       auto image = frame->image (bind(&PlayerVideo::keep_xyz_or_rgb, _1), VideoRange::FULL, false);
+       auto image = frame->image(
+               bind(&PlayerVideo::keep_xyz_or_rgb, _1),
+               container,
+               container,
+               VideoRange::FULL,
+               false
+               );
+
        if (frame->colour_conversion()) {
                xyz = dcp::rgb_to_xyz (
                        image->data()[0],
@@ -134,7 +142,7 @@ DCPVideo::encode_locally () const
        int const minimum_size = 16384;
        LOG_DEBUG_ENCODE("Using minimum frame size %1", minimum_size);
 
-       auto xyz = convert_to_xyz (_frame, boost::bind(&Log::dcp_log, dcpomatic_log.get(), _1, _2));
+       auto xyz = convert_to_xyz(_frame, _container, boost::bind(&Log::dcp_log, dcpomatic_log.get(), _1, _2));
        int noise_amount = 2;
        int pixel_skip = 16;
        while (true) {
@@ -159,7 +167,7 @@ DCPVideo::encode_locally () const
                 * convert_to_xyz() again because compress_j2k() corrupts its xyz parameter.
                 */
 
-               xyz = convert_to_xyz (_frame, boost::bind(&Log::dcp_log, dcpomatic_log.get(), _1, _2));
+               xyz = convert_to_xyz(_frame, _container, boost::bind(&Log::dcp_log, dcpomatic_log.get(), _1, _2));
                auto size = xyz->size ();
                auto pixels = size.width * size.height;
                dcpomatic::RNG rng(42);
index 3bd516ccd4ea676567e80ac70880d39b382568c6..0c211909911c56237dce1822e01407d4124e8641 100644 (file)
@@ -42,7 +42,7 @@ class PlayerVideo;
 class DCPVideo
 {
 public:
-       DCPVideo (std::shared_ptr<const PlayerVideo>, int index, int dcp_fps, int bandwidth, Resolution r);
+       DCPVideo (std::shared_ptr<const PlayerVideo>, dcp::Size container, int index, int dcp_fps, int bandwidth, Resolution resolution);
        DCPVideo (std::shared_ptr<const PlayerVideo>, cxml::ConstNodePtr);
 
        DCPVideo (DCPVideo const&) = default;
@@ -59,13 +59,14 @@ public:
 
        bool same (std::shared_ptr<const DCPVideo> other) const;
 
-       static std::shared_ptr<dcp::OpenJPEGImage> convert_to_xyz (std::shared_ptr<const PlayerVideo> frame, dcp::NoteHandler note);
+       static std::shared_ptr<dcp::OpenJPEGImage> convert_to_xyz(std::shared_ptr<const PlayerVideo> frame, dcp::Size container, dcp::NoteHandler note);
 
 private:
 
        void add_metadata (xmlpp::Element *) const;
 
        std::shared_ptr<const PlayerVideo> _frame;
+       dcp::Size _container;
        int _index;                      ///< frame index within the DCP's intrinsic duration
        int _frames_per_second;          ///< Frames per second that we will use for the DCP
        int _j2k_bandwidth;              ///< J2K bandwidth to use
index 6b31c4201901bf5004b7a1efc9a848615799c5fd..05131488ad11d69df2301ab29178780db6fa4974 100644 (file)
@@ -112,6 +112,8 @@ FFmpegEncoder::FFmpegEncoder (
                map,
                _output_audio_channels,
                bind(&PlayerVideo::force, FFmpegFileEncoder::pixel_format(format)),
+               _film->frame_size(),
+               _film->frame_size(),
                VideoRange::VIDEO,
                Image::Alignment::PADDED,
                false,
index 0d5167c496c109ae0b7f4db56d28ee350d4134e8..3af2db7ce4abd2a1c461eeb519cb264bae17f094 100644 (file)
@@ -402,7 +402,9 @@ FFmpegFileEncoder::video (shared_ptr<PlayerVideo> video, DCPTime time)
 {
        /* All our output formats are video range at the moment */
        auto image = video->image (
-               bind (&PlayerVideo::force, _pixel_format),
+               bind(&PlayerVideo::force, _pixel_format),
+               _video_frame_size,
+               _video_frame_size,
                VideoRange::VIDEO,
                false
                );
index 53e1c272fea9dacf9f90fac13263b76982d5b293..3e1bbc864d3d595c384219ab3d4fdb75aba887ab 100644 (file)
@@ -225,7 +225,7 @@ J2KEncoder::encode (shared_ptr<PlayerVideo> pv, DCPTime time)
                LOG_DEBUG_ENCODE("Frame @ %1 FAKE", to_string(time));
                _writer->fake_write (position, pv->eyes ());
                frame_done ();
-       } else if (pv->has_j2k() && !_film->reencode_j2k()) {
+       } else if (pv->has_j2k(_film->frame_size(), _film->frame_size()) && !_film->reencode_j2k()) {
                LOG_DEBUG_ENCODE("Frame @ %1 J2K", to_string(time));
                /* This frame already has J2K data, so just write it */
                _writer->write (pv->j2k(), position, pv->eyes ());
@@ -239,6 +239,7 @@ J2KEncoder::encode (shared_ptr<PlayerVideo> pv, DCPTime time)
                LOG_TIMING ("add-frame-to-queue queue=%1", _queue.size ());
                _queue.push_back (DCPVideo(
                                pv,
+                               _film->frame_size(),
                                position,
                                _film->video_frame_rate(),
                                _film->j2k_bandwidth(),
index 7c1d285cffd3d0c1b55b0384f73cc582b10cd135..ad3ee1d7a6c7fff1040dbe8ca866dff7aa8b9456 100644 (file)
@@ -66,3 +66,17 @@ max (PixelQuanta const& a, PixelQuanta const& b)
        return { std::max(a.x, b.x), std::max(a.y, b.y) };
 }
 
+
+bool
+operator==(PixelQuanta const& a, PixelQuanta const& b)
+{
+       return a.x == b.x && a.y == b.y;
+}
+
+
+bool
+operator!=(PixelQuanta const& a, PixelQuanta const& b)
+{
+       return a.x != b.x || a.y != b.y;
+}
+
index 37d2321f45b8474caeb777e2fe3cd4247f838b2a..46bfdffd0b7cd03c57fcf69f7544c525297e600e 100644 (file)
@@ -62,6 +62,8 @@ public:
 
 
 PixelQuanta max (PixelQuanta const& a, PixelQuanta const& b);
+bool operator==(PixelQuanta const& a, PixelQuanta const& b);
+bool operator!=(PixelQuanta const& a, PixelQuanta const& b);
 
 #endif
 
index de9be2b71b43686e8eb0fd261a3eac181b44e329..23a56ddfecef134d183700c314c212db1b80f84e 100644 (file)
@@ -302,10 +302,9 @@ Player::playlist_content_change (ChangeType type, int property, bool frequent)
 {
        if (property == VideoContentProperty::CROP) {
                if (type == ChangeType::DONE) {
-                       auto const vcs = video_container_size();
                        boost::mutex::scoped_lock lm (_mutex);
                        for (auto const& i: _delay) {
-                               i.first->reset_metadata (_film, vcs);
+                               i.first->reset_metadata(_film);
                        }
                }
        } else {
index d45bf9f432b90c996feb870baf1580fc3a5796a4..2fe9173936be88aba9c069e6bec1526ea59578b1 100644 (file)
@@ -26,6 +26,7 @@
 #include "j2k_image_proxy.h"
 #include "player.h"
 #include "player_video.h"
+#include "util.h"
 #include "video_content.h"
 #include <dcp/raw_convert.h>
 extern "C" {
@@ -51,8 +52,8 @@ PlayerVideo::PlayerVideo (
        shared_ptr<const ImageProxy> in,
        Crop crop,
        boost::optional<double> fade,
-       dcp::Size inter_size,
-       dcp::Size out_size,
+       dcp::Size size_in_film,
+       PixelQuanta pixel_quanta,
        Eyes eyes,
        Part part,
        optional<ColourConversion> colour_conversion,
@@ -64,8 +65,8 @@ PlayerVideo::PlayerVideo (
        : _in (in)
        , _crop (crop)
        , _fade (fade)
-       , _inter_size (inter_size)
-       , _out_size (out_size)
+       , _size_in_film(size_in_film)
+       , _pixel_quanta(pixel_quanta)
        , _eyes (eyes)
        , _part (part)
        , _colour_conversion (colour_conversion)
@@ -83,8 +84,8 @@ PlayerVideo::PlayerVideo (shared_ptr<cxml::Node> node, shared_ptr<Socket> socket
        _crop = Crop (node);
        _fade = node->optional_number_child<double> ("Fade");
 
-       _inter_size = dcp::Size (node->number_child<int> ("InterWidth"), node->number_child<int> ("InterHeight"));
-       _out_size = dcp::Size (node->number_child<int> ("OutWidth"), node->number_child<int> ("OutHeight"));
+       _size_in_film = dcp::Size(node->number_child<int>("SizeInFilmWidth"), node->number_child<int>("SizeInFilmHeight"));
+       _pixel_quanta = PixelQuanta(node->number_child<int>("PixelQuantumX"), node->number_child<int>("PixelQuantumY"));
        _eyes = static_cast<Eyes>(node->number_child<int>("Eyes"));
        _part = static_cast<Part>(node->number_child<int>("Part"));
        _video_range = static_cast<VideoRange>(node->number_child<int>("VideoRange"));
@@ -116,22 +117,29 @@ PlayerVideo::set_text (PositionImage image)
 
 
 shared_ptr<Image>
-PlayerVideo::image (function<AVPixelFormat (AVPixelFormat)> pixel_format, VideoRange video_range, bool fast) const
+PlayerVideo::image(
+       function<AVPixelFormat (AVPixelFormat)> pixel_format,
+       dcp::Size display_container,
+       dcp::Size film_container,
+       VideoRange video_range,
+       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, video_range, fast);
+       if (!_image || _crop != _image_crop || _size_in_film != _image_size_in_film || _pixel_quanta != _image_pixel_quanta || _fade != _image_fade) {
+               make_image(pixel_format, display_container, film_container, video_range, fast);
        }
        return _image;
 }
 
 
 shared_ptr<const Image>
-PlayerVideo::raw_image () const
+PlayerVideo::raw_image(dcp::Size display_container, dcp::Size film_container) const
 {
-       return _in->image(Image::Alignment::COMPACT, _inter_size).image;
+       auto const inter_size = scale_for_display(_size_in_film, display_container, film_container, _pixel_quanta);
+       return _in->image(Image::Alignment::COMPACT, inter_size).image;
 }
 
 
@@ -142,14 +150,22 @@ PlayerVideo::raw_image () const
  *  @param fast true to be fast at the expense of quality.
  */
 void
-PlayerVideo::make_image (function<AVPixelFormat (AVPixelFormat)> pixel_format, VideoRange video_range, bool fast) const
+PlayerVideo::make_image (
+       function<AVPixelFormat (AVPixelFormat)> pixel_format,
+       dcp::Size display_container,
+       dcp::Size film_container,
+       VideoRange video_range,
+       bool fast
+       ) const
 {
        _image_crop = _crop;
-       _image_inter_size = _inter_size;
-       _image_out_size = _out_size;
+       _image_size_in_film = _size_in_film;
+       _image_pixel_quanta = _pixel_quanta;
        _image_fade = _fade;
 
-       auto prox = _in->image (Image::Alignment::PADDED, _inter_size);
+       auto const inter_size = scale_for_display(_size_in_film, display_container, film_container, _pixel_quanta);
+
+       auto prox = _in->image (Image::Alignment::PADDED, inter_size);
        _error = prox.error;
 
        auto total_crop = _crop;
@@ -185,7 +201,7 @@ PlayerVideo::make_image (function<AVPixelFormat (AVPixelFormat)> pixel_format, V
        }
 
        _image = prox.image->crop_scale_window (
-               total_crop, _inter_size, _out_size, yuv_to_rgb, _video_range, pixel_format (prox.image->pixel_format()), video_range, Image::Alignment::COMPACT, fast
+               total_crop, inter_size, display_container, yuv_to_rgb, _video_range, pixel_format(prox.image->pixel_format()), video_range, Image::Alignment::COMPACT, fast
                );
 
        if (_text) {
@@ -206,10 +222,10 @@ PlayerVideo::add_metadata (xmlpp::Node* node) const
                node->add_child("Fade")->add_child_text (raw_convert<string> (_fade.get ()));
        }
        _in->add_metadata (node->add_child ("In"));
-       node->add_child("InterWidth")->add_child_text (raw_convert<string> (_inter_size.width));
-       node->add_child("InterHeight")->add_child_text (raw_convert<string> (_inter_size.height));
-       node->add_child("OutWidth")->add_child_text (raw_convert<string> (_out_size.width));
-       node->add_child("OutHeight")->add_child_text (raw_convert<string> (_out_size.height));
+       node->add_child("SizeInFilmWidth")->add_child_text(raw_convert<string>(_size_in_film.width));
+       node->add_child("SizeInFilmHeight")->add_child_text(raw_convert<string>(_size_in_film.height));
+       node->add_child("PixelQuantumX")->add_child_text(raw_convert<string>(_pixel_quanta.x));
+       node->add_child("PixelQuantumY")->add_child_text(raw_convert<string>(_pixel_quanta.y));
        node->add_child("Eyes")->add_child_text (raw_convert<string> (static_cast<int> (_eyes)));
        node->add_child("Part")->add_child_text (raw_convert<string> (static_cast<int> (_part)));
        node->add_child("VideoRange")->add_child_text(raw_convert<string>(static_cast<int>(_video_range)));
@@ -237,7 +253,7 @@ PlayerVideo::write_to_socket (shared_ptr<Socket> socket) const
 
 
 bool
-PlayerVideo::has_j2k () const
+PlayerVideo::has_j2k(dcp::Size display_container, dcp::Size film_container) const
 {
        /* XXX: maybe other things */
 
@@ -246,7 +262,8 @@ PlayerVideo::has_j2k () const
                return false;
        }
 
-       return _crop == Crop() && _out_size == j2k->size() && _inter_size == j2k->size() && !_text && !_fade && !_colour_conversion;
+       auto const inter_size = scale_for_display(_size_in_film, display_container, film_container, _pixel_quanta);
+       return _crop == Crop() && film_container == j2k->size() && inter_size == j2k->size() && !_text && !_fade && !_colour_conversion;
 }
 
 
@@ -259,21 +276,14 @@ PlayerVideo::j2k () const
 }
 
 
-Position<int>
-PlayerVideo::inter_position () const
-{
-       return Position<int> ((_out_size.width - _inter_size.width) / 2, (_out_size.height - _inter_size.height) / 2);
-}
-
-
 /** @return true if this PlayerVideo is definitely the same as another, false if it is probably not */
 bool
 PlayerVideo::same (shared_ptr<const PlayerVideo> other) const
 {
        if (_crop != other->_crop ||
            _fade != other->_fade ||
-           _inter_size != other->_inter_size ||
-           _out_size != other->_out_size ||
+           _size_in_film != other->_size_in_film ||
+           _pixel_quanta != other->_pixel_quanta ||
            _eyes != other->_eyes ||
            _part != other->_part ||
            _colour_conversion != other->_colour_conversion ||
@@ -311,12 +321,21 @@ PlayerVideo::keep_xyz_or_rgb (AVPixelFormat p)
 
 
 void
-PlayerVideo::prepare (function<AVPixelFormat (AVPixelFormat)> pixel_format, VideoRange video_range, Image::Alignment alignment, bool fast, bool proxy_only)
+PlayerVideo::prepare(
+       function<AVPixelFormat (AVPixelFormat)> pixel_format,
+       dcp::Size display_container,
+       dcp::Size film_container,
+       VideoRange video_range,
+       Image::Alignment alignment,
+       bool fast,
+       bool proxy_only
+       )
 {
-       _in->prepare (alignment, _inter_size);
+       auto const inter_size = scale_for_display(_size_in_film, display_container, film_container, _pixel_quanta);
+       _in->prepare(alignment, inter_size);
        boost::mutex::scoped_lock lm (_mutex);
        if (!_image && !proxy_only) {
-               make_image (pixel_format, video_range, fast);
+               make_image(pixel_format, display_container, film_container, video_range, fast);
        }
 }
 
@@ -336,8 +355,8 @@ PlayerVideo::shallow_copy () const
                _in,
                _crop,
                _fade,
-               _inter_size,
-               _out_size,
+               _size_in_film,
+               _pixel_quanta,
                _eyes,
                _part,
                _colour_conversion,
@@ -349,11 +368,11 @@ PlayerVideo::shallow_copy () const
 }
 
 
-/** Re-read crop, fade, inter/out size, colour conversion and video range from our content.
+/** Re-read crop, fade, colour conversion and video range from our content.
  *  @return true if this was possible, false if not.
  */
 bool
-PlayerVideo::reset_metadata (shared_ptr<const Film> film, dcp::Size player_video_container_size)
+PlayerVideo::reset_metadata (shared_ptr<const Film> film)
 {
        auto content = _content.lock();
        if (!content || !_video_frame) {
@@ -362,13 +381,6 @@ 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(),
-               content->video->pixel_quanta()
-               );
-       _out_size = player_video_container_size;
        _colour_conversion = content->video->colour_conversion();
        _video_range = content->video->range();
 
index f2781c1a0c51c3e099dd0009604e04a89ce2c3df..3be0bafbc7b2711d8996843a785abc6d08cbe00a 100644 (file)
@@ -26,6 +26,7 @@
 #include "colour_conversion.h"
 #include "dcpomatic_time.h"
 #include "image.h"
+#include "pixel_quanta.h"
 #include "position.h"
 #include "position_image.h"
 #include "types.h"
@@ -52,8 +53,8 @@ public:
                std::shared_ptr<const ImageProxy> image,
                Crop crop,
                boost::optional<double> fade,
-               dcp::Size inter_size,
-               dcp::Size out_size,
+               dcp::Size size_in_film,
+               PixelQuanta pixel_quanta,
                Eyes eyes,
                Part part,
                boost::optional<ColourConversion> colour_conversion,
@@ -75,9 +76,28 @@ public:
                return _text;
        }
 
-       void prepare (std::function<AVPixelFormat (AVPixelFormat)> pixel_format, VideoRange video_range, Image::Alignment alignment, bool fast, bool proxy_only);
-       std::shared_ptr<Image> image (std::function<AVPixelFormat (AVPixelFormat)> pixel_format, VideoRange video_range, bool fast) const;
-       std::shared_ptr<const Image> raw_image () const;
+       void prepare(
+               std::function<AVPixelFormat (AVPixelFormat)> pixel_format,
+               dcp::Size display_container,
+               dcp::Size film_container,
+               VideoRange video_range,
+               Image::Alignment alignment,
+               bool fast,
+               bool proxy_only
+               );
+
+       std::shared_ptr<Image> image(
+               std::function<AVPixelFormat (AVPixelFormat)> pixel_format,
+               dcp::Size display_container,
+               dcp::Size film_container,
+               VideoRange video_range,
+               bool fast
+               ) const;
+
+       std::shared_ptr<const Image> raw_image(
+               dcp::Size display_container,
+               dcp::Size film_container
+               ) const;
 
        static AVPixelFormat force (AVPixelFormat);
        static AVPixelFormat keep_xyz_or_rgb (AVPixelFormat);
@@ -85,9 +105,13 @@ public:
        void add_metadata (xmlpp::Node* node) const;
        void write_to_socket (std::shared_ptr<Socket> socket) const;
 
-       bool reset_metadata (std::shared_ptr<const Film> film, dcp::Size player_video_container_size);
+       bool reset_metadata(std::shared_ptr<const Film> film);
+
+       bool has_j2k(
+               dcp::Size display_container,
+               dcp::Size film_container
+               ) const;
 
-       bool has_j2k () const;
        std::shared_ptr<const dcp::Data> j2k () const;
 
        Eyes eyes () const {
@@ -102,18 +126,6 @@ public:
                return _colour_conversion;
        }
 
-       /** @return Position of the content within the overall image once it has been scaled up */
-       Position<int> inter_position () const;
-
-       /** @return Size of the content within the overall image once it has been scaled up */
-       dcp::Size inter_size () const {
-               return _inter_size;
-       }
-
-       dcp::Size out_size () const {
-               return _out_size;
-       }
-
        bool same (std::shared_ptr<const PlayerVideo> other) const;
 
        size_t memory_used () const;
@@ -127,13 +139,19 @@ public:
        }
 
 private:
-       void make_image (std::function<AVPixelFormat (AVPixelFormat)> pixel_format, VideoRange video_range, bool fast) const;
+       void make_image(
+               std::function<AVPixelFormat (AVPixelFormat)> pixel_format,
+               dcp::Size display_container,
+               dcp::Size film_container,
+               VideoRange video_range,
+               bool fast
+               ) const;
 
        std::shared_ptr<const ImageProxy> _in;
        Crop _crop;
        boost::optional<double> _fade;
-       dcp::Size _inter_size;
-       dcp::Size _out_size;
+       dcp::Size _size_in_film;
+       PixelQuanta _pixel_quanta;
        Eyes _eyes;
        Part _part;
        boost::optional<ColourConversion> _colour_conversion;
@@ -148,10 +166,10 @@ private:
        mutable std::shared_ptr<Image> _image;
        /** _crop that was used to make _image */
        mutable Crop _image_crop;
-       /** _inter_size that was used to make _image */
-       mutable dcp::Size _image_inter_size;
-       /** _out_size that was used to make _image */
-       mutable dcp::Size _image_out_size;
+       /** _size_in_film that was used to make _image */
+       mutable dcp::Size _image_size_in_film;
+       /** _pixel_quanta that was used to make _image */
+       mutable PixelQuanta _image_pixel_quanta;
        /** _fade that was used to make _image */
        mutable boost::optional<double> _image_fade;
        /** true if there was an error when decoding our image */
index 63c52ee068879c0b262268ca94589b8c80928781..f44dc9c7a2d122ca779f3e5234dd398091d839cf 100644 (file)
@@ -94,11 +94,11 @@ VideoRingBuffers::memory_used () const
 
 
 void
-VideoRingBuffers::reset_metadata (shared_ptr<const Film> film, dcp::Size player_video_container_size)
+VideoRingBuffers::reset_metadata (shared_ptr<const Film> film)
 {
        boost::mutex::scoped_lock lm (_mutex);
        for (auto const& i: _data) {
-               i.first->reset_metadata (film, player_video_container_size);
+               i.first->reset_metadata(film);
        }
 }
 
index 47fda01f7fd7b9c503a84d6cffc7c2dde60b15a3..df06122d03d5fc8a95d3c4714c8decac6fc19183 100644 (file)
@@ -45,7 +45,7 @@ public:
        Frame size () const;
        bool empty () const;
 
-       void reset_metadata (std::shared_ptr<const Film> film, dcp::Size player_video_container_size);
+       void reset_metadata(std::shared_ptr<const Film> film);
 
        std::pair<size_t, std::string> memory_used () const;
 
index 00d81ab47a4d89f89e552b55ab017348e7220363..87d7ddadd831e629667abb2a00eb2548dbbd3f4f 100644 (file)
@@ -241,7 +241,11 @@ SimpleVideoView::update ()
 
        _state_timer.set ("get image");
 
-       _image = player_video().first->image(boost::bind(&PlayerVideo::force, AV_PIX_FMT_RGB24), VideoRange::FULL, true);
+       _image = player_video().first->image(
+               boost::bind(&PlayerVideo::force, AV_PIX_FMT_RGB24),
+               VideoRange::FULL,
+               true
+               );
 
        _state_timer.set ("ImageChanged");
        _viewer->image_changed (player_video().first);
index 8e3284682485833dc7395c65b75e1c1edeb3be14..6ec1734690e7b503186bc2a0e4b6b72e6f9d4432 100644 (file)
@@ -195,10 +195,15 @@ VideoWaveformPlot::set_image (shared_ptr<PlayerVideo> image)
                return;
        }
 
+       auto film = _film.lock ();
+       if (!film) {
+               return;
+       }
+
        /* We must copy the PlayerVideo here as we will call ::image() on it, potentially
           with a different pixel_format than was used when ::prepare() was called.
        */
-       _image = DCPVideo::convert_to_xyz (image->shallow_copy(), [](dcp::NoteType, string) {});
+       _image = DCPVideo::convert_to_xyz(image->shallow_copy(), film->frame_size(), [](dcp::NoteType, string) {});
        _dirty = true;
        Refresh ();
 }
diff --git a/test/player_video_test.cc b/test/player_video_test.cc
new file mode 100644 (file)
index 0000000..c4241ed
--- /dev/null
@@ -0,0 +1,73 @@
+/*
+    Copyright (C) 2022 Carl Hetherington <cth@carlh.net>
+
+    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.
+
+    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 DCP-o-matic.  If not, see <http://www.gnu.org/licenses/>.
+
+*/
+
+
+#include "lib/colour_conversion.h"
+#include "lib/j2k_image_proxy.h"
+#include "lib/player_video.h"
+#include <dcp/openjpeg_image.h>
+#include <dcp/j2k_transcode.h>
+#include <dcp/mono_picture_frame.h>
+#include <boost/optional.hpp>
+#include <boost/test/unit_test.hpp>
+
+
+using std::make_shared;
+using std::weak_ptr;
+using boost::optional;
+
+
+BOOST_AUTO_TEST_CASE(player_video_j2k_passthrough_test)
+{
+       auto size = dcp::Size(4096, 2048);
+       auto image = make_shared<dcp::OpenJPEGImage>(size);
+       for (int x = 0; x < size.width; ++x) {
+               image->data(0)[x] = x;
+               image->data(1)[x] = x;
+               image->data(2)[x] = x;
+       }
+       for (int y = 1; y < size.height; ++y) {
+               memcpy(image->data(0) + y * size.width, image->data(0), size.width);
+               memcpy(image->data(1) + y * size.width, image->data(1), size.width);
+               memcpy(image->data(2) + y * size.width, image->data(2), size.width);
+       }
+       auto compressed = compress_j2k(image, 250000000LL, 24, false, true);
+       auto decompressed = decompress_j2k(compressed, 0);
+       auto frame = make_shared<dcp::MonoPictureFrame>(compressed.data(), compressed.size());
+       auto proxy = make_shared<J2KImageProxy>(frame, size, AV_PIX_FMT_XYZ12LE, optional<int>());
+       auto video = make_shared<PlayerVideo>(proxy, Crop(), optional<double>(), size, size, Eyes::BOTH, Part::WHOLE, optional<ColourConversion>(), VideoRange::FULL, weak_ptr<Content>(), optional<Frame>(), false);
+       auto out_image = video->image([](AVPixelFormat) { return AV_PIX_FMT_XYZ12LE; }, VideoRange::FULL, false);
+
+       BOOST_REQUIRE_EQUAL(out_image->size().width, size.width);
+       BOOST_REQUIRE_EQUAL(out_image->size().height, size.height);
+
+       for (int c = 0; c < 3; ++c) {
+               for (auto y = 0; y < size.height; ++y) {
+                       auto in = decompressed->data(c) + y * size.width;
+                       auto out = reinterpret_cast<uint16_t*>(out_image->data()[0] + y * out_image->stride()[0]) + c;
+                       for (int x = 0; x < size.width; ++x) {
+                               BOOST_REQUIRE_MESSAGE(*in == (*out >> 4), *in << " != " << *out << " at x=" << x << ", y=" << y << ", c=" << c);
+                               ++in;
+                               out += 3;
+                       }
+               }
+       }
+}
+