[FFmpeg-devel,v3,2/2] avcodec/videotoolbox: add support for full range pixel formats

Submitted by der richter on April 13, 2019, 2:36 p.m.

Details

Message ID 20190413143601.74858-2-der.richter@gmx.de
State New
Headers show

Commit Message

der richter April 13, 2019, 2:36 p.m.
From: Akemi <der.richter@gmx.de>

---
 fftools/ffmpeg_videotoolbox.c      |  6 ++++--
 libavcodec/videotoolbox.c          | 14 +++++++++-----
 libavutil/hwcontext_videotoolbox.c | 20 ++++++++++++++------
 libavutil/hwcontext_videotoolbox.h |  6 ++++++
 4 files changed, 33 insertions(+), 13 deletions(-)

--
2.21.0

Patch hide | download patch | download mbox

diff --git a/fftools/ffmpeg_videotoolbox.c b/fftools/ffmpeg_videotoolbox.c
index ad6174d3c7..628fb5e32c 100644
--- a/fftools/ffmpeg_videotoolbox.c
+++ b/fftools/ffmpeg_videotoolbox.c
@@ -51,10 +51,12 @@  static int videotoolbox_retrieve_data(AVCodecContext *s, AVFrame *frame)
     case kCVPixelFormatType_422YpCbCr8:       vt->tmp_frame->format = AV_PIX_FMT_UYVY422; break;
     case kCVPixelFormatType_32BGRA:           vt->tmp_frame->format = AV_PIX_FMT_BGRA; break;
 #ifdef kCFCoreFoundationVersionNumber10_7
-    case kCVPixelFormatType_420YpCbCr8BiPlanarVideoRange: vt->tmp_frame->format = AV_PIX_FMT_NV12; break;
+    case kCVPixelFormatType_420YpCbCr8BiPlanarVideoRange:
+    case kCVPixelFormatType_420YpCbCr8BiPlanarFullRange: vt->tmp_frame->format = AV_PIX_FMT_NV12; break;
 #endif
 #if HAVE_KCVPIXELFORMATTYPE_420YPCBCR10BIPLANARVIDEORANGE
-    case kCVPixelFormatType_420YpCbCr10BiPlanarVideoRange: vt->tmp_frame->format = AV_PIX_FMT_P010; break;
+    case kCVPixelFormatType_420YpCbCr10BiPlanarVideoRange:
+    case kCVPixelFormatType_420YpCbCr10BiPlanarFullRange: vt->tmp_frame->format = AV_PIX_FMT_P010; break;
 #endif
     default:
         av_log(NULL, AV_LOG_ERROR,
diff --git a/libavcodec/videotoolbox.c b/libavcodec/videotoolbox.c
index c718e82cc5..b3b38dbde3 100644
--- a/libavcodec/videotoolbox.c
+++ b/libavcodec/videotoolbox.c
@@ -1084,8 +1084,9 @@  static int videotoolbox_common_init(AVCodecContext *avctx)
         goto fail;
     }

+    bool full_range = avctx->color_range == AVCOL_RANGE_JPEG;
     vtctx->vt_ctx->cv_pix_fmt_type =
