2 Copyright (C) 2012-2015 Carl Hetherington <cth@carlh.net>
4 This program is free software; you can redistribute it and/or modify
5 it under the terms of the GNU General Public License as published by
6 the Free Software Foundation; either version 2 of the License, or
7 (at your option) any later version.
9 This program is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 GNU General Public License for more details.
14 You should have received a copy of the GNU General Public License
15 along with this program; if not, write to the Free Software
16 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
20 /** @file src/image.cc
21 * @brief A class to describe a video image.
25 #include "exceptions.h"
29 #include "md5_digester.h"
30 #include "dcpomatic_socket.h"
32 #include <libswscale/swscale.h>
33 #include <libavutil/pixfmt.h>
34 #include <libavutil/pixdesc.h>
35 #include <libavutil/frame.h>
46 using boost::shared_ptr;
50 Image::line_factor (int n) const
56 AVPixFmtDescriptor const * d = av_pix_fmt_desc_get(_pixel_format);
58 throw PixelFormatError ("line_factor()", _pixel_format);
61 return pow (2.0f, d->log2_chroma_h);
64 /** @param n Component index.
65 * @return Number of samples (i.e. pixels, unless sub-sampled) in each direction for this component.
68 Image::sample_size (int n) const
70 int horizontal_factor = 1;
72 AVPixFmtDescriptor const * d = av_pix_fmt_desc_get (_pixel_format);
74 throw PixelFormatError ("sample_size()", _pixel_format);
76 horizontal_factor = pow (2.0f, d->log2_chroma_w);
80 lrint (ceil (static_cast<double>(size().width) / horizontal_factor)),
81 lrint (ceil (static_cast<double>(size().height) / line_factor (n)))
86 Image::components () const
88 AVPixFmtDescriptor const * d = av_pix_fmt_desc_get(_pixel_format);
90 throw PixelFormatError ("components()", _pixel_format);
93 return d->nb_components;
96 /** @return Number of planes */
98 Image::planes () const
100 AVPixFmtDescriptor const * d = av_pix_fmt_desc_get(_pixel_format);
102 throw PixelFormatError ("planes()", _pixel_format);
105 if ((d->flags & PIX_FMT_PLANAR) == 0) {
109 return d->nb_components;
112 /** Crop this image, scale it to `inter_size' and then place it in a black frame of `out_size' */
114 Image::crop_scale_window (
115 Crop crop, dcp::Size inter_size, dcp::Size out_size, dcp::YUVToRGB yuv_to_rgb, AVPixelFormat out_format, bool out_aligned
118 /* Empirical testing suggests that sws_scale() will crash if
119 the input image is not aligned.
121 DCPOMATIC_ASSERT (aligned ());
123 DCPOMATIC_ASSERT (out_size.width >= inter_size.width);
124 DCPOMATIC_ASSERT (out_size.height >= inter_size.height);
126 /* Here's an image of out_size */
127 shared_ptr<Image> out (new Image (out_format, out_size, out_aligned));
130 /* Size of the image after any crop */
131 dcp::Size const cropped_size = crop.apply (size ());
133 /* Scale context for a scale from cropped_size to inter_size */
134 struct SwsContext* scale_context = sws_getContext (
135 cropped_size.width, cropped_size.height, pixel_format(),
136 inter_size.width, inter_size.height, out_format,
140 if (!scale_context) {
141 throw StringError (N_("Could not allocate SwsContext"));
144 DCPOMATIC_ASSERT (yuv_to_rgb < dcp::YUV_TO_RGB_COUNT);
145 int const lut[dcp::YUV_TO_RGB_COUNT] = {
150 sws_setColorspaceDetails (
152 sws_getCoefficients (lut[yuv_to_rgb]), 0,
153 sws_getCoefficients (lut[yuv_to_rgb]), 0,
157 AVPixFmtDescriptor const * desc = av_pix_fmt_desc_get (_pixel_format);
159 throw PixelFormatError ("crop_scale_window()", _pixel_format);
162 /* Prepare input data pointers with crop */
163 uint8_t* scale_in_data[planes()];
164 for (int c = 0; c < planes(); ++c) {
165 /* To work out the crop in bytes, start by multiplying
166 the crop by the (average) bytes per pixel. Then
167 round down so that we don't crop a subsampled pixel until
168 we've cropped all of its Y-channel pixels.
170 int const x = lrintf (bytes_per_pixel(c) * crop.left) & ~ ((int) desc->log2_chroma_w);
171 scale_in_data[c] = data()[c] + x + stride()[c] * (crop.top / line_factor(c));
174 /* Corner of the image within out_size */
175 Position<int> const corner ((out_size.width - inter_size.width) / 2, (out_size.height - inter_size.height) / 2);
177 uint8_t* scale_out_data[out->planes()];
178 for (int c = 0; c < out->planes(); ++c) {
179 scale_out_data[c] = out->data()[c] + lrintf (out->bytes_per_pixel(c) * corner.x) + out->stride()[c] * corner.y;
184 scale_in_data, stride(),
185 0, cropped_size.height,
186 scale_out_data, out->stride()
189 sws_freeContext (scale_context);
195 Image::scale (dcp::Size out_size, dcp::YUVToRGB yuv_to_rgb, AVPixelFormat out_format, bool out_aligned) const
197 /* Empirical testing suggests that sws_scale() will crash if
198 the input image is not aligned.
200 DCPOMATIC_ASSERT (aligned ());
202 shared_ptr<Image> scaled (new Image (out_format, out_size, out_aligned));
204 struct SwsContext* scale_context = sws_getContext (
205 size().width, size().height, pixel_format(),
206 out_size.width, out_size.height, out_format,
210 DCPOMATIC_ASSERT (yuv_to_rgb < dcp::YUV_TO_RGB_COUNT);
211 int const lut[dcp::YUV_TO_RGB_COUNT] = {
216 sws_setColorspaceDetails (
218 sws_getCoefficients (lut[yuv_to_rgb]), 0,
219 sws_getCoefficients (lut[yuv_to_rgb]), 0,
227 scaled->data(), scaled->stride()
230 sws_freeContext (scale_context);
235 /** Blacken a YUV image whose bits per pixel is rounded up to 16 */
237 Image::yuv_16_black (uint16_t v, bool alpha)
239 memset (data()[0], 0, sample_size(0).height * stride()[0]);
240 for (int i = 1; i < 3; ++i) {
241 int16_t* p = reinterpret_cast<int16_t*> (data()[i]);
242 int const lines = sample_size(i).height;
243 for (int y = 0; y < lines; ++y) {
244 /* We divide by 2 here because we are writing 2 bytes at a time */
245 for (int x = 0; x < line_size()[i] / 2; ++x) {
248 p += stride()[i] / 2;
253 memset (data()[3], 0, sample_size(3).height * stride()[3]);
258 Image::swap_16 (uint16_t v)
260 return ((v >> 8) & 0xff) | ((v & 0xff) << 8);
266 /* U/V black value for 8-bit colour */
267 static uint8_t const eight_bit_uv = (1 << 7) - 1;
268 /* U/V black value for 9-bit colour */
269 static uint16_t const nine_bit_uv = (1 << 8) - 1;
270 /* U/V black value for 10-bit colour */
271 static uint16_t const ten_bit_uv = (1 << 9) - 1;
272 /* U/V black value for 16-bit colour */
273 static uint16_t const sixteen_bit_uv = (1 << 15) - 1;
275 switch (_pixel_format) {
276 case PIX_FMT_YUV420P:
277 case PIX_FMT_YUV422P:
278 case PIX_FMT_YUV444P:
279 case PIX_FMT_YUV411P:
280 memset (data()[0], 0, sample_size(0).height * stride()[0]);
281 memset (data()[1], eight_bit_uv, sample_size(1).height * stride()[1]);
282 memset (data()[2], eight_bit_uv, sample_size(2).height * stride()[2]);
285 case PIX_FMT_YUVJ420P:
286 case PIX_FMT_YUVJ422P:
287 case PIX_FMT_YUVJ444P:
288 memset (data()[0], 0, sample_size(0).height * stride()[0]);
289 memset (data()[1], eight_bit_uv + 1, sample_size(1).height * stride()[1]);
290 memset (data()[2], eight_bit_uv + 1, sample_size(2).height * stride()[2]);
293 case PIX_FMT_YUV422P9LE:
294 case PIX_FMT_YUV444P9LE:
295 yuv_16_black (nine_bit_uv, false);
298 case PIX_FMT_YUV422P9BE:
299 case PIX_FMT_YUV444P9BE:
300 yuv_16_black (swap_16 (nine_bit_uv), false);
303 case PIX_FMT_YUV422P10LE:
304 case PIX_FMT_YUV444P10LE:
305 yuv_16_black (ten_bit_uv, false);
308 case PIX_FMT_YUV422P16LE:
309 case PIX_FMT_YUV444P16LE:
310 yuv_16_black (sixteen_bit_uv, false);
313 case PIX_FMT_YUV444P10BE:
314 case PIX_FMT_YUV422P10BE:
315 yuv_16_black (swap_16 (ten_bit_uv), false);
318 case AV_PIX_FMT_YUVA420P9BE:
319 case AV_PIX_FMT_YUVA422P9BE:
320 case AV_PIX_FMT_YUVA444P9BE:
321 yuv_16_black (swap_16 (nine_bit_uv), true);
324 case AV_PIX_FMT_YUVA420P9LE:
325 case AV_PIX_FMT_YUVA422P9LE:
326 case AV_PIX_FMT_YUVA444P9LE:
327 yuv_16_black (nine_bit_uv, true);
330 case AV_PIX_FMT_YUVA420P10BE:
331 case AV_PIX_FMT_YUVA422P10BE:
332 case AV_PIX_FMT_YUVA444P10BE:
333 yuv_16_black (swap_16 (ten_bit_uv), true);
336 case AV_PIX_FMT_YUVA420P10LE:
337 case AV_PIX_FMT_YUVA422P10LE:
338 case AV_PIX_FMT_YUVA444P10LE:
339 yuv_16_black (ten_bit_uv, true);
342 case AV_PIX_FMT_YUVA420P16BE:
343 case AV_PIX_FMT_YUVA422P16BE:
344 case AV_PIX_FMT_YUVA444P16BE:
345 yuv_16_black (swap_16 (sixteen_bit_uv), true);
348 case AV_PIX_FMT_YUVA420P16LE:
349 case AV_PIX_FMT_YUVA422P16LE:
350 case AV_PIX_FMT_YUVA444P16LE:
351 yuv_16_black (sixteen_bit_uv, true);
359 case PIX_FMT_RGB555LE:
360 case PIX_FMT_RGB48LE:
361 case PIX_FMT_RGB48BE:
362 memset (data()[0], 0, sample_size(0).height * stride()[0]);
365 case PIX_FMT_UYVY422:
367 int const Y = sample_size(0).height;
368 int const X = line_size()[0];
369 uint8_t* p = data()[0];
370 for (int y = 0; y < Y; ++y) {
371 for (int x = 0; x < X / 4; ++x) {
372 *p++ = eight_bit_uv; // Cb
374 *p++ = eight_bit_uv; // Cr
382 throw PixelFormatError ("make_black()", _pixel_format);
387 Image::make_transparent ()
389 if (_pixel_format != PIX_FMT_RGBA) {
390 throw PixelFormatError ("make_transparent()", _pixel_format);
393 memset (data()[0], 0, sample_size(0).height * stride()[0]);
397 Image::alpha_blend (shared_ptr<const Image> other, Position<int> position)
399 DCPOMATIC_ASSERT (other->pixel_format() == PIX_FMT_RGBA);
400 int const other_bpp = 4;
402 int start_tx = position.x;
406 start_ox = -start_tx;
410 int start_ty = position.y;
414 start_oy = -start_ty;
418 switch (_pixel_format) {
421 int const this_bpp = 3;
422 for (int ty = start_ty, oy = start_oy; ty < size().height && oy < other->size().height; ++ty, ++oy) {
423 uint8_t* tp = data()[0] + ty * stride()[0] + start_tx * this_bpp;
424 uint8_t* op = other->data()[0] + oy * other->stride()[0];
425 for (int tx = start_tx, ox = start_ox; tx < size().width && ox < other->size().width; ++tx, ++ox) {
426 float const alpha = float (op[3]) / 255;
427 tp[0] = op[0] * alpha + tp[0] * (1 - alpha);
428 tp[1] = op[1] * alpha + tp[1] * (1 - alpha);
429 tp[2] = op[2] * alpha + tp[2] * (1 - alpha);
440 int const this_bpp = 4;
441 for (int ty = start_ty, oy = start_oy; ty < size().height && oy < other->size().height; ++ty, ++oy) {
442 uint8_t* tp = data()[0] + ty * stride()[0] + start_tx * this_bpp;
443 uint8_t* op = other->data()[0] + oy * other->stride()[0];
444 for (int tx = start_tx, ox = start_ox; tx < size().width && ox < other->size().width; ++tx, ++ox) {
445 float const alpha = float (op[3]) / 255;
446 tp[0] = op[0] * alpha + tp[0] * (1 - alpha);
447 tp[1] = op[1] * alpha + tp[1] * (1 - alpha);
448 tp[2] = op[2] * alpha + tp[2] * (1 - alpha);
449 tp[3] = op[3] * alpha + tp[3] * (1 - alpha);
457 case PIX_FMT_RGB48LE:
459 int const this_bpp = 6;
460 for (int ty = start_ty, oy = start_oy; ty < size().height && oy < other->size().height; ++ty, ++oy) {
461 uint8_t* tp = data()[0] + ty * stride()[0] + start_tx * this_bpp;
462 uint8_t* op = other->data()[0] + oy * other->stride()[0];
463 for (int tx = start_tx, ox = start_ox; tx < size().width && ox < other->size().width; ++tx, ++ox) {
464 float const alpha = float (op[3]) / 255;
465 /* Blend high bytes */
466 tp[1] = op[0] * alpha + tp[1] * (1 - alpha);
467 tp[3] = op[1] * alpha + tp[3] * (1 - alpha);
468 tp[5] = op[2] * alpha + tp[5] * (1 - alpha);
477 DCPOMATIC_ASSERT (false);
482 Image::copy (shared_ptr<const Image> other, Position<int> position)
484 /* Only implemented for RGB24 onto RGB24 so far */
485 DCPOMATIC_ASSERT (_pixel_format == PIX_FMT_RGB24 && other->pixel_format() == PIX_FMT_RGB24);
486 DCPOMATIC_ASSERT (position.x >= 0 && position.y >= 0);
488 int const N = min (position.x + other->size().width, size().width) - position.x;
489 for (int ty = position.y, oy = 0; ty < size().height && oy < other->size().height; ++ty, ++oy) {
490 uint8_t * const tp = data()[0] + ty * stride()[0] + position.x * 3;
491 uint8_t * const op = other->data()[0] + oy * other->stride()[0];
492 memcpy (tp, op, N * 3);
497 Image::read_from_socket (shared_ptr<Socket> socket)
499 for (int i = 0; i < planes(); ++i) {
500 uint8_t* p = data()[i];
501 int const lines = sample_size(i).height;
502 for (int y = 0; y < lines; ++y) {
503 socket->read (p, line_size()[i]);
510 Image::write_to_socket (shared_ptr<Socket> socket) const
512 for (int i = 0; i < planes(); ++i) {
513 uint8_t* p = data()[i];
514 int const lines = sample_size(i).height;
515 for (int y = 0; y < lines; ++y) {
516 socket->write (p, line_size()[i]);
523 Image::bytes_per_pixel (int c) const
525 AVPixFmtDescriptor const * d = av_pix_fmt_desc_get(_pixel_format);
527 throw PixelFormatError ("bytes_per_pixel()", _pixel_format);
534 float bpp[4] = { 0, 0, 0, 0 };
536 bpp[0] = floor ((d->comp[0].depth_minus1 + 1 + 7) / 8);
537 if (d->nb_components > 1) {
538 bpp[1] = floor ((d->comp[1].depth_minus1 + 1 + 7) / 8) / pow (2.0f, d->log2_chroma_w);
540 if (d->nb_components > 2) {
541 bpp[2] = floor ((d->comp[2].depth_minus1 + 1 + 7) / 8) / pow (2.0f, d->log2_chroma_w);
543 if (d->nb_components > 3) {
544 bpp[3] = floor ((d->comp[3].depth_minus1 + 1 + 7) / 8) / pow (2.0f, d->log2_chroma_w);
547 if ((d->flags & PIX_FMT_PLANAR) == 0) {
548 /* Not planar; sum them up */
549 return bpp[0] + bpp[1] + bpp[2] + bpp[3];
555 /** Construct a Image of a given size and format, allocating memory
558 * @param p Pixel format.
559 * @param s Size in pixels.
561 Image::Image (AVPixelFormat p, dcp::Size s, bool aligned)
572 _data = (uint8_t **) wrapped_av_malloc (4 * sizeof (uint8_t *));
573 _data[0] = _data[1] = _data[2] = _data[3] = 0;
575 _line_size = (int *) wrapped_av_malloc (4 * sizeof (int));
576 _line_size[0] = _line_size[1] = _line_size[2] = _line_size[3] = 0;
578 _stride = (int *) wrapped_av_malloc (4 * sizeof (int));
579 _stride[0] = _stride[1] = _stride[2] = _stride[3] = 0;
581 for (int i = 0; i < planes(); ++i) {
582 _line_size[i] = ceil (_size.width * bytes_per_pixel(i));
583 _stride[i] = stride_round_up (i, _line_size, _aligned ? 32 : 1);
585 /* The assembler function ff_rgb24ToY_avx (in libswscale/x86/input.asm)
586 uses a 16-byte fetch to read three bytes (R/G/B) of image data.
587 Hence on the last pixel of the last line it reads over the end of
588 the actual data by 1 byte. If the width of an image is a multiple
589 of the stride alignment there will be no padding at the end of image lines.
590 OS X crashes on this illegal read, though other operating systems don't
591 seem to mind. The nasty + 1 in this malloc makes sure there is always a byte
592 for that instruction to read safely.
594 Further to the above, valgrind is now telling me that ff_rgb24ToY_ssse3
595 over-reads by more then _avx. I can't follow the code to work out how much,
596 so I'll just over-allocate by 32 bytes and have done with it. Empirical
597 testing suggests that it works.
599 _data[i] = (uint8_t *) wrapped_av_malloc (_stride[i] * sample_size(i).height + 32);
603 Image::Image (Image const & other)
604 : _size (other._size)
605 , _pixel_format (other._pixel_format)
606 , _aligned (other._aligned)
610 for (int i = 0; i < planes(); ++i) {
611 uint8_t* p = _data[i];
612 uint8_t* q = other._data[i];
613 int const lines = sample_size(i).height;
614 for (int j = 0; j < lines; ++j) {
615 memcpy (p, q, _line_size[i]);
617 q += other.stride()[i];
622 Image::Image (AVFrame* frame)
623 : _size (frame->width, frame->height)
624 , _pixel_format (static_cast<AVPixelFormat> (frame->format))
629 for (int i = 0; i < planes(); ++i) {
630 uint8_t* p = _data[i];
631 uint8_t* q = frame->data[i];
632 int const lines = sample_size(i).height;
633 for (int j = 0; j < lines; ++j) {
634 memcpy (p, q, _line_size[i]);
636 /* AVFrame's linesize is what we call `stride' */
637 q += frame->linesize[i];
642 Image::Image (shared_ptr<const Image> other, bool aligned)
643 : _size (other->_size)
644 , _pixel_format (other->_pixel_format)
649 for (int i = 0; i < planes(); ++i) {
650 DCPOMATIC_ASSERT (line_size()[i] == other->line_size()[i]);
651 uint8_t* p = _data[i];
652 uint8_t* q = other->data()[i];
653 int const lines = sample_size(i).height;
654 for (int j = 0; j < lines; ++j) {
655 memcpy (p, q, line_size()[i]);
657 q += other->stride()[i];
663 Image::operator= (Image const & other)
665 if (this == &other) {
675 Image::swap (Image & other)
677 std::swap (_size, other._size);
678 std::swap (_pixel_format, other._pixel_format);
680 for (int i = 0; i < 4; ++i) {
681 std::swap (_data[i], other._data[i]);
682 std::swap (_line_size[i], other._line_size[i]);
683 std::swap (_stride[i], other._stride[i]);
686 std::swap (_aligned, other._aligned);
689 /** Destroy a Image */
692 for (int i = 0; i < planes(); ++i) {
697 av_free (_line_size);
708 Image::line_size () const
714 Image::stride () const
726 Image::aligned () const
732 merge (list<PositionImage> images)
734 if (images.empty ()) {
735 return PositionImage ();
738 if (images.size() == 1) {
739 return images.front ();
742 dcpomatic::Rect<int> all (images.front().position, images.front().image->size().width, images.front().image->size().height);
743 for (list<PositionImage>::const_iterator i = images.begin(); i != images.end(); ++i) {
744 all.extend (dcpomatic::Rect<int> (i->position, i->image->size().width, i->image->size().height));
747 shared_ptr<Image> merged (new Image (images.front().image->pixel_format (), dcp::Size (all.width, all.height), true));
748 merged->make_transparent ();
749 for (list<PositionImage>::const_iterator i = images.begin(); i != images.end(); ++i) {
750 merged->alpha_blend (i->image, i->position - all.position());
753 return PositionImage (merged, all.position ());
757 operator== (Image const & a, Image const & b)
759 if (a.planes() != b.planes() || a.pixel_format() != b.pixel_format() || a.aligned() != b.aligned()) {
763 for (int c = 0; c < a.planes(); ++c) {
764 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]) {
768 uint8_t* p = a.data()[c];
769 uint8_t* q = b.data()[c];
770 int const lines = a.sample_size(c).height;
771 for (int y = 0; y < lines; ++y) {
772 if (memcmp (p, q, a.line_size()[c]) != 0) {
785 * @param f Amount to fade by; 0 is black, 1 is no fade.
788 Image::fade (float f)
790 switch (_pixel_format) {
791 case PIX_FMT_YUV420P:
792 case PIX_FMT_YUV422P:
793 case PIX_FMT_YUV444P:
794 case PIX_FMT_YUV411P:
795 case PIX_FMT_YUVJ420P:
796 case PIX_FMT_YUVJ422P:
797 case PIX_FMT_YUVJ444P:
803 case PIX_FMT_RGB555LE:
805 for (int c = 0; c < 3; ++c) {
806 uint8_t* p = data()[c];
807 int const lines = sample_size(c).height;
808 for (int y = 0; y < lines; ++y) {
810 for (int x = 0; x < line_size()[c]; ++x) {
811 *q = int (float (*q) * f);
819 case PIX_FMT_YUV422P9LE:
820 case PIX_FMT_YUV444P9LE:
821 case PIX_FMT_YUV422P10LE:
822 case PIX_FMT_YUV444P10LE:
823 case PIX_FMT_YUV422P16LE:
824 case PIX_FMT_YUV444P16LE:
825 case AV_PIX_FMT_YUVA420P9LE:
826 case AV_PIX_FMT_YUVA422P9LE:
827 case AV_PIX_FMT_YUVA444P9LE:
828 case AV_PIX_FMT_YUVA420P10LE:
829 case AV_PIX_FMT_YUVA422P10LE:
830 case AV_PIX_FMT_YUVA444P10LE:
831 case AV_PIX_FMT_RGB48LE:
832 /* 16-bit little-endian */
833 for (int c = 0; c < 3; ++c) {
834 int const stride_pixels = stride()[c] / 2;
835 int const line_size_pixels = line_size()[c] / 2;
836 uint16_t* p = reinterpret_cast<uint16_t*> (data()[c]);
837 int const lines = sample_size(c).height;
838 for (int y = 0; y < lines; ++y) {
840 for (int x = 0; x < line_size_pixels; ++x) {
841 *q = int (float (*q) * f);
849 case PIX_FMT_YUV422P9BE:
850 case PIX_FMT_YUV444P9BE:
851 case PIX_FMT_YUV444P10BE:
852 case PIX_FMT_YUV422P10BE:
853 case AV_PIX_FMT_YUVA420P9BE:
854 case AV_PIX_FMT_YUVA422P9BE:
855 case AV_PIX_FMT_YUVA444P9BE:
856 case AV_PIX_FMT_YUVA420P10BE:
857 case AV_PIX_FMT_YUVA422P10BE:
858 case AV_PIX_FMT_YUVA444P10BE:
859 case AV_PIX_FMT_YUVA420P16BE:
860 case AV_PIX_FMT_YUVA422P16BE:
861 case AV_PIX_FMT_YUVA444P16BE:
862 case AV_PIX_FMT_RGB48BE:
863 /* 16-bit big-endian */
864 for (int c = 0; c < 3; ++c) {
865 int const stride_pixels = stride()[c] / 2;
866 int const line_size_pixels = line_size()[c] / 2;
867 uint16_t* p = reinterpret_cast<uint16_t*> (data()[c]);
868 int const lines = sample_size(c).height;
869 for (int y = 0; y < lines; ++y) {
871 for (int x = 0; x < line_size_pixels; ++x) {
872 *q = swap_16 (int (float (swap_16 (*q)) * f));
880 case PIX_FMT_UYVY422:
882 int const Y = sample_size(0).height;
883 int const X = line_size()[0];
884 uint8_t* p = data()[0];
885 for (int y = 0; y < Y; ++y) {
886 for (int x = 0; x < X; ++x) {
887 *p = int (float (*p) * f);
895 throw PixelFormatError ("fade()", _pixel_format);