]> git.sesse.net Git - ffmpeg/blobdiff - libavutil/hwcontext_qsv.c
lavu/hwcontext_qsv: Mark a pointer as const.
[ffmpeg] / libavutil / hwcontext_qsv.c
index 250091c4e85a26b16d018663a12c35ae3f403216..8f9838d7d819b64db7e5251988a6c77d871451ef 100644 (file)
 
 #include "config.h"
 
+#if HAVE_PTHREADS
+#include <pthread.h>
+#endif
+
 #if CONFIG_VAAPI
 #include "hwcontext_vaapi.h"
 #endif
@@ -56,7 +60,13 @@ typedef struct QSVDeviceContext {
 
 typedef struct QSVFramesContext {
     mfxSession session_download;
+    int session_download_init;
     mfxSession session_upload;
+    int session_upload_init;
+#if HAVE_PTHREADS
+    pthread_mutex_t session_lock;
+    pthread_cond_t session_cond;
+#endif
 
     AVBufferRef *child_frames_ref;
     mfxFrameSurface1 *surfaces_internal;
@@ -90,6 +100,7 @@ static const struct {
     uint32_t           fourcc;
 } supported_pixel_formats[] = {
     { AV_PIX_FMT_NV12, MFX_FOURCC_NV12 },
+    { AV_PIX_FMT_BGRA, MFX_FOURCC_RGB4 },
     { AV_PIX_FMT_P010, MFX_FOURCC_P010 },
     { AV_PIX_FMT_PAL8, MFX_FOURCC_P8   },
 };
@@ -147,12 +158,19 @@ static void qsv_frames_uninit(AVHWFramesContext *ctx)
         MFXClose(s->session_download);
     }
     s->session_download = NULL;
+    s->session_download_init = 0;
 
     if (s->session_upload) {
         MFXVideoVPP_Close(s->session_upload);
         MFXClose(s->session_upload);
     }
     s->session_upload = NULL;
+    s->session_upload_init = 0;
+
+#if HAVE_PTHREADS
+    pthread_mutex_destroy(&s->session_lock);
+    pthread_cond_destroy(&s->session_cond);
+#endif
 
     av_freep(&s->mem_ids);
     av_freep(&s->surface_ptrs);
@@ -371,7 +389,7 @@ static mfxStatus frame_alloc(mfxHDL pthis, mfxFrameAllocRequest *req,
         !(req->Type & (MFX_MEMTYPE_FROM_VPPIN | MFX_MEMTYPE_FROM_VPPOUT)) ||
         !(req->Type & MFX_MEMTYPE_EXTERNAL_FRAME))
         return MFX_ERR_UNSUPPORTED;
-    if (i->Width  != i1->Width || i->Height != i1->Height ||
+    if (i->Width  > i1->Width || i->Height > i1->Height ||
         i->FourCC != i1->FourCC || i->ChromaFormat != i1->ChromaFormat) {
         av_log(ctx, AV_LOG_ERROR, "Mismatching surface properties in an "
                "allocation request: %dx%d %d %d vs %dx%d %d %d\n",
@@ -535,13 +553,16 @@ static int qsv_frames_init(AVHWFramesContext *ctx)
             s->mem_ids[i] = frames_hwctx->surfaces[i].Data.MemId;
     }
 
-    ret = qsv_init_internal_session(ctx, &s->session_download, 0);
-    if (ret < 0)
-        return ret;
+    s->session_download = NULL;
+    s->session_upload   = NULL;
 
-    ret = qsv_init_internal_session(ctx, &s->session_upload, 1);
-    if (ret < 0)
-        return ret;
+    s->session_download_init = 0;
+    s->session_upload_init   = 0;
+
+#if HAVE_PTHREADS
+    pthread_mutex_init(&s->session_lock, NULL);
+    pthread_cond_init(&s->session_cond, NULL);
+#endif
 
     return 0;
 }
@@ -731,6 +752,37 @@ static int qsv_transfer_data_child(AVHWFramesContext *ctx, AVFrame *dst,
     return ret;
 }
 
+static int map_frame_to_surface(const AVFrame *frame, mfxFrameSurface1 *surface)
+{
+    switch (frame->format) {
+    case AV_PIX_FMT_NV12:
+    case AV_PIX_FMT_P010:
+        surface->Data.Y  = frame->data[0];
+        surface->Data.UV = frame->data[1];
+        break;
+
+    case AV_PIX_FMT_YUV420P:
+        surface->Data.Y = frame->data[0];
+        surface->Data.U = frame->data[1];
+        surface->Data.V = frame->data[2];
+        break;
+
+    case AV_PIX_FMT_BGRA:
+        surface->Data.B = frame->data[0];
+        surface->Data.G = frame->data[0] + 1;
+        surface->Data.R = frame->data[0] + 2;
+        surface->Data.A = frame->data[0] + 3;
+        break;
+
+    default:
+        return MFX_ERR_UNSUPPORTED;
+    }
+    surface->Data.Pitch     = frame->linesize[0];
+    surface->Data.TimeStamp = frame->pts;
+
+    return 0;
+}
+
 static int qsv_transfer_data_from(AVHWFramesContext *ctx, AVFrame *dst,
                                   const AVFrame *src)
 {
@@ -740,6 +792,32 @@ static int qsv_transfer_data_from(AVHWFramesContext *ctx, AVFrame *dst,
 
     mfxSyncPoint sync = NULL;
     mfxStatus err;
+    int ret = 0;
+
+    while (!s->session_download_init && !s->session_download && !ret) {
+#if HAVE_PTHREADS
+        if (pthread_mutex_trylock(&s->session_lock) == 0) {
+#endif
+            if (!s->session_download_init) {
+                ret = qsv_init_internal_session(ctx, &s->session_download, 0);
+                if (s->session_download)
+                    s->session_download_init = 1;
+            }
+#if HAVE_PTHREADS
+            pthread_mutex_unlock(&s->session_lock);
+            pthread_cond_signal(&s->session_cond);
+        } else {
+            pthread_mutex_lock(&s->session_lock);
+            while (!s->session_download_init && !s->session_download) {
+                pthread_cond_wait(&s->session_cond, &s->session_lock);
+            }
+            pthread_mutex_unlock(&s->session_lock);
+        }
+#endif
+    }
+
+    if (ret < 0)
+        return ret;
 
     if (!s->session_download) {
         if (s->child_frames_ref)
@@ -750,11 +828,7 @@ static int qsv_transfer_data_from(AVHWFramesContext *ctx, AVFrame *dst,
     }
 
     out.Info = in->Info;
-    out.Data.PitchLow = dst->linesize[0];
-    out.Data.Y        = dst->data[0];
-    out.Data.U        = dst->data[1];
-    out.Data.V        = dst->data[2];
-    out.Data.A        = dst->data[3];
+    map_frame_to_surface(dst, &out);
 
     do {
         err = MFXVideoVPP_RunFrameVPPAsync(s->session_download, in, &out, NULL, &sync);
@@ -787,21 +861,67 @@ static int qsv_transfer_data_to(AVHWFramesContext *ctx, AVFrame *dst,
 
     mfxSyncPoint sync = NULL;
     mfxStatus err;
+    int ret = 0;
+    /* make a copy if the input is not padded as libmfx requires */
+    AVFrame tmp_frame;
+    const AVFrame *src_frame;
+    int realigned = 0;
+
+
+    while (!s->session_upload_init && !s->session_upload && !ret) {
+#if HAVE_PTHREADS
+        if (pthread_mutex_trylock(&s->session_lock) == 0) {
+#endif
+            if (!s->session_upload_init) {
+                ret = qsv_init_internal_session(ctx, &s->session_upload, 1);
+                if (s->session_upload)
+                    s->session_upload_init = 1;
+            }
+#if HAVE_PTHREADS
+            pthread_mutex_unlock(&s->session_lock);
+            pthread_cond_signal(&s->session_cond);
+        } else {
+            pthread_mutex_lock(&s->session_lock);
+            while (!s->session_upload_init && !s->session_upload) {
+                pthread_cond_wait(&s->session_cond, &s->session_lock);
+            }
+            pthread_mutex_unlock(&s->session_lock);
+        }
+#endif
+    }
+    if (ret < 0)
+        return ret;
+
+
+    if (src->height & 16 || src->linesize[0] & 16) {
+        realigned = 1;
+        memset(&tmp_frame, 0, sizeof(tmp_frame));
+        tmp_frame.format         = src->format;
+        tmp_frame.width          = FFALIGN(src->width, 16);
+        tmp_frame.height         = FFALIGN(src->height, 16);
+        ret = av_frame_get_buffer(&tmp_frame, 32);
+        if (ret < 0)
+            return ret;
+
+        ret = av_frame_copy(&tmp_frame, src);
+        if (ret < 0) {
+            av_frame_unref(&tmp_frame);
+            return ret;
+        }
+    }
+
+    src_frame = realigned ? &tmp_frame : src;
 
     if (!s->session_upload) {
         if (s->child_frames_ref)
-            return qsv_transfer_data_child(ctx, dst, src);
+            return qsv_transfer_data_child(ctx, dst, src_frame);
 
         av_log(ctx, AV_LOG_ERROR, "Surface upload not possible\n");
         return AVERROR(ENOSYS);
     }
 
     in.Info = out->Info;
-    in.Data.PitchLow = src->linesize[0];
-    in.Data.Y        = src->data[0];
-    in.Data.U        = src->data[1];
-    in.Data.V        = src->data[2];
-    in.Data.A        = src->data[3];
+    map_frame_to_surface(src_frame, &in);
 
     do {
         err = MFXVideoVPP_RunFrameVPPAsync(s->session_upload, &in, out, NULL, &sync);
@@ -822,6 +942,9 @@ static int qsv_transfer_data_to(AVHWFramesContext *ctx, AVFrame *dst,
         return AVERROR_UNKNOWN;
     }
 
+    if (realigned)
+        av_frame_unref(&tmp_frame);
+
     return 0;
 }