-        av_map_videotoolbox_format_from_pixfmt(hw_frames->sw_format);
+        av_map_videotoolbox_format_from_pixfmt2(hw_frames->sw_format, full_range);
     if (!vtctx->vt_ctx->cv_pix_fmt_type) {
         av_log(avctx, AV_LOG_ERROR, "Unknown sw_format.\n");
         err = AVERROR(EINVAL);
@@ -1208,14 +1209,15 @@  const AVHWAccel ff_mpeg4_videotoolbox_hwaccel = {
     .priv_data_size = sizeof(VTContext),
 };

-static AVVideotoolboxContext *av_videotoolbox_alloc_context_with_pix_fmt(enum AVPixelFormat pix_fmt)
+static AVVideotoolboxContext *av_videotoolbox_alloc_context_with_pix_fmt(enum AVPixelFormat pix_fmt,
+                                                                         bool full_range)
 {
     AVVideotoolboxContext *ret = av_mallocz(sizeof(*ret));

     if (ret) {
         ret->output_callback = videotoolbox_decoder_callback;

-        OSType cv_pix_fmt_type = av_map_videotoolbox_format_from_pixfmt(pix_fmt);
+        OSType cv_pix_fmt_type = av_map_videotoolbox_format_from_pixfmt2(pix_fmt, full_range);
         if (cv_pix_fmt_type == 0) {
             cv_pix_fmt_type = kCVPixelFormatType_420YpCbCr8BiPlanarVideoRange;
         }
@@ -1227,7 +1229,7 @@  static AVVideotoolboxContext *av_videotoolbox_alloc_context_with_pix_fmt(enum AV

 AVVideotoolboxContext *av_videotoolbox_alloc_context(void)
 {
-    return av_videotoolbox_alloc_context_with_pix_fmt(AV_PIX_FMT_NONE);
+    return av_videotoolbox_alloc_context_with_pix_fmt(AV_PIX_FMT_NONE, false);
 }

 int av_videotoolbox_default_init(AVCodecContext *avctx)
@@ -1237,7 +1239,9 @@  int av_videotoolbox_default_init(AVCodecContext *avctx)

 int av_videotoolbox_default_init2(AVCodecContext *avctx, AVVideotoolboxContext *vtctx)
 {
-    avctx->hwaccel_context = vtctx ?: av_videotoolbox_alloc_context_with_pix_fmt(videotoolbox_best_pixel_format(avctx));
+    enum AVPixelFormat pix_fmt = videotoolbox_best_pixel_format(avctx);
+    bool full_range = avctx->color_range == AVCOL_RANGE_JPEG;
+    avctx->hwaccel_context = vtctx ?: av_videotoolbox_alloc_context_with_pix_fmt(pix_fmt, full_range);
     if (!avctx->hwaccel_context)
         return AVERROR(ENOMEM);
     return videotoolbox_start(avctx);
diff --git a/libavutil/hwcontext_videotoolbox.c b/libavutil/hwcontext_videotoolbox.c
index 6eac2c0774..bded9873fe 100644
--- a/libavutil/hwcontext_videotoolbox.c
+++ b/libavutil/hwcontext_videotoolbox.c
@@ -34,16 +34,19 @@ 

 static const struct {
     uint32_t cv_fmt;
+    bool full_range;
     enum AVPixelFormat pix_fmt;
 } cv_pix_fmts[] = {
-    { kCVPixelFormatType_420YpCbCr8Planar,              AV_PIX_FMT_YUV420P },
-    { kCVPixelFormatType_422YpCbCr8,                    AV_PIX_FMT_UYVY422 },
-    { kCVPixelFormatType_32BGRA,                        AV_PIX_FMT_BGRA },
+    { kCVPixelFormatType_420YpCbCr8Planar,              false, AV_PIX_FMT_YUV420P },
+    { kCVPixelFormatType_422YpCbCr8,                    false, AV_PIX_FMT_UYVY422 },
+    { kCVPixelFormatType_32BGRA,                        false, AV_PIX_FMT_BGRA },
 #ifdef kCFCoreFoundationVersionNumber10_7
-    { kCVPixelFormatType_420YpCbCr8BiPlanarVideoRange,  AV_PIX_FMT_NV12 },
+    { kCVPixelFormatType_420YpCbCr8BiPlanarVideoRange,  false, AV_PIX_FMT_NV12 },
+    { kCVPixelFormatType_420YpCbCr8BiPlanarFullRange,   true,  AV_PIX_FMT_NV12 },
 #endif
 #if HAVE_KCVPIXELFORMATTYPE_420YPCBCR10BIPLANARVIDEORANGE
-    { kCVPixelFormatType_420YpCbCr10BiPlanarVideoRange, AV_PIX_FMT_P010 },
+    { kCVPixelFormatType_420YpCbCr10BiPlanarVideoRange, false, AV_PIX_FMT_P010 },
+    { kCVPixelFormatType_420YpCbCr10BiPlanarFullRange,  true,  AV_PIX_FMT_P010 },
 #endif
 };

@@ -58,10 +61,15 @@  enum AVPixelFormat av_map_videotoolbox_format_to_pixfmt(uint32_t cv_fmt)
 }

 uint32_t av_map_videotoolbox_format_from_pixfmt(enum AVPixelFormat pix_fmt)
+{
+    return av_map_videotoolbox_format_from_pixfmt2(pix_fmt, false);
+}
+
+uint32_t av_map_videotoolbox_format_from_pixfmt2(enum AVPixelFormat pix_fmt, bool full_range)
 {
     int i;
     for (i = 0; i < FF_ARRAY_ELEMS(cv_pix_fmts); i++) {
-        if (cv_pix_fmts[i].pix_fmt == pix_fmt)
+        if (cv_pix_fmts[i].pix_fmt == pix_fmt && cv_pix_fmts[i].full_range == full_range)
             return cv_pix_fmts[i].cv_fmt;
     }
     return 0;
diff --git a/libavutil/hwcontext_videotoolbox.h b/libavutil/hwcontext_videotoolbox.h
index 380918d92e..5074d79e68 100644
--- a/libavutil/hwcontext_videotoolbox.h
+++ b/libavutil/hwcontext_videotoolbox.h
@@ -51,4 +51,10 @@  enum AVPixelFormat av_map_videotoolbox_format_to_pixfmt(uint32_t cv_fmt);
  */
 uint32_t av_map_videotoolbox_format_from_pixfmt(enum AVPixelFormat pix_fmt);

+/**
+ * Same as av_map_videotoolbox_format_from_pixfmt function, but can map and
+ * return full range pixel formats via a flag.
+ */
+uint32_t av_map_videotoolbox_format_from_pixfmt2(enum AVPixelFormat pix_fmt, bool full_range);
+
 #endif /* AVUTIL_HWCONTEXT_VIDEOTOOLBOX_H */