]> git.sesse.net Git - ffmpeg/blobdiff - libavcodec/amfenc.c
Merge commit '23be4eebf8aaa7519b12b2a49e5c5c6c4d076e6a'
[ffmpeg] / libavcodec / amfenc.c
index 1ac4ebf45687d7c59402d911fc5678e4eeba906e..384d8efc92cf894014b4314cf5998abcfcb5f7bf 100644 (file)
 #if CONFIG_D3D11VA
 #include "libavutil/hwcontext_d3d11va.h"
 #endif
+#if CONFIG_DXVA2
+#define COBJMACROS
+#include "libavutil/hwcontext_dxva2.h"
+#endif
 #include "libavutil/mem.h"
 #include "libavutil/pixdesc.h"
 #include "libavutil/time.h"
@@ -50,6 +54,9 @@ const enum AVPixelFormat ff_amf_pix_fmts[] = {
     AV_PIX_FMT_YUV420P,
 #if CONFIG_D3D11VA
     AV_PIX_FMT_D3D11,
+#endif
+#if CONFIG_DXVA2
+    AV_PIX_FMT_DXVA2_VLD,
 #endif
     AV_PIX_FMT_NONE
 };
@@ -100,16 +107,11 @@ static AMFTraceWriterVtbl tracer_vtbl =
 
 static int amf_load_library(AVCodecContext *avctx)
 {
-    AmfContext             *ctx = avctx->priv_data;
-    AMFInit_Fn              init_fun = NULL;
-    AMFQueryVersion_Fn      version_fun = NULL;
-    AMF_RESULT              res = AMF_OK;
+    AmfContext        *ctx = avctx->priv_data;
+    AMFInit_Fn         init_fun;
+    AMFQueryVersion_Fn version_fun;
+    AMF_RESULT         res;
 
-    ctx->eof = 0;
-    ctx->delayed_drain = 0;
-    ctx->hw_frames_ctx = NULL;
-    ctx->hw_device_ctx = NULL;
-    ctx->delayed_surface = NULL;
     ctx->delayed_frame = av_frame_alloc();
     if (!ctx->delayed_frame) {
         return AVERROR(ENOMEM);
@@ -162,6 +164,52 @@ static int amf_init_from_d3d11_device(AVCodecContext *avctx, AVD3D11VADeviceCont
 }
 #endif
 
+#if CONFIG_DXVA2
+static int amf_init_from_dxva2_device(AVCodecContext *avctx, AVDXVA2DeviceContext *hwctx)
+{
+    AmfContext *ctx = avctx->priv_data;
+    HANDLE device_handle;
+    IDirect3DDevice9 *device;
+    HRESULT hr;
+    AMF_RESULT res;
+    int ret;
+
+    hr = IDirect3DDeviceManager9_OpenDeviceHandle(hwctx->devmgr, &device_handle);
+    if (FAILED(hr)) {
+        av_log(avctx, AV_LOG_ERROR, "Failed to open device handle for Direct3D9 device: %lx.\n", (unsigned long)hr);
+        return AVERROR_EXTERNAL;
+    }
+
+    hr = IDirect3DDeviceManager9_LockDevice(hwctx->devmgr, device_handle, &device, FALSE);
+    if (SUCCEEDED(hr)) {
+        IDirect3DDeviceManager9_UnlockDevice(hwctx->devmgr, device_handle, FALSE);
+        ret = 0;
+    } else {
+        av_log(avctx, AV_LOG_ERROR, "Failed to lock device handle for Direct3D9 device: %lx.\n", (unsigned long)hr);
+        ret = AVERROR_EXTERNAL;
+    }
+
+    IDirect3DDeviceManager9_CloseDeviceHandle(hwctx->devmgr, device_handle);
+
+    if (ret < 0)
+        return ret;
+
+    res = ctx->context->pVtbl->InitDX9(ctx->context, device);
+
+    IDirect3DDevice9_Release(device);
+
+    if (res != AMF_OK) {
+        if (res == AMF_NOT_SUPPORTED)
+            av_log(avctx, AV_LOG_ERROR, "AMF via D3D9 is not supported on the given device.\n");
+        else
+            av_log(avctx, AV_LOG_ERROR, "AMF failed to initialise on given D3D9 device: %d.\n", res);
+        return AVERROR(ENODEV);
+    }
+
+    return 0;
+}
+#endif
+
 static int amf_init_context(AVCodecContext *avctx)
 {
     AmfContext *ctx = avctx->priv_data;
@@ -205,6 +253,13 @@ static int amf_init_context(AVCodecContext *avctx)
             if (ret < 0)
                 return ret;
             break;
+#endif
+#if CONFIG_DXVA2
+        case AV_HWDEVICE_TYPE_DXVA2:
+            ret = amf_init_from_dxva2_device(avctx, frames_ctx->device_ctx->hwctx);
+            if (ret < 0)
+                return ret;
+            break;
 #endif
         default:
             av_log(avctx, AV_LOG_ERROR, "AMF initialisation from a %s frames context is not supported.\n",
@@ -229,6 +284,13 @@ static int amf_init_context(AVCodecContext *avctx)
             if (ret < 0)
                 return ret;
             break;
+#endif
+#if CONFIG_DXVA2
+        case AV_HWDEVICE_TYPE_DXVA2:
+            ret = amf_init_from_dxva2_device(avctx, device_ctx->hwctx);
+            if (ret < 0)
+                return ret;
+            break;
 #endif
         default:
             av_log(avctx, AV_LOG_ERROR, "AMF initialisation from a %s device is not supported.\n",
@@ -259,10 +321,10 @@ static int amf_init_context(AVCodecContext *avctx)
 
 static int amf_init_encoder(AVCodecContext *avctx)
 {
-    AmfContext          *ctx = avctx->priv_data;
-    const wchar_t       *codec_id = NULL;
-    AMF_RESULT           res = AMF_OK;
-    enum AVPixelFormat   pix_fmt;
+    AmfContext        *ctx = avctx->priv_data;
+    const wchar_t     *codec_id = NULL;
+    AMF_RESULT         res;
+    enum AVPixelFormat pix_fmt;
 
     switch (avctx->codec->id) {
         case AV_CODEC_ID_H264:
@@ -293,9 +355,9 @@ static int amf_init_encoder(AVCodecContext *avctx)
 
 int av_cold ff_amf_encode_close(AVCodecContext *avctx)
 {
-    AmfContext      *ctx = avctx->priv_data;
-    if (ctx->delayed_surface)
-    {
+    AmfContext *ctx = avctx->priv_data;
+
+    if (ctx->delayed_surface) {
         ctx->delayed_surface->pVtbl->Release(ctx->delayed_surface);
         ctx->delayed_surface = NULL;
     }
@@ -335,11 +397,11 @@ int av_cold ff_amf_encode_close(AVCodecContext *avctx)
 static int amf_copy_surface(AVCodecContext *avctx, const AVFrame *frame,
     AMFSurface* surface)
 {
-    AMFPlane       *plane = NULL;
-    uint8_t        *dst_data[4];
-    int             dst_linesize[4];
-    int             planes;
-    int             i;
+    AMFPlane *plane;
+    uint8_t  *dst_data[4];
+    int       dst_linesize[4];
+    int       planes;
+    int       i;
 
     planes = surface->pVtbl->GetPlanesCount(surface);
     av_assert0(planes < FF_ARRAY_ELEMS(dst_data));
@@ -370,11 +432,11 @@ static inline int timestamp_queue_enqueue(AVCodecContext *avctx, int64_t timesta
 
 static int amf_copy_buffer(AVCodecContext *avctx, AVPacket *pkt, AMFBuffer *buffer)
 {
-    AmfContext             *ctx = avctx->priv_data;
-    int                     ret;
-    AMFVariantStruct        var = {0};
-    int64_t                 timestamp = AV_NOPTS_VALUE;
-    int64_t                 size = buffer->pVtbl->GetSize(buffer);
+    AmfContext      *ctx = avctx->priv_data;
+    int              ret;
+    AMFVariantStruct var = {0};
+    int64_t          timestamp = AV_NOPTS_VALUE;
+    int64_t          size = buffer->pVtbl->GetSize(buffer);
 
     if ((ret = ff_alloc_packet2(avctx, pkt, size, 0)) < 0) {
         return ret;
@@ -430,20 +492,7 @@ static int amf_copy_buffer(AVCodecContext *avctx, AVPacket *pkt, AMFBuffer *buff
 // amfenc API implementation
 int ff_amf_encode_init(AVCodecContext *avctx)
 {
-    AmfContext     *ctx = avctx->priv_data;
-    int             ret;
-
-    ctx->factory = NULL;
-    ctx->debug = NULL;
-    ctx->trace = NULL;
-    ctx->context = NULL;
-    ctx->encoder = NULL;
-    ctx->library = NULL;
-    ctx->version = 0;
-    ctx->eof = 0;
-    ctx->format = 0;
-    ctx->tracer.vtbl = NULL;
-    ctx->tracer.avctx = NULL;
+    int ret;
 
     if ((ret = amf_load_library(avctx)) == 0) {
         if ((ret = amf_init_context(avctx)) == 0) {
@@ -520,18 +569,18 @@ static AMFBuffer *amf_create_buffer_with_frame_ref(const AVFrame *frame, AMFCont
 
 static void amf_release_buffer_with_frame_ref(AMFBuffer *frame_ref_storage_buffer)
 {
-    AVFrame *av_frame_ref;
-    memcpy(&av_frame_ref, frame_ref_storage_buffer->pVtbl->GetNative(frame_ref_storage_buffer), sizeof(av_frame_ref));
-    av_frame_free(&av_frame_ref);
+    AVFrame *frame_ref;
+    memcpy(&frame_ref, frame_ref_storage_buffer->pVtbl->GetNative(frame_ref_storage_buffer), sizeof(frame_ref));
+    av_frame_free(&frame_ref);
     frame_ref_storage_buffer->pVtbl->Release(frame_ref_storage_buffer);
 }
 
 int ff_amf_send_frame(AVCodecContext *avctx, const AVFrame *frame)
 {
-    AMF_RESULT      res = AMF_OK;
-    AmfContext     *ctx = avctx->priv_data;
-    AMFSurface     *surface = NULL;
-    int             ret;
+    AmfContext *ctx = avctx->priv_data;
+    AMFSurface *surface;
+    AMF_RESULT  res;
+    int         ret;
 
     if (!ctx->encoder)
         return AVERROR(EINVAL);
@@ -580,6 +629,18 @@ int ff_amf_send_frame(AVCodecContext *avctx, const AVFrame *frame)
                 hw_surface = 1;
             }
             break;
+#endif
+#if CONFIG_DXVA2
+        case AV_PIX_FMT_DXVA2_VLD:
+            {
+                IDirect3DSurface9 *texture = (IDirect3DSurface9 *)frame->data[3]; // actual texture
+
+                res = ctx->context->pVtbl->CreateSurfaceFromDX9Native(ctx->context, texture, &surface, NULL); // wrap to AMF surface
+                AMF_RETURN_IF_FALSE(ctx, res == AMF_OK, AVERROR(ENOMEM), "CreateSurfaceFromDX9Native() failed  with error %d\n", res);
+
+                hw_surface = 1;
+            }
+            break;
 #endif
         default:
             {