From 3799e91d126d243d41c44dcb0ca1bfa66b53a57e Mon Sep 17 00:00:00 2001 From: Carl Hetherington Date: Wed, 15 Sep 2021 23:36:21 +0200 Subject: [PATCH] Replace aligned bool with enum Alignment. --- src/lib/butler.cc | 8 +-- src/lib/butler.h | 4 +- src/lib/dcp_video.cc | 6 +- src/lib/encoder.cc | 2 +- src/lib/ffmpeg_decoder.cc | 56 ++++++++--------- src/lib/ffmpeg_encoder.cc | 16 ++--- src/lib/ffmpeg_file_encoder.cc | 14 ++--- src/lib/ffmpeg_image_proxy.cc | 4 +- src/lib/ffmpeg_image_proxy.h | 2 +- src/lib/hints.cc | 5 +- src/lib/image.cc | 73 +++++++++++----------- src/lib/image.h | 25 +++++--- src/lib/image_examiner.cc | 2 +- src/lib/image_proxy.h | 14 ++++- src/lib/j2k_image_proxy.cc | 12 ++-- src/lib/j2k_image_proxy.h | 4 +- src/lib/player.cc | 10 +-- src/lib/player.h | 7 ++- src/lib/player_video.cc | 24 ++++---- src/lib/player_video.h | 13 ++-- src/lib/raw_image_proxy.cc | 10 +-- src/lib/raw_image_proxy.h | 2 +- src/lib/render_text.cc | 2 +- src/lib/util.cc | 63 +++++++++---------- src/lib/video_filter_graph.cc | 5 +- src/tools/server_test.cc | 2 +- src/wx/film_viewer.cc | 10 +-- src/wx/gl_video_view.cc | 8 +-- src/wx/simple_video_view.cc | 22 ++++--- src/wx/video_waveform_plot.cc | 4 +- test/butler_test.cc | 2 +- test/client_server_test.cc | 10 +-- test/dcp_decoder_test.cc | 6 +- test/dcp_playback_test.cc | 6 +- test/ffmpeg_audio_only_test.cc | 2 +- test/ffmpeg_audio_test.cc | 6 +- test/ffmpeg_decoder_sequential_test.cc | 2 +- test/image_test.cc | 85 +++++++++++++------------- test/low_bitrate_test.cc | 20 +++++- test/overlap_video_test.cc | 3 +- test/pixel_formats_test.cc | 2 +- test/player_test.cc | 47 +++++++------- test/test.cc | 4 +- test/time_calculation_test.cc | 7 +-- test/upmixer_a_test.cc | 2 +- test/vf_test.cc | 2 +- test/video_level_test.cc | 9 ++- 47 files changed, 331 insertions(+), 313 deletions(-) diff --git a/src/lib/butler.cc b/src/lib/butler.cc index ca0887a4c..5a5cc4912 100644 --- a/src/lib/butler.cc +++ b/src/lib/butler.cc @@ -57,7 +57,7 @@ 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 aligned Same as above for the `aligned' flag. + * @param alignment Same as above for the `alignment' value. * @param fast Same as above for the `fast' flag. */ Butler::Butler ( @@ -67,7 +67,7 @@ Butler::Butler ( int audio_channels, function pixel_format, VideoRange video_range, - bool aligned, + Image::Alignment alignment, bool fast, bool prepare_only_proxy ) @@ -84,7 +84,7 @@ Butler::Butler ( , _disable_audio (false) , _pixel_format (pixel_format) , _video_range (video_range) - , _aligned (aligned) + , _alignment (alignment) , _fast (fast) , _prepare_only_proxy (prepare_only_proxy) { @@ -325,7 +325,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, _aligned, _fast, _prepare_only_proxy); + video->prepare (_pixel_format, _video_range, _alignment, _fast, _prepare_only_proxy); LOG_TIMING("finish-prepare in %1", thread_id()); } } diff --git a/src/lib/butler.h b/src/lib/butler.h index 320e56bf9..cd3891754 100644 --- a/src/lib/butler.h +++ b/src/lib/butler.h @@ -45,7 +45,7 @@ public: int audio_channels, std::function pixel_format, VideoRange video_range, - bool aligned, + Image::Alignment alignment, bool fast, bool prepare_only_proxy ); @@ -125,7 +125,7 @@ private: std::function _pixel_format; VideoRange _video_range; - bool _aligned; + Image::Alignment _alignment; bool _fast; /** true to ask PlayerVideo::prepare to only prepare the ImageProxy and not also diff --git a/src/lib/dcp_video.cc b/src/lib/dcp_video.cc index 4a505a7e1..9daeb45c8 100644 --- a/src/lib/dcp_video.cc +++ b/src/lib/dcp_video.cc @@ -59,19 +59,21 @@ DCPOMATIC_ENABLE_WARNINGS #include "i18n.h" + using std::cout; using std::make_shared; using std::shared_ptr; using std::string; -using dcp::Size; using dcp::ArrayData; using dcp::raw_convert; #if BOOST_VERSION >= 106100 using namespace boost::placeholders; #endif + #define DCI_COEFFICENT (48.0 / 52.37) + /** Construct a DCP video frame. * @param frame Input frame. * @param index Index of the frame within the DCP. @@ -103,7 +105,7 @@ DCPVideo::convert_to_xyz (shared_ptr frame, dcp::NoteHandler { shared_ptr xyz; - auto image = frame->image (bind(&PlayerVideo::keep_xyz_or_rgb, _1), VideoRange::FULL, true, false); + auto image = frame->image (bind(&PlayerVideo::keep_xyz_or_rgb, _1), VideoRange::FULL, Image::Alignment::PADDED, false); if (frame->colour_conversion()) { xyz = dcp::rgb_to_xyz ( image->data()[0], diff --git a/src/lib/encoder.cc b/src/lib/encoder.cc index 0b7c241d8..1d688c318 100644 --- a/src/lib/encoder.cc +++ b/src/lib/encoder.cc @@ -41,7 +41,7 @@ Encoder::Encoder (std::shared_ptr film, std::weak_ptr job) : _film (film) , _job (job) - , _player (new Player(film, true)) + , _player (new Player(film, Image::Alignment::PADDED)) { } diff --git a/src/lib/ffmpeg_decoder.cc b/src/lib/ffmpeg_decoder.cc index 70f9b0545..2baa99876 100644 --- a/src/lib/ffmpeg_decoder.cc +++ b/src/lib/ffmpeg_decoder.cc @@ -18,31 +18,33 @@ */ + /** @file src/ffmpeg_decoder.cc * @brief A decoder using FFmpeg to decode content. */ -#include "filter.h" -#include "exceptions.h" -#include "image.h" -#include "util.h" -#include "log.h" + +#include "audio_buffers.h" +#include "audio_content.h" +#include "audio_decoder.h" +#include "compose.hpp" #include "dcpomatic_log.h" -#include "ffmpeg_decoder.h" -#include "text_decoder.h" +#include "exceptions.h" #include "ffmpeg_audio_stream.h" -#include "ffmpeg_subtitle_stream.h" -#include "video_filter_graph.h" -#include "audio_buffers.h" #include "ffmpeg_content.h" -#include "raw_image_proxy.h" -#include "video_decoder.h" +#include "ffmpeg_decoder.h" +#include "ffmpeg_subtitle_stream.h" #include "film.h" -#include "audio_decoder.h" -#include "compose.hpp" -#include "text_content.h" -#include "audio_content.h" +#include "filter.h" #include "frame_interval_checker.h" +#include "image.h" +#include "log.h" +#include "raw_image_proxy.h" +#include "text_content.h" +#include "text_decoder.h" +#include "util.h" +#include "video_decoder.h" +#include "video_filter_graph.h" #include #include #include @@ -52,28 +54,22 @@ extern "C" { #include } #include -#include #include #include +#include #include #include "i18n.h" + using std::cout; -using std::string; -using std::vector; -using std::list; +using std::dynamic_pointer_cast; +using std::make_shared; using std::min; -using std::pair; -using std::max; -using std::map; using std::shared_ptr; -using std::make_shared; -using std::make_pair; -using boost::is_any_of; -using boost::split; +using std::string; +using std::vector; using boost::optional; -using std::dynamic_pointer_cast; using dcp::Size; using namespace dcpomatic; @@ -86,7 +82,7 @@ FFmpegDecoder::FFmpegDecoder (shared_ptr film, shared_ptr(this, c); _pts_offset = pts_offset (c->ffmpeg_audio_streams(), c->first_video(), c->active_video_frame_rate(film)); /* It doesn't matter what size or pixel format this is, it just needs to be black */ - _black_image = make_shared(AV_PIX_FMT_RGB24, dcp::Size (128, 128), true); + _black_image = make_shared(AV_PIX_FMT_RGB24, dcp::Size (128, 128), Image::Alignment::PADDED); _black_image->make_black (); } else { _pts_offset = {}; @@ -684,7 +680,7 @@ FFmpegDecoder::process_bitmap_subtitle (AVSubtitleRect const * rect, ContentTime /* Note BGRA is expressed little-endian, so the first byte in the word is B, second G, third R, fourth A. */ - auto image = make_shared(AV_PIX_FMT_BGRA, dcp::Size (rect->w, rect->h), true); + auto image = make_shared(AV_PIX_FMT_BGRA, dcp::Size (rect->w, rect->h), Image::Alignment::PADDED); #ifdef DCPOMATIC_HAVE_AVSUBTITLERECT_PICT /* Start of the first line in the subtitle */ diff --git a/src/lib/ffmpeg_encoder.cc b/src/lib/ffmpeg_encoder.cc index 77f27d519..dd773168a 100644 --- a/src/lib/ffmpeg_encoder.cc +++ b/src/lib/ffmpeg_encoder.cc @@ -18,26 +18,25 @@ */ + +#include "butler.h" +#include "cross.h" #include "ffmpeg_encoder.h" #include "film.h" +#include "image.h" #include "job.h" +#include "log.h" #include "player.h" #include "player_video.h" -#include "log.h" -#include "image.h" -#include "cross.h" -#include "butler.h" #include "compose.hpp" #include #include "i18n.h" + using std::cout; using std::list; using std::make_shared; -using std::map; -using std::pair; -using std::runtime_error; using std::shared_ptr; using std::string; using std::weak_ptr; @@ -48,6 +47,7 @@ using namespace dcpomatic; using namespace boost::placeholders; #endif + /** @param key Key to use to encrypt MP4 outputs */ FFmpegEncoder::FFmpegEncoder ( shared_ptr film, @@ -108,7 +108,7 @@ FFmpegEncoder::FFmpegEncoder ( } _butler = std::make_shared( - _film, _player, map, _output_audio_channels, bind(&PlayerVideo::force, _1, FFmpegFileEncoder::pixel_format(format)), VideoRange::VIDEO, true, false, false + _film, _player, map, _output_audio_channels, bind(&PlayerVideo::force, _1, FFmpegFileEncoder::pixel_format(format)), VideoRange::VIDEO, Image::Alignment::PADDED, false, false ); } diff --git a/src/lib/ffmpeg_file_encoder.cc b/src/lib/ffmpeg_file_encoder.cc index 533fd151c..ef02f30c8 100644 --- a/src/lib/ffmpeg_file_encoder.cc +++ b/src/lib/ffmpeg_file_encoder.cc @@ -19,16 +19,16 @@ */ +#include "compose.hpp" +#include "cross.h" #include "ffmpeg_encoder.h" #include "ffmpeg_wrapper.h" #include "film.h" +#include "image.h" #include "job.h" +#include "log.h" #include "player.h" #include "player_video.h" -#include "log.h" -#include "image.h" -#include "cross.h" -#include "compose.hpp" extern "C" { #include } @@ -39,13 +39,9 @@ extern "C" { using std::cout; using std::make_shared; -using std::pair; -using std::runtime_error; using std::shared_ptr; using std::string; -using std::weak_ptr; using boost::bind; -using boost::optional; using namespace dcpomatic; #if BOOST_VERSION >= 106100 using namespace boost::placeholders; @@ -406,7 +402,7 @@ FFmpegFileEncoder::video (shared_ptr video, DCPTime time) auto image = video->image ( bind (&PlayerVideo::force, _1, _pixel_format), VideoRange::VIDEO, - true, + Image::Alignment::PADDED, false ); diff --git a/src/lib/ffmpeg_image_proxy.cc b/src/lib/ffmpeg_image_proxy.cc index dd2f80e0e..4b3c3084c 100644 --- a/src/lib/ffmpeg_image_proxy.cc +++ b/src/lib/ffmpeg_image_proxy.cc @@ -122,7 +122,7 @@ FFmpegImageProxy::avio_seek (int64_t const pos, int whence) ImageProxy::Result -FFmpegImageProxy::image (bool aligned, optional) const +FFmpegImageProxy::image (Image::Alignment alignment, optional) const { auto constexpr name_for_errors = "FFmpegImageProxy::image"; @@ -205,7 +205,7 @@ FFmpegImageProxy::image (bool aligned, optional) const throw DecodeError (N_("avcodec_receive_frame"), name_for_errors, r, *_path); } - _image = make_shared(frame, aligned); + _image = make_shared(frame, alignment); av_packet_unref (&packet); av_frame_free (&frame); diff --git a/src/lib/ffmpeg_image_proxy.h b/src/lib/ffmpeg_image_proxy.h index f4e5bf66c..48317ed75 100644 --- a/src/lib/ffmpeg_image_proxy.h +++ b/src/lib/ffmpeg_image_proxy.h @@ -32,7 +32,7 @@ public: FFmpegImageProxy (std::shared_ptr socket); Result image ( - bool aligned, + Image::Alignment alignment, boost::optional size = boost::optional () ) const; diff --git a/src/lib/hints.cc b/src/lib/hints.cc index f21c51db9..46704ebf8 100644 --- a/src/lib/hints.cc +++ b/src/lib/hints.cc @@ -51,11 +51,8 @@ using std::cout; using std::make_shared; using std::max; -using std::min; -using std::pair; using std::shared_ptr; using std::string; -using std::vector; using std::weak_ptr; using boost::optional; using boost::bind; @@ -408,7 +405,7 @@ try emit (bind(boost::ref(Progress), _("Examining audio, subtitles and closed captions"))); } - auto player = make_shared(film, false); + auto player = make_shared(film, Image::Alignment::COMPACT); player->set_ignore_video (); if (check_loudness_done) { /* We don't need to analyse audio because we already loaded a suitable analysis */ diff --git a/src/lib/image.cc b/src/lib/image.cc index ce3f5817d..30589ef9c 100644 --- a/src/lib/image.cc +++ b/src/lib/image.cc @@ -64,8 +64,8 @@ using std::string; using dcp::Size; -/** The memory alignment, in bytes, used for each row of an image if aligment is requested */ -#define ALIGNMENT 64 +/** The memory alignment, in bytes, used for each row of an image if Alignment::PADDED is requested */ +int constexpr ALIGNMENT = 64; /* U/V black value for 8-bit colour */ static uint8_t const eight_bit_uv = (1 << 7) - 1; @@ -177,19 +177,19 @@ Image::crop_scale_window ( VideoRange video_range, AVPixelFormat out_format, VideoRange out_video_range, - bool out_aligned, + Alignment out_alignment, bool fast ) const { /* Empirical testing suggests that sws_scale() will crash if - the input image is not aligned. + the input image is not padded. */ - DCPOMATIC_ASSERT (aligned ()); + DCPOMATIC_ASSERT (alignment() == Alignment::PADDED); DCPOMATIC_ASSERT (out_size.width >= inter_size.width); DCPOMATIC_ASSERT (out_size.height >= inter_size.height); - auto out = make_shared(out_format, out_size, out_aligned); + auto out = make_shared(out_format, out_size, out_alignment); out->make_black (); auto in_desc = av_pix_fmt_desc_get (_pixel_format); @@ -310,27 +310,27 @@ Image::crop_scale_window ( } shared_ptr -Image::convert_pixel_format (dcp::YUVToRGB yuv_to_rgb, AVPixelFormat out_format, bool out_aligned, bool fast) const +Image::convert_pixel_format (dcp::YUVToRGB yuv_to_rgb, AVPixelFormat out_format, Alignment out_alignment, bool fast) const { - return scale(size(), yuv_to_rgb, out_format, out_aligned, fast); + return scale(size(), yuv_to_rgb, out_format, out_alignment, fast); } /** @param out_size Size to scale to. * @param yuv_to_rgb YUVToRGB transform transform to use, if required. * @param out_format Output pixel format. - * @param out_aligned true to make an aligned output image. + * @param out_aligment Output alignment. * @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::scale (dcp::Size out_size, dcp::YUVToRGB yuv_to_rgb, AVPixelFormat out_format, bool out_aligned, bool fast) const +Image::scale (dcp::Size out_size, dcp::YUVToRGB yuv_to_rgb, AVPixelFormat out_format, Alignment out_alignment, bool fast) const { /* Empirical testing suggests that sws_scale() will crash if - the input image is not aligned. + the input image alignment is not PADDED. */ - DCPOMATIC_ASSERT (aligned ()); + DCPOMATIC_ASSERT (alignment() == Alignment::PADDED); - auto scaled = make_shared(out_format, out_size, out_aligned); + auto scaled = make_shared(out_format, out_size, out_alignment); auto scale_context = sws_getContext ( size().width, size().height, pixel_format(), out_size.width, out_size.height, out_format, @@ -736,7 +736,7 @@ Image::alpha_blend (shared_ptr other, Position position) } case AV_PIX_FMT_YUV420P: { - auto yuv = other->convert_pixel_format (dcp::YUVToRGB::REC709, _pixel_format, false, false); + auto yuv = other->convert_pixel_format (dcp::YUVToRGB::REC709, _pixel_format, Alignment::COMPACT, false); dcp::Size const ts = size(); dcp::Size const os = yuv->size(); for (int ty = start_ty, oy = start_oy; ty < ts.height && oy < os.height; ++ty, ++oy) { @@ -771,7 +771,7 @@ Image::alpha_blend (shared_ptr other, Position position) } case AV_PIX_FMT_YUV420P10: { - auto yuv = other->convert_pixel_format (dcp::YUVToRGB::REC709, _pixel_format, false, false); + auto yuv = other->convert_pixel_format (dcp::YUVToRGB::REC709, _pixel_format, Alignment::COMPACT, false); dcp::Size const ts = size(); dcp::Size const os = yuv->size(); for (int ty = start_ty, oy = start_oy; ty < ts.height && oy < os.height; ++ty, ++oy) { @@ -806,7 +806,7 @@ Image::alpha_blend (shared_ptr other, Position position) } case AV_PIX_FMT_YUV422P10LE: { - auto yuv = other->convert_pixel_format (dcp::YUVToRGB::REC709, _pixel_format, false, false); + auto yuv = other->convert_pixel_format (dcp::YUVToRGB::REC709, _pixel_format, Alignment::COMPACT, false); dcp::Size const ts = size(); dcp::Size const os = yuv->size(); for (int ty = start_ty, oy = start_oy; ty < ts.height && oy < os.height; ++ty, ++oy) { @@ -934,16 +934,17 @@ Image::bytes_per_pixel (int c) const * * @param p Pixel format. * @param s Size in pixels. - * @param aligned true to make each row of this image aligned to a ALIGNMENT-byte boundary. + * @param alignment PADDED to make each row of this image aligned to a ALIGNMENT-byte boundary, otherwise COMPACT. */ -Image::Image (AVPixelFormat p, dcp::Size s, bool aligned) +Image::Image (AVPixelFormat p, dcp::Size s, Alignment alignment) : _size (s) , _pixel_format (p) - , _aligned (aligned) + , _alignment (alignment) { allocate (); } + void Image::allocate () { @@ -958,7 +959,7 @@ Image::allocate () for (int i = 0; i < planes(); ++i) { _line_size[i] = ceil (_size.width * bytes_per_pixel(i)); - _stride[i] = stride_round_up (i, _line_size, _aligned ? ALIGNMENT : 1); + _stride[i] = stride_round_up (i, _line_size, _alignment == Alignment::PADDED ? ALIGNMENT : 1); /* The assembler function ff_rgb24ToY_avx (in libswscale/x86/input.asm) uses a 16-byte fetch to read three bytes (R/G/B) of image data. @@ -1011,7 +1012,7 @@ Image::Image (Image const & other) : std::enable_shared_from_this(other) , _size (other._size) , _pixel_format (other._pixel_format) - , _aligned (other._aligned) + , _alignment (other._alignment) { allocate (); @@ -1027,10 +1028,10 @@ Image::Image (Image const & other) } } -Image::Image (AVFrame const * frame, bool aligned) +Image::Image (AVFrame const * frame, Alignment alignment) : _size (frame->width, frame->height) , _pixel_format (static_cast(frame->format)) - , _aligned (aligned) + , _alignment (alignment) { DCPOMATIC_ASSERT (_pixel_format != AV_PIX_FMT_NONE); @@ -1049,10 +1050,10 @@ Image::Image (AVFrame const * frame, bool aligned) } } -Image::Image (shared_ptr other, bool aligned) +Image::Image (shared_ptr other, Alignment alignment) : _size (other->_size) , _pixel_format (other->_pixel_format) - , _aligned (aligned) + , _alignment (alignment) { allocate (); @@ -1093,7 +1094,7 @@ Image::swap (Image & other) std::swap (_stride[i], other._stride[i]); } - std::swap (_aligned, other._aligned); + std::swap (_alignment, other._alignment); } Image::~Image () @@ -1131,15 +1132,15 @@ Image::size () const return _size; } -bool -Image::aligned () const +Image::Alignment +Image::alignment () const { - return _aligned; + return _alignment; } PositionImage -merge (list images, bool aligned) +merge (list images, Image::Alignment alignment) { if (images.empty ()) { return {}; @@ -1154,7 +1155,7 @@ merge (list images, bool aligned) all.extend (dcpomatic::Rect(i.position, i.image->size().width, i.image->size().height)); } - auto merged = make_shared(images.front().image->pixel_format(), dcp::Size(all.width, all.height), aligned); + auto merged = make_shared(images.front().image->pixel_format(), dcp::Size(all.width, all.height), alignment); merged->make_transparent (); for (auto const& i: images) { merged->alpha_blend (i.image, i.position - all.position()); @@ -1167,7 +1168,7 @@ merge (list images, bool aligned) bool operator== (Image const & a, Image const & b) { - if (a.planes() != b.planes() || a.pixel_format() != b.pixel_format() || a.aligned() != b.aligned()) { + if (a.planes() != b.planes() || a.pixel_format() != b.pixel_format() || a.alignment() != b.alignment()) { return false; } @@ -1314,13 +1315,13 @@ Image::fade (float f) shared_ptr -Image::ensure_aligned (shared_ptr image, bool aligned) +Image::ensure_alignment (shared_ptr image, Image::Alignment alignment) { - if (image->aligned() == aligned) { + if (image->alignment() == alignment) { return image; } - return make_shared(image, aligned); + return make_shared(image, alignment); } @@ -1395,7 +1396,7 @@ Image::as_png () const DCPOMATIC_ASSERT (bytes_per_pixel(0) == 4); DCPOMATIC_ASSERT (planes() == 1); if (pixel_format() != AV_PIX_FMT_RGBA) { - return convert_pixel_format(dcp::YUVToRGB::REC709, AV_PIX_FMT_RGBA, true, false)->as_png(); + return convert_pixel_format(dcp::YUVToRGB::REC709, AV_PIX_FMT_RGBA, Image::Alignment::PADDED, false)->as_png(); } /* error handling? */ diff --git a/src/lib/image.h b/src/lib/image.h index 3cba8f7e5..128b546b5 100644 --- a/src/lib/image.h +++ b/src/lib/image.h @@ -40,10 +40,15 @@ class Socket; class Image : public std::enable_shared_from_this { public: - Image (AVPixelFormat p, dcp::Size s, bool aligned); - explicit Image (AVFrame const *, bool aligned); + enum class Alignment { + COMPACT, + PADDED + }; + + Image (AVPixelFormat p, dcp::Size s, Alignment alignment); + explicit Image (AVFrame const *, Alignment alignment); explicit Image (Image const &); - Image (std::shared_ptr, bool); + Image (std::shared_ptr, Alignment alignment); Image& operator= (Image const &); ~Image (); @@ -53,7 +58,7 @@ public: /** @return array of sizes of the data in each line, in bytes (including any alignment padding) */ int const * stride () const; dcp::Size size () const; - bool aligned () const; + Alignment alignment () const; int planes () const; int vertical_factor (int) const; @@ -61,8 +66,8 @@ public: dcp::Size sample_size (int) const; float bytes_per_pixel (int) const; - std::shared_ptr convert_pixel_format (dcp::YUVToRGB yuv_to_rgb, AVPixelFormat out_format, bool aligned, bool fast) const; - std::shared_ptr scale (dcp::Size out_size, dcp::YUVToRGB yuv_to_rgb, AVPixelFormat out_format, bool aligned, bool fast) const; + std::shared_ptr convert_pixel_format (dcp::YUVToRGB yuv_to_rgb, AVPixelFormat out_format, Alignment alignment, bool fast) const; + std::shared_ptr scale (dcp::Size out_size, dcp::YUVToRGB yuv_to_rgb, AVPixelFormat out_format, Alignment alignment, bool fast) const; std::shared_ptr crop_scale_window ( Crop crop, dcp::Size inter_size, @@ -71,7 +76,7 @@ public: VideoRange video_range, AVPixelFormat out_format, VideoRange out_video_range, - bool aligned, + Alignment alignment, bool fast ) const; @@ -94,7 +99,7 @@ public: void png_error (char const * message); - static std::shared_ptr ensure_aligned (std::shared_ptr image, bool aligned); + static std::shared_ptr ensure_alignment (std::shared_ptr image, Alignment alignment); private: friend struct pixel_formats_test; @@ -112,10 +117,10 @@ private: uint8_t** _data; ///< array of pointers to components int* _line_size; ///< array of sizes of the data in each line, in bytes (without any alignment padding bytes) int* _stride; ///< array of strides for each line, in bytes (including any alignment padding bytes) - bool _aligned; + Alignment _alignment; }; -extern PositionImage merge (std::list images, bool aligned); +extern PositionImage merge (std::list images, Image::Alignment alignment); extern bool operator== (Image const & a, Image const & b); #endif diff --git a/src/lib/image_examiner.cc b/src/lib/image_examiner.cc index 8b2096214..ae12d7adb 100644 --- a/src/lib/image_examiner.cc +++ b/src/lib/image_examiner.cc @@ -67,7 +67,7 @@ ImageExaminer::ImageExaminer (shared_ptr film, shared_ptrpath(0)); - _video_size = proxy.image(false).image->size(); + _video_size = proxy.image(Image::Alignment::COMPACT).image->size(); } if (content->still ()) { diff --git a/src/lib/image_proxy.h b/src/lib/image_proxy.h index 8817845d9..a37be580f 100644 --- a/src/lib/image_proxy.h +++ b/src/lib/image_proxy.h @@ -1,5 +1,5 @@ /* - Copyright (C) 2014 Carl Hetherington + Copyright (C) 2014-2021 Carl Hetherington This file is part of DCP-o-matic. @@ -18,13 +18,17 @@ */ + #ifndef DCPOMATIC_IMAGE_PROXY_H #define DCPOMATIC_IMAGE_PROXY_H + /** @file src/lib/image_proxy.h * @brief ImageProxy and subclasses. */ + +#include "image.h" extern "C" { #include } @@ -32,6 +36,7 @@ extern "C" { #include #include + class Image; class Socket; @@ -43,6 +48,7 @@ namespace cxml { class Node; } + /** @class ImageProxy * @brief A class which holds an Image, and can produce it on request. * @@ -91,7 +97,7 @@ public: * can be used as an optimisation. */ virtual Result image ( - bool aligned, + Image::Alignment alignment, boost::optional size = boost::optional () ) const = 0; @@ -103,10 +109,12 @@ public: * This method may be called in a different thread to image(). * @return log2 of any scaling down that will be applied to the image. */ - virtual int prepare (bool, boost::optional = boost::optional()) const { return 0; } + virtual int prepare (Image::Alignment, boost::optional = boost::optional()) const { return 0; } virtual size_t memory_used () const = 0; }; + std::shared_ptr image_proxy_factory (std::shared_ptr xml, std::shared_ptr socket); + #endif diff --git a/src/lib/j2k_image_proxy.cc b/src/lib/j2k_image_proxy.cc index 21507ca15..00d3cf2ef 100644 --- a/src/lib/j2k_image_proxy.cc +++ b/src/lib/j2k_image_proxy.cc @@ -42,10 +42,8 @@ DCPOMATIC_ENABLE_WARNINGS using std::cout; using std::dynamic_pointer_cast; -using std::make_pair; using std::make_shared; using std::max; -using std::pair; using std::shared_ptr; using std::string; using boost::optional; @@ -120,7 +118,7 @@ J2KImageProxy::J2KImageProxy (shared_ptr xml, shared_ptr soc int -J2KImageProxy::prepare (bool aligned, optional target_size) const +J2KImageProxy::prepare (Image::Alignment alignment, optional target_size) const { boost::mutex::scoped_lock lm (_mutex); @@ -145,7 +143,7 @@ J2KImageProxy::prepare (bool aligned, optional target_size) const try { /* XXX: should check that potentially trashing _data here doesn't matter */ auto decompressed = dcp::decompress_j2k (const_cast(_data->data()), _data->size(), reduce); - _image = make_shared(_pixel_format, decompressed->size(), aligned); + _image = make_shared(_pixel_format, decompressed->size(), alignment); int const shift = 16 - decompressed->precision (0); @@ -169,7 +167,7 @@ J2KImageProxy::prepare (bool aligned, optional target_size) const } } } catch (dcp::J2KDecompressionError& e) { - _image = make_shared(_pixel_format, _size, aligned); + _image = make_shared(_pixel_format, _size, alignment); _image->make_black (); _error = true; } @@ -182,9 +180,9 @@ J2KImageProxy::prepare (bool aligned, optional target_size) const ImageProxy::Result -J2KImageProxy::image (bool aligned, optional target_size) const +J2KImageProxy::image (Image::Alignment alignment, optional target_size) const { - int const r = prepare (aligned, target_size); + int const r = prepare (alignment, target_size); /* I think this is safe without a lock on mutex. _image is guaranteed to be set up when prepare() has happened. diff --git a/src/lib/j2k_image_proxy.h b/src/lib/j2k_image_proxy.h index a23ec6d98..d925bef86 100644 --- a/src/lib/j2k_image_proxy.h +++ b/src/lib/j2k_image_proxy.h @@ -57,7 +57,7 @@ public: J2KImageProxy (dcp::ArrayData data, dcp::Size size, AVPixelFormat pixel_format); Result image ( - bool aligned, + Image::Alignment alignment, boost::optional size = boost::optional () ) const; @@ -65,7 +65,7 @@ public: void write_to_socket (std::shared_ptr) const; /** @return true if our image is definitely the same as another, false if it is probably not */ bool same (std::shared_ptr) const; - int prepare (bool aligned, boost::optional = boost::optional()) const; + int prepare (Image::Alignment alignment, boost::optional = boost::optional()) const; std::shared_ptr j2k () const { return _data; diff --git a/src/lib/player.cc b/src/lib/player.cc index 810d949d9..7c1a57aa9 100644 --- a/src/lib/player.cc +++ b/src/lib/player.cc @@ -95,12 +95,12 @@ int const PlayerProperty::DCP_DECODE_REDUCTION = 704; int const PlayerProperty::PLAYBACK_LENGTH = 705; -Player::Player (shared_ptr film, bool aligned) +Player::Player (shared_ptr film, Image::Alignment subtitle_alignment) : _film (film) , _suspended (0) , _tolerant (film->tolerant()) , _audio_merger (_film->audio_frame_rate()) - , _aligned_subtitles (aligned) + , _subtitle_alignment (subtitle_alignment) { construct (); } @@ -332,7 +332,7 @@ Player::set_video_container_size (dcp::Size s) _video_container_size = s; - _black_image.reset (new Image (AV_PIX_FMT_RGB24, _video_container_size, true)); + _black_image = make_shared(AV_PIX_FMT_RGB24, _video_container_size, Image::Alignment::PADDED); _black_image->make_black (); } @@ -828,7 +828,7 @@ Player::open_subtitles_for_frame (DCPTime time) const return {}; } - return merge (captions, _aligned_subtitles); + return merge (captions, _subtitle_alignment); } @@ -1056,7 +1056,7 @@ Player::bitmap_text_start (weak_ptr wp, weak_ptr wc, C } dcp::Size scaled_size (width, height); - ps.bitmap.push_back (BitmapText(image->scale(scaled_size, dcp::YUVToRGB::REC601, image->pixel_format(), true, _fast), subtitle.sub.rectangle)); + ps.bitmap.push_back (BitmapText(image->scale(scaled_size, dcp::YUVToRGB::REC601, image->pixel_format(), Image::Alignment::PADDED, _fast), subtitle.sub.rectangle)); DCPTime from (content_time_to_dcp (piece, subtitle.from())); _active_texts[static_cast(text->type())].add_from (wc, ps, from); diff --git a/src/lib/player.h b/src/lib/player.h index 767218379..b74aeeefd 100644 --- a/src/lib/player.h +++ b/src/lib/player.h @@ -34,6 +34,7 @@ #include "content_video.h" #include "empty.h" #include "film.h" +#include "image.h" #include "piece.h" #include "player_text.h" #include "position_image.h" @@ -76,7 +77,7 @@ public: class Player : public std::enable_shared_from_this { public: - Player (std::shared_ptr, bool aligned_subtitles); + Player (std::shared_ptr, Image::Alignment subtitle_alignment); Player (std::shared_ptr, std::shared_ptr playlist); Player (Player const& Player) = delete; @@ -233,8 +234,8 @@ private: dcpomatic::DCPTime _playback_length; - /** aligned flag for subtitle images that we create */ - bool _aligned_subtitles = true; + /** Alignment for subtitle images that we create */ + Image::Alignment _subtitle_alignment = Image::Alignment::PADDED; boost::signals2::scoped_connection _film_changed_connection; boost::signals2::scoped_connection _playlist_change_connection; diff --git a/src/lib/player_video.cc b/src/lib/player_video.cc index a687e7ea5..2d60efe10 100644 --- a/src/lib/player_video.cc +++ b/src/lib/player_video.cc @@ -94,7 +94,7 @@ PlayerVideo::PlayerVideo (shared_ptr node, shared_ptr socket if (node->optional_number_child("SubtitleX")) { auto image = make_shared ( - AV_PIX_FMT_BGRA, dcp::Size(node->number_child("SubtitleWidth"), node->number_child("SubtitleHeight")), true + AV_PIX_FMT_BGRA, dcp::Size(node->number_child("SubtitleWidth"), node->number_child("SubtitleHeight")), Image::Alignment::PADDED ); image->read_from_socket (socket); @@ -110,13 +110,13 @@ PlayerVideo::set_text (PositionImage image) } shared_ptr -PlayerVideo::image (function pixel_format, VideoRange video_range, bool aligned, bool fast) const +PlayerVideo::image (function pixel_format, VideoRange video_range, Image::Alignment alignment, 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, aligned, fast); + make_image (pixel_format, video_range, alignment, fast); } return _image; } @@ -125,7 +125,7 @@ PlayerVideo::image (function pixel_format, VideoR shared_ptr PlayerVideo::raw_image () const { - return _in->image(false, _inter_size).image; + return _in->image(Image::Alignment::COMPACT, _inter_size).image; } @@ -133,18 +133,18 @@ PlayerVideo::raw_image () const * @param pixel_format Function which is called to decide what pixel format the output image should be; * it is passed the pixel format of the input image from the ImageProxy, and should return the desired * output pixel format. Two functions force and keep_xyz_or_rgb are provided for use here. - * @param aligned true if the output image should be aligned to 32-byte boundaries. + * @param alignment PADDED if the output image should be aligned to 32-byte boundaries, otherwise COMPACT. * @param fast true to be fast at the expense of quality. */ void -PlayerVideo::make_image (function pixel_format, VideoRange video_range, bool aligned, bool fast) const +PlayerVideo::make_image (function pixel_format, VideoRange video_range, Image::Alignment alignment, bool fast) const { _image_crop = _crop; _image_inter_size = _inter_size; _image_out_size = _out_size; _image_fade = _fade; - auto prox = _in->image (true, _inter_size); + auto prox = _in->image (Image::Alignment::PADDED, _inter_size); _error = prox.error; auto total_crop = _crop; @@ -180,11 +180,11 @@ PlayerVideo::make_image (function 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, aligned, fast + total_crop, _inter_size, _out_size, yuv_to_rgb, _video_range, pixel_format (prox.image->pixel_format()), video_range, alignment, fast ); if (_text) { - _image->alpha_blend (Image::ensure_aligned(_text->image, true), _text->position); + _image->alpha_blend (Image::ensure_alignment(_text->image, Image::Alignment::PADDED), _text->position); } if (_fade) { @@ -298,12 +298,12 @@ PlayerVideo::keep_xyz_or_rgb (AVPixelFormat p) } void -PlayerVideo::prepare (function pixel_format, VideoRange video_range, bool aligned, bool fast, bool proxy_only) +PlayerVideo::prepare (function pixel_format, VideoRange video_range, Image::Alignment alignment, bool fast, bool proxy_only) { - _in->prepare (aligned, _inter_size); + _in->prepare (alignment, _inter_size); boost::mutex::scoped_lock lm (_mutex); if (!_image && !proxy_only) { - make_image (pixel_format, video_range, aligned, fast); + make_image (pixel_format, video_range, alignment, fast); } } diff --git a/src/lib/player_video.h b/src/lib/player_video.h index 872bc9864..d24620c7e 100644 --- a/src/lib/player_video.h +++ b/src/lib/player_video.h @@ -23,11 +23,12 @@ #define DCPOMATIC_PLAYER_VIDEO_H -#include "types.h" -#include "position.h" -#include "dcpomatic_time.h" #include "colour_conversion.h" +#include "dcpomatic_time.h" +#include "image.h" +#include "position.h" #include "position_image.h" +#include "types.h" extern "C" { #include } @@ -74,8 +75,8 @@ public: return _text; } - void prepare (std::function pixel_format, VideoRange video_range, bool aligned, bool fast, bool proxy_only); - std::shared_ptr image (std::function pixel_format, VideoRange video_range, bool aligned, bool fast) const; + void prepare (std::function pixel_format, VideoRange video_range, Image::Alignment alignment, bool fast, bool proxy_only); + std::shared_ptr image (std::function pixel_format, VideoRange video_range, Image::Alignment alignment, bool fast) const; std::shared_ptr raw_image () const; static AVPixelFormat force (AVPixelFormat, AVPixelFormat); @@ -126,7 +127,7 @@ public: } private: - void make_image (std::function pixel_format, VideoRange video_range, bool aligned, bool fast) const; + void make_image (std::function pixel_format, VideoRange video_range, Image::Alignment alignment, bool fast) const; std::shared_ptr _in; Crop _crop; diff --git a/src/lib/raw_image_proxy.cc b/src/lib/raw_image_proxy.cc index ac8ff0763..fb0d16df8 100644 --- a/src/lib/raw_image_proxy.cc +++ b/src/lib/raw_image_proxy.cc @@ -58,16 +58,16 @@ RawImageProxy::RawImageProxy (shared_ptr xml, shared_ptr soc xml->number_child("Width"), xml->number_child("Height") ); - _image = make_shared(static_cast(xml->number_child("PixelFormat")), size, true); + _image = make_shared(static_cast(xml->number_child("PixelFormat")), size, Image::Alignment::PADDED); _image->read_from_socket (socket); } ImageProxy::Result -RawImageProxy::image (bool aligned, optional) const +RawImageProxy::image (Image::Alignment alignment, optional) const { - /* This ensure_aligned could be wasteful */ - return Result (Image::ensure_aligned(_image, aligned), 0); + /* This ensure_alignment could be wasteful */ + return Result (Image::ensure_alignment(_image, alignment), 0); } @@ -96,7 +96,7 @@ RawImageProxy::same (shared_ptr other) const return false; } - return (*_image.get()) == (*rp->image(_image->aligned()).image.get()); + return (*_image.get()) == (*rp->image(_image->alignment()).image.get()); } diff --git a/src/lib/raw_image_proxy.h b/src/lib/raw_image_proxy.h index 7e0861104..c9885654b 100644 --- a/src/lib/raw_image_proxy.h +++ b/src/lib/raw_image_proxy.h @@ -33,7 +33,7 @@ public: RawImageProxy (std::shared_ptr xml, std::shared_ptr socket); Result image ( - bool aligned, + Image::Alignment alignment, boost::optional size = boost::optional () ) const; diff --git a/src/lib/render_text.cc b/src/lib/render_text.cc index 7bb7d6b45..96b832c57 100644 --- a/src/lib/render_text.cc +++ b/src/lib/render_text.cc @@ -96,7 +96,7 @@ static shared_ptr create_image (dcp::Size size) { /* FFmpeg BGRA means first byte blue, second byte green, third byte red, fourth byte alpha */ - auto image = make_shared(AV_PIX_FMT_BGRA, size, false); + auto image = make_shared(AV_PIX_FMT_BGRA, size, Image::Alignment::COMPACT); image->make_black (); return image; } diff --git a/src/lib/util.cc b/src/lib/util.cc index c65b2bc85..981cfa521 100644 --- a/src/lib/util.cc +++ b/src/lib/util.cc @@ -22,31 +22,33 @@ * @brief Some utility functions and classes. */ + #define UNICODE 1 -#include "util.h" -#include "exceptions.h" -#include "dcp_content_type.h" -#include "filter.h" + +#include "audio_buffers.h" +#include "audio_processor.h" #include "cinema_sound_processor.h" +#include "compose.hpp" #include "config.h" -#include "ratio.h" -#include "job.h" #include "cross.h" -#include "video_content.h" -#include "rect.h" -#include "digester.h" -#include "audio_processor.h" #include "crypto.h" -#include "compose.hpp" -#include "audio_buffers.h" -#include "string_text.h" -#include "font.h" -#include "render_text.h" +#include "dcp_content_type.h" +#include "digester.h" +#include "exceptions.h" #include "ffmpeg_image_proxy.h" +#include "filter.h" +#include "font.h" #include "image.h" -#include "text_decoder.h" +#include "job.h" #include "job_manager.h" +#include "ratio.h" +#include "rect.h" +#include "render_text.h" +#include "string_text.h" +#include "text_decoder.h" +#include "util.h" +#include "video_content.h" #include "warnings.h" #include #include @@ -93,25 +95,23 @@ DCPOMATIC_ENABLE_WARNINGS #include "i18n.h" -using std::string; -using std::wstring; -using std::setfill; -using std::ostream; + +using std::bad_alloc; +using std::cout; using std::endl; -using std::vector; -using std::min; -using std::max; -using std::map; -using std::list; -using std::multimap; using std::istream; +using std::list; +using std::make_pair; +using std::make_shared; +using std::map; +using std::min; +using std::ostream; using std::pair; -using std::cout; -using std::bad_alloc; using std::set_terminate; -using std::make_pair; using std::shared_ptr; -using std::make_shared; +using std::string; +using std::vector; +using std::wstring; using boost::thread; using boost::optional; using boost::lexical_cast; @@ -122,6 +122,7 @@ using dcp::raw_convert; using dcp::locale_convert; using namespace dcpomatic; + /** Path to our executable, required by the stacktrace stuff and filled * in during App::onInit(). */ @@ -956,7 +957,7 @@ emit_subtitle_image (ContentTimePeriod period, dcp::SubtitleImage sub, dcp::Size { /* XXX: this is rather inefficient; decoding the image just to get its size */ FFmpegImageProxy proxy (sub.png_image()); - auto image = proxy.image(false).image; + auto image = proxy.image(Image::Alignment::COMPACT).image; /* set up rect with height and width */ dcpomatic::Rect rect(0, 0, image->size().width / double(size.width), image->size().height / double(size.height)); diff --git a/src/lib/video_filter_graph.cc b/src/lib/video_filter_graph.cc index b4198da72..0c7e23b05 100644 --- a/src/lib/video_filter_graph.cc +++ b/src/lib/video_filter_graph.cc @@ -38,7 +38,6 @@ using std::make_shared; using std::pair; using std::shared_ptr; using std::string; -using std::vector; VideoFilterGraph::VideoFilterGraph (dcp::Size s, AVPixelFormat p, dcp::Fraction r) @@ -59,7 +58,7 @@ VideoFilterGraph::process (AVFrame* frame) list, int64_t>> images; if (_copy) { - images.push_back (make_pair(make_shared(frame, true), frame->best_effort_timestamp)); + images.push_back (make_pair(make_shared(frame, Image::Alignment::PADDED), frame->best_effort_timestamp)); } else { int r = av_buffersrc_write_frame (_buffer_src_context, frame); if (r < 0) { @@ -71,7 +70,7 @@ VideoFilterGraph::process (AVFrame* frame) break; } - images.push_back (make_pair(make_shared(_frame, true), frame->best_effort_timestamp)); + images.push_back (make_pair(make_shared(_frame, Image::Alignment::PADDED), frame->best_effort_timestamp)); av_frame_unref (_frame); } } diff --git a/src/tools/server_test.cc b/src/tools/server_test.cc index e32fd327e..ff3295599 100644 --- a/src/tools/server_test.cc +++ b/src/tools/server_test.cc @@ -155,7 +155,7 @@ main (int argc, char* argv[]) film = make_shared(film_dir); film->read_metadata (); - auto player = make_shared(film, false); + auto player = make_shared(film, Image::Alignment::COMPACT); player->Video.connect (bind(&process_video, _1)); while (!player->pass ()) {} } catch (std::exception& e) { diff --git a/src/wx/film_viewer.cc b/src/wx/film_viewer.cc index 735ba02eb..5609ebf86 100644 --- a/src/wx/film_viewer.cc +++ b/src/wx/film_viewer.cc @@ -63,17 +63,11 @@ extern "C" { using std::bad_alloc; using std::cout; using std::dynamic_pointer_cast; -using std::exception; -using std::list; -using std::make_pair; using std::make_shared; using std::max; -using std::min; -using std::pair; using std::shared_ptr; using std::string; using std::vector; -using std::weak_ptr; using boost::optional; #if BOOST_VERSION >= 106100 using namespace boost::placeholders; @@ -169,7 +163,7 @@ FilmViewer::set_film (shared_ptr film) } try { - _player = make_shared(_film, !_optimise_for_j2k); + _player = make_shared(_film, _optimise_for_j2k ? Image::Alignment::COMPACT : Image::Alignment::PADDED); _player->set_fast (); if (_dcp_decode_reduction) { _player->set_dcp_decode_reduction (_dcp_decode_reduction); @@ -221,7 +215,7 @@ FilmViewer::recreate_butler () _audio_channels, bind(&PlayerVideo::force, _1, AV_PIX_FMT_RGB24), VideoRange::FULL, - !_optimise_for_j2k, + _optimise_for_j2k ? Image::Alignment::COMPACT : Image::Alignment::PADDED, true, dynamic_pointer_cast(_video_view) && _optimise_for_j2k ); diff --git a/src/wx/gl_video_view.cc b/src/wx/gl_video_view.cc index 6288a24a3..046465864 100644 --- a/src/wx/gl_video_view.cc +++ b/src/wx/gl_video_view.cc @@ -497,12 +497,12 @@ GLVideoView::draw (Position, dcp::Size) void GLVideoView::set_image (shared_ptr pv) { - shared_ptr video = _optimise_for_j2k ? pv->raw_image() : pv->image(bind(&PlayerVideo::force, _1, AV_PIX_FMT_RGB24), VideoRange::FULL, false, true); + shared_ptr video = _optimise_for_j2k ? pv->raw_image() : pv->image(bind(&PlayerVideo::force, _1, AV_PIX_FMT_RGB24), VideoRange::FULL, Image::Alignment::COMPACT, true); /* Only the player's black frames should be aligned at this stage, so this should * almost always have no work to do. */ - video = Image::ensure_aligned (video, false); + video = Image::ensure_alignment (video, Image::Alignment::COMPACT); /** If _optimise_for_j2k is true we render a XYZ image, doing the colourspace * conversion, scaling and video range conversion in the GL shader. @@ -517,7 +517,7 @@ GLVideoView::set_image (shared_ptr pv) _have_subtitle_to_render = static_cast(text) && _optimise_for_j2k; if (_have_subtitle_to_render) { /* opt: only do this if it's a new subtitle? */ - DCPOMATIC_ASSERT (!text->image->aligned()); + DCPOMATIC_ASSERT (text->image->alignment() == Image::Alignment::COMPACT); _subtitle_texture->set (text->image); } @@ -788,7 +788,7 @@ Texture::set (shared_ptr image) glPixelStorei (GL_UNPACK_ALIGNMENT, _unpack_alignment); check_gl_error ("glPixelStorei"); - DCPOMATIC_ASSERT (!image->aligned()); + DCPOMATIC_ASSERT (image->alignment() == Image::Alignment::COMPACT); GLint internal_format; GLenum format; diff --git a/src/wx/simple_video_view.cc b/src/wx/simple_video_view.cc index 5dd47ce4c..e54c8390e 100644 --- a/src/wx/simple_video_view.cc +++ b/src/wx/simple_video_view.cc @@ -1,5 +1,5 @@ /* - Copyright (C) 2019 Carl Hetherington + Copyright (C) 2019-2021 Carl Hetherington This file is part of DCP-o-matic. @@ -18,21 +18,23 @@ */ -#include "simple_video_view.h" + +#include "closed_captions_dialog.h" #include "film_viewer.h" +#include "simple_video_view.h" #include "wx_util.h" -#include "closed_captions_dialog.h" -#include "lib/image.h" -#include "lib/dcpomatic_log.h" #include "lib/butler.h" +#include "lib/dcpomatic_log.h" +#include "lib/image.h" #include #include #include + using std::max; +using std::shared_ptr; using std::string; using boost::optional; -using std::shared_ptr; #if BOOST_VERSION >= 106100 using namespace boost::placeholders; #endif @@ -57,6 +59,7 @@ SimpleVideoView::SimpleVideoView (FilmViewer* viewer, wxWindow* parent) _timer.Bind (wxEVT_TIMER, boost::bind(&SimpleVideoView::timer, this)); } + void SimpleVideoView::paint () { @@ -113,6 +116,7 @@ SimpleVideoView::paint () _state_timer.unset(); } + void SimpleVideoView::refresh_panel () { @@ -122,6 +126,7 @@ SimpleVideoView::refresh_panel () _state_timer.unset (); } + void SimpleVideoView::timer () { @@ -145,6 +150,7 @@ SimpleVideoView::timer () } } + void SimpleVideoView::start () { @@ -152,6 +158,7 @@ SimpleVideoView::start () timer (); } + /** Try to get a frame from the butler and display it. * @param non_blocking true to return false quickly if no video is available quickly (i.e. we are waiting for the butler). * false to ask the butler to block until it has video (unless it is suspended). @@ -176,6 +183,7 @@ SimpleVideoView::display_next_frame (bool non_blocking) return SUCCESS; } + void SimpleVideoView::update () { @@ -214,7 +222,7 @@ SimpleVideoView::update () _state_timer.set ("get image"); set_image ( - player_video().first->image(bind(&PlayerVideo::force, _1, AV_PIX_FMT_RGB24), VideoRange::FULL, false, true) + player_video().first->image(bind(&PlayerVideo::force, _1, AV_PIX_FMT_RGB24), VideoRange::FULL, Image::Alignment::COMPACT, true) ); _state_timer.set ("ImageChanged"); diff --git a/src/wx/video_waveform_plot.cc b/src/wx/video_waveform_plot.cc index 2e45f3493..07b2955b3 100644 --- a/src/wx/video_waveform_plot.cc +++ b/src/wx/video_waveform_plot.cc @@ -155,7 +155,7 @@ VideoWaveformPlot::create_waveform () auto const image_size = _image->size(); int const waveform_height = GetSize().GetHeight() - _vertical_margin * 2; - _waveform = make_shared(AV_PIX_FMT_RGB24, dcp::Size (image_size.width, waveform_height), true); + _waveform = make_shared(AV_PIX_FMT_RGB24, dcp::Size (image_size.width, waveform_height), Image::Alignment::PADDED); for (int x = 0; x < image_size.width; ++x) { @@ -182,7 +182,7 @@ VideoWaveformPlot::create_waveform () _waveform = _waveform->scale ( dcp::Size (GetSize().GetWidth() - _x_axis_width, waveform_height), - dcp::YUVToRGB::REC709, AV_PIX_FMT_RGB24, false, false + dcp::YUVToRGB::REC709, AV_PIX_FMT_RGB24, Image::Alignment::COMPACT, false ); } diff --git a/test/butler_test.cc b/test/butler_test.cc index 99bd95fce..787d1c324 100644 --- a/test/butler_test.cc +++ b/test/butler_test.cc @@ -59,7 +59,7 @@ BOOST_AUTO_TEST_CASE (butler_test1) map.set (i, i, 1); } - Butler butler (film, make_shared(film, false), map, 6, bind(&PlayerVideo::force, _1, AV_PIX_FMT_RGB24), VideoRange::FULL, false, false, false); + Butler butler (film, make_shared(film, Image::Alignment::COMPACT), map, 6, bind(&PlayerVideo::force, _1, AV_PIX_FMT_RGB24), VideoRange::FULL, Image::Alignment::COMPACT, false, false); BOOST_CHECK (butler.get_video(true, 0).second == DCPTime()); BOOST_CHECK (butler.get_video(true, 0).second == DCPTime::from_frames(1, 24)); diff --git a/test/client_server_test.cc b/test/client_server_test.cc index f518f9383..7a99f7227 100644 --- a/test/client_server_test.cc +++ b/test/client_server_test.cc @@ -66,7 +66,7 @@ do_remote_encode (shared_ptr frame, EncodeServerDescription descriptio BOOST_AUTO_TEST_CASE (client_server_test_rgb) { - auto image = make_shared(AV_PIX_FMT_RGB24, dcp::Size (1998, 1080), true); + auto image = make_shared(AV_PIX_FMT_RGB24, dcp::Size (1998, 1080), Image::Alignment::PADDED); uint8_t* p = image->data()[0]; for (int y = 0; y < 1080; ++y) { @@ -79,7 +79,7 @@ BOOST_AUTO_TEST_CASE (client_server_test_rgb) p += image->stride()[0]; } - auto sub_image = make_shared(AV_PIX_FMT_BGRA, dcp::Size (100, 200), true); + auto sub_image = make_shared(AV_PIX_FMT_BGRA, dcp::Size (100, 200), Image::Alignment::PADDED); p = sub_image->data()[0]; for (int y = 0; y < 200; ++y) { uint8_t* q = p; @@ -153,7 +153,7 @@ BOOST_AUTO_TEST_CASE (client_server_test_rgb) BOOST_AUTO_TEST_CASE (client_server_test_yuv) { - auto image = make_shared(AV_PIX_FMT_YUV420P, dcp::Size (1998, 1080), true); + auto image = make_shared(AV_PIX_FMT_YUV420P, dcp::Size (1998, 1080), Image::Alignment::PADDED); for (int i = 0; i < image->planes(); ++i) { uint8_t* p = image->data()[i]; @@ -162,7 +162,7 @@ BOOST_AUTO_TEST_CASE (client_server_test_yuv) } } - auto sub_image = make_shared(AV_PIX_FMT_BGRA, dcp::Size (100, 200), true); + auto sub_image = make_shared(AV_PIX_FMT_BGRA, dcp::Size (100, 200), Image::Alignment::PADDED); uint8_t* p = sub_image->data()[0]; for (int y = 0; y < 200; ++y) { uint8_t* q = p; @@ -236,7 +236,7 @@ BOOST_AUTO_TEST_CASE (client_server_test_yuv) BOOST_AUTO_TEST_CASE (client_server_test_j2k) { - auto image = make_shared(AV_PIX_FMT_YUV420P, dcp::Size (1998, 1080), true); + auto image = make_shared(AV_PIX_FMT_YUV420P, dcp::Size (1998, 1080), Image::Alignment::PADDED); for (int i = 0; i < image->planes(); ++i) { uint8_t* p = image->data()[i]; diff --git a/test/dcp_decoder_test.cc b/test/dcp_decoder_test.cc index 9461effc5..66cd402c4 100644 --- a/test/dcp_decoder_test.cc +++ b/test/dcp_decoder_test.cc @@ -87,7 +87,7 @@ BOOST_AUTO_TEST_CASE (check_reuse_old_data_test) ov_content = make_shared(ov->dir(ov->dcp_name(false))); test->examine_and_add_content (ov_content); BOOST_REQUIRE (!wait_for_jobs()); - auto player = make_shared(test, false); + auto player = make_shared(test, Image::Alignment::COMPACT); auto decoder = std::dynamic_pointer_cast(player->_pieces.front()->decoder); BOOST_REQUIRE (decoder); @@ -105,7 +105,7 @@ BOOST_AUTO_TEST_CASE (check_reuse_old_data_test) auto vf_content = make_shared(vf->dir(vf->dcp_name(false))); test->examine_and_add_content (vf_content); BOOST_REQUIRE (!wait_for_jobs()); - player = make_shared(test, false); + player = make_shared(test, Image::Alignment::COMPACT); decoder = std::dynamic_pointer_cast(player->_pieces.front()->decoder); BOOST_REQUIRE (decoder); @@ -123,7 +123,7 @@ BOOST_AUTO_TEST_CASE (check_reuse_old_data_test) auto encrypted_content = make_shared(encrypted->dir(encrypted->dcp_name(false))); test->examine_and_add_content (encrypted_content); BOOST_REQUIRE (!wait_for_jobs()); - player = make_shared(test, false); + player = make_shared(test, Image::Alignment::COMPACT); decoder = std::dynamic_pointer_cast(player->_pieces.front()->decoder); BOOST_REQUIRE (decoder); diff --git a/test/dcp_playback_test.cc b/test/dcp_playback_test.cc index 2ea638d74..28368dc34 100644 --- a/test/dcp_playback_test.cc +++ b/test/dcp_playback_test.cc @@ -45,12 +45,12 @@ BOOST_AUTO_TEST_CASE (dcp_playback_test) auto butler = std::make_shared( film, - make_shared(film, false), + make_shared(film, Image::Alignment::COMPACT), AudioMapping(6, 6), 6, bind(&PlayerVideo::force, _1, AV_PIX_FMT_RGB24), VideoRange::FULL, - false, + Image::Alignment::COMPACT, true, false ); @@ -63,7 +63,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), VideoRange::FULL, false, true); + p.first->image(bind(&PlayerVideo::force, _1, AV_PIX_FMT_RGB24), VideoRange::FULL, Image::Alignment::COMPACT, true); } delete[] audio_buffer; } diff --git a/test/ffmpeg_audio_only_test.cc b/test/ffmpeg_audio_only_test.cc index 9f185fdf3..40c909b39 100644 --- a/test/ffmpeg_audio_only_test.cc +++ b/test/ffmpeg_audio_only_test.cc @@ -101,7 +101,7 @@ test (boost::filesystem::path file) ref_buffer_size = info.samplerate * info.channels; ref_buffer = new float[ref_buffer_size]; - auto player = make_shared(film, false); + auto player = make_shared(film, Image::Alignment::COMPACT); player->Audio.connect (bind (&audio, _1, info.channels)); while (!player->pass ()) {} diff --git a/test/ffmpeg_audio_test.cc b/test/ffmpeg_audio_test.cc index 0cc602a9a..6bdadce97 100644 --- a/test/ffmpeg_audio_test.cc +++ b/test/ffmpeg_audio_test.cc @@ -135,7 +135,7 @@ BOOST_AUTO_TEST_CASE (ffmpeg_audio_test2) film->examine_and_add_content (content); BOOST_REQUIRE (!wait_for_jobs ()); - auto player = make_shared(film, false); + auto player = make_shared(film, Image::Alignment::COMPACT); while (!player->pass ()) {} } @@ -148,7 +148,7 @@ BOOST_AUTO_TEST_CASE (ffmpeg_audio_test3) film->examine_and_add_content (content); BOOST_REQUIRE (!wait_for_jobs ()); - auto player = make_shared(film, false); + auto player = make_shared(film, Image::Alignment::COMPACT); player->set_fast (); while (!player->pass ()) {} } @@ -162,7 +162,7 @@ BOOST_AUTO_TEST_CASE (ffmpeg_audio_test4) film->examine_and_add_content (content); BOOST_REQUIRE (!wait_for_jobs ()); - auto player = make_shared(film, false); + auto player = make_shared(film, Image::Alignment::COMPACT); player->set_fast (); BOOST_CHECK_NO_THROW (while (!player->pass()) {}); } diff --git a/test/ffmpeg_decoder_sequential_test.cc b/test/ffmpeg_decoder_sequential_test.cc index 7d6d547ff..73eea719f 100644 --- a/test/ffmpeg_decoder_sequential_test.cc +++ b/test/ffmpeg_decoder_sequential_test.cc @@ -75,7 +75,7 @@ ffmpeg_decoder_sequential_test_one (boost::filesystem::path file, float fps, int film->examine_and_add_content (content); BOOST_REQUIRE (!wait_for_jobs()); film->write_metadata (); - auto player = make_shared(film, false); + auto player = make_shared(film, Image::Alignment::COMPACT); BOOST_REQUIRE (content->video_frame_rate()); BOOST_CHECK_CLOSE (content->video_frame_rate().get(), fps, 0.01); diff --git a/test/image_test.cc b/test/image_test.cc index 9d0d43664..395aef8fd 100644 --- a/test/image_test.cc +++ b/test/image_test.cc @@ -39,13 +39,12 @@ using std::cout; using std::list; using std::make_shared; -using std::shared_ptr; using std::string; BOOST_AUTO_TEST_CASE (aligned_image_test) { - auto s = new Image (AV_PIX_FMT_RGB24, dcp::Size (50, 50), true); + auto s = new Image (AV_PIX_FMT_RGB24, dcp::Size (50, 50), Image::Alignment::PADDED); BOOST_CHECK_EQUAL (s->planes(), 1); /* 192 is 150 aligned to the nearest 64 bytes */ BOOST_CHECK_EQUAL (s->stride()[0], 192); @@ -72,7 +71,7 @@ BOOST_AUTO_TEST_CASE (aligned_image_test) BOOST_CHECK_EQUAL (t->stride()[0], s->stride()[0]); /* assignment operator */ - auto u = new Image (AV_PIX_FMT_YUV422P, dcp::Size (150, 150), false); + auto u = new Image (AV_PIX_FMT_YUV422P, dcp::Size (150, 150), Image::Alignment::COMPACT); *u = *s; BOOST_CHECK_EQUAL (u->planes(), 1); BOOST_CHECK_EQUAL (u->stride()[0], 192); @@ -96,7 +95,7 @@ BOOST_AUTO_TEST_CASE (aligned_image_test) BOOST_AUTO_TEST_CASE (compact_image_test) { - auto s = new Image (AV_PIX_FMT_RGB24, dcp::Size (50, 50), false); + auto s = new Image (AV_PIX_FMT_RGB24, dcp::Size (50, 50), Image::Alignment::COMPACT); BOOST_CHECK_EQUAL (s->planes(), 1); BOOST_CHECK_EQUAL (s->stride()[0], 50 * 3); BOOST_CHECK_EQUAL (s->line_size()[0], 50 * 3); @@ -122,7 +121,7 @@ BOOST_AUTO_TEST_CASE (compact_image_test) BOOST_CHECK_EQUAL (t->stride()[0], s->stride()[0]); /* assignment operator */ - auto u = new Image (AV_PIX_FMT_YUV422P, dcp::Size (150, 150), true); + auto u = new Image (AV_PIX_FMT_YUV422P, dcp::Size (150, 150), Image::Alignment::PADDED); *u = *s; BOOST_CHECK_EQUAL (u->planes(), 1); BOOST_CHECK_EQUAL (u->stride()[0], 50 * 3); @@ -148,10 +147,10 @@ void alpha_blend_test_one (AVPixelFormat format, string suffix) { auto proxy = make_shared(TestPaths::private_data() / "prophet_frame.tiff"); - auto raw = proxy->image(false).image; - auto background = raw->convert_pixel_format (dcp::YUVToRGB::REC709, format, true, false); + auto raw = proxy->image(Image::Alignment::COMPACT).image; + auto background = raw->convert_pixel_format (dcp::YUVToRGB::REC709, format, Image::Alignment::PADDED, false); - auto overlay = make_shared(AV_PIX_FMT_BGRA, dcp::Size(431, 891), true); + auto overlay = make_shared(AV_PIX_FMT_BGRA, dcp::Size(431, 891), Image::Alignment::PADDED); overlay->make_transparent (); for (int y = 0; y < 128; ++y) { @@ -180,7 +179,7 @@ alpha_blend_test_one (AVPixelFormat format, string suffix) background->alpha_blend (overlay, Position (13, 17)); - auto save = background->convert_pixel_format (dcp::YUVToRGB::REC709, AV_PIX_FMT_RGB24, false, false); + auto save = background->convert_pixel_format (dcp::YUVToRGB::REC709, AV_PIX_FMT_RGB24, Image::Alignment::COMPACT, false); write_image (save, "build/test/image_test_" + suffix + ".png"); check_image ("build/test/image_test_" + suffix + ".png", TestPaths::private_data() / ("image_test_" + suffix + ".png")); @@ -205,7 +204,7 @@ BOOST_AUTO_TEST_CASE (merge_test1) { int const stride = 48 * 4; - auto A = make_shared(AV_PIX_FMT_BGRA, dcp::Size (48, 48), false); + auto A = make_shared(AV_PIX_FMT_BGRA, dcp::Size (48, 48), Image::Alignment::COMPACT); A->make_transparent (); auto a = A->data()[0]; @@ -221,7 +220,7 @@ BOOST_AUTO_TEST_CASE (merge_test1) list all; all.push_back (PositionImage (A, Position(0, 0))); - auto merged = merge (all, false); + auto merged = merge (all, Image::Alignment::COMPACT); BOOST_CHECK (merged.position == Position(0, 0)); BOOST_CHECK_EQUAL (memcmp (merged.image->data()[0], A->data()[0], stride * 48), 0); @@ -231,7 +230,7 @@ BOOST_AUTO_TEST_CASE (merge_test1) /** Test merge (list) with two images */ BOOST_AUTO_TEST_CASE (merge_test2) { - auto A = make_shared(AV_PIX_FMT_BGRA, dcp::Size (48, 1), false); + auto A = make_shared(AV_PIX_FMT_BGRA, dcp::Size (48, 1), Image::Alignment::COMPACT); A->make_transparent (); auto a = A->data()[0]; for (int x = 0; x < 16; ++x) { @@ -241,7 +240,7 @@ BOOST_AUTO_TEST_CASE (merge_test2) a[x * 4 + 3] = 255; } - auto B = make_shared(AV_PIX_FMT_BGRA, dcp::Size (48, 1), false); + auto B = make_shared(AV_PIX_FMT_BGRA, dcp::Size (48, 1), Image::Alignment::COMPACT); B->make_transparent (); auto b = B->data()[0]; for (int x = 0; x < 16; ++x) { @@ -254,7 +253,7 @@ BOOST_AUTO_TEST_CASE (merge_test2) list all; all.push_back (PositionImage(A, Position(0, 0))); all.push_back (PositionImage(B, Position(0, 0))); - auto merged = merge (all, false); + auto merged = merge (all, Image::Alignment::COMPACT); BOOST_CHECK (merged.position == Position(0, 0)); @@ -274,11 +273,11 @@ BOOST_AUTO_TEST_CASE (merge_test2) BOOST_AUTO_TEST_CASE (crop_scale_window_test) { auto proxy = make_shared("test/data/flat_red.png"); - auto raw = proxy->image(false).image; + auto raw = proxy->image(Image::Alignment::COMPACT).image; auto out = raw->crop_scale_window( - Crop(), dcp::Size(1998, 836), dcp::Size(1998, 1080), dcp::YUVToRGB::REC709, VideoRange::FULL, AV_PIX_FMT_YUV420P, VideoRange::FULL, true, false + Crop(), dcp::Size(1998, 836), dcp::Size(1998, 1080), dcp::YUVToRGB::REC709, VideoRange::FULL, AV_PIX_FMT_YUV420P, VideoRange::FULL, Image::Alignment::PADDED, false ); - auto save = out->scale(dcp::Size(1998, 1080), dcp::YUVToRGB::REC709, AV_PIX_FMT_RGB24, false, false); + auto save = out->scale(dcp::Size(1998, 1080), dcp::YUVToRGB::REC709, AV_PIX_FMT_RGB24, Image::Alignment::COMPACT, 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"); } @@ -287,12 +286,12 @@ BOOST_AUTO_TEST_CASE (crop_scale_window_test) /** Special cases of Image::crop_scale_window which triggered some valgrind warnings */ BOOST_AUTO_TEST_CASE (crop_scale_window_test2) { - auto image = make_shared(AV_PIX_FMT_XYZ12LE, dcp::Size(2048, 858), true); + auto image = make_shared(AV_PIX_FMT_XYZ12LE, dcp::Size(2048, 858), Image::Alignment::PADDED); image->crop_scale_window ( - Crop(279, 0, 0, 0), dcp::Size(1069, 448), dcp::Size(1069, 578), dcp::YUVToRGB::REC709, VideoRange::FULL, AV_PIX_FMT_RGB24, VideoRange::FULL, false, false + Crop(279, 0, 0, 0), dcp::Size(1069, 448), dcp::Size(1069, 578), dcp::YUVToRGB::REC709, VideoRange::FULL, AV_PIX_FMT_RGB24, VideoRange::FULL, Image::Alignment::COMPACT, false ); image->crop_scale_window ( - Crop(2048, 0, 0, 0), dcp::Size(1069, 448), dcp::Size(1069, 578), dcp::YUVToRGB::REC709, VideoRange::FULL, AV_PIX_FMT_RGB24, VideoRange::FULL, false, false + Crop(2048, 0, 0, 0), dcp::Size(1069, 448), dcp::Size(1069, 578), dcp::YUVToRGB::REC709, VideoRange::FULL, AV_PIX_FMT_RGB24, VideoRange::FULL, Image::Alignment::COMPACT, false ); } @@ -300,9 +299,9 @@ BOOST_AUTO_TEST_CASE (crop_scale_window_test2) BOOST_AUTO_TEST_CASE (crop_scale_window_test3) { auto proxy = make_shared(TestPaths::private_data() / "player_seek_test_0.png"); - auto xyz = proxy->image(false).image->convert_pixel_format(dcp::YUVToRGB::REC709, AV_PIX_FMT_RGB24, true, false); + auto xyz = proxy->image(Image::Alignment::COMPACT).image->convert_pixel_format(dcp::YUVToRGB::REC709, AV_PIX_FMT_RGB24, Image::Alignment::PADDED, false); auto cropped = xyz->crop_scale_window( - Crop(512, 0, 0, 0), dcp::Size(1486, 1080), dcp::Size(1998, 1080), dcp::YUVToRGB::REC709, VideoRange::FULL, AV_PIX_FMT_RGB24, VideoRange::FULL, false, false + Crop(512, 0, 0, 0), dcp::Size(1486, 1080), dcp::Size(1998, 1080), dcp::YUVToRGB::REC709, VideoRange::FULL, AV_PIX_FMT_RGB24, VideoRange::FULL, Image::Alignment::COMPACT, 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"); @@ -312,9 +311,9 @@ BOOST_AUTO_TEST_CASE (crop_scale_window_test3) BOOST_AUTO_TEST_CASE (crop_scale_window_test4) { auto proxy = make_shared(TestPaths::private_data() / "player_seek_test_0.png"); - auto xyz = proxy->image(false).image->convert_pixel_format(dcp::YUVToRGB::REC709, AV_PIX_FMT_RGB24, true, false); + auto xyz = proxy->image(Image::Alignment::COMPACT).image->convert_pixel_format(dcp::YUVToRGB::REC709, AV_PIX_FMT_RGB24, Image::Alignment::PADDED, false); auto cropped = xyz->crop_scale_window( - Crop(512, 0, 0, 0), dcp::Size(1486, 1080), dcp::Size(1998, 1080), dcp::YUVToRGB::REC709, VideoRange::FULL, AV_PIX_FMT_XYZ12LE, VideoRange::FULL, false, false + Crop(512, 0, 0, 0), dcp::Size(1486, 1080), dcp::Size(1998, 1080), dcp::YUVToRGB::REC709, VideoRange::FULL, AV_PIX_FMT_XYZ12LE, VideoRange::FULL, Image::Alignment::COMPACT, 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); @@ -324,9 +323,9 @@ BOOST_AUTO_TEST_CASE (crop_scale_window_test4) BOOST_AUTO_TEST_CASE (crop_scale_window_test5) { auto proxy = make_shared(TestPaths::private_data() / "player_seek_test_0.png"); - auto xyz = proxy->image(false).image->convert_pixel_format(dcp::YUVToRGB::REC709, AV_PIX_FMT_XYZ12LE, true, false); + auto xyz = proxy->image(Image::Alignment::COMPACT).image->convert_pixel_format(dcp::YUVToRGB::REC709, AV_PIX_FMT_XYZ12LE, Image::Alignment::PADDED, false); auto cropped = xyz->crop_scale_window( - Crop(512, 0, 0, 0), dcp::Size(1486, 1080), dcp::Size(1998, 1080), dcp::YUVToRGB::REC709, VideoRange::FULL, AV_PIX_FMT_RGB24, VideoRange::FULL, false, false + Crop(512, 0, 0, 0), dcp::Size(1486, 1080), dcp::Size(1998, 1080), dcp::YUVToRGB::REC709, VideoRange::FULL, AV_PIX_FMT_RGB24, VideoRange::FULL, Image::Alignment::COMPACT, 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"); @@ -336,9 +335,9 @@ BOOST_AUTO_TEST_CASE (crop_scale_window_test5) BOOST_AUTO_TEST_CASE (crop_scale_window_test6) { auto proxy = make_shared(TestPaths::private_data() / "player_seek_test_0.png"); - auto xyz = proxy->image(false).image->convert_pixel_format(dcp::YUVToRGB::REC709, AV_PIX_FMT_XYZ12LE, true, false); + auto xyz = proxy->image(Image::Alignment::COMPACT).image->convert_pixel_format(dcp::YUVToRGB::REC709, AV_PIX_FMT_XYZ12LE, Image::Alignment::PADDED, false); auto cropped = xyz->crop_scale_window( - Crop(512, 0, 0, 0), dcp::Size(1486, 1080), dcp::Size(1998, 1080), dcp::YUVToRGB::REC709, VideoRange::FULL, AV_PIX_FMT_XYZ12LE, VideoRange::FULL, false, false + Crop(512, 0, 0, 0), dcp::Size(1486, 1080), dcp::Size(1998, 1080), dcp::YUVToRGB::REC709, VideoRange::FULL, AV_PIX_FMT_XYZ12LE, VideoRange::FULL, Image::Alignment::COMPACT, 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); @@ -351,7 +350,7 @@ BOOST_AUTO_TEST_CASE (crop_scale_window_test7) using namespace boost::filesystem; for (int left_crop = 0; left_crop < 8; ++left_crop) { auto proxy = make_shared("test/data/rgb_grey_testcard.png"); - auto yuv = proxy->image(false).image->convert_pixel_format(dcp::YUVToRGB::REC709, AV_PIX_FMT_YUV420P, true, false); + auto yuv = proxy->image(Image::Alignment::COMPACT).image->convert_pixel_format(dcp::YUVToRGB::REC709, AV_PIX_FMT_YUV420P, Image::Alignment::PADDED, false); int rounded = left_crop - (left_crop % 2); auto cropped = yuv->crop_scale_window( Crop(left_crop, 0, 0, 0), @@ -361,7 +360,7 @@ BOOST_AUTO_TEST_CASE (crop_scale_window_test7) VideoRange::VIDEO, AV_PIX_FMT_RGB24, VideoRange::VIDEO, - true, + Image::Alignment::PADDED, false ); path file = String::compose("crop_scale_window_test7-%1.png", left_crop); @@ -374,8 +373,8 @@ BOOST_AUTO_TEST_CASE (crop_scale_window_test7) BOOST_AUTO_TEST_CASE (as_png_test) { auto proxy = make_shared("test/data/3d_test/000001.png"); - auto image_rgb = proxy->image(false).image; - auto image_bgr = image_rgb->convert_pixel_format(dcp::YUVToRGB::REC709, AV_PIX_FMT_BGRA, true, false); + auto image_rgb = proxy->image(Image::Alignment::COMPACT).image; + auto image_bgr = image_rgb->convert_pixel_format(dcp::YUVToRGB::REC709, AV_PIX_FMT_BGRA, Image::Alignment::PADDED, false); image_rgb->as_png().write ("build/test/as_png_rgb.png"); image_bgr->as_png().write ("build/test/as_png_bgr.png"); @@ -388,11 +387,11 @@ BOOST_AUTO_TEST_CASE (as_png_test) static void fade_test_format_black (AVPixelFormat f, string name) { - Image yuv (f, dcp::Size(640, 480), true); + Image yuv (f, dcp::Size(640, 480), Image::Alignment::PADDED); yuv.make_black (); yuv.fade (0); string const filename = "fade_test_black_" + name + ".png"; - yuv.convert_pixel_format(dcp::YUVToRGB::REC709, AV_PIX_FMT_RGBA, true, false)->as_png().write("build/test/" + filename); + yuv.convert_pixel_format(dcp::YUVToRGB::REC709, AV_PIX_FMT_RGBA, Image::Alignment::PADDED, false)->as_png().write("build/test/" + filename); check_image ("test/data/" + filename, "build/test/" + filename); } @@ -402,10 +401,10 @@ static void fade_test_format_red (AVPixelFormat f, float amount, string name) { auto proxy = make_shared("test/data/flat_red.png"); - auto red = proxy->image(false).image->convert_pixel_format(dcp::YUVToRGB::REC709, f, true, false); + auto red = proxy->image(Image::Alignment::COMPACT).image->convert_pixel_format(dcp::YUVToRGB::REC709, f, Image::Alignment::PADDED, false); red->fade (amount); string const filename = "fade_test_red_" + name + ".png"; - red->convert_pixel_format(dcp::YUVToRGB::REC709, AV_PIX_FMT_RGBA, true, false)->as_png().write("build/test/" + filename); + red->convert_pixel_format(dcp::YUVToRGB::REC709, AV_PIX_FMT_RGBA, Image::Alignment::PADDED, false)->as_png().write("build/test/" + filename); check_image ("test/data/" + filename, "build/test/" + filename); } @@ -482,9 +481,9 @@ BOOST_AUTO_TEST_CASE (make_black_test) int N = 0; for (auto i: pix_fmts) { - auto foo = make_shared(i, in_size, true); + auto foo = make_shared(i, in_size, Image::Alignment::PADDED); foo->make_black (); - auto bar = foo->scale (out_size, dcp::YUVToRGB::REC601, AV_PIX_FMT_RGB24, true, false); + auto bar = foo->scale (out_size, dcp::YUVToRGB::REC601, AV_PIX_FMT_RGB24, Image::Alignment::PADDED, false); uint8_t* p = bar->data()[0]; for (int y = 0; y < bar->size().height; ++y) { @@ -506,7 +505,7 @@ BOOST_AUTO_TEST_CASE (make_black_test) BOOST_AUTO_TEST_CASE (make_part_black_test) { auto proxy = make_shared("test/data/flat_red.png"); - auto original = proxy->image(false).image; + auto original = proxy->image(Image::Alignment::COMPACT).image; list pix_fmts = { AV_PIX_FMT_RGB24, @@ -526,9 +525,9 @@ BOOST_AUTO_TEST_CASE (make_part_black_test) int N = 0; for (auto i: pix_fmts) { for (auto j: positions) { - auto foo = original->convert_pixel_format(dcp::YUVToRGB::REC601, i, true, false); + auto foo = original->convert_pixel_format(dcp::YUVToRGB::REC601, i, Image::Alignment::PADDED, false); foo->make_part_black (j.first, j.second); - auto bar = foo->convert_pixel_format (dcp::YUVToRGB::REC601, AV_PIX_FMT_RGB24, true, false); + auto bar = foo->convert_pixel_format (dcp::YUVToRGB::REC601, AV_PIX_FMT_RGB24, Image::Alignment::PADDED, false); auto p = bar->data()[0]; for (int y = 0; y < bar->size().height; ++y) { @@ -569,10 +568,10 @@ BOOST_AUTO_TEST_CASE (make_part_black_test) */ BOOST_AUTO_TEST_CASE (over_crop_test) { - auto image = make_shared(AV_PIX_FMT_RGB24, dcp::Size(128, 128), true); + auto image = make_shared(AV_PIX_FMT_RGB24, dcp::Size(128, 128), Image::Alignment::PADDED); image->make_black (); auto scaled = image->crop_scale_window ( - Crop(0, 0, 128, 128), dcp::Size(1323, 565), dcp::Size(1349, 565), dcp::YUVToRGB::REC709, VideoRange::FULL, AV_PIX_FMT_RGB24, VideoRange::FULL, true, true + Crop(0, 0, 128, 128), dcp::Size(1323, 565), dcp::Size(1349, 565), dcp::YUVToRGB::REC709, VideoRange::FULL, AV_PIX_FMT_RGB24, VideoRange::FULL, Image::Alignment::PADDED, true ); string const filename = "over_crop_test.png"; write_image (scaled, "build/test/" + filename); diff --git a/test/low_bitrate_test.cc b/test/low_bitrate_test.cc index 33ce2635d..7050dd771 100644 --- a/test/low_bitrate_test.cc +++ b/test/low_bitrate_test.cc @@ -35,10 +35,26 @@ using std::make_shared; BOOST_AUTO_TEST_CASE (low_bitrate_test) { - auto image = make_shared(AV_PIX_FMT_RGB24, dcp::Size(1998, 1080), true); + auto image = make_shared(AV_PIX_FMT_RGB24, dcp::Size(1998, 1080), Image::Alignment::PADDED); image->make_black (); + auto proxy = make_shared(image); - auto frame = make_shared(proxy, Crop(), boost::optional(), dcp::Size(1998, 1080), dcp::Size(1998, 1080), Eyes::BOTH, Part::WHOLE, boost::optional(), VideoRange::FULL, std::weak_ptr(), boost::optional(), false); + + auto frame = make_shared( + proxy, + Crop(), + boost::optional(), + dcp::Size(1998, 1080), + dcp::Size(1998, 1080), + Eyes::BOTH, + Part::WHOLE, + boost::optional(), + VideoRange::FULL, + std::weak_ptr(), + boost::optional(), + false + ); + auto dcp_video = make_shared(frame, 0, 24, 100000000, Resolution::TWO_K); auto j2k = dcp_video->encode_locally(); BOOST_REQUIRE (j2k.size() >= 16536); diff --git a/test/overlap_video_test.cc b/test/overlap_video_test.cc index d0d5a8bbf..3c969921d 100644 --- a/test/overlap_video_test.cc +++ b/test/overlap_video_test.cc @@ -40,7 +40,6 @@ using std::dynamic_pointer_cast; using std::make_shared; -using std::shared_ptr; BOOST_AUTO_TEST_CASE (overlap_video_test1) @@ -57,7 +56,7 @@ BOOST_AUTO_TEST_CASE (overlap_video_test1) B->video->set_length (24); B->set_position (film, dcpomatic::DCPTime::from_seconds(1)); - auto player = make_shared(film, false); + auto player = make_shared(film, Image::Alignment::COMPACT); auto pieces = player->_pieces; BOOST_REQUIRE_EQUAL (pieces.size(), 2U); BOOST_CHECK_EQUAL (pieces.front()->content, A); diff --git a/test/pixel_formats_test.cc b/test/pixel_formats_test.cc index a4d42e399..12a95bd69 100644 --- a/test/pixel_formats_test.cc +++ b/test/pixel_formats_test.cc @@ -88,7 +88,7 @@ BOOST_AUTO_TEST_CASE (pixel_formats_test) f->height = 480; f->format = static_cast (i.format); av_frame_get_buffer (f, true); - Image t (f, false); + Image t (f, Image::Alignment::COMPACT); BOOST_CHECK_EQUAL(t.planes(), i.planes); BOOST_CHECK_EQUAL(t.sample_size(0).height, i.lines[0]); BOOST_CHECK_EQUAL(t.sample_size(1).height, i.lines[1]); diff --git a/test/player_test.cc b/test/player_test.cc index c1e2d2cbe..2caa34753 100644 --- a/test/player_test.cc +++ b/test/player_test.cc @@ -25,21 +25,21 @@ */ -#include "lib/film.h" -#include "lib/ffmpeg_content.h" -#include "lib/dcp_content_type.h" -#include "lib/ratio.h" #include "lib/audio_buffers.h" -#include "lib/player.h" -#include "lib/video_content.h" -#include "lib/image_content.h" -#include "lib/string_text_file_content.h" -#include "lib/content_factory.h" -#include "lib/dcp_content.h" -#include "lib/text_content.h" #include "lib/butler.h" #include "lib/compose.hpp" +#include "lib/content_factory.h" #include "lib/cross.h" +#include "lib/dcp_content.h" +#include "lib/dcp_content_type.h" +#include "lib/ffmpeg_content.h" +#include "lib/film.h" +#include "lib/image_content.h" +#include "lib/player.h" +#include "lib/ratio.h" +#include "lib/string_text_file_content.h" +#include "lib/text_content.h" +#include "lib/video_content.h" #include "test.h" #include #include @@ -48,7 +48,6 @@ using std::cout; using std::list; -using std::pair; using std::shared_ptr; using std::make_shared; using boost::bind; @@ -84,7 +83,7 @@ BOOST_AUTO_TEST_CASE (player_silence_padding_test) accumulated = std::make_shared(film->audio_channels(), 0); - auto player = std::make_shared(film, false); + auto player = std::make_shared(film, Image::Alignment::COMPACT); player->Audio.connect (bind (&accumulate, _1, _2)); while (!player->pass ()) {} BOOST_REQUIRE (accumulated->frames() >= 48000); @@ -164,7 +163,7 @@ BOOST_AUTO_TEST_CASE (player_subframe_test) /* Length should be rounded up from B's length to the next video frame */ BOOST_CHECK (film->length() == DCPTime::from_frames(3 * 24 + 1, 24)); - auto player = std::make_shared(film, false); + auto player = std::make_shared(film, Image::Alignment::COMPACT); player->setup_pieces (); BOOST_REQUIRE_EQUAL (player->_black._periods.size(), 1U); BOOST_CHECK (player->_black._periods.front() == DCPTimePeriod(DCPTime::from_frames(3 * 24, 24), DCPTime::from_frames(3 * 24 + 1, 24))); @@ -206,7 +205,7 @@ BOOST_AUTO_TEST_CASE (player_interleave_test) film->examine_and_add_content (s); BOOST_REQUIRE (!wait_for_jobs ()); - auto player = std::make_shared(film, false); + auto player = std::make_shared(film, Image::Alignment::COMPACT); player->Video.connect (bind (&video, _1, _2)); player->Audio.connect (bind (&audio, _1, _2)); video_frames = audio_frames = 0; @@ -229,12 +228,12 @@ BOOST_AUTO_TEST_CASE (player_seek_test) BOOST_REQUIRE (!wait_for_jobs ()); dcp->only_text()->set_use (true); - auto player = std::make_shared(film, false); + auto player = std::make_shared(film, Image::Alignment::COMPACT); player->set_fast (); player->set_always_burn_open_subtitles (); player->set_play_referenced (); - auto butler = std::make_shared(film, player, AudioMapping(), 2, bind(PlayerVideo::force, _1, AV_PIX_FMT_RGB24), VideoRange::FULL, false, true, false); + auto butler = std::make_shared(film, player, AudioMapping(), 2, bind(PlayerVideo::force, _1, AV_PIX_FMT_RGB24), VideoRange::FULL, Image::Alignment::COMPACT, true, false); butler->disable_audio(); for (int i = 0; i < 10; ++i) { @@ -242,7 +241,7 @@ BOOST_AUTO_TEST_CASE (player_seek_test) butler->seek (t, true); auto 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), VideoRange::FULL, 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), VideoRange::FULL, Image::Alignment::COMPACT, 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. @@ -261,12 +260,12 @@ BOOST_AUTO_TEST_CASE (player_seek_test2) BOOST_REQUIRE (!wait_for_jobs ()); dcp->only_text()->set_use (true); - auto player = std::make_shared(film, false); + auto player = std::make_shared(film, Image::Alignment::COMPACT); player->set_fast (); player->set_always_burn_open_subtitles (); player->set_play_referenced (); - auto butler = std::make_shared(film, player, AudioMapping(), 2, bind(PlayerVideo::force, _1, AV_PIX_FMT_RGB24), VideoRange::FULL, false, true, false); + auto butler = std::make_shared(film, player, AudioMapping(), 2, bind(PlayerVideo::force, _1, AV_PIX_FMT_RGB24), VideoRange::FULL, Image::Alignment::COMPACT, true, false); butler->disable_audio(); butler->seek(DCPTime::from_seconds(5), true); @@ -277,7 +276,7 @@ BOOST_AUTO_TEST_CASE (player_seek_test2) auto 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), VideoRange::FULL, false, true), String::compose("build/test/player_seek_test2_%1.png", i) + video.first->image(bind(PlayerVideo::force, _1, AV_PIX_FMT_RGB24), VideoRange::FULL, Image::Alignment::COMPACT, true), String::compose("build/test/player_seek_test2_%1.png", i) ); check_image(TestPaths::private_data() / String::compose("player_seek_test2_%1.png", i), String::compose("build/test/player_seek_test2_%1.png", i), 14.08); } @@ -335,7 +334,7 @@ BOOST_AUTO_TEST_CASE (player_ignore_video_and_audio_test) text->only_text()->set_type (TextType::CLOSED_CAPTION); text->only_text()->set_use (true); - auto player = std::make_shared(film, false); + auto player = std::make_shared(film, Image::Alignment::COMPACT); player->set_ignore_video (); player->set_ignore_audio (); @@ -355,9 +354,9 @@ BOOST_AUTO_TEST_CASE (player_trim_crash) film->examine_and_add_content (boon); BOOST_REQUIRE (!wait_for_jobs()); - auto player = std::make_shared(film, false); + auto player = std::make_shared(film, Image::Alignment::COMPACT); player->set_fast (); - auto butler = std::make_shared(film, player, AudioMapping(), 6, bind(&PlayerVideo::force, _1, AV_PIX_FMT_RGB24), VideoRange::FULL, false, true, false); + auto butler = std::make_shared(film, player, AudioMapping(), 6, bind(&PlayerVideo::force, _1, AV_PIX_FMT_RGB24), VideoRange::FULL, Image::Alignment::COMPACT, true, false); /* Wait for the butler to fill */ dcpomatic_sleep_seconds (5); diff --git a/test/test.cc b/test/test.cc index 3395d9672..8417b30d2 100644 --- a/test/test.cc +++ b/test/test.cc @@ -364,9 +364,9 @@ double rms_error (boost::filesystem::path ref, boost::filesystem::path check) { FFmpegImageProxy ref_proxy (ref); - auto ref_image = ref_proxy.image(false).image; + auto ref_image = ref_proxy.image(Image::Alignment::COMPACT).image; FFmpegImageProxy check_proxy (check); - auto check_image = check_proxy.image(false).image; + auto check_image = check_proxy.image(Image::Alignment::COMPACT).image; BOOST_REQUIRE_EQUAL (ref_image->pixel_format(), check_image->pixel_format()); AVPixelFormat const format = ref_image->pixel_format(); diff --git a/test/time_calculation_test.cc b/test/time_calculation_test.cc index 285285395..4ab5d0942 100644 --- a/test/time_calculation_test.cc +++ b/test/time_calculation_test.cc @@ -36,7 +36,6 @@ using std::list; using std::make_shared; -using std::shared_ptr; using std::string; using namespace dcpomatic; @@ -197,7 +196,7 @@ BOOST_AUTO_TEST_CASE (player_time_calculation_test1) film->set_sequence (false); film->add_content (content); - auto player = make_shared(film, false); + auto player = make_shared(film, Image::Alignment::COMPACT); /* Position 0, no trim, content rate = DCP rate */ content->set_position (film, DCPTime()); @@ -403,7 +402,7 @@ BOOST_AUTO_TEST_CASE (player_time_calculation_test2) film->set_sequence (false); film->add_content (content); - auto player = make_shared(film, false); + auto player = make_shared(film, Image::Alignment::COMPACT); /* Position 0, no trim, content rate = DCP rate */ content->set_position (film, DCPTime()); @@ -580,7 +579,7 @@ BOOST_AUTO_TEST_CASE (player_time_calculation_test3) film->set_sequence (false); film->add_content (content); - auto player = make_shared(film, false); + auto player = make_shared(film, Image::Alignment::COMPACT); /* Position 0, no trim, video/audio content rate = video/audio DCP rate */ content->set_position (film, DCPTime()); diff --git a/test/upmixer_a_test.cc b/test/upmixer_a_test.cc index 3310a9277..af6c8b9e2 100644 --- a/test/upmixer_a_test.cc +++ b/test/upmixer_a_test.cc @@ -89,7 +89,7 @@ BOOST_AUTO_TEST_CASE (upmixer_a_test) Ls = sf_open ("build/test/upmixer_a_test/Ls.wav", SFM_WRITE, &info); Rs = sf_open ("build/test/upmixer_a_test/Rs.wav", SFM_WRITE, &info); - auto player = make_shared(film, false); + auto player = make_shared(film, Image::Alignment::COMPACT); player->Audio.connect (bind (&write, _1, _2)); while (!player->pass()) {} diff --git a/test/vf_test.cc b/test/vf_test.cc index d25eb3cca..4db48dd60 100644 --- a/test/vf_test.cc +++ b/test/vf_test.cc @@ -291,7 +291,7 @@ BOOST_AUTO_TEST_CASE (vf_test5) make_and_verify_dcp (vf, {dcp::VerificationNote::Code::EXTERNAL_ASSET}); /* Check that the selected reel assets are right */ - auto player = make_shared(vf, false); + auto player = make_shared(vf, Image::Alignment::COMPACT); auto a = player->get_reel_assets(); BOOST_REQUIRE_EQUAL (a.size(), 4U); auto i = a.begin(); diff --git a/test/video_level_test.cc b/test/video_level_test.cc index 8d82e9d76..54513464c 100644 --- a/test/video_level_test.cc +++ b/test/video_level_test.cc @@ -54,7 +54,6 @@ using std::min; -using std::make_pair; using std::max; using std::pair; using std::string; @@ -71,7 +70,7 @@ static shared_ptr grey_image (dcp::Size size, uint8_t pixel) { - auto grey = make_shared(AV_PIX_FMT_RGB24, size, true); + auto grey = make_shared(AV_PIX_FMT_RGB24, size, Image::Alignment::PADDED); for (int y = 0; y < size.height; ++y) { uint8_t* p = grey->data()[0] + y * grey->stride()[0]; for (int x = 0; x < size.width; ++x) { @@ -94,7 +93,7 @@ BOOST_AUTO_TEST_CASE (ffmpeg_image_full_range_not_changed) write_image (grey_image(size, grey_pixel), file); FFmpegImageProxy proxy (file); - ImageProxy::Result result = proxy.image (false); + ImageProxy::Result result = proxy.image (Image::Alignment::COMPACT); BOOST_REQUIRE (!result.error); for (int y = 0; y < size.height; ++y) { @@ -128,7 +127,7 @@ BOOST_AUTO_TEST_CASE (ffmpeg_image_video_range_expanded) BOOST_REQUIRE (!player->pass()); } - auto image = player_video->image ([](AVPixelFormat f) { return f; }, VideoRange::FULL, true, false); + auto image = player_video->image ([](AVPixelFormat f) { return f; }, VideoRange::FULL, Image::Alignment::PADDED, false); for (int y = 0; y < size.height; ++y) { uint8_t* p = image->data()[0] + y * image->stride()[0]; @@ -214,7 +213,7 @@ pixel_range (shared_ptr film, shared_ptr content) BOOST_REQUIRE (!decoder->pass()); } - return pixel_range (content_video->image->image(false).image); + return pixel_range (content_video->image->image(Image::Alignment::COMPACT).image); } -- 2.30.2