Fix failure to open v2.14.x documents with invalid or empty subtitle languages (...
[dcpomatic.git] / src / lib / image.cc
index 63ae34ce96e5d58e411749baab3001f93b7264ec..8e6c5717b9064025a1adb03a619731a13835b347 100644 (file)
 #include "rect.h"
 #include "timer.h"
 #include "util.h"
+#include "warnings.h"
 #include <dcp/rgb_xyz.h>
 #include <dcp/transfer_function.h>
+DCPOMATIC_DISABLE_WARNINGS
 extern "C" {
 #include <libavutil/frame.h>
 #include <libavutil/pixdesc.h>
 #include <libavutil/pixfmt.h>
 #include <libswscale/swscale.h>
 }
+DCPOMATIC_ENABLE_WARNINGS
 #include <png.h>
 #if HAVE_VALGRIND_MEMCHECK_H
 #include <valgrind/memcheck.h>
@@ -294,6 +297,15 @@ Image::crop_scale_window (
                out->make_part_black (corner.x + cropped_size.width, out_size.width - cropped_size.width);
        }
 
+       if (
+               video_range == VideoRange::VIDEO &&
+               out_video_range == VideoRange::FULL &&
+               av_pix_fmt_desc_get(_pixel_format)->flags & AV_PIX_FMT_FLAG_RGB
+          ) {
+               /* libswscale will not convert video range for RGB sources, so we have to do it ourselves */
+               out->video_range_to_full_range ();
+       }
+
        return out;
 }
 
@@ -392,6 +404,17 @@ Image::swap_16 (uint16_t v)
 void
 Image::make_part_black (int const start, int const width)
 {
+       auto y_part = [&]() {
+               int const bpp = bytes_per_pixel(0);
+               int const h = sample_size(0).height;
+               int const s = stride()[0];
+               auto p = data()[0];
+               for (int y = 0; y < h; ++y) {
+                       memset (p + start * bpp, 0, width * bpp);
+                       p += s;
+               }
+       };
+
        switch (_pixel_format) {
        case AV_PIX_FMT_RGB24:
        case AV_PIX_FMT_ARGB:
@@ -413,20 +436,28 @@ Image::make_part_black (int const start, int const width)
                }
                break;
        }
-       case AV_PIX_FMT_YUV422P10LE:
+       case AV_PIX_FMT_YUV420P:
        {
-               int const bpp_0 = bytes_per_pixel(0);
-               int const h_0 = sample_size(0).height;
-               int const stride_0 = stride()[0];
-               auto p = data()[0];
-               for (int y = 0; y < h_0; ++y) {
-                       memset (p + start * bpp_0, 0xff, width * bpp_0);
-                       p += stride_0;
+               y_part ();
+               for (int i = 1; i < 3; ++i) {
+                       auto p = data()[i];
+                       int const h = sample_size(i).height;
+                       for (int y = 0; y < h; ++y) {
+                               for (int x = start / 2; x < (start + width) / 2; ++x) {
+                                       p[x] = eight_bit_uv;
+                               }
+                               p += stride()[i];
+                       }
                }
+               break;
+       }
+       case AV_PIX_FMT_YUV422P10LE:
+       {
+               y_part ();
                for (int i = 1; i < 3; ++i) {
                        auto p = reinterpret_cast<int16_t*>(data()[i]);
-                       int const lines = sample_size(i).height;
-                       for (int y = 0; y < lines; ++y) {
+                       int const h = sample_size(i).height;
+                       for (int y = 0; y < h; ++y) {
                                for (int x = start / 2; x < (start + width) / 2; ++x) {
                                        p[x] = ten_bit_uv;
                                }
@@ -996,7 +1027,7 @@ Image::Image (Image const & other)
        }
 }
 
-Image::Image (AVFrame* frame)
+Image::Image (AVFrame const * frame)
        : _size (frame->width, frame->height)
        , _pixel_format (static_cast<AVPixelFormat>(frame->format))
        , _aligned (true)
@@ -1411,13 +1442,29 @@ Image::video_range_to_full_range ()
                for (int y = 0; y < lines; ++y) {
                        uint8_t* q = p;
                        for (int x = 0; x < line_size()[0]; ++x) {
-                               *q = int((*q - 16) * factor);
+                               *q = clamp(lrintf((*q - 16) * factor), 0L, 255L);
                                ++q;
                        }
                        p += stride()[0];
                }
                break;
        }
+       case AV_PIX_FMT_RGB48LE:
+       {
+               float const factor = 65536.0 / 56064.0;
+               uint16_t* p = reinterpret_cast<uint16_t*>(data()[0]);
+               int const lines = sample_size(0).height;
+               for (int y = 0; y < lines; ++y) {
+                       uint16_t* q = p;
+                       int const line_size_pixels = line_size()[0] / 2;
+                       for (int x = 0; x < line_size_pixels; ++x) {
+                               *q = clamp(lrintf((*q - 4096) * factor), 0L, 65535L);
+                               ++q;
+                       }
+                       p += stride()[0] / 2;
+               }
+               break;
+       }
        case AV_PIX_FMT_GBRP12LE:
        {
                float const factor = 4096.0 / 3504.0;
@@ -1428,7 +1475,7 @@ Image::video_range_to_full_range ()
                                uint16_t* q = p;
                                int const line_size_pixels = line_size()[c] / 2;
                                for (int x = 0; x < line_size_pixels; ++x) {
-                                       *q = int((*q - 256) * factor);
+                                       *q = clamp(lrintf((*q - 256) * factor), 0L, 4095L);
                                        ++q;
                                }
                        }