Adds a new hwaccel flag REUSE_CONTEXT for the user to indicate that
this is desired, and adds an additional refcounted state structure
hwaccel_priv_persistent which persists across hwaccel reinitialisation
and can be used to store context information for reuse.
---
 doc/APIchanges             |  3 +++
 libavcodec/avcodec.h       |  6 ++++++
 libavcodec/decode.c        | 15 +++++++++++++--
 libavcodec/internal.h      |  8 ++++++++
 libavcodec/pthread_frame.c |  9 +++++++++
 libavcodec/utils.c         |  1 +
 6 files changed, 40 insertions(+), 2 deletions(-)

diff --git a/doc/APIchanges b/doc/APIchanges
index 6de6971fb..6f70f3c96 100644
--- a/doc/APIchanges
+++ b/doc/APIchanges
@@ -13,6 +13,9 @@ libavutil:     2017-03-23
 
 API changes, most recent first:
 
+2017-xx-xx - xxxxxxx - lavc 58.x+1.0 - avcodec.h
+  Add AV_HWACCEL_FLAG_REUSE_CONTEXT.
+
 2017-xx-xx - xxxxxxx - lavfi 7.x+1.0 - avfilter.h
   Add AVFilterContext.extra_hw_frames.
 
diff --git a/libavcodec/avcodec.h b/libavcodec/avcodec.h
index 680a7b5e4..89e432d16 100644
--- a/libavcodec/avcodec.h
+++ b/libavcodec/avcodec.h
@@ -3058,6 +3058,12 @@ typedef struct AVHWAccel {
 #define AV_HWACCEL_FLAG_ALLOW_PROFILE_MISMATCH (1 << 2)
 
 /**
+ * Hardware acceleration may reuse an existing context when a stream changes
+ * but parameters are still compatible.
+ */
+#define AV_HWACCEL_FLAG_REUSE_CONTEXT (1 << 3)
+
+/**
  * @}
  */
 
diff --git a/libavcodec/decode.c b/libavcodec/decode.c
index 2f4ebd12a..c2cc009ff 100644
--- a/libavcodec/decode.c
+++ b/libavcodec/decode.c
@@ -672,7 +672,7 @@ static AVHWAccel *find_hwaccel(enum AVCodecID codec_id,
 
 static int setup_hwaccel(AVCodecContext *avctx,
                          const enum AVPixelFormat fmt,
-                         const char *name)
+                         const char *name, AVHWAccel *prev_hwaccel)
 {
     AVHWAccel *hwa = find_hwaccel(avctx->codec_id, fmt);
     int ret        = 0;
@@ -690,6 +690,12 @@ static int setup_hwaccel(AVCodecContext *avctx,
             return AVERROR(ENOMEM);
     }
 
+    if (hwa != prev_hwaccel) {
+        // Persistent context only applies to the same hwaccel, so
+        // unreference it if the hwaccel changes.
+        av_buffer_unref(&avctx->internal->hwaccel_priv_persistent);
+    }
+
     avctx->hwaccel = hwa;
     if (hwa->init) {
         ret = hwa->init(avctx);
@@ -705,6 +711,7 @@ static int setup_hwaccel(AVCodecContext *avctx,
 
 int ff_get_format(AVCodecContext *avctx, const enum AVPixelFormat *fmt)
 {
+    AVHWAccel *prev_hwaccel;
     const AVPixFmtDescriptor *desc;
     enum AVPixelFormat *choices;
     enum AVPixelFormat ret;
@@ -723,9 +730,13 @@ int ff_get_format(AVCodecContext *avctx, const enum 
AVPixelFormat *fmt)
 
     memcpy(choices, fmt, (n + 1) * sizeof(*choices));
 
+    prev_hwaccel = avctx->hwaccel;
+
     for (;;) {
         if (avctx->hwaccel && avctx->hwaccel->uninit)
             avctx->hwaccel->uninit(avctx);
+        if (!(avctx->hwaccel_flags & AV_HWACCEL_FLAG_REUSE_CONTEXT))
+            av_buffer_unref(&avctx->internal->hwaccel_priv_persistent);
         av_freep(&avctx->internal->hwaccel_priv_data);
         avctx->hwaccel = NULL;
 
@@ -752,7 +763,7 @@ int ff_get_format(AVCodecContext *avctx, const enum 
AVPixelFormat *fmt)
             }
         }
 
-        if (!setup_hwaccel(avctx, ret, desc->name))
+        if (!setup_hwaccel(avctx, ret, desc->name, prev_hwaccel))
             break;
 
         /* Remove failed hwaccel from choices */
diff --git a/libavcodec/internal.h b/libavcodec/internal.h
index da1b2fa7d..c9f29d913 100644
--- a/libavcodec/internal.h
+++ b/libavcodec/internal.h
@@ -159,6 +159,14 @@ typedef struct AVCodecInternal {
     void *hwaccel_priv_data;
 
     /**
+     * Reference to any persistent private data for the current hwaccel.
+     *
+     * It will be unreferenced when the context is closed or when the hwaccel
+     * is changed, but persists across hwaccel uninitialisation.
+     */
+    AVBufferRef *hwaccel_priv_persistent;
+
+    /**
      * checks API usage: after codec draining, flush is required to resume 
operation
      */
     int draining;
diff --git a/libavcodec/pthread_frame.c b/libavcodec/pthread_frame.c
index a72391ba3..90cd8492a 100644
--- a/libavcodec/pthread_frame.c
+++ b/libavcodec/pthread_frame.c
@@ -256,6 +256,14 @@ static int update_context_from_thread(AVCodecContext *dst, 
AVCodecContext *src,
         dst->hwaccel_context = src->hwaccel_context;
         dst->internal->hwaccel_priv_data = src->internal->hwaccel_priv_data;
 
+        av_buffer_unref(&dst->internal->hwaccel_priv_persistent);
+        if (src->internal->hwaccel_priv_persistent) {
+            dst->internal->hwaccel_priv_persistent =
+                av_buffer_ref(src->internal->hwaccel_priv_persistent);
+            if (!dst->internal->hwaccel_priv_persistent)
+                return AVERROR(ENOMEM);
+        }
+
         if (!!dst->hw_frames_ctx != !!src->hw_frames_ctx ||
             (dst->hw_frames_ctx && dst->hw_frames_ctx->data != 
src->hw_frames_ctx->data)) {
             av_buffer_unref(&dst->hw_frames_ctx);
@@ -634,6 +642,7 @@ void ff_frame_thread_free(AVCodecContext *avctx, int 
thread_count)
             av_freep(&p->avctx->slice_offset);
         }
 
+        av_buffer_unref(&p->avctx->internal->hwaccel_priv_persistent);
         av_buffer_unref(&p->avctx->hw_frames_ctx);
 
         av_freep(&p->avctx->internal);
diff --git a/libavcodec/utils.c b/libavcodec/utils.c
index bc421f67f..e28cdb32d 100644
--- a/libavcodec/utils.c
+++ b/libavcodec/utils.c
@@ -758,6 +758,7 @@ av_cold int avcodec_close(AVCodecContext *avctx)
         if (avctx->hwaccel && avctx->hwaccel->uninit)
             avctx->hwaccel->uninit(avctx);
         av_freep(&avctx->internal->hwaccel_priv_data);
+        av_buffer_unref(&avctx->internal->hwaccel_priv_persistent);
 
         ff_decode_bsfs_uninit(avctx);
 
-- 
2.11.0

_______________________________________________
libav-devel mailing list
libav-devel@libav.org
https://lists.libav.org/mailman/listinfo/libav-devel

Reply via email to