2 Copyright (C) 2012-2021 Carl Hetherington <cth@carlh.net>
4 This file is part of DCP-o-matic.
6 DCP-o-matic is free software; you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published by
8 the Free Software Foundation; either version 2 of the License, or
9 (at your option) any later version.
11 DCP-o-matic is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 GNU General Public License for more details.
16 You should have received a copy of the GNU General Public License
17 along with DCP-o-matic. If not, see <http://www.gnu.org/licenses/>.
22 /** @file src/image.cc
23 * @brief A class to describe a video image.
27 #include "compose.hpp"
28 #include "dcpomatic_assert.h"
29 #include "dcpomatic_socket.h"
30 #include "enum_indexed_vector.h"
31 #include "exceptions.h"
33 #include "maths_util.h"
34 #include "memory_util.h"
37 #include <dcp/rgb_xyz.h>
38 #include <dcp/transfer_function.h>
39 #include <dcp/warnings.h>
40 LIBDCP_DISABLE_WARNINGS
42 #include <libavutil/frame.h>
43 #include <libavutil/pixdesc.h>
44 #include <libavutil/pixfmt.h>
45 #include <libswscale/swscale.h>
47 LIBDCP_ENABLE_WARNINGS
48 #if HAVE_VALGRIND_MEMCHECK_H
49 #include <valgrind/memcheck.h>
60 using std::make_shared;
63 using std::runtime_error;
64 using std::shared_ptr;
69 /** The memory alignment, in bytes, used for each row of an image if Alignment::PADDED is requested */
70 int constexpr ALIGNMENT = 64;
72 /* U/V black value for 8-bit colour */
73 static uint8_t const eight_bit_uv = (1 << 7) - 1;
74 /* U/V black value for 9-bit colour */
75 static uint16_t const nine_bit_uv = (1 << 8) - 1;
76 /* U/V black value for 10-bit colour */
77 static uint16_t const ten_bit_uv = (1 << 9) - 1;
78 /* U/V black value for 16-bit colour */
79 static uint16_t const sixteen_bit_uv = (1 << 15) - 1;
83 Image::vertical_factor (int n) const
89 auto d = av_pix_fmt_desc_get(_pixel_format);
91 throw PixelFormatError ("line_factor()", _pixel_format);
94 return lrintf(powf(2.0f, d->log2_chroma_h));
98 Image::horizontal_factor (int n) const
104 auto d = av_pix_fmt_desc_get(_pixel_format);
106 throw PixelFormatError ("sample_size()", _pixel_format);
109 return lrintf(powf(2.0f, d->log2_chroma_w));
113 /** @param n Component index.
114 * @return Number of samples (i.e. pixels, unless sub-sampled) in each direction for this component.
117 Image::sample_size (int n) const
120 lrint (ceil(static_cast<double>(size().width) / horizontal_factor(n))),
121 lrint (ceil(static_cast<double>(size().height) / vertical_factor(n)))
126 /** @return Number of planes */
128 Image::planes () const
130 if (_pixel_format == AV_PIX_FMT_PAL8) {
134 auto d = av_pix_fmt_desc_get(_pixel_format);
136 throw PixelFormatError ("planes()", _pixel_format);
139 if ((d->flags & AV_PIX_FMT_FLAG_PLANAR) == 0) {
143 return d->nb_components;
149 round_width_for_subsampling (int p, AVPixFmtDescriptor const * desc)
151 return p & ~ ((1 << desc->log2_chroma_w) - 1);
157 round_height_for_subsampling (int p, AVPixFmtDescriptor const * desc)
159 return p & ~ ((1 << desc->log2_chroma_h) - 1);
163 /** Crop this image, scale it to `inter_size' and then place it in a black frame of `out_size'.
164 * @param crop Amount to crop by.
165 * @param inter_size Size to scale the cropped image to.
166 * @param out_size Size of output frame; if this is larger than inter_size there will be black padding.
167 * @param yuv_to_rgb YUV to RGB transformation to use, if required.
168 * @param video_range Video range of the image.
169 * @param out_format Output pixel format.
170 * @param out_aligned true to make the output image aligned.
171 * @param out_video_range Video range to use for the output image.
172 * @param fast Try to be fast at the possible expense of quality; at present this means using
173 * fast bilinear rather than bicubic scaling.
176 Image::crop_scale_window (
178 dcp::Size inter_size,
180 dcp::YUVToRGB yuv_to_rgb,
181 VideoRange video_range,
182 AVPixelFormat out_format,
183 VideoRange out_video_range,
184 Alignment out_alignment,
188 /* Empirical testing suggests that sws_scale() will crash if
189 the input image is not padded.
191 DCPOMATIC_ASSERT (alignment() == Alignment::PADDED);
193 DCPOMATIC_ASSERT (out_size.width >= inter_size.width);
194 DCPOMATIC_ASSERT (out_size.height >= inter_size.height);
196 auto out = make_shared<Image>(out_format, out_size, out_alignment);
199 auto in_desc = av_pix_fmt_desc_get (_pixel_format);
201 throw PixelFormatError ("crop_scale_window()", _pixel_format);
204 /* Round down so that we crop only the number of pixels that is straightforward
205 * considering any subsampling.
208 round_width_for_subsampling(crop.left, in_desc),
209 round_width_for_subsampling(crop.right, in_desc),
210 round_height_for_subsampling(crop.top, in_desc),
211 round_height_for_subsampling(crop.bottom, in_desc)
214 /* Also check that we aren't cropping more image than there actually is */
215 if ((corrected_crop.left + corrected_crop.right) >= (size().width - 4)) {
216 corrected_crop.left = 0;
217 corrected_crop.right = size().width - 4;
220 if ((corrected_crop.top + corrected_crop.bottom) >= (size().height - 4)) {
221 corrected_crop.top = 0;
222 corrected_crop.bottom = size().height - 4;
225 /* Size of the image after any crop */
226 auto const cropped_size = corrected_crop.apply (size());
228 /* Scale context for a scale from cropped_size to inter_size */
229 auto scale_context = sws_getContext (
230 cropped_size.width, cropped_size.height, pixel_format(),
231 inter_size.width, inter_size.height, out_format,
232 fast ? SWS_FAST_BILINEAR : SWS_BICUBIC, 0, 0, 0
235 if (!scale_context) {
236 throw runtime_error (N_("Could not allocate SwsContext"));
239 DCPOMATIC_ASSERT (yuv_to_rgb < dcp::YUVToRGB::COUNT);
240 EnumIndexedVector<int, dcp::YUVToRGB> lut;
241 lut[dcp::YUVToRGB::REC601] = SWS_CS_ITU601;
242 lut[dcp::YUVToRGB::REC709] = SWS_CS_ITU709;
243 lut[dcp::YUVToRGB::REC2020] = SWS_CS_BT2020;
245 /* The 3rd parameter here is:
246 0 -> source range MPEG (i.e. "video", 16-235)
247 1 -> source range JPEG (i.e. "full", 0-255)
249 0 -> destination range MPEG (i.e. "video", 16-235)
250 1 -> destination range JPEG (i.e. "full", 0-255)
252 But remember: sws_setColorspaceDetails ignores these
253 parameters unless the both source and destination images
254 are isYUV or isGray. (If either is not, it uses video range).
256 sws_setColorspaceDetails (
258 sws_getCoefficients(lut[yuv_to_rgb]), video_range == VideoRange::VIDEO ? 0 : 1,
259 sws_getCoefficients(lut[yuv_to_rgb]), out_video_range == VideoRange::VIDEO ? 0 : 1,
263 /* Prepare input data pointers with crop */
264 uint8_t* scale_in_data[planes()];
265 for (int c = 0; c < planes(); ++c) {
266 int const x = lrintf(bytes_per_pixel(c) * corrected_crop.left);
267 scale_in_data[c] = data()[c] + x + stride()[c] * (corrected_crop.top / vertical_factor(c));
270 auto out_desc = av_pix_fmt_desc_get (out_format);
272 throw PixelFormatError ("crop_scale_window()", out_format);
275 /* Corner of the image within out_size */
276 Position<int> const corner (
277 round_width_for_subsampling((out_size.width - inter_size.width) / 2, out_desc),
278 round_height_for_subsampling((out_size.height - inter_size.height) / 2, out_desc)
281 uint8_t* scale_out_data[out->planes()];
282 for (int c = 0; c < out->planes(); ++c) {
283 int const x = lrintf(out->bytes_per_pixel(c) * corner.x);
284 scale_out_data[c] = out->data()[c] + x + out->stride()[c] * (corner.y / out->vertical_factor(c));
289 scale_in_data, stride(),
290 0, cropped_size.height,
291 scale_out_data, out->stride()
294 sws_freeContext (scale_context);
296 /* There are some cases where there will be unwanted image data left in the image at this point:
298 * 1. When we are cropping without any scaling or pixel format conversion.
299 * 2. When we are scaling to certain sizes and placing the result into a larger
302 * Clear out the sides of the image to take care of those cases.
304 auto const pad = (out_size.width - inter_size.width) / 2;
305 out->make_part_black(0, pad);
306 out->make_part_black(corner.x + inter_size.width, pad);
309 video_range == VideoRange::VIDEO &&
310 out_video_range == VideoRange::FULL &&
311 av_pix_fmt_desc_get(_pixel_format)->flags & AV_PIX_FMT_FLAG_RGB
313 /* libswscale will not convert video range for RGB sources, so we have to do it ourselves */
314 out->video_range_to_full_range ();
322 Image::convert_pixel_format (dcp::YUVToRGB yuv_to_rgb, AVPixelFormat out_format, Alignment out_alignment, bool fast) const
324 return scale(size(), yuv_to_rgb, out_format, out_alignment, fast);
328 /** @param out_size Size to scale to.
329 * @param yuv_to_rgb YUVToRGB transform transform to use, if required.
330 * @param out_format Output pixel format.
331 * @param out_alignment Output alignment.
332 * @param fast Try to be fast at the possible expense of quality; at present this means using
333 * fast bilinear rather than bicubic scaling.
336 Image::scale (dcp::Size out_size, dcp::YUVToRGB yuv_to_rgb, AVPixelFormat out_format, Alignment out_alignment, bool fast) const
338 /* Empirical testing suggests that sws_scale() will crash if
339 the input image alignment is not PADDED.
341 DCPOMATIC_ASSERT (alignment() == Alignment::PADDED);
343 auto scaled = make_shared<Image>(out_format, out_size, out_alignment);
344 auto scale_context = sws_getContext (
345 size().width, size().height, pixel_format(),
346 out_size.width, out_size.height, out_format,
347 (fast ? SWS_FAST_BILINEAR : SWS_BICUBIC) | SWS_ACCURATE_RND, 0, 0, 0
350 DCPOMATIC_ASSERT (yuv_to_rgb < dcp::YUVToRGB::COUNT);
351 EnumIndexedVector<int, dcp::YUVToRGB> lut;
352 lut[dcp::YUVToRGB::REC601] = SWS_CS_ITU601;
353 lut[dcp::YUVToRGB::REC709] = SWS_CS_ITU709;
354 lut[dcp::YUVToRGB::REC2020] = SWS_CS_BT2020;
356 /* The 3rd parameter here is:
357 0 -> source range MPEG (i.e. "video", 16-235)
358 1 -> source range JPEG (i.e. "full", 0-255)
360 0 -> destination range MPEG (i.e. "video", 16-235)
361 1 -> destination range JPEG (i.e. "full", 0-255)
363 But remember: sws_setColorspaceDetails ignores these
364 parameters unless the corresponding image isYUV or isGray.
365 (If it's neither, it uses video range).
367 sws_setColorspaceDetails (
369 sws_getCoefficients(lut[yuv_to_rgb]), 0,
370 sws_getCoefficients(lut[yuv_to_rgb]), 0,
378 scaled->data(), scaled->stride()
381 sws_freeContext (scale_context);
387 /** Blacken a YUV image whose bits per pixel is rounded up to 16 */
389 Image::yuv_16_black (uint16_t v, bool alpha)
391 memset (data()[0], 0, sample_size(0).height * stride()[0]);
392 for (int i = 1; i < 3; ++i) {
393 auto p = reinterpret_cast<int16_t*> (data()[i]);
394 int const lines = sample_size(i).height;
395 for (int y = 0; y < lines; ++y) {
396 /* We divide by 2 here because we are writing 2 bytes at a time */
397 for (int x = 0; x < line_size()[i] / 2; ++x) {
400 p += stride()[i] / 2;
405 memset (data()[3], 0, sample_size(3).height * stride()[3]);
411 Image::swap_16 (uint16_t v)
413 return ((v >> 8) & 0xff) | ((v & 0xff) << 8);
418 Image::make_part_black (int const start, int const width)
420 auto y_part = [&]() {
421 int const bpp = bytes_per_pixel(0);
422 int const h = sample_size(0).height;
423 int const s = stride()[0];
425 for (int y = 0; y < h; ++y) {
426 memset (p + start * bpp, 0, width * bpp);
431 switch (_pixel_format) {
432 case AV_PIX_FMT_RGB24:
433 case AV_PIX_FMT_ARGB:
434 case AV_PIX_FMT_RGBA:
435 case AV_PIX_FMT_ABGR:
436 case AV_PIX_FMT_BGRA:
437 case AV_PIX_FMT_RGB555LE:
438 case AV_PIX_FMT_RGB48LE:
439 case AV_PIX_FMT_RGB48BE:
440 case AV_PIX_FMT_XYZ12LE:
442 int const h = sample_size(0).height;
443 int const bpp = bytes_per_pixel(0);
444 int const s = stride()[0];
445 uint8_t* p = data()[0];
446 for (int y = 0; y < h; y++) {
447 memset (p + start * bpp, 0, width * bpp);
452 case AV_PIX_FMT_YUV420P:
455 for (int i = 1; i < 3; ++i) {
457 int const h = sample_size(i).height;
458 for (int y = 0; y < h; ++y) {
459 for (int x = start / 2; x < (start + width) / 2; ++x) {
467 case AV_PIX_FMT_YUV422P10LE:
470 for (int i = 1; i < 3; ++i) {
471 auto p = reinterpret_cast<int16_t*>(data()[i]);
472 int const h = sample_size(i).height;
473 for (int y = 0; y < h; ++y) {
474 for (int x = start / 2; x < (start + width) / 2; ++x) {
477 p += stride()[i] / 2;
482 case AV_PIX_FMT_YUV444P10LE:
485 for (int i = 1; i < 3; ++i) {
486 auto p = reinterpret_cast<int16_t*>(data()[i]);
487 int const h = sample_size(i).height;
488 for (int y = 0; y < h; ++y) {
489 for (int x = start; x < (start + width); ++x) {
492 p += stride()[i] / 2;
498 throw PixelFormatError ("make_part_black()", _pixel_format);
506 switch (_pixel_format) {
507 case AV_PIX_FMT_YUV420P:
508 case AV_PIX_FMT_YUV422P:
509 case AV_PIX_FMT_YUV444P:
510 case AV_PIX_FMT_YUV411P:
511 memset (data()[0], 0, sample_size(0).height * stride()[0]);
512 memset (data()[1], eight_bit_uv, sample_size(1).height * stride()[1]);
513 memset (data()[2], eight_bit_uv, sample_size(2).height * stride()[2]);
516 case AV_PIX_FMT_YUVJ420P:
517 case AV_PIX_FMT_YUVJ422P:
518 case AV_PIX_FMT_YUVJ444P:
519 memset (data()[0], 0, sample_size(0).height * stride()[0]);
520 memset (data()[1], eight_bit_uv + 1, sample_size(1).height * stride()[1]);
521 memset (data()[2], eight_bit_uv + 1, sample_size(2).height * stride()[2]);
524 case AV_PIX_FMT_YUV422P9LE:
525 case AV_PIX_FMT_YUV444P9LE:
526 yuv_16_black (nine_bit_uv, false);
529 case AV_PIX_FMT_YUV422P9BE:
530 case AV_PIX_FMT_YUV444P9BE:
531 yuv_16_black (swap_16 (nine_bit_uv), false);
534 case AV_PIX_FMT_YUV422P10LE:
535 case AV_PIX_FMT_YUV444P10LE:
536 yuv_16_black (ten_bit_uv, false);
539 case AV_PIX_FMT_YUV422P16LE:
540 case AV_PIX_FMT_YUV444P16LE:
541 yuv_16_black (sixteen_bit_uv, false);
544 case AV_PIX_FMT_YUV444P10BE:
545 case AV_PIX_FMT_YUV422P10BE:
546 yuv_16_black (swap_16 (ten_bit_uv), false);
549 case AV_PIX_FMT_YUVA420P9BE:
550 case AV_PIX_FMT_YUVA422P9BE:
551 case AV_PIX_FMT_YUVA444P9BE:
552 yuv_16_black (swap_16 (nine_bit_uv), true);
555 case AV_PIX_FMT_YUVA420P9LE:
556 case AV_PIX_FMT_YUVA422P9LE:
557 case AV_PIX_FMT_YUVA444P9LE:
558 yuv_16_black (nine_bit_uv, true);
561 case AV_PIX_FMT_YUVA420P10BE:
562 case AV_PIX_FMT_YUVA422P10BE:
563 case AV_PIX_FMT_YUVA444P10BE:
564 yuv_16_black (swap_16 (ten_bit_uv), true);
567 case AV_PIX_FMT_YUVA420P10LE:
568 case AV_PIX_FMT_YUVA422P10LE:
569 case AV_PIX_FMT_YUVA444P10LE:
570 yuv_16_black (ten_bit_uv, true);
573 case AV_PIX_FMT_YUVA420P16BE:
574 case AV_PIX_FMT_YUVA422P16BE:
575 case AV_PIX_FMT_YUVA444P16BE:
576 yuv_16_black (swap_16 (sixteen_bit_uv), true);
579 case AV_PIX_FMT_YUVA420P16LE:
580 case AV_PIX_FMT_YUVA422P16LE:
581 case AV_PIX_FMT_YUVA444P16LE:
582 yuv_16_black (sixteen_bit_uv, true);
585 case AV_PIX_FMT_RGB24:
586 case AV_PIX_FMT_ARGB:
587 case AV_PIX_FMT_RGBA:
588 case AV_PIX_FMT_ABGR:
589 case AV_PIX_FMT_BGRA:
590 case AV_PIX_FMT_RGB555LE:
591 case AV_PIX_FMT_RGB48LE:
592 case AV_PIX_FMT_RGB48BE:
593 case AV_PIX_FMT_XYZ12LE:
594 memset (data()[0], 0, sample_size(0).height * stride()[0]);
597 case AV_PIX_FMT_UYVY422:
599 int const Y = sample_size(0).height;
600 int const X = line_size()[0];
601 uint8_t* p = data()[0];
602 for (int y = 0; y < Y; ++y) {
603 for (int x = 0; x < X / 4; ++x) {
604 *p++ = eight_bit_uv; // Cb
606 *p++ = eight_bit_uv; // Cr
614 throw PixelFormatError ("make_black()", _pixel_format);
620 Image::make_transparent ()
622 if (_pixel_format != AV_PIX_FMT_BGRA && _pixel_format != AV_PIX_FMT_RGBA && _pixel_format != AV_PIX_FMT_RGBA64BE) {
623 throw PixelFormatError ("make_transparent()", _pixel_format);
626 memset (data()[0], 0, sample_size(0).height * stride()[0]);
635 uint8_t* const* data;
639 uint8_t* line_pointer(int y) const {
640 return data[0] + y * stride[0] + start_x * bpp;
645 /** Parameters of the other image (the one being blended onto the target) when target and other are RGB */
646 struct OtherRGBParams
651 uint8_t* const* data;
655 uint8_t* line_pointer(int y) const {
656 return data[0] + y * stride[0];
659 float alpha_divisor() const {
660 return pow(2, bpp * 2) - 1;
665 /** Parameters of the other image (the one being blended onto the target) when target and other are YUV */
666 struct OtherYUVParams
671 uint8_t* const* data;
674 uint8_t* const* alpha_data;
675 int const* alpha_stride;
680 template <class OtherType>
682 alpha_blend_onto_rgb24(TargetParams const& target, OtherRGBParams const& other, int red, int blue, std::function<float (OtherType*)> get, int value_divisor)
684 /* Going onto RGB24. First byte is red, second green, third blue */
685 auto const alpha_divisor = other.alpha_divisor();
686 for (int ty = target.start_y, oy = other.start_y; ty < target.size.height && oy < other.size.height; ++ty, ++oy) {
687 auto tp = target.line_pointer(ty);
688 auto op = reinterpret_cast<OtherType*>(other.line_pointer(oy));
689 for (int tx = target.start_x, ox = other.start_x; tx < target.size.width && ox < other.size.width; ++tx, ++ox) {
690 float const alpha = get(op + 3) / alpha_divisor;
691 tp[0] = (get(op + red) / value_divisor) * alpha + tp[0] * (1 - alpha);
692 tp[1] = (get(op + 1) / value_divisor) * alpha + tp[1] * (1 - alpha);
693 tp[2] = (get(op + blue) / value_divisor) * alpha + tp[2] * (1 - alpha);
696 op += other.bpp / sizeof(OtherType);
702 template <class OtherType>
704 alpha_blend_onto_bgra(TargetParams const& target, OtherRGBParams const& other, int red, int blue, std::function<float (OtherType*)> get, int value_divisor)
706 auto const alpha_divisor = other.alpha_divisor();
707 for (int ty = target.start_y, oy = other.start_y; ty < target.size.height && oy < other.size.height; ++ty, ++oy) {
708 auto tp = target.line_pointer(ty);
709 auto op = reinterpret_cast<OtherType*>(other.line_pointer(oy));
710 for (int tx = target.start_x, ox = other.start_x; tx < target.size.width && ox < other.size.width; ++tx, ++ox) {
711 float const alpha = get(op + 3) / alpha_divisor;
712 tp[0] = (get(op + blue) / value_divisor) * alpha + tp[0] * (1 - alpha);
713 tp[1] = (get(op + 1) / value_divisor) * alpha + tp[1] * (1 - alpha);
714 tp[2] = (get(op + red) / value_divisor) * alpha + tp[2] * (1 - alpha);
715 tp[3] = (get(op + 3) / value_divisor) * alpha + tp[3] * (1 - alpha);
718 op += other.bpp / sizeof(OtherType);
724 template <class OtherType>
726 alpha_blend_onto_rgba(TargetParams const& target, OtherRGBParams const& other, int red, int blue, std::function<float (OtherType*)> get, int value_divisor)
728 auto const alpha_divisor = other.alpha_divisor();
729 for (int ty = target.start_y, oy = other.start_y; ty < target.size.height && oy < other.size.height; ++ty, ++oy) {
730 auto tp = target.line_pointer(ty);
731 auto op = reinterpret_cast<OtherType*>(other.line_pointer(oy));
732 for (int tx = target.start_x, ox = other.start_x; tx < target.size.width && ox < other.size.width; ++tx, ++ox) {
733 float const alpha = get(op + 3) / alpha_divisor;
734 tp[0] = (get(op + red) / value_divisor) * alpha + tp[0] * (1 - alpha);
735 tp[1] = (get(op + 1) / value_divisor) * alpha + tp[1] * (1 - alpha);
736 tp[2] = (get(op + blue) / value_divisor) * alpha + tp[2] * (1 - alpha);
737 tp[3] = (get(op + 3) / value_divisor) * alpha + tp[3] * (1 - alpha);
740 op += other.bpp / sizeof(OtherType);
746 template <class OtherType>
748 alpha_blend_onto_rgb48le(TargetParams const& target, OtherRGBParams const& other, int red, int blue, std::function<float (OtherType*)> get, int value_scale)
750 auto const alpha_divisor = other.alpha_divisor();
751 for (int ty = target.start_y, oy = other.start_y; ty < target.size.height && oy < other.size.height; ++ty, ++oy) {
752 auto tp = reinterpret_cast<uint16_t*>(target.line_pointer(ty));
753 auto op = reinterpret_cast<OtherType*>(other.line_pointer(oy));
754 for (int tx = target.start_x, ox = other.start_x; tx < target.size.width && ox < other.size.width; ++tx, ++ox) {
755 float const alpha = get(op + 3) / alpha_divisor;
756 tp[0] = get(op + red) * value_scale * alpha + tp[0] * (1 - alpha);
757 tp[1] = get(op + 1) * value_scale * alpha + tp[1] * (1 - alpha);
758 tp[2] = get(op + blue) * value_scale * alpha + tp[2] * (1 - alpha);
760 tp += target.bpp / 2;
761 op += other.bpp / sizeof(OtherType);
767 template <class OtherType>
769 alpha_blend_onto_xyz12le(TargetParams const& target, OtherRGBParams const& other, int red, int blue, std::function<float (OtherType*)> get, int value_divisor)
771 auto const alpha_divisor = other.alpha_divisor();
772 auto conv = dcp::ColourConversion::srgb_to_xyz();
773 double fast_matrix[9];
774 dcp::combined_rgb_to_xyz(conv, fast_matrix);
775 auto lut_in = conv.in()->double_lut(0, 1, 8, false);
776 auto lut_out = conv.out()->int_lut(0, 1, 16, true, 65535);
777 for (int ty = target.start_y, oy = other.start_y; ty < target.size.height && oy < other.size.height; ++ty, ++oy) {
778 auto tp = reinterpret_cast<uint16_t*>(target.data[0] + ty * target.stride[0] + target.start_x * target.bpp);
779 auto op = reinterpret_cast<OtherType*>(other.data[0] + oy * other.stride[0]);
780 for (int tx = target.start_x, ox = other.start_x; tx < target.size.width && ox < other.size.width; ++tx, ++ox) {
781 float const alpha = get(op + 3) / alpha_divisor;
783 /* Convert sRGB to XYZ; op is BGRA. First, input gamma LUT */
784 double const r = lut_in[get(op + red) / value_divisor];
785 double const g = lut_in[get(op + 1) / value_divisor];
786 double const b = lut_in[get(op + blue) / value_divisor];
788 /* RGB to XYZ, including Bradford transform and DCI companding */
789 double const x = max(0.0, min(1.0, r * fast_matrix[0] + g * fast_matrix[1] + b * fast_matrix[2]));
790 double const y = max(0.0, min(1.0, r * fast_matrix[3] + g * fast_matrix[4] + b * fast_matrix[5]));
791 double const z = max(0.0, min(1.0, r * fast_matrix[6] + g * fast_matrix[7] + b * fast_matrix[8]));
793 /* Out gamma LUT and blend */
794 tp[0] = lut_out[lrint(x * 65535)] * alpha + tp[0] * (1 - alpha);
795 tp[1] = lut_out[lrint(y * 65535)] * alpha + tp[1] * (1 - alpha);
796 tp[2] = lut_out[lrint(z * 65535)] * alpha + tp[2] * (1 - alpha);
798 tp += target.bpp / 2;
799 op += other.bpp / sizeof(OtherType);
807 alpha_blend_onto_yuv420p(TargetParams const& target, OtherYUVParams const& other, std::function<float (uint8_t* data)> get_alpha)
809 auto const ts = target.size;
810 auto const os = other.size;
811 for (int ty = target.start_y, oy = other.start_y; ty < ts.height && oy < os.height; ++ty, ++oy) {
812 int const hty = ty / 2;
813 int const hoy = oy / 2;
814 uint8_t* tY = target.data[0] + (ty * target.stride[0]) + target.start_x;
815 uint8_t* tU = target.data[1] + (hty * target.stride[1]) + target.start_x / 2;
816 uint8_t* tV = target.data[2] + (hty * target.stride[2]) + target.start_x / 2;
817 uint8_t* oY = other.data[0] + (oy * other.stride[0]) + other.start_x;
818 uint8_t* oU = other.data[1] + (hoy * other.stride[1]) + other.start_x / 2;
819 uint8_t* oV = other.data[2] + (hoy * other.stride[2]) + other.start_x / 2;
820 uint8_t* alpha = other.alpha_data[0] + (oy * other.alpha_stride[0]) + other.start_x * other.alpha_bpp;
821 for (int tx = target.start_x, ox = other.start_x; tx < ts.width && ox < os.width; ++tx, ++ox) {
822 float const a = get_alpha(alpha);
823 *tY = *oY * a + *tY * (1 - a);
824 *tU = *oU * a + *tU * (1 - a);
825 *tV = *oV * a + *tV * (1 - a);
836 alpha += other.alpha_bpp;
844 alpha_blend_onto_yuv420p10(TargetParams const& target, OtherYUVParams const& other, std::function<float (uint8_t* data)> get_alpha)
846 auto const ts = target.size;
847 auto const os = other.size;
848 for (int ty = target.start_y, oy = other.start_y; ty < ts.height && oy < os.height; ++ty, ++oy) {
849 int const hty = ty / 2;
850 int const hoy = oy / 2;
851 uint16_t* tY = reinterpret_cast<uint16_t*>(target.data[0] + (ty * target.stride[0])) + target.start_x;
852 uint16_t* tU = reinterpret_cast<uint16_t*>(target.data[1] + (hty * target.stride[1])) + target.start_x / 2;
853 uint16_t* tV = reinterpret_cast<uint16_t*>(target.data[2] + (hty * target.stride[2])) + target.start_x / 2;
854 uint16_t* oY = reinterpret_cast<uint16_t*>(other.data[0] + (oy * other.stride[0])) + other.start_x;
855 uint16_t* oU = reinterpret_cast<uint16_t*>(other.data[1] + (hoy * other.stride[1])) + other.start_x / 2;
856 uint16_t* oV = reinterpret_cast<uint16_t*>(other.data[2] + (hoy * other.stride[2])) + other.start_x / 2;
857 uint8_t* alpha = other.alpha_data[0] + (oy * other.alpha_stride[0]) + other.start_x * other.alpha_bpp;
858 for (int tx = target.start_x, ox = other.start_x; tx < ts.width && ox < os.width; ++tx, ++ox) {
859 float const a = get_alpha(alpha);
860 *tY = *oY * a + *tY * (1 - a);
861 *tU = *oU * a + *tU * (1 - a);
862 *tV = *oV * a + *tV * (1 - a);
873 alpha += other.alpha_bpp;
881 alpha_blend_onto_yuv422p9or10le(TargetParams const& target, OtherYUVParams const& other, std::function<float (uint8_t* data)> get_alpha)
883 auto const ts = target.size;
884 auto const os = other.size;
885 for (int ty = target.start_y, oy = other.start_y; ty < ts.height && oy < os.height; ++ty, ++oy) {
886 uint16_t* tY = reinterpret_cast<uint16_t*>(target.data[0] + (ty * target.stride[0])) + target.start_x;
887 uint16_t* tU = reinterpret_cast<uint16_t*>(target.data[1] + (ty * target.stride[1])) + target.start_x / 2;
888 uint16_t* tV = reinterpret_cast<uint16_t*>(target.data[2] + (ty * target.stride[2])) + target.start_x / 2;
889 uint16_t* oY = reinterpret_cast<uint16_t*>(other.data[0] + (oy * other.stride[0])) + other.start_x;
890 uint16_t* oU = reinterpret_cast<uint16_t*>(other.data[1] + (oy * other.stride[1])) + other.start_x / 2;
891 uint16_t* oV = reinterpret_cast<uint16_t*>(other.data[2] + (oy * other.stride[2])) + other.start_x / 2;
892 uint8_t* alpha = other.alpha_data[0] + (oy * other.alpha_stride[0]) + other.start_x * other.alpha_bpp;
893 for (int tx = target.start_x, ox = other.start_x; tx < ts.width && ox < os.width; ++tx, ++ox) {
894 float const a = get_alpha(alpha);
895 *tY = *oY * a + *tY * (1 - a);
896 *tU = *oU * a + *tU * (1 - a);
897 *tV = *oV * a + *tV * (1 - a);
908 alpha += other.alpha_bpp;
916 alpha_blend_onto_yuv444p9or10le(TargetParams const& target, OtherYUVParams const& other, std::function<float (uint8_t* data)> get_alpha)
918 auto const ts = target.size;
919 auto const os = other.size;
920 for (int ty = target.start_y, oy = other.start_y; ty < ts.height && oy < os.height; ++ty, ++oy) {
921 uint16_t* tY = reinterpret_cast<uint16_t*>(target.data[0] + (ty * target.stride[0])) + target.start_x;
922 uint16_t* tU = reinterpret_cast<uint16_t*>(target.data[1] + (ty * target.stride[1])) + target.start_x;
923 uint16_t* tV = reinterpret_cast<uint16_t*>(target.data[2] + (ty * target.stride[2])) + target.start_x;
924 uint16_t* oY = reinterpret_cast<uint16_t*>(other.data[0] + (oy * other.stride[0])) + other.start_x;
925 uint16_t* oU = reinterpret_cast<uint16_t*>(other.data[1] + (oy * other.stride[1])) + other.start_x;
926 uint16_t* oV = reinterpret_cast<uint16_t*>(other.data[2] + (oy * other.stride[2])) + other.start_x;
927 uint8_t* alpha = other.alpha_data[0] + (oy * other.alpha_stride[0]) + other.start_x * other.alpha_bpp;
928 for (int tx = target.start_x, ox = other.start_x; tx < ts.width && ox < os.width; ++tx, ++ox) {
929 float const a = get_alpha(alpha);
930 *tY = *oY * a + *tY * (1 - a);
931 *tU = *oU * a + *tU * (1 - a);
932 *tV = *oV * a + *tV * (1 - a);
939 alpha += other.alpha_bpp;
946 Image::alpha_blend (shared_ptr<const Image> other, Position<int> position)
949 other->pixel_format() == AV_PIX_FMT_BGRA ||
950 other->pixel_format() == AV_PIX_FMT_RGBA ||
951 other->pixel_format() == AV_PIX_FMT_RGBA64BE
954 int const blue = other->pixel_format() == AV_PIX_FMT_BGRA ? 0 : 2;
955 int const red = other->pixel_format() == AV_PIX_FMT_BGRA ? 2 : 0;
957 int start_tx = position.x;
961 start_ox = -start_tx;
965 int start_ty = position.y;
969 start_oy = -start_ty;
973 TargetParams target_params = {
982 OtherRGBParams other_rgb_params = {
988 other->pixel_format() == AV_PIX_FMT_RGBA64BE ? 8 : 4
991 OtherYUVParams other_yuv_params = {
999 other->pixel_format() == AV_PIX_FMT_RGBA64BE ? 8 : 4
1002 auto byteswap = [](uint16_t* p) {
1003 return (*p >> 8) | ((*p & 0xff) << 8);
1006 auto pass = [](uint8_t* p) {
1010 auto get_alpha_64be = [](uint8_t* p) {
1011 return ((static_cast<int16_t>(p[6]) << 8) | p[7]) / 65535.0f;
1014 auto get_alpha_byte = [](uint8_t* p) {
1015 return p[3] / 255.0f;
1018 switch (_pixel_format) {
1019 case AV_PIX_FMT_RGB24:
1020 target_params.bpp = 3;
1021 if (other->pixel_format() == AV_PIX_FMT_RGBA64BE) {
1022 alpha_blend_onto_rgb24<uint16_t>(target_params, other_rgb_params, red, blue, byteswap, 256);
1024 alpha_blend_onto_rgb24<uint8_t>(target_params, other_rgb_params, red, blue, pass, 1);
1027 case AV_PIX_FMT_BGRA:
1028 target_params.bpp = 4;
1029 if (other->pixel_format() == AV_PIX_FMT_RGBA64BE) {
1030 alpha_blend_onto_bgra<uint16_t>(target_params, other_rgb_params, red, blue, byteswap, 256);
1032 alpha_blend_onto_bgra<uint8_t>(target_params, other_rgb_params, red, blue, pass, 1);
1035 case AV_PIX_FMT_RGBA:
1036 target_params.bpp = 4;
1037 if (other->pixel_format() == AV_PIX_FMT_RGBA64BE) {
1038 alpha_blend_onto_rgba<uint16_t>(target_params, other_rgb_params, red, blue, byteswap, 256);
1040 alpha_blend_onto_rgba<uint8_t>(target_params, other_rgb_params, red, blue, pass, 1);
1043 case AV_PIX_FMT_RGB48LE:
1044 target_params.bpp = 6;
1045 if (other->pixel_format() == AV_PIX_FMT_RGBA64BE) {
1046 alpha_blend_onto_rgb48le<uint16_t>(target_params, other_rgb_params, red, blue, byteswap, 1);
1048 alpha_blend_onto_rgb48le<uint8_t>(target_params, other_rgb_params, red, blue, pass, 256);
1051 case AV_PIX_FMT_XYZ12LE:
1052 target_params.bpp = 6;
1053 if (other->pixel_format() == AV_PIX_FMT_RGBA64BE) {
1054 alpha_blend_onto_xyz12le<uint16_t>(target_params, other_rgb_params, red, blue, byteswap, 256);
1056 alpha_blend_onto_xyz12le<uint8_t>(target_params, other_rgb_params, red, blue, pass, 1);
1059 case AV_PIX_FMT_YUV420P:
1061 auto yuv = other->convert_pixel_format (dcp::YUVToRGB::REC709, _pixel_format, Alignment::COMPACT, false);
1062 other_yuv_params.data = yuv->data();
1063 other_yuv_params.stride = yuv->stride();
1064 other_yuv_params.alpha_data = other->data();
1065 other_yuv_params.alpha_stride = other->stride();
1066 if (other->pixel_format() == AV_PIX_FMT_RGBA64BE) {
1067 alpha_blend_onto_yuv420p(target_params, other_yuv_params, get_alpha_64be);
1069 alpha_blend_onto_yuv420p(target_params, other_yuv_params, get_alpha_byte);
1073 case AV_PIX_FMT_YUV420P10:
1075 auto yuv = other->convert_pixel_format (dcp::YUVToRGB::REC709, _pixel_format, Alignment::COMPACT, false);
1076 other_yuv_params.data = yuv->data();
1077 other_yuv_params.stride = yuv->stride();
1078 other_yuv_params.alpha_data = other->data();
1079 other_yuv_params.alpha_stride = other->stride();
1080 if (other->pixel_format() == AV_PIX_FMT_RGBA64BE) {
1081 alpha_blend_onto_yuv420p10(target_params, other_yuv_params, get_alpha_64be);
1083 alpha_blend_onto_yuv420p10(target_params, other_yuv_params, get_alpha_byte);
1087 case AV_PIX_FMT_YUV422P9LE:
1088 case AV_PIX_FMT_YUV422P10LE:
1090 auto yuv = other->convert_pixel_format (dcp::YUVToRGB::REC709, _pixel_format, Alignment::COMPACT, false);
1091 other_yuv_params.data = yuv->data();
1092 other_yuv_params.stride = yuv->stride();
1093 other_yuv_params.alpha_data = other->data();
1094 other_yuv_params.alpha_stride = other->stride();
1095 if (other->pixel_format() == AV_PIX_FMT_RGBA64BE) {
1096 alpha_blend_onto_yuv422p9or10le(target_params, other_yuv_params, get_alpha_64be);
1098 alpha_blend_onto_yuv422p9or10le(target_params, other_yuv_params, get_alpha_byte);
1102 case AV_PIX_FMT_YUV444P9LE:
1103 case AV_PIX_FMT_YUV444P10LE:
1105 auto yuv = other->convert_pixel_format (dcp::YUVToRGB::REC709, _pixel_format, Alignment::COMPACT, false);
1106 other_yuv_params.data = yuv->data();
1107 other_yuv_params.stride = yuv->stride();
1108 other_yuv_params.alpha_data = other->data();
1109 other_yuv_params.alpha_stride = other->stride();
1110 if (other->pixel_format() == AV_PIX_FMT_RGBA64BE) {
1111 alpha_blend_onto_yuv444p9or10le(target_params, other_yuv_params, get_alpha_64be);
1113 alpha_blend_onto_yuv444p9or10le(target_params, other_yuv_params, get_alpha_byte);
1118 throw PixelFormatError ("alpha_blend()", _pixel_format);
1124 Image::copy (shared_ptr<const Image> other, Position<int> position)
1126 /* Only implemented for RGB24 onto RGB24 so far */
1127 DCPOMATIC_ASSERT (_pixel_format == AV_PIX_FMT_RGB24 && other->pixel_format() == AV_PIX_FMT_RGB24);
1128 DCPOMATIC_ASSERT (position.x >= 0 && position.y >= 0);
1130 int const N = min (position.x + other->size().width, size().width) - position.x;
1131 for (int ty = position.y, oy = 0; ty < size().height && oy < other->size().height; ++ty, ++oy) {
1132 uint8_t * const tp = data()[0] + ty * stride()[0] + position.x * 3;
1133 uint8_t * const op = other->data()[0] + oy * other->stride()[0];
1134 memcpy (tp, op, N * 3);
1140 Image::read_from_socket (shared_ptr<Socket> socket)
1142 for (int i = 0; i < planes(); ++i) {
1143 uint8_t* p = data()[i];
1144 int const lines = sample_size(i).height;
1145 for (int y = 0; y < lines; ++y) {
1146 socket->read (p, line_size()[i]);
1154 Image::write_to_socket (shared_ptr<Socket> socket) const
1156 for (int i = 0; i < planes(); ++i) {
1157 uint8_t* p = data()[i];
1158 int const lines = sample_size(i).height;
1159 for (int y = 0; y < lines; ++y) {
1160 socket->write (p, line_size()[i]);
1168 Image::bytes_per_pixel (int c) const
1170 auto d = av_pix_fmt_desc_get(_pixel_format);
1172 throw PixelFormatError ("bytes_per_pixel()", _pixel_format);
1175 if (c >= planes()) {
1179 float bpp[4] = { 0, 0, 0, 0 };
1181 #ifdef DCPOMATIC_HAVE_AVCOMPONENTDESCRIPTOR_DEPTH_MINUS1
1182 bpp[0] = floor ((d->comp[0].depth_minus1 + 8) / 8);
1183 if (d->nb_components > 1) {
1184 bpp[1] = floor ((d->comp[1].depth_minus1 + 8) / 8) / pow (2.0f, d->log2_chroma_w);
1186 if (d->nb_components > 2) {
1187 bpp[2] = floor ((d->comp[2].depth_minus1 + 8) / 8) / pow (2.0f, d->log2_chroma_w);
1189 if (d->nb_components > 3) {
1190 bpp[3] = floor ((d->comp[3].depth_minus1 + 8) / 8) / pow (2.0f, d->log2_chroma_w);
1193 bpp[0] = floor ((d->comp[0].depth + 7) / 8);
1194 if (d->nb_components > 1) {
1195 bpp[1] = floor ((d->comp[1].depth + 7) / 8) / pow (2.0f, d->log2_chroma_w);
1197 if (d->nb_components > 2) {
1198 bpp[2] = floor ((d->comp[2].depth + 7) / 8) / pow (2.0f, d->log2_chroma_w);
1200 if (d->nb_components > 3) {
1201 bpp[3] = floor ((d->comp[3].depth + 7) / 8) / pow (2.0f, d->log2_chroma_w);
1205 if ((d->flags & AV_PIX_FMT_FLAG_PLANAR) == 0) {
1206 /* Not planar; sum them up */
1207 return bpp[0] + bpp[1] + bpp[2] + bpp[3];
1214 /** Construct a Image of a given size and format, allocating memory
1217 * @param p Pixel format.
1218 * @param s Size in pixels.
1219 * @param alignment PADDED to make each row of this image aligned to a ALIGNMENT-byte boundary, otherwise COMPACT.
1221 Image::Image (AVPixelFormat p, dcp::Size s, Alignment alignment)
1224 , _alignment (alignment)
1233 _data = (uint8_t **) wrapped_av_malloc (4 * sizeof (uint8_t *));
1234 _data[0] = _data[1] = _data[2] = _data[3] = 0;
1236 _line_size = (int *) wrapped_av_malloc (4 * sizeof (int));
1237 _line_size[0] = _line_size[1] = _line_size[2] = _line_size[3] = 0;
1239 _stride = (int *) wrapped_av_malloc (4 * sizeof (int));
1240 _stride[0] = _stride[1] = _stride[2] = _stride[3] = 0;
1242 auto stride_round_up = [](int stride, int t) {
1243 int const a = stride + (t - 1);
1247 for (int i = 0; i < planes(); ++i) {
1248 _line_size[i] = ceil (_size.width * bytes_per_pixel(i));
1249 _stride[i] = stride_round_up (_line_size[i], _alignment == Alignment::PADDED ? ALIGNMENT : 1);
1251 /* The assembler function ff_rgb24ToY_avx (in libswscale/x86/input.asm)
1252 uses a 16-byte fetch to read three bytes (R/G/B) of image data.
1253 Hence on the last pixel of the last line it reads over the end of
1254 the actual data by 1 byte. If the width of an image is a multiple
1255 of the stride alignment there will be no padding at the end of image lines.
1256 OS X crashes on this illegal read, though other operating systems don't
1257 seem to mind. The nasty + 1 in this malloc makes sure there is always a byte
1258 for that instruction to read safely.
1260 Further to the above, valgrind is now telling me that ff_rgb24ToY_ssse3
1261 over-reads by more then _avx. I can't follow the code to work out how much,
1262 so I'll just over-allocate by ALIGNMENT bytes and have done with it. Empirical
1263 testing suggests that it works.
1265 In addition to these concerns, we may read/write as much as a whole extra line
1266 at the end of each plane in cases where we are messing with offsets in order to
1267 do pad or crop. To solve this we over-allocate by an extra _stride[i] bytes.
1269 As an example: we may write to images starting at an offset so we get some padding.
1270 Hence we want to write in the following pattern:
1272 block start write start line end
1273 |..(padding)..|<------line-size------------->|..(padding)..|
1274 |..(padding)..|<------line-size------------->|..(padding)..|
1275 |..(padding)..|<------line-size------------->|..(padding)..|
1277 where line-size is of the smaller (inter_size) image and the full padded line length is that of
1278 out_size. To get things to work we have to tell FFmpeg that the stride is that of out_size.
1279 However some parts of FFmpeg (notably rgb48Toxyz12 in swscale.c) process data for the full
1280 specified *stride*. This does not matter until we get to the last line:
1282 block start write start line end
1283 |..(padding)..|<------line-size------------->|XXXwrittenXXX|
1284 |XXXwrittenXXX|<------line-size------------->|XXXwrittenXXX|
1285 |XXXwrittenXXX|<------line-size------------->|XXXwrittenXXXXXXwrittenXXX
1288 _data[i] = (uint8_t *) wrapped_av_malloc (_stride[i] * (sample_size(i).height + 1) + ALIGNMENT);
1289 #if HAVE_VALGRIND_MEMCHECK_H
1290 /* The data between the end of the line size and the stride is undefined but processed by
1291 libswscale, causing lots of valgrind errors. Mark it all defined to quell these errors.
1293 VALGRIND_MAKE_MEM_DEFINED (_data[i], _stride[i] * (sample_size(i).height + 1) + ALIGNMENT);
1299 Image::Image (Image const & other)
1300 : std::enable_shared_from_this<Image>(other)
1301 , _size (other._size)
1302 , _pixel_format (other._pixel_format)
1303 , _alignment (other._alignment)
1307 for (int i = 0; i < planes(); ++i) {
1308 uint8_t* p = _data[i];
1309 uint8_t* q = other._data[i];
1310 int const lines = sample_size(i).height;
1311 for (int j = 0; j < lines; ++j) {
1312 memcpy (p, q, _line_size[i]);
1314 q += other.stride()[i];
1320 Image::Image (AVFrame const * frame, Alignment alignment)
1321 : _size (frame->width, frame->height)
1322 , _pixel_format (static_cast<AVPixelFormat>(frame->format))
1323 , _alignment (alignment)
1325 DCPOMATIC_ASSERT (_pixel_format != AV_PIX_FMT_NONE);
1329 for (int i = 0; i < planes(); ++i) {
1330 uint8_t* p = _data[i];
1331 uint8_t* q = frame->data[i];
1332 int const lines = sample_size(i).height;
1333 for (int j = 0; j < lines; ++j) {
1334 memcpy (p, q, _line_size[i]);
1336 /* AVFrame's linesize is what we call `stride' */
1337 q += frame->linesize[i];
1343 Image::Image (shared_ptr<const Image> other, Alignment alignment)
1344 : _size (other->_size)
1345 , _pixel_format (other->_pixel_format)
1346 , _alignment (alignment)
1350 for (int i = 0; i < planes(); ++i) {
1351 DCPOMATIC_ASSERT (line_size()[i] == other->line_size()[i]);
1352 uint8_t* p = _data[i];
1353 uint8_t* q = other->data()[i];
1354 int const lines = sample_size(i).height;
1355 for (int j = 0; j < lines; ++j) {
1356 memcpy (p, q, line_size()[i]);
1358 q += other->stride()[i];
1365 Image::operator= (Image const & other)
1367 if (this == &other) {
1378 Image::swap (Image & other)
1380 std::swap (_size, other._size);
1381 std::swap (_pixel_format, other._pixel_format);
1383 for (int i = 0; i < 4; ++i) {
1384 std::swap (_data[i], other._data[i]);
1385 std::swap (_line_size[i], other._line_size[i]);
1386 std::swap (_stride[i], other._stride[i]);
1389 std::swap (_alignment, other._alignment);
1395 for (int i = 0; i < planes(); ++i) {
1400 av_free (_line_size);
1406 Image::data () const
1413 Image::line_size () const
1420 Image::stride () const
1427 Image::size () const
1434 Image::alignment () const
1441 merge (list<PositionImage> images, Image::Alignment alignment)
1443 if (images.empty ()) {
1447 if (images.size() == 1) {
1448 images.front().image = Image::ensure_alignment(images.front().image, alignment);
1449 return images.front();
1452 dcpomatic::Rect<int> all (images.front().position, images.front().image->size().width, images.front().image->size().height);
1453 for (auto const& i: images) {
1454 all.extend (dcpomatic::Rect<int>(i.position, i.image->size().width, i.image->size().height));
1457 auto merged = make_shared<Image>(images.front().image->pixel_format(), dcp::Size(all.width, all.height), alignment);
1458 merged->make_transparent ();
1459 for (auto const& i: images) {
1460 merged->alpha_blend (i.image, i.position - all.position());
1463 return PositionImage (merged, all.position ());
1468 operator== (Image const & a, Image const & b)
1470 if (a.planes() != b.planes() || a.pixel_format() != b.pixel_format() || a.alignment() != b.alignment()) {
1474 for (int c = 0; c < a.planes(); ++c) {
1475 if (a.sample_size(c).height != b.sample_size(c).height || a.line_size()[c] != b.line_size()[c] || a.stride()[c] != b.stride()[c]) {
1479 uint8_t* p = a.data()[c];
1480 uint8_t* q = b.data()[c];
1481 int const lines = a.sample_size(c).height;
1482 for (int y = 0; y < lines; ++y) {
1483 if (memcmp (p, q, a.line_size()[c]) != 0) {
1497 * @param f Amount to fade by; 0 is black, 1 is no fade.
1500 Image::fade (float f)
1502 /* U/V black value for 8-bit colour */
1503 static int const eight_bit_uv = (1 << 7) - 1;
1504 /* U/V black value for 10-bit colour */
1505 static uint16_t const ten_bit_uv = (1 << 9) - 1;
1507 switch (_pixel_format) {
1508 case AV_PIX_FMT_YUV420P:
1511 uint8_t* p = data()[0];
1512 int const lines = sample_size(0).height;
1513 for (int y = 0; y < lines; ++y) {
1515 for (int x = 0; x < line_size()[0]; ++x) {
1516 *q = int(float(*q) * f);
1523 for (int c = 1; c < 3; ++c) {
1524 uint8_t* p = data()[c];
1525 int const lines = sample_size(c).height;
1526 for (int y = 0; y < lines; ++y) {
1528 for (int x = 0; x < line_size()[c]; ++x) {
1529 *q = eight_bit_uv + int((int(*q) - eight_bit_uv) * f);
1539 case AV_PIX_FMT_RGB24:
1542 uint8_t* p = data()[0];
1543 int const lines = sample_size(0).height;
1544 for (int y = 0; y < lines; ++y) {
1546 for (int x = 0; x < line_size()[0]; ++x) {
1547 *q = int (float (*q) * f);
1555 case AV_PIX_FMT_XYZ12LE:
1556 case AV_PIX_FMT_RGB48LE:
1557 /* 16-bit little-endian */
1558 for (int c = 0; c < 3; ++c) {
1559 int const stride_pixels = stride()[c] / 2;
1560 int const line_size_pixels = line_size()[c] / 2;
1561 uint16_t* p = reinterpret_cast<uint16_t*> (data()[c]);
1562 int const lines = sample_size(c).height;
1563 for (int y = 0; y < lines; ++y) {
1565 for (int x = 0; x < line_size_pixels; ++x) {
1566 *q = int (float (*q) * f);
1574 case AV_PIX_FMT_YUV422P10LE:
1578 int const stride_pixels = stride()[0] / 2;
1579 int const line_size_pixels = line_size()[0] / 2;
1580 uint16_t* p = reinterpret_cast<uint16_t*> (data()[0]);
1581 int const lines = sample_size(0).height;
1582 for (int y = 0; y < lines; ++y) {
1584 for (int x = 0; x < line_size_pixels; ++x) {
1585 *q = int(float(*q) * f);
1593 for (int c = 1; c < 3; ++c) {
1594 int const stride_pixels = stride()[c] / 2;
1595 int const line_size_pixels = line_size()[c] / 2;
1596 uint16_t* p = reinterpret_cast<uint16_t*> (data()[c]);
1597 int const lines = sample_size(c).height;
1598 for (int y = 0; y < lines; ++y) {
1600 for (int x = 0; x < line_size_pixels; ++x) {
1601 *q = ten_bit_uv + int((int(*q) - ten_bit_uv) * f);
1612 throw PixelFormatError ("fade()", _pixel_format);
1617 shared_ptr<const Image>
1618 Image::ensure_alignment (shared_ptr<const Image> image, Image::Alignment alignment)
1620 if (image->alignment() == alignment) {
1624 return make_shared<Image>(image, alignment);
1629 Image::memory_used () const
1632 for (int i = 0; i < planes(); ++i) {
1633 m += _stride[i] * sample_size(i).height;
1640 Image::video_range_to_full_range ()
1642 switch (_pixel_format) {
1643 case AV_PIX_FMT_RGB24:
1645 float const factor = 256.0 / 219.0;
1646 uint8_t* p = data()[0];
1647 int const lines = sample_size(0).height;
1648 for (int y = 0; y < lines; ++y) {
1650 for (int x = 0; x < line_size()[0]; ++x) {
1651 *q = clamp(lrintf((*q - 16) * factor), 0L, 255L);
1658 case AV_PIX_FMT_RGB48LE:
1660 float const factor = 65536.0 / 56064.0;
1661 uint16_t* p = reinterpret_cast<uint16_t*>(data()[0]);
1662 int const lines = sample_size(0).height;
1663 for (int y = 0; y < lines; ++y) {
1665 int const line_size_pixels = line_size()[0] / 2;
1666 for (int x = 0; x < line_size_pixels; ++x) {
1667 *q = clamp(lrintf((*q - 4096) * factor), 0L, 65535L);
1670 p += stride()[0] / 2;
1674 case AV_PIX_FMT_GBRP12LE:
1676 float const factor = 4096.0 / 3504.0;
1677 for (int c = 0; c < 3; ++c) {
1678 uint16_t* p = reinterpret_cast<uint16_t*>(data()[c]);
1679 int const lines = sample_size(c).height;
1680 for (int y = 0; y < lines; ++y) {
1682 int const line_size_pixels = line_size()[c] / 2;
1683 for (int x = 0; x < line_size_pixels; ++x) {
1684 *q = clamp(lrintf((*q - 256) * factor), 0L, 4095L);
1692 throw PixelFormatError ("video_range_to_full_range()", _pixel_format);