From b1f01e85a92d401a9b29c79f23db36b7685e8c09 Mon Sep 17 00:00:00 2001
From: Mark Thompson <mrt@jkqxz.net>
Date: Thu, 18 Feb 2016 23:25:52 +0000
Subject: [PATCH] lavu: add a way to query hwcontext frame constraints

Signed-off-by: Anton Khirnov <anton@khirnov.net>
---
 doc/APIchanges                 |  3 ++
 libavutil/hwcontext.c          | 45 ++++++++++++++++++++++
 libavutil/hwcontext.h          | 69 ++++++++++++++++++++++++++++++++++
 libavutil/hwcontext_internal.h | 10 +++++
 libavutil/version.h            |  2 +-
 5 files changed, 128 insertions(+), 1 deletion(-)

diff --git a/doc/APIchanges b/doc/APIchanges
index 20fecb995d..759816bd70 100644
--- a/doc/APIchanges
+++ b/doc/APIchanges
@@ -13,6 +13,9 @@ libavutil:     2015-08-28
 
 API changes, most recent first:
 
+2016-xx-xx - xxxxxxx - lavu 55.7.0 - hwcontext.h
+  Add AVHWFramesConstraints and associated API.
+
 2016-02-23 - 9200514 - lavf 57.5.0 - avformat.h
   Add AVStream.codecpar, deprecate AVStream.codec.
 
diff --git a/libavutil/hwcontext.c b/libavutil/hwcontext.c
index b6d05181c4..53e11b8eae 100644
--- a/libavutil/hwcontext.c
+++ b/libavutil/hwcontext.c
@@ -400,3 +400,48 @@ int av_hwframe_get_buffer(AVBufferRef *hwframe_ref, AVFrame *frame, int flags)
 
     return 0;
 }
+
+void *av_hwdevice_hwconfig_alloc(AVBufferRef *ref)
+{
+    AVHWDeviceContext *ctx = (AVHWDeviceContext*)ref->data;
+    const HWContextType  *hw_type = ctx->internal->hw_type;
+
+    if (hw_type->device_hwconfig_size == 0)
+        return NULL;
+
+    return av_mallocz(hw_type->device_hwconfig_size);
+}
+
+AVHWFramesConstraints *av_hwdevice_get_hwframe_constraints(AVBufferRef *ref,
+                                                           const void *hwconfig)
+{
+    AVHWDeviceContext *ctx = (AVHWDeviceContext*)ref->data;
+    const HWContextType  *hw_type = ctx->internal->hw_type;
+    AVHWFramesConstraints *constraints;
+
+    if (!hw_type->frames_get_constraints)
+        return NULL;
+
+    constraints = av_mallocz(sizeof(*constraints));
+    if (!constraints)
+        return NULL;
+
+    constraints->min_width = constraints->min_height = 0;
+    constraints->max_width = constraints->max_height = INT_MAX;
+
+    if (hw_type->frames_get_constraints(ctx, hwconfig, constraints) >= 0) {
+        return constraints;
+    } else {
+        av_hwframe_constraints_free(&constraints);
+        return NULL;
+    }
+}
+
+void av_hwframe_constraints_free(AVHWFramesConstraints **constraints)
+{
+    if (*constraints) {
+        av_freep(&(*constraints)->valid_hw_formats);
+        av_freep(&(*constraints)->valid_sw_formats);
+    }
+    av_freep(constraints);
+}
diff --git a/libavutil/hwcontext.h b/libavutil/hwcontext.h
index 81ae817eb3..681b55566c 100644
--- a/libavutil/hwcontext.h
+++ b/libavutil/hwcontext.h
@@ -326,4 +326,73 @@ int av_hwframe_transfer_get_formats(AVBufferRef *hwframe_ctx,
                                     enum AVPixelFormat **formats, int flags);
 
 
