diff options
| author | Carl Hetherington <cth@carlh.net> | 2021-09-27 13:43:19 +0200 |
|---|---|---|
| committer | Carl Hetherington <cth@carlh.net> | 2021-09-27 13:43:19 +0200 |
| commit | 952084c4221c5708e02c783284cf0f7239c6b4c4 (patch) | |
| tree | c1521dab0586b6c33e02c9338c94abdc6b4c2ea9 /src/lib | |
| parent | 6e3e984162ca7a181bc7c98d90c295e88e4e7f6c (diff) | |
| parent | 81b9ea804cb9953bb1a4074f208f63374adbf09b (diff) | |
Merge branch 'better-gl' into v2.15.x
This changes the GL video view to use more modern GL (GLSL etc.) It
also special-cases JPEG2000 video playback and does scaling and
colourspace conversion on the GPU.
Diffstat (limited to 'src/lib')
32 files changed, 254 insertions, 201 deletions
diff --git a/src/lib/bitmap_text.h b/src/lib/bitmap_text.h index b8861c10a..46b6fd142 100644 --- a/src/lib/bitmap_text.h +++ b/src/lib/bitmap_text.h @@ -31,12 +31,12 @@ class Image; class BitmapText { public: - BitmapText (std::shared_ptr<Image> i, dcpomatic::Rect<double> r) + BitmapText (std::shared_ptr<const Image> i, dcpomatic::Rect<double> r) : image (i) , rectangle (r) {} - std::shared_ptr<Image> image; + std::shared_ptr<const Image> image; /** Area that the subtitle covers on its corresponding video, expressed in * proportions of the image size; e.g. rectangle.x = 0.5 would mean that * the rectangle starts half-way across the video. diff --git a/src/lib/butler.cc b/src/lib/butler.cc index 5a8e646aa..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,8 +67,9 @@ Butler::Butler ( int audio_channels, function<AVPixelFormat (AVPixelFormat)> pixel_format, VideoRange video_range, - bool aligned, - bool fast + Image::Alignment alignment, + bool fast, + bool prepare_only_proxy ) : _film (film) , _player (player) @@ -83,8 +84,9 @@ 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) { _player_video_connection = _player->Video.connect (bind (&Butler::video, this, _1, _2)); _player_audio_connection = _player->Audio.connect (bind (&Butler::audio, this, _1, _2, _3)); @@ -323,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); + 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 a231fd099..cd3891754 100644 --- a/src/lib/butler.h +++ b/src/lib/butler.h @@ -45,8 +45,9 @@ public: int audio_channels, std::function<AVPixelFormat (AVPixelFormat)> pixel_format, VideoRange video_range, - bool aligned, - bool fast + Image::Alignment alignment, + bool fast, + bool prepare_only_proxy ); ~Butler (); @@ -124,9 +125,17 @@ private: std::function<AVPixelFormat (AVPixelFormat)> _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 + * the final image. We want to do this when the viewer is intending to call + * PlayerVideo::raw_image() and do the things in PlayerVideo::make_imgae() itself: + * this is the case for the GLVideoView which can do scale, pixfmt conversion etc. + * in the shader. + */ + bool _prepare_only_proxy = false; + /** If we are waiting to be refilled following a seek, this is the time we were seeking to. */ diff --git a/src/lib/content_text.h b/src/lib/content_text.h index c6d7d6ec2..5edb9af20 100644 --- a/src/lib/content_text.h +++ b/src/lib/content_text.h @@ -48,7 +48,7 @@ private: class ContentBitmapText : public ContentText { public: - ContentBitmapText (dcpomatic::ContentTime f, std::shared_ptr<Image> im, dcpomatic::Rect<double> r) + ContentBitmapText (dcpomatic::ContentTime f, std::shared_ptr<const Image> im, dcpomatic::Rect<double> r) : ContentText (f) , sub (im, r) {} diff --git a/src/lib/dcp_video.cc b/src/lib/dcp_video.cc index 4a505a7e1..3a85a5ac6 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<const PlayerVideo> frame, dcp::NoteHandler { shared_ptr<dcp::OpenJPEGImage> 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, 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 fe27cb7dd..1d688c318 100644 --- a/src/lib/encoder.cc +++ b/src/lib/encoder.cc @@ -41,7 +41,7 @@ Encoder::Encoder (std::shared_ptr<const Film> film, std::weak_ptr<Job> job) : _film (film) , _job (job) - , _player (new Player(film)) + , _player (new Player(film, Image::Alignment::PADDED)) { } diff --git a/src/lib/exceptions.cc b/src/lib/exceptions.cc index ebb607b94..3f87a2ebe 100644 --- a/src/lib/exceptions.cc +++ b/src/lib/exceptions.cc @@ -132,6 +132,13 @@ GLError::GLError (char const* last, int e) } +GLError::GLError (char const* message) + : runtime_error (message) +{ + +} + + CopyError::CopyError (string m, optional<int> n) : runtime_error (String::compose("%1%2", m, n ? String::compose(" (%1)", *n) : "")) , _message (m) diff --git a/src/lib/exceptions.h b/src/lib/exceptions.h index d0ba1f068..9b7837a46 100644 --- a/src/lib/exceptions.h +++ b/src/lib/exceptions.h @@ -378,6 +378,7 @@ class GLError : public std::runtime_error { public: GLError (char const* last, int e); + GLError (char const* message); }; diff --git a/src/lib/ffmpeg_decoder.cc b/src/lib/ffmpeg_decoder.cc index 72372fca8..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 <dcp/subtitle_string.h> #include <sub/ssa_reader.h> #include <sub/subtitle.h> @@ -52,28 +54,22 @@ extern "C" { #include <libavformat/avformat.h> } #include <boost/algorithm/string.hpp> -#include <vector> #include <iomanip> #include <iostream> +#include <vector> #include <stdint.h> #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<const Film> film, shared_ptr<const FFmp video = make_shared<VideoDecoder>(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.reset (new Image (AV_PIX_FMT_RGB24, dcp::Size (128, 128), true)); + _black_image = make_shared<Image>(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<Image>(AV_PIX_FMT_BGRA, dcp::Size (rect->w, rect->h), true); + auto image = make_shared<Image>(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 61ca1ae00..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 <iostream> #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<const Film> film, @@ -108,7 +108,7 @@ FFmpegEncoder::FFmpegEncoder ( } _butler = std::make_shared<Butler>( - _film, _player, map, _output_audio_channels, bind(&PlayerVideo::force, _1, FFmpegFileEncoder::pixel_format(format)), VideoRange::VIDEO, true, 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..705557f79 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 <libavutil/channel_layout.h> } @@ -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,6 @@ FFmpegFileEncoder::video (shared_ptr<PlayerVideo> video, DCPTime time) auto image = video->image ( bind (&PlayerVideo::force, _1, _pixel_format), VideoRange::VIDEO, - true, false ); diff --git a/src/lib/ffmpeg_image_proxy.cc b/src/lib/ffmpeg_image_proxy.cc index e7d5b424d..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 (optional<dcp::Size>) const +FFmpegImageProxy::image (Image::Alignment alignment, optional<dcp::Size>) const { auto constexpr name_for_errors = "FFmpegImageProxy::image"; @@ -205,7 +205,7 @@ FFmpegImageProxy::image (optional<dcp::Size>) const throw DecodeError (N_("avcodec_receive_frame"), name_for_errors, r, *_path); } - _image = make_shared<Image>(frame); + _image = make_shared<Image>(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 21109c9d6..48317ed75 100644 --- a/src/lib/ffmpeg_image_proxy.h +++ b/src/lib/ffmpeg_image_proxy.h @@ -32,6 +32,7 @@ public: FFmpegImageProxy (std::shared_ptr<Socket> socket); Result image ( + Image::Alignment alignment, boost::optional<dcp::Size> size = boost::optional<dcp::Size> () ) const; diff --git a/src/lib/hints.cc b/src/lib/hints.cc index 64122db8d..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<Player>(film); + auto player = make_shared<Player>(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 8e6c5717b..a4e04bb62 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<Image>(out_format, out_size, out_aligned); + auto out = make_shared<Image>(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> -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> -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<Image>(out_format, out_size, out_aligned); + auto scaled = make_shared<Image>(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<const Image> other, Position<int> 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<const Image> other, Position<int> 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<const Image> other, Position<int> 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<Image>(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) +Image::Image (AVFrame const * frame, Alignment alignment) : _size (frame->width, frame->height) , _pixel_format (static_cast<AVPixelFormat>(frame->format)) - , _aligned (true) + , _alignment (alignment) { DCPOMATIC_ASSERT (_pixel_format != AV_PIX_FMT_NONE); @@ -1049,10 +1050,10 @@ Image::Image (AVFrame const * frame) } } -Image::Image (shared_ptr<const Image> other, bool aligned) +Image::Image (shared_ptr<const Image> 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,22 +1132,23 @@ Image::size () const return _size; } -bool -Image::aligned () const +Image::Alignment +Image::alignment () const { - return _aligned; + return _alignment; } PositionImage -merge (list<PositionImage> images) +merge (list<PositionImage> images, Image::Alignment alignment) { if (images.empty ()) { return {}; } if (images.size() == 1) { - return images.front (); + images.front().image = Image::ensure_alignment(images.front().image, alignment); + return images.front(); } dcpomatic::Rect<int> all (images.front().position, images.front().image->size().width, images.front().image->size().height); @@ -1154,7 +1156,7 @@ merge (list<PositionImage> images) all.extend (dcpomatic::Rect<int>(i.position, i.image->size().width, i.image->size().height)); } - auto merged = make_shared<Image>(images.front().image->pixel_format(), dcp::Size(all.width, all.height), true); + auto merged = make_shared<Image>(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 +1169,7 @@ merge (list<PositionImage> images) 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; } @@ -1312,16 +1314,18 @@ Image::fade (float f) } } + shared_ptr<const Image> -Image::ensure_aligned (shared_ptr<const Image> image) +Image::ensure_alignment (shared_ptr<const Image> image, Image::Alignment alignment) { - if (image->aligned()) { + if (image->alignment() == alignment) { return image; } - return make_shared<Image>(image, true); + return make_shared<Image>(image, alignment); } + size_t Image::memory_used () const { @@ -1393,7 +1397,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 cb8f11ffc..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<Image> { public: - Image (AVPixelFormat p, dcp::Size s, bool aligned); - explicit Image (AVFrame const *); + 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<const Image>, bool); + Image (std::shared_ptr<const Image>, 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<Image> convert_pixel_format (dcp::YUVToRGB yuv_to_rgb, AVPixelFormat out_format, bool aligned, bool fast) const; - std::shared_ptr<Image> scale (dcp::Size out_size, dcp::YUVToRGB yuv_to_rgb, AVPixelFormat out_format, bool aligned, bool fast) const; + std::shared_ptr<Image> convert_pixel_format (dcp::YUVToRGB yuv_to_rgb, AVPixelFormat out_format, Alignment alignment, bool fast) const; + std::shared_ptr<Image> scale (dcp::Size out_size, dcp::YUVToRGB yuv_to_rgb, AVPixelFormat out_format, Alignment alignment, bool fast) const; std::shared_ptr<Image> 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<const Image> ensure_aligned (std::shared_ptr<const Image> image); + static std::shared_ptr<const Image> ensure_alignment (std::shared_ptr<const Image> 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<PositionImage> images); +extern PositionImage merge (std::list<PositionImage> 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 89d1517ce..ae12d7adb 100644 --- a/src/lib/image_examiner.cc +++ b/src/lib/image_examiner.cc @@ -67,7 +67,7 @@ ImageExaminer::ImageExaminer (shared_ptr<const Film> film, shared_ptr<const Imag delete[] buffer; } else { FFmpegImageProxy proxy(content->path(0)); - _video_size = proxy.image().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 22946ed98..a37be580f 100644 --- a/src/lib/image_proxy.h +++ b/src/lib/image_proxy.h @@ -1,5 +1,5 @@ /* - Copyright (C) 2014 Carl Hetherington <cth@carlh.net> + Copyright (C) 2014-2021 Carl Hetherington <cth@carlh.net> 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 <libavutil/pixfmt.h> } @@ -32,6 +36,7 @@ extern "C" { #include <boost/optional.hpp> #include <boost/utility.hpp> + 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. * @@ -64,7 +70,7 @@ public: ImageProxy& operator= (ImageProxy const&) = delete; struct Result { - Result (std::shared_ptr<Image> image_, int log2_scaling_) + Result (std::shared_ptr<const Image> image_, int log2_scaling_) : image (image_) , log2_scaling (log2_scaling_) , error (false) @@ -76,8 +82,7 @@ public: , error (error_) {} - /** Image (which will be aligned) */ - std::shared_ptr<Image> image; + std::shared_ptr<const Image> image; /** log2 of any scaling down that has already been applied to the image; * e.g. if the image is already half the size of the original, this value * will be 1. @@ -92,6 +97,7 @@ public: * can be used as an optimisation. */ virtual Result image ( + Image::Alignment alignment, boost::optional<dcp::Size> size = boost::optional<dcp::Size> () ) 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 (boost::optional<dcp::Size> = boost::optional<dcp::Size>()) const { return 0; } + virtual int prepare (Image::Alignment, boost::optional<dcp::Size> = boost::optional<dcp::Size>()) const { return 0; } virtual size_t memory_used () const = 0; }; + std::shared_ptr<ImageProxy> image_proxy_factory (std::shared_ptr<cxml::Node> xml, std::shared_ptr<Socket> socket); + #endif diff --git a/src/lib/j2k_image_proxy.cc b/src/lib/j2k_image_proxy.cc index 144da396d..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; @@ -108,7 +106,7 @@ J2KImageProxy::J2KImageProxy (shared_ptr<cxml::Node> xml, shared_ptr<Socket> soc if (xml->optional_number_child<int>("Eye")) { _eye = static_cast<dcp::Eye>(xml->number_child<int>("Eye")); } - shared_ptr<ArrayData> data(new ArrayData(xml->number_child<int>("Size"))); + auto data = make_shared<ArrayData>(xml->number_child<int>("Size")); /* This only matters when we are using J2KImageProxy for the preview, which will never use this constructor (which is only used for passing data to encode servers). So we can put anything in here. It's a bit of a hack. @@ -120,7 +118,7 @@ J2KImageProxy::J2KImageProxy (shared_ptr<cxml::Node> xml, shared_ptr<Socket> soc int -J2KImageProxy::prepare (optional<dcp::Size> target_size) const +J2KImageProxy::prepare (Image::Alignment alignment, optional<dcp::Size> target_size) const { boost::mutex::scoped_lock lm (_mutex); @@ -145,7 +143,7 @@ J2KImageProxy::prepare (optional<dcp::Size> target_size) const try { /* XXX: should check that potentially trashing _data here doesn't matter */ auto decompressed = dcp::decompress_j2k (const_cast<uint8_t*>(_data->data()), _data->size(), reduce); - _image.reset (new Image (_pixel_format, decompressed->size(), true)); + _image = make_shared<Image>(_pixel_format, decompressed->size(), alignment); int const shift = 16 - decompressed->precision (0); @@ -169,7 +167,7 @@ J2KImageProxy::prepare (optional<dcp::Size> target_size) const } } } catch (dcp::J2KDecompressionError& e) { - _image = make_shared<Image>(_pixel_format, _size, true); + _image = make_shared<Image>(_pixel_format, _size, alignment); _image->make_black (); _error = true; } @@ -182,9 +180,9 @@ J2KImageProxy::prepare (optional<dcp::Size> target_size) const ImageProxy::Result -J2KImageProxy::image (optional<dcp::Size> target_size) const +J2KImageProxy::image (Image::Alignment alignment, optional<dcp::Size> target_size) const { - int const r = prepare (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 5235d8e42..d925bef86 100644 --- a/src/lib/j2k_image_proxy.h +++ b/src/lib/j2k_image_proxy.h @@ -57,6 +57,7 @@ public: J2KImageProxy (dcp::ArrayData data, dcp::Size size, AVPixelFormat pixel_format); Result image ( + Image::Alignment alignment, boost::optional<dcp::Size> size = boost::optional<dcp::Size> () ) const; @@ -64,7 +65,7 @@ public: void write_to_socket (std::shared_ptr<Socket>) const; /** @return true if our image is definitely the same as another, false if it is probably not */ bool same (std::shared_ptr<const ImageProxy>) const; - int prepare (boost::optional<dcp::Size> = boost::optional<dcp::Size>()) const; + int prepare (Image::Alignment alignment, boost::optional<dcp::Size> = boost::optional<dcp::Size>()) const; std::shared_ptr<const dcp::Data> j2k () const { return _data; diff --git a/src/lib/player.cc b/src/lib/player.cc index 5de089ba9..7951926e6 100644 --- a/src/lib/player.cc +++ b/src/lib/player.cc @@ -70,7 +70,6 @@ using std::dynamic_pointer_cast; using std::list; using std::make_pair; using std::make_shared; -using std::map; using std::max; using std::min; using std::min; @@ -95,11 +94,12 @@ int const PlayerProperty::DCP_DECODE_REDUCTION = 704; int const PlayerProperty::PLAYBACK_LENGTH = 705; -Player::Player (shared_ptr<const Film> film) +Player::Player (shared_ptr<const Film> film, Image::Alignment subtitle_alignment) : _film (film) , _suspended (0) , _tolerant (film->tolerant()) , _audio_merger (_film->audio_frame_rate()) + , _subtitle_alignment (subtitle_alignment) { construct (); } @@ -331,7 +331,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<Image>(AV_PIX_FMT_RGB24, _video_container_size, Image::Alignment::PADDED); _black_image->make_black (); } @@ -827,7 +827,7 @@ Player::open_subtitles_for_frame (DCPTime time) const return {}; } - return merge (captions); + return merge (captions, _subtitle_alignment); } @@ -1055,7 +1055,7 @@ Player::bitmap_text_start (weak_ptr<Piece> wp, weak_ptr<const TextContent> 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<int>(text->type())].add_from (wc, ps, from); diff --git a/src/lib/player.h b/src/lib/player.h index 6cefbe232..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<Player> { public: - Player (std::shared_ptr<const Film>); + Player (std::shared_ptr<const Film>, Image::Alignment subtitle_alignment); Player (std::shared_ptr<const Film>, std::shared_ptr<const Playlist> playlist); Player (Player const& Player) = delete; @@ -233,6 +234,9 @@ private: dcpomatic::DCPTime _playback_length; + /** 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; boost::signals2::scoped_connection _playlist_content_change_connection; diff --git a/src/lib/player_video.cc b/src/lib/player_video.cc index b0e75972c..7c36af31b 100644 --- a/src/lib/player_video.cc +++ b/src/lib/player_video.cc @@ -94,7 +94,7 @@ PlayerVideo::PlayerVideo (shared_ptr<cxml::Node> node, shared_ptr<Socket> socket if (node->optional_number_child<int>("SubtitleX")) { auto image = make_shared<Image> ( - AV_PIX_FMT_BGRA, dcp::Size(node->number_child<int>("SubtitleWidth"), node->number_child<int>("SubtitleHeight")), true + AV_PIX_FMT_BGRA, dcp::Size(node->number_child<int>("SubtitleWidth"), node->number_child<int>("SubtitleHeight")), Image::Alignment::PADDED ); image->read_from_socket (socket); @@ -110,33 +110,40 @@ PlayerVideo::set_text (PositionImage image) } shared_ptr<Image> -PlayerVideo::image (function<AVPixelFormat (AVPixelFormat)> pixel_format, VideoRange video_range, bool aligned, bool fast) const +PlayerVideo::image (function<AVPixelFormat (AVPixelFormat)> pixel_format, 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, aligned, fast); + make_image (pixel_format, video_range, fast); } return _image; } + +shared_ptr<const Image> +PlayerVideo::raw_image () const +{ + return _in->image(Image::Alignment::COMPACT, _inter_size).image; +} + + /** Create an image for this frame. A lock must be held on _mutex. * @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 fast true to be fast at the expense of quality. */ void -PlayerVideo::make_image (function<AVPixelFormat (AVPixelFormat)> pixel_format, VideoRange video_range, bool aligned, bool fast) const +PlayerVideo::make_image (function<AVPixelFormat (AVPixelFormat)> pixel_format, VideoRange video_range, bool fast) const { _image_crop = _crop; _image_inter_size = _inter_size; _image_out_size = _out_size; _image_fade = _fade; - auto prox = _in->image (_inter_size); + auto prox = _in->image (Image::Alignment::PADDED, _inter_size); _error = prox.error; auto total_crop = _crop; @@ -172,11 +179,11 @@ 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, aligned, fast + total_crop, _inter_size, _out_size, yuv_to_rgb, _video_range, pixel_format (prox.image->pixel_format()), video_range, Image::Alignment::COMPACT, fast ); if (_text) { - _image->alpha_blend (Image::ensure_aligned (_text->image), _text->position); + _image->alpha_blend (_text->image, _text->position); } if (_fade) { @@ -290,12 +297,12 @@ PlayerVideo::keep_xyz_or_rgb (AVPixelFormat p) } void -PlayerVideo::prepare (function<AVPixelFormat (AVPixelFormat)> pixel_format, VideoRange video_range, bool aligned, bool fast) +PlayerVideo::prepare (function<AVPixelFormat (AVPixelFormat)> pixel_format, VideoRange video_range, Image::Alignment alignment, bool fast, bool proxy_only) { - _in->prepare (_inter_size); + _in->prepare (alignment, _inter_size); boost::mutex::scoped_lock lm (_mutex); - if (!_image) { - make_image (pixel_format, video_range, aligned, fast); + if (!_image && !proxy_only) { + make_image (pixel_format, video_range, fast); } } diff --git a/src/lib/player_video.h b/src/lib/player_video.h index f29684832..237d2e3fe 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 <libavutil/pixfmt.h> } @@ -70,9 +71,13 @@ public: std::shared_ptr<PlayerVideo> shallow_copy () const; void set_text (PositionImage); + boost::optional<PositionImage> text () const { + return _text; + } - void prepare (std::function<AVPixelFormat (AVPixelFormat)> pixel_format, VideoRange video_range, bool aligned, bool fast); - std::shared_ptr<Image> image (std::function<AVPixelFormat (AVPixelFormat)> pixel_format, VideoRange video_range, bool aligned, bool fast) const; + 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; static AVPixelFormat force (AVPixelFormat, AVPixelFormat); static AVPixelFormat keep_xyz_or_rgb (AVPixelFormat); @@ -105,6 +110,10 @@ public: 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; @@ -118,7 +127,7 @@ public: } private: - void make_image (std::function<AVPixelFormat (AVPixelFormat)> pixel_format, VideoRange video_range, bool aligned, bool fast) const; + void make_image (std::function<AVPixelFormat (AVPixelFormat)> pixel_format, VideoRange video_range, bool fast) const; std::shared_ptr<const ImageProxy> _in; Crop _crop; diff --git a/src/lib/position_image.h b/src/lib/position_image.h index 2b7e7080a..ee352647c 100644 --- a/src/lib/position_image.h +++ b/src/lib/position_image.h @@ -35,12 +35,12 @@ class PositionImage public: PositionImage () {} - PositionImage (std::shared_ptr<Image> i, Position<int> p) + PositionImage (std::shared_ptr<const Image> i, Position<int> p) : image (i) , position (p) {} - std::shared_ptr<Image> image; + std::shared_ptr<const Image> image; Position<int> position; bool same (PositionImage const & other) const; diff --git a/src/lib/raw_image_proxy.cc b/src/lib/raw_image_proxy.cc index fed40c45e..fb0d16df8 100644 --- a/src/lib/raw_image_proxy.cc +++ b/src/lib/raw_image_proxy.cc @@ -58,15 +58,16 @@ RawImageProxy::RawImageProxy (shared_ptr<cxml::Node> xml, shared_ptr<Socket> soc xml->number_child<int>("Width"), xml->number_child<int>("Height") ); - _image = make_shared<Image>(static_cast<AVPixelFormat>(xml->number_child<int>("PixelFormat")), size, true); + _image = make_shared<Image>(static_cast<AVPixelFormat>(xml->number_child<int>("PixelFormat")), size, Image::Alignment::PADDED); _image->read_from_socket (socket); } ImageProxy::Result -RawImageProxy::image (optional<dcp::Size>) const +RawImageProxy::image (Image::Alignment alignment, optional<dcp::Size>) const { - return Result (_image, 0); + /* This ensure_alignment could be wasteful */ + return Result (Image::ensure_alignment(_image, alignment), 0); } @@ -95,7 +96,7 @@ RawImageProxy::same (shared_ptr<const ImageProxy> other) const return false; } - return (*_image.get()) == (*rp->image().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 ec30f5a29..c9885654b 100644 --- a/src/lib/raw_image_proxy.h +++ b/src/lib/raw_image_proxy.h @@ -33,6 +33,7 @@ public: RawImageProxy (std::shared_ptr<cxml::Node> xml, std::shared_ptr<Socket> socket); Result image ( + Image::Alignment alignment, boost::optional<dcp::Size> size = boost::optional<dcp::Size> () ) const; diff --git a/src/lib/render_text.cc b/src/lib/render_text.cc index 7bb7d6b45..94b412856 100644 --- a/src/lib/render_text.cc +++ b/src/lib/render_text.cc @@ -48,8 +48,6 @@ using std::min; using std::pair; using std::shared_ptr; using std::string; -using boost::optional; -using boost::algorithm::replace_all; using namespace dcpomatic; @@ -95,8 +93,10 @@ set_source_rgba (Cairo::RefPtr<Cairo::Context> context, dcp::Colour colour, floa static shared_ptr<Image> create_image (dcp::Size size) { - /* FFmpeg BGRA means first byte blue, second byte green, third byte red, fourth byte alpha */ - auto image = make_shared<Image>(AV_PIX_FMT_BGRA, size, false); + /* FFmpeg BGRA means first byte blue, second byte green, third byte red, fourth byte alpha. + * This must be COMPACT as we're using it with Cairo::ImageSurface::create + */ + auto image = make_shared<Image>(AV_PIX_FMT_BGRA, size, Image::Alignment::COMPACT); image->make_black (); return image; } @@ -105,6 +105,11 @@ create_image (dcp::Size size) static Cairo::RefPtr<Cairo::ImageSurface> create_surface (shared_ptr<Image> image) { + /* XXX: I don't think it's guaranteed that format_stride_for_width will return a stride without any padding, + * so it's lucky that this works. + */ + DCPOMATIC_ASSERT (image->alignment() == Image::Alignment::COMPACT); + DCPOMATIC_ASSERT (image->pixel_format() == AV_PIX_FMT_BGRA); return Cairo::ImageSurface::create ( image->data()[0], Cairo::FORMAT_ARGB32, diff --git a/src/lib/text_decoder.cc b/src/lib/text_decoder.cc index 6ee6ed079..8111154e3 100644 --- a/src/lib/text_decoder.cc +++ b/src/lib/text_decoder.cc @@ -61,7 +61,7 @@ TextDecoder::TextDecoder ( * of the video frame) */ void -TextDecoder::emit_bitmap_start (ContentTime from, shared_ptr<Image> image, dcpomatic::Rect<double> rect) +TextDecoder::emit_bitmap_start (ContentTime from, shared_ptr<const Image> image, dcpomatic::Rect<double> rect) { BitmapStart (ContentBitmapText (from, image, rect)); _position = from; @@ -286,7 +286,7 @@ TextDecoder::emit_plain (ContentTimePeriod period, sub::Subtitle const & s) * of the video frame) */ void -TextDecoder::emit_bitmap (ContentTimePeriod period, shared_ptr<Image> image, dcpomatic::Rect<double> rect) +TextDecoder::emit_bitmap (ContentTimePeriod period, shared_ptr<const Image> image, dcpomatic::Rect<double> rect) { emit_bitmap_start (period.from, image, rect); emit_stop (period.to); diff --git a/src/lib/text_decoder.h b/src/lib/text_decoder.h index 6e96b6b91..d1355afb0 100644 --- a/src/lib/text_decoder.h +++ b/src/lib/text_decoder.h @@ -52,8 +52,8 @@ public: return _position; } - void emit_bitmap_start (dcpomatic::ContentTime from, std::shared_ptr<Image> image, dcpomatic::Rect<double> rect); - void emit_bitmap (dcpomatic::ContentTimePeriod period, std::shared_ptr<Image> image, dcpomatic::Rect<double> rect); + void emit_bitmap_start (dcpomatic::ContentTime from, std::shared_ptr<const Image> image, dcpomatic::Rect<double> rect); + void emit_bitmap (dcpomatic::ContentTimePeriod period, std::shared_ptr<const Image> image, dcpomatic::Rect<double> rect); void emit_plain_start (dcpomatic::ContentTime from, std::list<dcp::SubtitleString> s); void emit_plain_start (dcpomatic::ContentTime from, sub::Subtitle const & subtitle); void emit_plain (dcpomatic::ContentTimePeriod period, std::list<dcp::SubtitleString> s); diff --git a/src/lib/util.cc b/src/lib/util.cc index 0646a4787..d3af74376 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 <dcp/decrypted_kdm.h> #include <dcp/locale_convert.h> @@ -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().image; + auto image = proxy.image(Image::Alignment::PADDED).image; /* set up rect with height and width */ dcpomatic::Rect<double> 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 a61da6773..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<pair<shared_ptr<Image>, int64_t>> images; if (_copy) { - images.push_back (make_pair(make_shared<Image>(frame), frame->best_effort_timestamp)); + images.push_back (make_pair(make_shared<Image>(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<Image>(_frame), frame->best_effort_timestamp)); + images.push_back (make_pair(make_shared<Image>(_frame, Image::Alignment::PADDED), frame->best_effort_timestamp)); av_frame_unref (_frame); } } |
