Set libswscale option which doesn't work.
[dcpomatic.git] / src / lib / image.cc
index f86c105d4f8aa2d2ab76ce465fd8820d44bfa9bd..86824539726309855b6a3dcfc8b01fbfd7c6a53b 100644 (file)
@@ -27,6 +27,7 @@
 #include "compose.hpp"
 #include "dcpomatic_assert.h"
 #include "dcpomatic_socket.h"
+#include "enum_indexed_vector.h"
 #include "exceptions.h"
 #include "image.h"
 #include "maths_util.h"
@@ -39,6 +40,7 @@
 LIBDCP_DISABLE_WARNINGS
 extern "C" {
 #include <libavutil/frame.h>
+#include <libavutil/opt.h>
 #include <libavutil/pixdesc.h>
 #include <libavutil/pixfmt.h>
 #include <libswscale/swscale.h>
@@ -236,10 +238,10 @@ Image::crop_scale_window (
        }
 
        DCPOMATIC_ASSERT (yuv_to_rgb < dcp::YUVToRGB::COUNT);
-       int const lut[static_cast<int>(dcp::YUVToRGB::COUNT)] = {
-               SWS_CS_ITU601,
-               SWS_CS_ITU709
-       };
+       EnumIndexedVector<int, dcp::YUVToRGB> lut;
+       lut[dcp::YUVToRGB::REC601] = SWS_CS_ITU601;
+       lut[dcp::YUVToRGB::REC709] = SWS_CS_ITU709;
+       lut[dcp::YUVToRGB::REC2020] = SWS_CS_BT2020;
 
        /* The 3rd parameter here is:
           0 -> source range MPEG (i.e. "video", 16-235)
@@ -254,11 +256,22 @@ Image::crop_scale_window (
        */
        sws_setColorspaceDetails (
                scale_context,
-               sws_getCoefficients (lut[static_cast<int>(yuv_to_rgb)]), video_range == VideoRange::VIDEO ? 0 : 1,
-               sws_getCoefficients (lut[static_cast<int>(yuv_to_rgb)]), out_video_range == VideoRange::VIDEO ? 0 : 1,
+               sws_getCoefficients(lut[yuv_to_rgb]), video_range == VideoRange::VIDEO ? 0 : 1,
+               sws_getCoefficients(lut[yuv_to_rgb]), out_video_range == VideoRange::VIDEO ? 0 : 1,
                0, 1 << 16, 1 << 16
                );
 
+       static int64_t uniform_color = -1;
+       if (uniform_color == -1) {
+               // auto error = av_opt_get_int(scale_context, "uniform_color", AV_OPT_SEARCH_CHILDREN, &uniform_color);
+               auto option = av_opt_find2(scale_context, "uniform_color", "alphablend", 0, AV_OPT_SEARCH_CHILDREN, nullptr);
+               DCPOMATIC_ASSERT(option->type == AV_OPT_TYPE_CONST);
+               uniform_color = option->default_val.i64;
+               std::cout << "uniform_color=" << uniform_color << "\n";
+       }
+
+       std::cout << "set it: " << av_opt_set_int(scale_context, "alphablend", uniform_color, AV_OPT_SEARCH_CHILDREN) << "\n";
+
        /* Prepare input data pointers with crop */
        uint8_t* scale_in_data[planes()];
        for (int c = 0; c < planes(); ++c) {
@@ -292,13 +305,17 @@ Image::crop_scale_window (
 
        sws_freeContext (scale_context);
 
-       if (corrected_crop != Crop() && cropped_size == inter_size) {
-               /* We are cropping without any scaling or pixel format conversion, so FFmpeg may have left some
-                  data behind in our image.  Clear it out.  It may get to the point where we should just stop
-                  trying to be clever with cropping.
-               */
-               out->make_part_black (corner.x + cropped_size.width, out_size.width - cropped_size.width);
-       }
+       /* There are some cases where there will be unwanted image data left in the image at this point:
+        *
+        * 1. When we are cropping without any scaling or pixel format conversion.
+        * 2. When we are scaling to certain sizes and placing the result into a larger
+        *    black frame.
+        *
+        * Clear out the sides of the image to take care of those cases.
+        */
+       auto const pad = (out_size.width - inter_size.width) / 2;
+       out->make_part_black(0, pad);
+       out->make_part_black(corner.x + inter_size.width, pad);
 
        if (
                video_range == VideoRange::VIDEO &&
@@ -323,7 +340,7 @@ Image::convert_pixel_format (dcp::YUVToRGB yuv_to_rgb, AVPixelFormat out_format,
 /** @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_aligment Output alignment.
+ *  @param out_alignment 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.
  */
@@ -343,10 +360,10 @@ Image::scale (dcp::Size out_size, dcp::YUVToRGB yuv_to_rgb, AVPixelFormat out_fo
                );
 
        DCPOMATIC_ASSERT (yuv_to_rgb < dcp::YUVToRGB::COUNT);
-       int const lut[static_cast<int>(dcp::YUVToRGB::COUNT)] = {
-               SWS_CS_ITU601,
-               SWS_CS_ITU709
-       };
+       EnumIndexedVector<int, dcp::YUVToRGB> lut;
+       lut[dcp::YUVToRGB::REC601] = SWS_CS_ITU601;
+       lut[dcp::YUVToRGB::REC709] = SWS_CS_ITU709;
+       lut[dcp::YUVToRGB::REC2020] = SWS_CS_BT2020;
 
        /* The 3rd parameter here is:
           0 -> source range MPEG (i.e. "video", 16-235)
@@ -361,8 +378,8 @@ Image::scale (dcp::Size out_size, dcp::YUVToRGB yuv_to_rgb, AVPixelFormat out_fo
        */
        sws_setColorspaceDetails (
                scale_context,
-               sws_getCoefficients (lut[static_cast<int>(yuv_to_rgb)]), 0,
-               sws_getCoefficients (lut[static_cast<int>(yuv_to_rgb)]), 0,
+               sws_getCoefficients(lut[yuv_to_rgb]), 0,
+               sws_getCoefficients(lut[yuv_to_rgb]), 0,
                0, 1 << 16, 1 << 16
                );
 
@@ -474,6 +491,21 @@ Image::make_part_black (int const start, int const width)
                }
                break;
        }
+       case AV_PIX_FMT_YUV444P10LE:
+       {
+               y_part();
+               for (int i = 1; i < 3; ++i) {
+                       auto p = reinterpret_cast<int16_t*>(data()[i]);
+                       int const h = sample_size(i).height;
+                       for (int y = 0; y < h; ++y) {
+                               for (int x = start; x < (start + width); ++x) {
+                                       p[x] = ten_bit_uv;
+                               }
+                               p += stride()[i] / 2;
+                       }
+               }
+               break;
+       }
        default:
                throw PixelFormatError ("make_part_black()", _pixel_format);
        }