+/**
+ * This struct describes the constraints on hardware frames attached to
+ * a given device with a hardware-specific configuration.  This is returned
+ * by av_hwdevice_get_hwframe_constraints() and must be freed by
+ * av_hwframe_constraints_free() after use.
+ */
+typedef struct AVHWFramesConstraints {
+    /**
+     * A list of possible values for format in the hw_frames_ctx,
+     * terminated by AV_PIX_FMT_NONE.  This member will always be filled.
+     */
+    enum AVPixelFormat *valid_hw_formats;
+
+    /**
+     * A list of possible values for sw_format in the hw_frames_ctx,
+     * terminated by AV_PIX_FMT_NONE.  Can be NULL if this information is
+     * not known.
+     */
+    enum AVPixelFormat *valid_sw_formats;
+
+    /**
+     * The minimum size of frames in this hw_frames_ctx.
+     * (Zero if not known.)
+     */
+    int min_width;
+    int min_height;
+
+    /**
+     * The maximum size of frames in this hw_frames_ctx.
+     * (INT_MAX if not known / no limit.)
+     */
+    int max_width;
+    int max_height;
+} AVHWFramesConstraints;
+
+/**
+ * Allocate a HW-specific configuration structure for a given HW device.
+ * After use, the user must free all members as required by the specific
+ * hardware structure being used, then free the structure itself with
+ * av_free().
+ *
+ * @param device_ctx a reference to the associated AVHWDeviceContext.
+ * @return The newly created HW-specific configuration structure on
+ *         success or NULL on failure.
+ */
+void *av_hwdevice_hwconfig_alloc(AVBufferRef *device_ctx);
+
+/**
+ * Get the constraints on HW frames given a device and the HW-specific
+ * configuration to be used with that device.  If no HW-specific
+ * confgiuration is provided, returns the maximum possible capabilities
+ * of the device.
+ *
+ * @param device_ctx a reference to the associated AVHWDeviceContext.
+ * @param hwconfig a filled HW-specific configuration structure, or NULL
+ *        to return the maximum possible capabilities of the device.
+ * @return AVHWFramesConstraints structure describing the constraints
+ *         on the device, or NULL if not available.
+ */
+AVHWFramesConstraints *av_hwdevice_get_hwframe_constraints(AVBufferRef *ref,
+                                                           const void *hwconfig);
+
+/**
+ * Free an AVHWFrameConstraints structure.
+ *
+ * @param constraints The (filled or unfilled) AVHWFrameConstraints structure.
+ */
+void av_hwframe_constraints_free(AVHWFramesConstraints **constraints);
+
 #endif /* AVUTIL_HWCONTEXT_H */
diff --git a/libavutil/hwcontext_internal.h b/libavutil/hwcontext_internal.h
index 641232f140..27de1f9e62 100644
--- a/libavutil/hwcontext_internal.h
+++ b/libavutil/hwcontext_internal.h
@@ -47,6 +47,12 @@ typedef struct HWContextType {
      */
     size_t             device_priv_size;
 
+    /**
+     * Size of the hardware-specific device configuration.
+     * (Used to query hwframe constraints.)
+     */
+    size_t             device_hwconfig_size;
+
     /**
      * size of the public frame pool hardware-specific context,
      * i.e. AVHWFramesContext.hwctx
@@ -61,6 +67,10 @@ typedef struct HWContextType {
     int              (*device_init)(AVHWDeviceContext *ctx);
     void             (*device_uninit)(AVHWDeviceContext *ctx);
 
+    int              (*frames_get_constraints)(AVHWDeviceContext *ctx,
+                                               const void *hwconfig,
+                                               AVHWFramesConstraints *constraints);
+
     int              (*frames_init)(AVHWFramesContext *ctx);
     void             (*frames_uninit)(AVHWFramesContext *ctx);
 
diff --git a/libavutil/version.h b/libavutil/version.h
index ebd548fe0d..b102e93fa0 100644
--- a/libavutil/version.h
+++ b/libavutil/version.h
@@ -54,7 +54,7 @@
  */
 
 #define LIBAVUTIL_VERSION_MAJOR 55
-#define LIBAVUTIL_VERSION_MINOR  6
+#define LIBAVUTIL_VERSION_MINOR  7
 #define LIBAVUTIL_VERSION_MICRO  0
 
 #define LIBAVUTIL_VERSION_INT   AV_VERSION_INT(LIBAVUTIL_VERSION_MAJOR, \
-- 
2.18.1