From 21014bcfa3cfa56b993d56c5697167b889228f08 Mon Sep 17 00:00:00 2001
From: Andrey Orlov <andrey.orlov@intel.com>
Date: Wed, 18 Sep 2019 16:19:52 +0300
Subject: [PATCH] avcodec/qsv: polling free synchronization

synchronization by sync point after DEVICE_BUSY

Fixes: CPU usage on AVC decode cases (18% -> 9%)
---
 libavcodec/qsv.c          | 17 +++++++++++++++++
 libavcodec/qsv_internal.h |  2 ++
 libavcodec/qsvdec.c       | 12 ++++++++----
 libavcodec/qsvdec.h       |  2 ++
 libavcodec/qsvenc.c       | 13 +++++++++----
 libavcodec/qsvenc.h       |  2 ++
 6 files changed, 40 insertions(+), 8 deletions(-)

diff --git a/libavcodec/qsv.c b/libavcodec/qsv.c
index 65ad070e1f..fd5e52dbfd 100644
--- a/libavcodec/qsv.c
+++ b/libavcodec/qsv.c
@@ -32,6 +32,7 @@
 #include "libavutil/hwcontext_qsv.h"
 #include "libavutil/imgutils.h"
 #include "libavutil/avassert.h"
+#include "libavutil/time.h"
 
 #include "avcodec.h"
 #include "qsv_internal.h"
@@ -758,3 +759,19 @@ int ff_qsv_init_session_frames(AVCodecContext *avctx, mfxSession *psession,
     *psession = session;
     return 0;
 }
+
+void ff_qsv_handle_device_busy(mfxSession *session, mfxSyncPoint *sync, mfxStatus *ret, unsigned sleep)
+{
+    int sync_ret;
+
+    if (*sync) {
+        sync_ret = MFXVideoCORE_SyncOperation(*session, *sync, MFX_INFINITE);
+        if (sync_ret == MFX_ERR_NONE) {
+            *sync = NULL;
+        } else {
+            *ret = MFX_ERR_ABORTED;
+        }
+    } else {
+        av_usleep(sleep);
+    }
+}
diff --git a/libavcodec/qsv_internal.h b/libavcodec/qsv_internal.h
index c50e9c792c..9e3921e815 100644
--- a/libavcodec/qsv_internal.h
+++ b/libavcodec/qsv_internal.h
@@ -111,4 +111,6 @@ int ff_qsv_init_session_frames(AVCodecContext *avctx, mfxSession *session,
 
 int ff_qsv_find_surface_idx(QSVFramesContext *ctx, QSVFrame *frame);
 
+void ff_qsv_handle_device_busy(mfxSession *session, mfxSyncPoint *sync, mfxStatus *ret, unsigned sleep);
+
 #endif /* AVCODEC_QSV_INTERNAL_H */
diff --git a/libavcodec/qsvdec.c b/libavcodec/qsvdec.c
index eef4fe7138..245163f932 100644
--- a/libavcodec/qsvdec.c
+++ b/libavcodec/qsvdec.c
@@ -404,8 +404,12 @@ static int qsv_decode(AVCodecContext *avctx, QSVContext *q,
 
         ret = MFXVideoDECODE_DecodeFrameAsync(q->session, avpkt->size ? &bs : NULL,
                                               insurf, &outsurf, sync);
+
+        if (ret == MFX_ERR_NONE)
+            q->last_dec_sync = *sync;
+
         if (ret == MFX_WRN_DEVICE_BUSY)
-            av_usleep(500);
+            ff_qsv_handle_device_busy(&q->session, &q->last_dec_sync, &ret, 500);
 
     } while (ret == MFX_WRN_DEVICE_BUSY || ret == MFX_ERR_MORE_SURFACE);
 
@@ -457,9 +461,9 @@ static int qsv_decode(AVCodecContext *avctx, QSVContext *q,
         out_frame->queued = 0;
 
         if (avctx->pix_fmt != AV_PIX_FMT_QSV) {
-            do {
-                ret = MFXVideoCORE_SyncOperation(q->session, *sync, 1000);
-            } while (ret == MFX_WRN_IN_EXECUTION);
+            ret = MFXVideoCORE_SyncOperation(q->session, *sync, MFX_INFINITE);
+            if (ret < 0)
+                return ret;
         }
 
         av_freep(&sync);
diff --git a/libavcodec/qsvdec.h b/libavcodec/qsvdec.h
index c057bc6722..0b9198c86c 100644
--- a/libavcodec/qsvdec.h
+++ b/libavcodec/qsvdec.h
@@ -70,6 +70,8 @@ typedef struct QSVContext {
 
     mfxExtBuffer **ext_buffers;
     int         nb_ext_buffers;
+
+    mfxSyncPoint last_dec_sync;
 } QSVContext;
 
 extern const AVCodecHWConfigInternal *ff_qsv_hw_configs[];
diff --git a/libavcodec/qsvenc.c b/libavcodec/qsvenc.c
index 9bf8574e30..08535151f6 100644
--- a/libavcodec/qsvenc.c
+++ b/libavcodec/qsvenc.c
@@ -1366,8 +1366,13 @@ static int encode_frame(AVCodecContext *avctx, QSVEncContext *q,
 
     do {
         ret = MFXVideoENCODE_EncodeFrameAsync(q->session, enc_ctrl, surf, bs, sync);
+
+        if (ret == MFX_ERR_NONE)
+            q->last_enc_sync = *sync;
+
         if (ret == MFX_WRN_DEVICE_BUSY)
-            av_usleep(500);
+            ff_qsv_handle_device_busy(&q->session, &q->last_enc_sync, &ret, 500);
+
     } while (ret == MFX_WRN_DEVICE_BUSY || ret == MFX_WRN_IN_EXECUTION);
 
     if (ret > 0)
@@ -1433,9 +1438,9 @@ int ff_qsv_encode(AVCodecContext *avctx, QSVEncContext *q,
         av_fifo_generic_read(q->async_fifo, &sync,    sizeof(sync),    NULL);
         av_fifo_generic_read(q->async_fifo, &bs,      sizeof(bs),      NULL);
 
-        do {
-            ret = MFXVideoCORE_SyncOperation(q->session, *sync, 1000);
-        } while (ret == MFX_WRN_IN_EXECUTION);
+        ret = MFXVideoCORE_SyncOperation(q->session, *sync, MFX_INFINITE);
+        if (ret < 0)
+            return ret;
 
         new_pkt.dts  = av_rescale_q(bs->DecodeTimeStamp, (AVRational){1, 90000}, avctx->time_base);
         new_pkt.pts  = av_rescale_q(bs->TimeStamp,       (AVRational){1, 90000}, avctx->time_base);
diff --git a/libavcodec/qsvenc.h b/libavcodec/qsvenc.h
index f2f4d38503..6b81e86a63 100644
--- a/libavcodec/qsvenc.h
+++ b/libavcodec/qsvenc.h
@@ -185,6 +185,8 @@ typedef struct QSVEncContext {
     char *load_plugins;
     SetEncodeCtrlCB *set_encode_ctrl_cb;
     int forced_idr;
+
+    mfxSyncPoint last_enc_sync;
 } QSVEncContext;
 
 int ff_qsv_enc_init(AVCodecContext *avctx, QSVEncContext *q);
-- 
2.17.1

