mfxStatus Initialize(mfxIMPL impl, mfxVersion ver, mfxSession *pSession, mfxFrameAllocator* pmfxAllocator, bool bCreateSharedHandles) { mfxStatus sts = MFX_ERR_NONE; // Initialize Intel Media SDK Session sts = MFXInit(impl, &ver, pSession); MSDK_CHECK_RESULT(sts, MFX_ERR_NONE, sts); // Create VA display mfxHDL displayHandle = { 0 }; sts = CreateVAEnvDRM(&displayHandle); MSDK_CHECK_RESULT(sts, MFX_ERR_NONE, sts); // Provide VA display handle to Media SDK sts = MFXVideoCORE_SetHandle(*pSession, MFX_HANDLE_VA_DISPLAY, displayHandle); MSDK_CHECK_RESULT(sts, MFX_ERR_NONE, sts); // If mfxFrameAllocator is provided it means we need to setup memory allocator if (pmfxAllocator) { pmfxAllocator->pthis = *pSession; // We use Media SDK session ID as the allocation identifier pmfxAllocator->Alloc = simple_alloc; pmfxAllocator->Free = simple_free; pmfxAllocator->Lock = simple_lock; pmfxAllocator->Unlock = simple_unlock; pmfxAllocator->GetHDL = simple_gethdl; // Since we are using video memory we must provide Media SDK with an external allocator sts = MFXVideoCORE_SetFrameAllocator(*pSession, pmfxAllocator); MSDK_CHECK_RESULT(sts, MFX_ERR_NONE, sts); } return sts; }
/* create the QSV session */ static int init_vpp_session(AVFilterContext *avctx, QSVVPPContext *s) { AVFilterLink *inlink = avctx->inputs[0]; AVFilterLink *outlink = avctx->outputs[0]; AVQSVFramesContext *in_frames_hwctx = NULL; AVQSVFramesContext *out_frames_hwctx = NULL; AVBufferRef *device_ref; AVHWDeviceContext *device_ctx; AVQSVDeviceContext *device_hwctx; mfxHDL handle; mfxHandleType handle_type; mfxVersion ver; mfxIMPL impl; int ret, i; if (inlink->hw_frames_ctx) { AVHWFramesContext *frames_ctx = (AVHWFramesContext *)inlink->hw_frames_ctx->data; device_ref = frames_ctx->device_ref; in_frames_hwctx = frames_ctx->hwctx; s->in_mem_mode = in_frames_hwctx->frame_type; s->surface_ptrs_in = av_mallocz_array(in_frames_hwctx->nb_surfaces, sizeof(*s->surface_ptrs_in)); if (!s->surface_ptrs_in) return AVERROR(ENOMEM); for (i = 0; i < in_frames_hwctx->nb_surfaces; i++) s->surface_ptrs_in[i] = in_frames_hwctx->surfaces + i; s->nb_surface_ptrs_in = in_frames_hwctx->nb_surfaces; } else if (avctx->hw_device_ctx) { device_ref = avctx->hw_device_ctx; s->in_mem_mode = MFX_MEMTYPE_SYSTEM_MEMORY; } else { av_log(avctx, AV_LOG_ERROR, "No hw context provided.\n"); return AVERROR(EINVAL); } device_ctx = (AVHWDeviceContext *)device_ref->data; device_hwctx = device_ctx->hwctx; if (outlink->format == AV_PIX_FMT_QSV) { AVHWFramesContext *out_frames_ctx; AVBufferRef *out_frames_ref = av_hwframe_ctx_alloc(device_ref); if (!out_frames_ref) return AVERROR(ENOMEM); s->out_mem_mode = IS_OPAQUE_MEMORY(s->in_mem_mode) ? MFX_MEMTYPE_OPAQUE_FRAME : MFX_MEMTYPE_VIDEO_MEMORY_DECODER_TARGET; out_frames_ctx = (AVHWFramesContext *)out_frames_ref->data; out_frames_hwctx = out_frames_ctx->hwctx; out_frames_ctx->format = AV_PIX_FMT_QSV; out_frames_ctx->width = FFALIGN(outlink->w, 32); out_frames_ctx->height = FFALIGN(outlink->h, 32); out_frames_ctx->sw_format = s->out_sw_format; out_frames_ctx->initial_pool_size = 64; out_frames_hwctx->frame_type = s->out_mem_mode; ret = av_hwframe_ctx_init(out_frames_ref); if (ret < 0) { av_buffer_unref(&out_frames_ref); av_log(avctx, AV_LOG_ERROR, "Error creating frames_ctx for output pad.\n"); return ret; } s->surface_ptrs_out = av_mallocz_array(out_frames_hwctx->nb_surfaces, sizeof(*s->surface_ptrs_out)); if (!s->surface_ptrs_out) { av_buffer_unref(&out_frames_ref); return AVERROR(ENOMEM); } for (i = 0; i < out_frames_hwctx->nb_surfaces; i++) s->surface_ptrs_out[i] = out_frames_hwctx->surfaces + i; s->nb_surface_ptrs_out = out_frames_hwctx->nb_surfaces; av_buffer_unref(&outlink->hw_frames_ctx); outlink->hw_frames_ctx = out_frames_ref; } else s->out_mem_mode = MFX_MEMTYPE_SYSTEM_MEMORY; /* extract the properties of the "master" session given to us */ ret = MFXQueryIMPL(device_hwctx->session, &impl); if (ret == MFX_ERR_NONE) ret = MFXQueryVersion(device_hwctx->session, &ver); if (ret != MFX_ERR_NONE) { av_log(avctx, AV_LOG_ERROR, "Error querying the session attributes\n"); return AVERROR_UNKNOWN; } for (i = 0; i < FF_ARRAY_ELEMS(handle_types); i++) { ret = MFXVideoCORE_GetHandle(device_hwctx->session, handle_types[i], &handle); if (ret == MFX_ERR_NONE) { handle_type = handle_types[i]; break; } } if (ret != MFX_ERR_NONE) { av_log(avctx, AV_LOG_ERROR, "Error getting the session handle\n"); return AVERROR_UNKNOWN; } /* create a "slave" session with those same properties, to be used for vpp */ ret = MFXInit(impl, &ver, &s->session); if (ret != MFX_ERR_NONE) { av_log(avctx, AV_LOG_ERROR, "Error initializing a session for scaling\n"); return AVERROR_UNKNOWN; } if (handle) { ret = MFXVideoCORE_SetHandle(s->session, handle_type, handle); if (ret != MFX_ERR_NONE) return AVERROR_UNKNOWN; } if (QSV_RUNTIME_VERSION_ATLEAST(ver, 1, 25)) { ret = MFXJoinSession(device_hwctx->session, s->session); if (ret != MFX_ERR_NONE) return AVERROR_UNKNOWN; } if (IS_OPAQUE_MEMORY(s->in_mem_mode) || IS_OPAQUE_MEMORY(s->out_mem_mode)) { s->opaque_alloc.In.Surfaces = s->surface_ptrs_in; s->opaque_alloc.In.NumSurface = s->nb_surface_ptrs_in; s->opaque_alloc.In.Type = s->in_mem_mode; s->opaque_alloc.Out.Surfaces = s->surface_ptrs_out; s->opaque_alloc.Out.NumSurface = s->nb_surface_ptrs_out; s->opaque_alloc.Out.Type = s->out_mem_mode; s->opaque_alloc.Header.BufferId = MFX_EXTBUFF_OPAQUE_SURFACE_ALLOCATION; s->opaque_alloc.Header.BufferSz = sizeof(s->opaque_alloc); } else if (IS_VIDEO_MEMORY(s->in_mem_mode) || IS_VIDEO_MEMORY(s->out_mem_mode)) { mfxFrameAllocator frame_allocator = { .pthis = s, .Alloc = frame_alloc, .Lock = frame_lock, .Unlock = frame_unlock, .GetHDL = frame_get_hdl, .Free = frame_free, }; ret = MFXVideoCORE_SetFrameAllocator(s->session, &frame_allocator); if (ret != MFX_ERR_NONE) return AVERROR_UNKNOWN; }
static int init_out_session(AVFilterContext *ctx) { QSVScaleContext *s = ctx->priv; AVHWFramesContext *in_frames_ctx = (AVHWFramesContext*)ctx->inputs[0]->hw_frames_ctx->data; AVHWFramesContext *out_frames_ctx = (AVHWFramesContext*)ctx->outputs[0]->hw_frames_ctx->data; AVQSVFramesContext *in_frames_hwctx = in_frames_ctx->hwctx; AVQSVFramesContext *out_frames_hwctx = out_frames_ctx->hwctx; AVQSVDeviceContext *device_hwctx = in_frames_ctx->device_ctx->hwctx; int opaque = !!(in_frames_hwctx->frame_type & MFX_MEMTYPE_OPAQUE_FRAME); mfxHDL handle = NULL; mfxHandleType handle_type; mfxVersion ver; mfxIMPL impl; mfxVideoParam par; mfxStatus err; int i; /* extract the properties of the "master" session given to us */ err = MFXQueryIMPL(device_hwctx->session, &impl); if (err == MFX_ERR_NONE) err = MFXQueryVersion(device_hwctx->session, &ver); if (err != MFX_ERR_NONE) { av_log(ctx, AV_LOG_ERROR, "Error querying the session attributes\n"); return AVERROR_UNKNOWN; } for (i = 0; i < FF_ARRAY_ELEMS(handle_types); i++) { err = MFXVideoCORE_GetHandle(device_hwctx->session, handle_types[i], &handle); if (err == MFX_ERR_NONE) { handle_type = handle_types[i]; break; } } /* create a "slave" session with those same properties, to be used for * actual scaling */ err = MFXInit(impl, &ver, &s->session); if (err != MFX_ERR_NONE) { av_log(ctx, AV_LOG_ERROR, "Error initializing a session for scaling\n"); return AVERROR_UNKNOWN; } if (handle) { err = MFXVideoCORE_SetHandle(s->session, handle_type, handle); if (err != MFX_ERR_NONE) return AVERROR_UNKNOWN; } memset(&par, 0, sizeof(par)); if (opaque) { s->surface_ptrs_in = av_mallocz_array(in_frames_hwctx->nb_surfaces, sizeof(*s->surface_ptrs_in)); if (!s->surface_ptrs_in) return AVERROR(ENOMEM); for (i = 0; i < in_frames_hwctx->nb_surfaces; i++) s->surface_ptrs_in[i] = in_frames_hwctx->surfaces + i; s->nb_surface_ptrs_in = in_frames_hwctx->nb_surfaces; s->surface_ptrs_out = av_mallocz_array(out_frames_hwctx->nb_surfaces, sizeof(*s->surface_ptrs_out)); if (!s->surface_ptrs_out) return AVERROR(ENOMEM); for (i = 0; i < out_frames_hwctx->nb_surfaces; i++) s->surface_ptrs_out[i] = out_frames_hwctx->surfaces + i; s->nb_surface_ptrs_out = out_frames_hwctx->nb_surfaces; s->opaque_alloc.In.Surfaces = s->surface_ptrs_in; s->opaque_alloc.In.NumSurface = s->nb_surface_ptrs_in; s->opaque_alloc.In.Type = in_frames_hwctx->frame_type; s->opaque_alloc.Out.Surfaces = s->surface_ptrs_out; s->opaque_alloc.Out.NumSurface = s->nb_surface_ptrs_out; s->opaque_alloc.Out.Type = out_frames_hwctx->frame_type; s->opaque_alloc.Header.BufferId = MFX_EXTBUFF_OPAQUE_SURFACE_ALLOCATION; s->opaque_alloc.Header.BufferSz = sizeof(s->opaque_alloc); s->ext_buffers[0] = (mfxExtBuffer*)&s->opaque_alloc; par.ExtParam = s->ext_buffers; par.NumExtParam = FF_ARRAY_ELEMS(s->ext_buffers); par.IOPattern = MFX_IOPATTERN_IN_OPAQUE_MEMORY | MFX_IOPATTERN_OUT_OPAQUE_MEMORY; } else { mfxFrameAllocator frame_allocator = { .pthis = ctx, .Alloc = frame_alloc, .Lock = frame_lock, .Unlock = frame_unlock, .GetHDL = frame_get_hdl, .Free = frame_free, }; s->mem_ids_in = av_mallocz_array(in_frames_hwctx->nb_surfaces, sizeof(*s->mem_ids_in)); if (!s->mem_ids_in) return AVERROR(ENOMEM); for (i = 0; i < in_frames_hwctx->nb_surfaces; i++) s->mem_ids_in[i] = in_frames_hwctx->surfaces[i].Data.MemId; s->nb_mem_ids_in = in_frames_hwctx->nb_surfaces; s->mem_ids_out = av_mallocz_array(out_frames_hwctx->nb_surfaces, sizeof(*s->mem_ids_out)); if (!s->mem_ids_out) return AVERROR(ENOMEM); for (i = 0; i < out_frames_hwctx->nb_surfaces; i++) s->mem_ids_out[i] = out_frames_hwctx->surfaces[i].Data.MemId; s->nb_mem_ids_out = out_frames_hwctx->nb_surfaces; err = MFXVideoCORE_SetFrameAllocator(s->session, &frame_allocator); if (err != MFX_ERR_NONE) return AVERROR_UNKNOWN; par.IOPattern = MFX_IOPATTERN_IN_VIDEO_MEMORY | MFX_IOPATTERN_OUT_VIDEO_MEMORY; } par.AsyncDepth = 1; // TODO async par.vpp.In = in_frames_hwctx->surfaces[0].Info; par.vpp.Out = out_frames_hwctx->surfaces[0].Info; /* Apparently VPP requires the frame rate to be set to some value, otherwise * init will fail (probably for the framerate conversion filter). Since we * are only doing scaling here, we just invent an arbitrary * value */ par.vpp.In.FrameRateExtN = 25; par.vpp.In.FrameRateExtD = 1; par.vpp.Out.FrameRateExtN = 25; par.vpp.Out.FrameRateExtD = 1; err = MFXVideoVPP_Init(s->session, &par); if (err != MFX_ERR_NONE) { av_log(ctx, AV_LOG_ERROR, "Error opening the VPP for scaling\n"); return AVERROR_UNKNOWN; } return 0; }
static int qsv_init_internal_session(AVHWFramesContext *ctx, mfxSession *session, int upload) { QSVFramesContext *s = ctx->internal->priv; AVQSVFramesContext *frames_hwctx = ctx->hwctx; QSVDeviceContext *device_priv = ctx->device_ctx->internal->priv; int opaque = !!(frames_hwctx->frame_type & MFX_MEMTYPE_OPAQUE_FRAME); mfxFrameAllocator frame_allocator = { .pthis = ctx, .Alloc = frame_alloc, .Lock = frame_lock, .Unlock = frame_unlock, .GetHDL = frame_get_hdl, .Free = frame_free, }; mfxVideoParam par; mfxStatus err; err = MFXInit(device_priv->impl, &device_priv->ver, session); if (err != MFX_ERR_NONE) { av_log(ctx, AV_LOG_ERROR, "Error initializing an internal session\n"); return AVERROR_UNKNOWN; } if (device_priv->handle) { err = MFXVideoCORE_SetHandle(*session, device_priv->handle_type, device_priv->handle); if (err != MFX_ERR_NONE) return AVERROR_UNKNOWN; } if (!opaque) { err = MFXVideoCORE_SetFrameAllocator(*session, &frame_allocator); if (err != MFX_ERR_NONE) return AVERROR_UNKNOWN; } memset(&par, 0, sizeof(par)); if (opaque) { par.ExtParam = s->ext_buffers; par.NumExtParam = FF_ARRAY_ELEMS(s->ext_buffers); par.IOPattern = upload ? MFX_IOPATTERN_OUT_OPAQUE_MEMORY : MFX_IOPATTERN_IN_OPAQUE_MEMORY; } else { par.IOPattern = upload ? MFX_IOPATTERN_OUT_VIDEO_MEMORY : MFX_IOPATTERN_IN_VIDEO_MEMORY; } par.IOPattern |= upload ? MFX_IOPATTERN_IN_SYSTEM_MEMORY : MFX_IOPATTERN_OUT_SYSTEM_MEMORY; par.AsyncDepth = 1; par.vpp.In = frames_hwctx->surfaces[0].Info; /* Apparently VPP requires the frame rate to be set to some value, otherwise * init will fail (probably for the framerate conversion filter). Since we * are only doing data upload/download here, we just invent an arbitrary * value */ par.vpp.In.FrameRateExtN = 25; par.vpp.In.FrameRateExtD = 1; par.vpp.Out = par.vpp.In; err = MFXVideoVPP_Init(*session, &par); if (err != MFX_ERR_NONE) { av_log(ctx, AV_LOG_VERBOSE, "Error opening the internal VPP session." "Surface upload/download will not be possible\n"); MFXClose(*session); *session = NULL; } return 0; }
static int qsv_device_derive_from_child(AVHWDeviceContext *ctx, mfxIMPL implementation, AVHWDeviceContext *child_device_ctx, int flags) { AVQSVDeviceContext *hwctx = ctx->hwctx; mfxVersion ver = { { 3, 1 } }; mfxHDL handle; mfxHandleType handle_type; mfxStatus err; int ret; switch (child_device_ctx->type) { #if CONFIG_VAAPI case AV_HWDEVICE_TYPE_VAAPI: { AVVAAPIDeviceContext *child_device_hwctx = child_device_ctx->hwctx; handle_type = MFX_HANDLE_VA_DISPLAY; handle = (mfxHDL)child_device_hwctx->display; } break; #endif #if CONFIG_DXVA2 case AV_HWDEVICE_TYPE_DXVA2: { AVDXVA2DeviceContext *child_device_hwctx = child_device_ctx->hwctx; handle_type = MFX_HANDLE_D3D9_DEVICE_MANAGER; handle = (mfxHDL)child_device_hwctx->devmgr; } break; #endif default: ret = AVERROR(ENOSYS); goto fail; } err = MFXInit(implementation, &ver, &hwctx->session); if (err != MFX_ERR_NONE) { av_log(ctx, AV_LOG_ERROR, "Error initializing an MFX session: " "%d.\n", err); ret = AVERROR_UNKNOWN; goto fail; } err = MFXQueryVersion(hwctx->session, &ver); if (err != MFX_ERR_NONE) { av_log(ctx, AV_LOG_ERROR, "Error querying an MFX session: %d.\n", err); ret = AVERROR_UNKNOWN; goto fail; } av_log(ctx, AV_LOG_VERBOSE, "Initialize MFX session: API version is %d.%d, implementation version is %d.%d\n", MFX_VERSION_MAJOR, MFX_VERSION_MINOR, ver.Major, ver.Minor); MFXClose(hwctx->session); err = MFXInit(implementation, &ver, &hwctx->session); if (err != MFX_ERR_NONE) { av_log(ctx, AV_LOG_ERROR, "Error initializing an MFX session: %d.\n", err); ret = AVERROR_UNKNOWN; goto fail; } err = MFXVideoCORE_SetHandle(hwctx->session, handle_type, handle); if (err != MFX_ERR_NONE) { av_log(ctx, AV_LOG_ERROR, "Error setting child device handle: " "%d\n", err); ret = AVERROR_UNKNOWN; goto fail; } ret = MFXQueryVersion(hwctx->session,&ver); if (ret == MFX_ERR_NONE) { av_log(ctx, AV_LOG_VERBOSE, "MFX compile/runtime API: %d.%d/%d.%d\n", MFX_VERSION_MAJOR, MFX_VERSION_MINOR, ver.Major, ver.Minor); } return 0; fail: if (hwctx->session) MFXClose(hwctx->session); return ret; }
static int qsv_device_create(AVHWDeviceContext *ctx, const char *device, AVDictionary *opts, int flags) { AVQSVDeviceContext *hwctx = ctx->hwctx; QSVDevicePriv *priv; enum AVHWDeviceType child_device_type; AVDictionaryEntry *e; mfxVersion ver = { { 3, 1 } }; mfxIMPL impl; mfxHDL handle; mfxHandleType handle_type; mfxStatus err; int ret; priv = av_mallocz(sizeof(*priv)); if (!priv) return AVERROR(ENOMEM); ctx->user_opaque = priv; ctx->free = qsv_device_free; e = av_dict_get(opts, "child_device", NULL, 0); if (CONFIG_VAAPI) child_device_type = AV_HWDEVICE_TYPE_VAAPI; else if (CONFIG_DXVA2) child_device_type = AV_HWDEVICE_TYPE_DXVA2; else { av_log(ctx, AV_LOG_ERROR, "No supported child device type is enabled\n"); return AVERROR(ENOSYS); } ret = av_hwdevice_ctx_create(&priv->child_device_ctx, child_device_type, e ? e->value : NULL, NULL, 0); if (ret < 0) return ret; { AVHWDeviceContext *child_device_ctx = (AVHWDeviceContext*)priv->child_device_ctx->data; #if CONFIG_VAAPI AVVAAPIDeviceContext *child_device_hwctx = child_device_ctx->hwctx; handle_type = MFX_HANDLE_VA_DISPLAY; handle = (mfxHDL)child_device_hwctx->display; #elif CONFIG_DXVA2 AVDXVA2DeviceContext *child_device_hwctx = child_device_ctx->hwctx; handle_type = MFX_HANDLE_D3D9_DEVICE_MANAGER; handle = (mfxHDL)child_device_hwctx->devmgr; #endif } impl = choose_implementation(device); err = MFXInit(impl, &ver, &hwctx->session); if (err != MFX_ERR_NONE) { av_log(ctx, AV_LOG_ERROR, "Error initializing an MFX session\n"); return AVERROR_UNKNOWN; } err = MFXVideoCORE_SetHandle(hwctx->session, handle_type, handle); if (err != MFX_ERR_NONE) return AVERROR_UNKNOWN; return 0; }
int ff_qsv_init_session_device(AVCodecContext *avctx, mfxSession *psession, AVBufferRef *device_ref, const char *load_plugins) { static const mfxHandleType handle_types[] = { MFX_HANDLE_VA_DISPLAY, MFX_HANDLE_D3D9_DEVICE_MANAGER, MFX_HANDLE_D3D11_DEVICE, }; AVHWDeviceContext *device_ctx = (AVHWDeviceContext*)device_ref->data; AVQSVDeviceContext *device_hwctx = device_ctx->hwctx; mfxSession parent_session = device_hwctx->session; mfxSession session; mfxVersion ver; mfxIMPL impl; mfxHDL handle = NULL; mfxHandleType handle_type; mfxStatus err; int i, ret; err = MFXQueryIMPL(parent_session, &impl); if (err == MFX_ERR_NONE) err = MFXQueryVersion(parent_session, &ver); if (err != MFX_ERR_NONE) return ff_qsv_print_error(avctx, err, "Error querying the session attributes"); for (i = 0; i < FF_ARRAY_ELEMS(handle_types); i++) { err = MFXVideoCORE_GetHandle(parent_session, handle_types[i], &handle); if (err == MFX_ERR_NONE) { handle_type = handle_types[i]; break; } handle = NULL; } if (!handle) { av_log(avctx, AV_LOG_VERBOSE, "No supported hw handle could be retrieved " "from the session\n"); } err = MFXInit(impl, &ver, &session); if (err != MFX_ERR_NONE) return ff_qsv_print_error(avctx, err, "Error initializing a child MFX session"); if (handle) { err = MFXVideoCORE_SetHandle(session, handle_type, handle); if (err != MFX_ERR_NONE) return ff_qsv_print_error(avctx, err, "Error setting a HW handle"); } if (QSV_RUNTIME_VERSION_ATLEAST(ver, 1, 25)) { err = MFXJoinSession(parent_session, session); if (err != MFX_ERR_NONE) return ff_qsv_print_error(avctx, err, "Error joining session"); } ret = qsv_load_plugins(session, load_plugins, avctx); if (ret < 0) { av_log(avctx, AV_LOG_ERROR, "Error loading plugins\n"); return ret; } *psession = session; return 0; }