The most compelling place to initialize the hardware of AVHWAccel-backed
decoders is the get_format callback. To avoid unneeded reinitializations
ff_get_format() calls get_format() only if the previously returned pixel
format is not in the new pixel format list.

On a frame size change codecs are expected to reset
avctx.internal.current_pix_fmt to AV_PIX_FMT_NONE.
---
 libavcodec/h264_slice.c | 15 +++++++++------
 libavcodec/internal.h   | 15 +++++++++++++++
 libavcodec/utils.c      | 20 ++++++++++++++++++++
 3 files changed, 44 insertions(+), 6 deletions(-)

diff --git a/libavcodec/h264_slice.c b/libavcodec/h264_slice.c
index aed2378..dfdc2aa 100644
--- a/libavcodec/h264_slice.c
+++ b/libavcodec/h264_slice.c
@@ -1011,11 +1011,11 @@ static enum AVPixelFormat get_pixel_format(H264Context 
*h)
             return h->avctx->color_range == AVCOL_RANGE_JPEG ? 
AV_PIX_FMT_YUVJ422P
                                                              : 
AV_PIX_FMT_YUV422P;
         } else {
-            return h->avctx->get_format(h->avctx, h->avctx->codec->pix_fmts ?
-                                        h->avctx->codec->pix_fmts :
-                                        h->avctx->color_range == 
AVCOL_RANGE_JPEG ?
-                                        h264_hwaccel_pixfmt_list_jpeg_420 :
-                                        h264_hwaccel_pixfmt_list_420);
+            return ff_get_format(h->avctx, h->avctx->codec->pix_fmts ?
+                                 h->avctx->codec->pix_fmts :
+                                 h->avctx->color_range == AVCOL_RANGE_JPEG ?
+                                 h264_hwaccel_pixfmt_list_jpeg_420 :
+                                 h264_hwaccel_pixfmt_list_420);
         }
         break;
     default:
@@ -1275,8 +1275,11 @@ int ff_h264_decode_slice_header(H264Context *h, 
H264Context *h0)
     h->avctx->refs    = h->sps.ref_frame_count;
 
     if (h->mb_width  != h->sps.mb_width ||
-        h->mb_height != h->sps.mb_height * (2 - h->sps.frame_mbs_only_flag))
+        h->mb_height != h->sps.mb_height * (2 - h->sps.frame_mbs_only_flag)) {
+        // size changes always need avctx->get_format() call
+        h->avctx->internal->current_pix_fmt = AV_PIX_FMT_NONE;
         needs_reinit = 1;
+    }
 
     h->mb_width  = h->sps.mb_width;
     h->mb_height = h->sps.mb_height * (2 - h->sps.frame_mbs_only_flag);
diff --git a/libavcodec/internal.h b/libavcodec/internal.h
index 268a758..10f3530 100644
--- a/libavcodec/internal.h
+++ b/libavcodec/internal.h
@@ -95,6 +95,13 @@ typedef struct AVCodecInternal {
      * packet into every function.
      */
     AVPacket *pkt;
+
+    /**
+     * AVPixelFormat returned by the last AVCodecContext.get_format() call.
+     * Used to avoid get_format() calls after flush/seeking if the pixel format
+     * has not changed.
+     */
+    enum AVPixelFormat current_pix_fmt;
 } AVCodecInternal;
 
 struct AVCodecDefault {
@@ -170,6 +177,14 @@ int ff_get_buffer(AVCodecContext *avctx, AVFrame *frame, 
int flags);
  */
 int ff_reget_buffer(AVCodecContext *avctx, AVFrame *frame);
 
+/**
+ * Let the user choose the preferred pixel format. This is a wrapper around
+ * AVCodecContext.get_format() and should be used instead calling get_format()
+ * directly when the codec supports AVHWAccels.
+ */
+enum AVPixelFormat ff_get_format(struct AVCodecContext *s,
+                                 const enum AVPixelFormat *fmt);
+
 const uint8_t *avpriv_find_start_code(const uint8_t *restrict p,
                                       const uint8_t *end,
                                       uint32_t *restrict state);
diff --git a/libavcodec/utils.c b/libavcodec/utils.c
index d9832e2..203ea8e 100644
--- a/libavcodec/utils.c
+++ b/libavcodec/utils.c
@@ -863,6 +863,25 @@ enum AVPixelFormat avcodec_default_get_format(struct 
AVCodecContext *s, const en
     return fmt[0];
 }
 
+enum AVPixelFormat ff_get_format(struct AVCodecContext *s,
+                                 const enum AVPixelFormat *fmt)
+{
+    unsigned i = 0;
+
+    if (s->internal->current_pix_fmt != AV_PIX_FMT_NONE &&
+        is_hwaccel_pix_fmt(s->internal->current_pix_fmt)) {
+        while (fmt[i] != AV_PIX_FMT_NONE) {
+            if (fmt[i] == s->internal->current_pix_fmt)
+                return s->internal->current_pix_fmt;
+            i++;
+        }
+    }
+
+    s->internal->current_pix_fmt = s->get_format(s, fmt);
+
+    return s->internal->current_pix_fmt;
+}
+
 #if FF_API_AVFRAME_LAVC
 void avcodec_get_frame_defaults(AVFrame *frame)
 {
@@ -942,6 +961,7 @@ int attribute_align_arg avcodec_open2(AVCodecContext 
*avctx, const AVCodec *code
         ret = AVERROR(ENOMEM);
         goto end;
     }
+    avctx->internal->current_pix_fmt = AV_PIX_FMT_NONE;
 
     avctx->internal->pool = av_mallocz(sizeof(*avctx->internal->pool));
     if (!avctx->internal->pool) {
-- 
1.9.2

_______________________________________________
libav-devel mailing list
[email protected]
https://lists.libav.org/mailman/listinfo/libav-devel

Reply via email to