diff mbox

[FFmpeg-devel,1/2] lavc/qsv: Fix MSDK initialization failure in system memory mode

Message ID 1567611642-11353-1-git-send-email-zhong.li@intel.com
State New
Headers show

Commit Message

Zhong Li Sept. 4, 2019, 3:40 p.m. UTC
MSDK does not create internal acceleration device on Linux,
So MFXVideoCORE_SetHandle() is necessary.
It has been added for ff_qsv_init_session_device().
But missed for ff_qsv_init_internal_session() due to commit
1f26a23 overwrited commit db89f45

Fix #7030

Signed-off-by: Zhong Li <zhong.li@intel.com>
---
 libavcodec/qsv.c          | 105 ++++++++++++++++++++++++++++++++++++++++++++--
 libavcodec/qsv_internal.h |  27 +++++++++++-
 libavcodec/qsvdec.c       |  29 +++++++------
 libavcodec/qsvdec.h       |   2 +-
 libavcodec/qsvenc.c       |  17 ++++----
 libavcodec/qsvenc.h       |   2 +-
 6 files changed, 151 insertions(+), 31 deletions(-)

Comments

Fu, Linjie Sept. 5, 2019, 2:53 a.m. UTC | #1
> -----Original Message-----

> From: ffmpeg-devel [mailto:ffmpeg-devel-bounces@ffmpeg.org] On Behalf

> Of Zhong Li

> Sent: Wednesday, September 4, 2019 23:41

> To: ffmpeg-devel@ffmpeg.org

> Cc: Li, Zhong <zhong.li@intel.com>

> Subject: [FFmpeg-devel] [PATCH 1/2] lavc/qsv: Fix MSDK initialization failure

> in system memory mode

> 

> MSDK does not create internal acceleration device on Linux,

> So MFXVideoCORE_SetHandle() is necessary.

> It has been added for ff_qsv_init_session_device().

> But missed for ff_qsv_init_internal_session() due to commit

> 1f26a23 overwrited commit db89f45

> 

> Fix #7030

> 

> Signed-off-by: Zhong Li <zhong.li@intel.com>

> ---

>  libavcodec/qsv.c          | 105

> ++++++++++++++++++++++++++++++++++++++++++++--

>  libavcodec/qsv_internal.h |  27 +++++++++++-

>  libavcodec/qsvdec.c       |  29 +++++++------

>  libavcodec/qsvdec.h       |   2 +-

>  libavcodec/qsvenc.c       |  17 ++++----

>  libavcodec/qsvenc.h       |   2 +-

>  6 files changed, 151 insertions(+), 31 deletions(-)

> 

> diff --git a/libavcodec/qsv.c b/libavcodec/qsv.c

> index 65ad070..126182b 100644

> --- a/libavcodec/qsv.c

> +++ b/libavcodec/qsv.c

> @@ -348,7 +348,79 @@ load_plugin_fail:

> 

>  }

> 

> -int ff_qsv_init_internal_session(AVCodecContext *avctx, mfxSession

> *session,

> +//This code is only required for Linux since a display handle is required.

> +//For Windows the session is complete and ready to use.

> +//For releases of Media Server Studio >= 2015 R4 the

> +//render nodes interface is preferred (/dev/dri/renderD).

> +//Using Media Server Studio 2015 R4 or newer is recommended

> +//but the older /dev/dri/card interface is also searched for broader

> compatibility.

> +

> +#ifdef AVCODEC_QSV_LINUX_SESSION_HANDLE

> +static int ff_qsv_set_display_handle(AVCodecContext *avctx, QSVSession

> *qs)

> +{

> +    // VAAPI display handle

> +    int ret = 0;

> +    VADisplay va_dpy = NULL;

> +    VAStatus va_res = VA_STATUS_SUCCESS;

> +    int major_version = 0, minor_version = 0;

> +    int fd = -1;

> +    char adapterpath[256];

> +    int adapter_num;

> +

> +    qs->fd_display = -1;

> +    qs->va_display = NULL;

> +

> +    //search for valid graphics device

> +    for (adapter_num = 0;adapter_num < 6;adapter_num++) {

> +

> +        if (adapter_num<3) {

> +            snprintf(adapterpath,sizeof(adapterpath),

> +                "/dev/dri/renderD%d", adapter_num+128);

> +        } else {

> +            snprintf(adapterpath,sizeof(adapterpath),

> +                "/dev/dri/card%d", adapter_num-3);

> +        }

> +

> +        fd = open(adapterpath, O_RDWR);

> +        if (fd < 0) {

> +            av_log(avctx, AV_LOG_ERROR,

> +                "mfx init: %s fd open failed\n", adapterpath);

> +            continue;

> +        }

> +

> +        va_dpy = vaGetDisplayDRM(fd);

> +        if (!va_dpy) {

> +            av_log(avctx, AV_LOG_ERROR,

> +                "mfx init: %s vaGetDisplayDRM failed\n", adapterpath);

> +            close(fd);

> +            continue;

> +        }

> +

> +        va_res = vaInitialize(va_dpy, &major_version, &minor_version);

> +        if (VA_STATUS_SUCCESS != va_res) {

> +            av_log(avctx, AV_LOG_ERROR,

> +                "mfx init: %s vaInitialize failed\n", adapterpath);

> +            close(fd);

> +            fd = -1;

> +            continue;

> +        } else {

> +            av_log(avctx, AV_LOG_VERBOSE,

> +            "mfx initialization: %s vaInitialize successful\n",adapterpath);

> +            qs->fd_display = fd;

> +            qs->va_display = va_dpy;

> +            ret = MFXVideoCORE_SetHandle(qs->session,

> +                  (mfxHandleType)MFX_HANDLE_VA_DISPLAY, (mfxHDL)va_dpy);

> +            if (ret < 0) {

> +                return ff_qsv_print_error(avctx, ret, "Error %d during set display

> handle\n");

> +            }

> +            break;

> +        }

> +    }

> +    return 0;

> +}

> +#endif //AVCODEC_QSV_LINUX_SESSION_HANDLE

> +

> +int ff_qsv_init_internal_session(AVCodecContext *avctx, QSVSession *qs,

>                                   const char *load_plugins)

>  {

>      mfxIMPL impl   = MFX_IMPL_AUTO_ANY;

> @@ -357,18 +429,24 @@ int ff_qsv_init_internal_session(AVCodecContext

> *avctx, mfxSession *session,

>      const char *desc;

>      int ret;

> 

> -    ret = MFXInit(impl, &ver, session);

> +    ret = MFXInit(impl, &ver, &qs->session);

>      if (ret < 0)

>          return ff_qsv_print_error(avctx, ret,

>                                    "Error initializing an internal MFX session");

> 

> -    ret = qsv_load_plugins(*session, load_plugins, avctx);


> +#ifdef AVCODEC_QSV_LINUX_SESSION_HANDLE

> +    ret = ff_qsv_set_display_handle(avctx, qs);

> +    if (ret < 0)

> +        return ret;

> +#endif


I think one "#ifdef" check may be good enough for ff_qsv_set_display_handle,
but current version is also ok.

Patch LGTM referring to commit 1f26a23.
And also verified it works on both Linux and Windows.

- linjie
Zhong Li Sept. 5, 2019, 3:13 a.m. UTC | #2
> From: Fu, Linjie

> Sent: Thursday, September 5, 2019 10:54 AM

> To: FFmpeg development discussions and patches <ffmpeg-devel@ffmpeg.org>

> Cc: Li, Zhong <zhong.li@intel.com>

> Subject: RE: [FFmpeg-devel] [PATCH 1/2] lavc/qsv: Fix MSDK initialization failure

> in system memory mode

> 

> > -----Original Message-----

> > From: ffmpeg-devel [mailto:ffmpeg-devel-bounces@ffmpeg.org] On Behalf

> > Of Zhong Li

> > Sent: Wednesday, September 4, 2019 23:41

> > To: ffmpeg-devel@ffmpeg.org

> > Cc: Li, Zhong <zhong.li@intel.com>

> > Subject: [FFmpeg-devel] [PATCH 1/2] lavc/qsv: Fix MSDK initialization

> > failure in system memory mode

> >

> > MSDK does not create internal acceleration device on Linux, So

> > MFXVideoCORE_SetHandle() is necessary.

> > It has been added for ff_qsv_init_session_device().

> > But missed for ff_qsv_init_internal_session() due to commit

> > 1f26a23 overwrited commit db89f45

> >

> > Fix #7030

> >

> > Signed-off-by: Zhong Li <zhong.li@intel.com>

> > ---

> >  libavcodec/qsv.c          | 105

> > ++++++++++++++++++++++++++++++++++++++++++++--

> >  libavcodec/qsv_internal.h |  27 +++++++++++-

> >  libavcodec/qsvdec.c       |  29 +++++++------

> >  libavcodec/qsvdec.h       |   2 +-

> >  libavcodec/qsvenc.c       |  17 ++++----

> >  libavcodec/qsvenc.h       |   2 +-

> >  6 files changed, 151 insertions(+), 31 deletions(-)

> >

> > diff --git a/libavcodec/qsv.c b/libavcodec/qsv.c index

> > 65ad070..126182b 100644

> > --- a/libavcodec/qsv.c

> > +++ b/libavcodec/qsv.c

> > @@ -348,7 +348,79 @@ load_plugin_fail:

> >

> >  }

> >

> > -int ff_qsv_init_internal_session(AVCodecContext *avctx, mfxSession

> > *session,

> > +//This code is only required for Linux since a display handle is required.

> > +//For Windows the session is complete and ready to use.

> > +//For releases of Media Server Studio >= 2015 R4 the //render nodes

> > +interface is preferred (/dev/dri/renderD).

> > +//Using Media Server Studio 2015 R4 or newer is recommended //but the

> > +older /dev/dri/card interface is also searched for broader

> > compatibility.

> > +

> > +#ifdef AVCODEC_QSV_LINUX_SESSION_HANDLE static int

> > +ff_qsv_set_display_handle(AVCodecContext *avctx, QSVSession

> > *qs)

> > +{

> > +    // VAAPI display handle

> > +    int ret = 0;

> > +    VADisplay va_dpy = NULL;

> > +    VAStatus va_res = VA_STATUS_SUCCESS;

> > +    int major_version = 0, minor_version = 0;

> > +    int fd = -1;

> > +    char adapterpath[256];

> > +    int adapter_num;

> > +

> > +    qs->fd_display = -1;

> > +    qs->va_display = NULL;

> > +

> > +    //search for valid graphics device

> > +    for (adapter_num = 0;adapter_num < 6;adapter_num++) {

> > +

> > +        if (adapter_num<3) {

> > +            snprintf(adapterpath,sizeof(adapterpath),

> > +                "/dev/dri/renderD%d", adapter_num+128);

> > +        } else {

> > +            snprintf(adapterpath,sizeof(adapterpath),

> > +                "/dev/dri/card%d", adapter_num-3);

> > +        }

> > +

> > +        fd = open(adapterpath, O_RDWR);

> > +        if (fd < 0) {

> > +            av_log(avctx, AV_LOG_ERROR,

> > +                "mfx init: %s fd open failed\n", adapterpath);

> > +            continue;

> > +        }

> > +

> > +        va_dpy = vaGetDisplayDRM(fd);

> > +        if (!va_dpy) {

> > +            av_log(avctx, AV_LOG_ERROR,

> > +                "mfx init: %s vaGetDisplayDRM failed\n", adapterpath);

> > +            close(fd);

> > +            continue;

> > +        }

> > +

> > +        va_res = vaInitialize(va_dpy, &major_version, &minor_version);

> > +        if (VA_STATUS_SUCCESS != va_res) {

> > +            av_log(avctx, AV_LOG_ERROR,

> > +                "mfx init: %s vaInitialize failed\n", adapterpath);

> > +            close(fd);

> > +            fd = -1;

> > +            continue;

> > +        } else {

> > +            av_log(avctx, AV_LOG_VERBOSE,

> > +            "mfx initialization: %s vaInitialize successful\n",adapterpath);

> > +            qs->fd_display = fd;

> > +            qs->va_display = va_dpy;

> > +            ret = MFXVideoCORE_SetHandle(qs->session,

> > +                  (mfxHandleType)MFX_HANDLE_VA_DISPLAY, (mfxHDL)va_dpy);

> > +            if (ret < 0) {

> > +                return ff_qsv_print_error(avctx, ret, "Error %d

> > + during set display

> > handle\n");

> > +            }

> > +            break;

> > +        }

> > +    }

> > +    return 0;

> > +}

> > +#endif //AVCODEC_QSV_LINUX_SESSION_HANDLE

> > +

> > +int ff_qsv_init_internal_session(AVCodecContext *avctx, QSVSession

> > +*qs,

> >                                   const char *load_plugins)  {

> >      mfxIMPL impl   = MFX_IMPL_AUTO_ANY;

> > @@ -357,18 +429,24 @@ int ff_qsv_init_internal_session(AVCodecContext

> > *avctx, mfxSession *session,

> >      const char *desc;

> >      int ret;

> >

> > -    ret = MFXInit(impl, &ver, session);

> > +    ret = MFXInit(impl, &ver, &qs->session);

> >      if (ret < 0)

> >          return ff_qsv_print_error(avctx, ret,

> >                                    "Error initializing an internal MFX

> > session");

> >

> > -    ret = qsv_load_plugins(*session, load_plugins, avctx);

> 

> > +#ifdef AVCODEC_QSV_LINUX_SESSION_HANDLE

> > +    ret = ff_qsv_set_display_handle(avctx, qs);

> > +    if (ret < 0)

> > +        return ret;

> > +#endif

> 

> I think one "#ifdef" check may be good enough for ff_qsv_set_display_handle, but

> current version is also ok.


If I understand your point, you mean that:

#ifdef AVCODEC_QSV_LINUX_SESSION_HANDLE static int
ff_qsv_set_display_handle(AVCodecContext *avctx, QSVSession
 *qs)
...
#endif

ret = ff_qsv_set_display_handle(avctx, qs);
if (ret < 0)
return ret;

Right? 
If so, it will definitely cause compile error on Windows since ff_qsv_set_display_handle is not defined.

> Patch LGTM referring to commit 1f26a23.

> And also verified it works on both Linux and Windows.


Great! Thanks

> 

> - linjie
Fu, Linjie Sept. 5, 2019, 4:06 a.m. UTC | #3
> -----Original Message-----

> From: Li, Zhong

> Sent: Thursday, September 5, 2019 11:14

> To: Fu, Linjie <linjie.fu@intel.com>; FFmpeg development discussions and

> patches <ffmpeg-devel@ffmpeg.org>

> Subject: RE: [FFmpeg-devel] [PATCH 1/2] lavc/qsv: Fix MSDK initialization

> failure in system memory mode

> 

> > From: Fu, Linjie

> > Sent: Thursday, September 5, 2019 10:54 AM

> > To: FFmpeg development discussions and patches <ffmpeg-

> devel@ffmpeg.org>

> > Cc: Li, Zhong <zhong.li@intel.com>

> > Subject: RE: [FFmpeg-devel] [PATCH 1/2] lavc/qsv: Fix MSDK initialization

> failure

> > in system memory mode

> >

> > > -----Original Message-----

> > > From: ffmpeg-devel [mailto:ffmpeg-devel-bounces@ffmpeg.org] On

> Behalf

> > > Of Zhong Li

> > > Sent: Wednesday, September 4, 2019 23:41

> > > To: ffmpeg-devel@ffmpeg.org

> > > Cc: Li, Zhong <zhong.li@intel.com>

> > > Subject: [FFmpeg-devel] [PATCH 1/2] lavc/qsv: Fix MSDK initialization

> > > failure in system memory mode

> > >

> > > MSDK does not create internal acceleration device on Linux, So

> > > MFXVideoCORE_SetHandle() is necessary.

> > > It has been added for ff_qsv_init_session_device().

> > > But missed for ff_qsv_init_internal_session() due to commit

> > > 1f26a23 overwrited commit db89f45

> > >

> > > Fix #7030

> > >

> > > Signed-off-by: Zhong Li <zhong.li@intel.com>

> > > ---

> > >  libavcodec/qsv.c          | 105

> > > ++++++++++++++++++++++++++++++++++++++++++++--

> > >  libavcodec/qsv_internal.h |  27 +++++++++++-

> > >  libavcodec/qsvdec.c       |  29 +++++++------

> > >  libavcodec/qsvdec.h       |   2 +-

> > >  libavcodec/qsvenc.c       |  17 ++++----

> > >  libavcodec/qsvenc.h       |   2 +-

> > >  6 files changed, 151 insertions(+), 31 deletions(-)

> > >

> > > diff --git a/libavcodec/qsv.c b/libavcodec/qsv.c index

> > > 65ad070..126182b 100644

> > > --- a/libavcodec/qsv.c

> > > +++ b/libavcodec/qsv.c

> > > @@ -348,7 +348,79 @@ load_plugin_fail:

> > >

> > >  }

> > >

> > > -int ff_qsv_init_internal_session(AVCodecContext *avctx, mfxSession

> > > *session,

> > > +//This code is only required for Linux since a display handle is required.

> > > +//For Windows the session is complete and ready to use.

> > > +//For releases of Media Server Studio >= 2015 R4 the //render nodes

> > > +interface is preferred (/dev/dri/renderD).

> > > +//Using Media Server Studio 2015 R4 or newer is recommended //but

> the

> > > +older /dev/dri/card interface is also searched for broader

> > > compatibility.

> > > +

> > > +#ifdef AVCODEC_QSV_LINUX_SESSION_HANDLE static int

> > > +ff_qsv_set_display_handle(AVCodecContext *avctx, QSVSession

> > > *qs)

> > > +{

> > > +    // VAAPI display handle

> > > +    int ret = 0;

> > > +    VADisplay va_dpy = NULL;

> > > +    VAStatus va_res = VA_STATUS_SUCCESS;

> > > +    int major_version = 0, minor_version = 0;

> > > +    int fd = -1;

> > > +    char adapterpath[256];

> > > +    int adapter_num;

> > > +

> > > +    qs->fd_display = -1;

> > > +    qs->va_display = NULL;

> > > +

> > > +    //search for valid graphics device

> > > +    for (adapter_num = 0;adapter_num < 6;adapter_num++) {

> > > +

> > > +        if (adapter_num<3) {

> > > +            snprintf(adapterpath,sizeof(adapterpath),

> > > +                "/dev/dri/renderD%d", adapter_num+128);

> > > +        } else {

> > > +            snprintf(adapterpath,sizeof(adapterpath),

> > > +                "/dev/dri/card%d", adapter_num-3);

> > > +        }

> > > +

> > > +        fd = open(adapterpath, O_RDWR);

> > > +        if (fd < 0) {

> > > +            av_log(avctx, AV_LOG_ERROR,

> > > +                "mfx init: %s fd open failed\n", adapterpath);

> > > +            continue;

> > > +        }

> > > +

> > > +        va_dpy = vaGetDisplayDRM(fd);

> > > +        if (!va_dpy) {

> > > +            av_log(avctx, AV_LOG_ERROR,

> > > +                "mfx init: %s vaGetDisplayDRM failed\n", adapterpath);

> > > +            close(fd);

> > > +            continue;

> > > +        }

> > > +

> > > +        va_res = vaInitialize(va_dpy, &major_version, &minor_version);

> > > +        if (VA_STATUS_SUCCESS != va_res) {

> > > +            av_log(avctx, AV_LOG_ERROR,

> > > +                "mfx init: %s vaInitialize failed\n", adapterpath);

> > > +            close(fd);

> > > +            fd = -1;

> > > +            continue;

> > > +        } else {

> > > +            av_log(avctx, AV_LOG_VERBOSE,

> > > +            "mfx initialization: %s vaInitialize successful\n",adapterpath);

> > > +            qs->fd_display = fd;

> > > +            qs->va_display = va_dpy;

> > > +            ret = MFXVideoCORE_SetHandle(qs->session,

> > > +                  (mfxHandleType)MFX_HANDLE_VA_DISPLAY,

> (mfxHDL)va_dpy);

> > > +            if (ret < 0) {

> > > +                return ff_qsv_print_error(avctx, ret, "Error %d

> > > + during set display

> > > handle\n");

> > > +            }

> > > +            break;

> > > +        }

> > > +    }

> > > +    return 0;

> > > +}

> > > +#endif //AVCODEC_QSV_LINUX_SESSION_HANDLE

> > > +

> > > +int ff_qsv_init_internal_session(AVCodecContext *avctx, QSVSession

> > > +*qs,

> > >                                   const char *load_plugins)  {

> > >      mfxIMPL impl   = MFX_IMPL_AUTO_ANY;

> > > @@ -357,18 +429,24 @@ int

> ff_qsv_init_internal_session(AVCodecContext

> > > *avctx, mfxSession *session,

> > >      const char *desc;

> > >      int ret;

> > >

> > > -    ret = MFXInit(impl, &ver, session);

> > > +    ret = MFXInit(impl, &ver, &qs->session);

> > >      if (ret < 0)

> > >          return ff_qsv_print_error(avctx, ret,

> > >                                    "Error initializing an internal MFX

> > > session");

> > >

> > > -    ret = qsv_load_plugins(*session, load_plugins, avctx);

> >

> > > +#ifdef AVCODEC_QSV_LINUX_SESSION_HANDLE

> > > +    ret = ff_qsv_set_display_handle(avctx, qs);

> > > +    if (ret < 0)

> > > +        return ret;

> > > +#endif

> >

> > I think one "#ifdef" check may be good enough for

> ff_qsv_set_display_handle, but

> > current version is also ok.

> 

> If I understand your point, you mean that:

> 

> #ifdef AVCODEC_QSV_LINUX_SESSION_HANDLE static int

> ff_qsv_set_display_handle(AVCodecContext *avctx, QSVSession

>  *qs)

> ...

> #endif

> 

> ret = ff_qsv_set_display_handle(avctx, qs);

> if (ret < 0)

> return ret;

> 

> Right?

> If so, it will definitely cause compile error on Windows since

> ff_qsv_set_display_handle is not defined.

> 


Not really, how about check inside the function:

Static int  ff_qsv_set_display_handle(AVCodecContext *avctx, QSVSession *qs)
{
#ifdef AVCODEC_QSV_LINUX_SESSION_HANDLE
...
#endif

    return 0;
}

ret = ff_qsv_set_display_handle(avctx, qs);
if (ret < 0)
    return ret;

- linjie
Zhong Li Sept. 5, 2019, 5:02 a.m. UTC | #4
> From: Fu, Linjie

> Sent: Thursday, September 5, 2019 12:07 PM

> To: Li, Zhong <zhong.li@intel.com>; FFmpeg development discussions and patches

> <ffmpeg-devel@ffmpeg.org>

> Subject: RE: [FFmpeg-devel] [PATCH 1/2] lavc/qsv: Fix MSDK initialization failure

> in system memory mode

> 

> > -----Original Message-----

> > From: Li, Zhong

> > Sent: Thursday, September 5, 2019 11:14

> > To: Fu, Linjie <linjie.fu@intel.com>; FFmpeg development discussions

> > and patches <ffmpeg-devel@ffmpeg.org>

> > Subject: RE: [FFmpeg-devel] [PATCH 1/2] lavc/qsv: Fix MSDK

> > initialization failure in system memory mode

> >

> > > From: Fu, Linjie

> > > Sent: Thursday, September 5, 2019 10:54 AM

> > > To: FFmpeg development discussions and patches <ffmpeg-

> > devel@ffmpeg.org>

> > > Cc: Li, Zhong <zhong.li@intel.com>

> > > Subject: RE: [FFmpeg-devel] [PATCH 1/2] lavc/qsv: Fix MSDK

> > > initialization

> > failure

> > > in system memory mode

> > >

> > > > -----Original Message-----

> > > > From: ffmpeg-devel [mailto:ffmpeg-devel-bounces@ffmpeg.org] On

> > Behalf

> > > > Of Zhong Li

> > > > Sent: Wednesday, September 4, 2019 23:41

> > > > To: ffmpeg-devel@ffmpeg.org

> > > > Cc: Li, Zhong <zhong.li@intel.com>

> > > > Subject: [FFmpeg-devel] [PATCH 1/2] lavc/qsv: Fix MSDK

> > > > initialization failure in system memory mode

> > > >

> > > > MSDK does not create internal acceleration device on Linux, So

> > > > MFXVideoCORE_SetHandle() is necessary.

> > > > It has been added for ff_qsv_init_session_device().

> > > > But missed for ff_qsv_init_internal_session() due to commit

> > > > 1f26a23 overwrited commit db89f45

> > > >

> > > > Fix #7030

> > > >

> > > > Signed-off-by: Zhong Li <zhong.li@intel.com>

> > > > ---

> > > >  libavcodec/qsv.c          | 105

> > > > ++++++++++++++++++++++++++++++++++++++++++++--

> > > >  libavcodec/qsv_internal.h |  27 +++++++++++-

> > > >  libavcodec/qsvdec.c       |  29 +++++++------

> > > >  libavcodec/qsvdec.h       |   2 +-

> > > >  libavcodec/qsvenc.c       |  17 ++++----

> > > >  libavcodec/qsvenc.h       |   2 +-

> > > >  6 files changed, 151 insertions(+), 31 deletions(-)

> > > >

> > > > diff --git a/libavcodec/qsv.c b/libavcodec/qsv.c index

> > > > 65ad070..126182b 100644

> > > > --- a/libavcodec/qsv.c

> > > > +++ b/libavcodec/qsv.c

> > > > @@ -348,7 +348,79 @@ load_plugin_fail:

> > > >

> > > >  }

> > > >

> > > > -int ff_qsv_init_internal_session(AVCodecContext *avctx,

> > > > mfxSession *session,

> > > > +//This code is only required for Linux since a display handle is required.

> > > > +//For Windows the session is complete and ready to use.

> > > > +//For releases of Media Server Studio >= 2015 R4 the //render

> > > > +nodes interface is preferred (/dev/dri/renderD).

> > > > +//Using Media Server Studio 2015 R4 or newer is recommended //but

> > the

> > > > +older /dev/dri/card interface is also searched for broader

> > > > compatibility.

> > > > +

> > > > +#ifdef AVCODEC_QSV_LINUX_SESSION_HANDLE static int

> > > > +ff_qsv_set_display_handle(AVCodecContext *avctx, QSVSession

> > > > *qs)

> > > > +{

> > > > +    // VAAPI display handle

> > > > +    int ret = 0;

> > > > +    VADisplay va_dpy = NULL;

> > > > +    VAStatus va_res = VA_STATUS_SUCCESS;

> > > > +    int major_version = 0, minor_version = 0;

> > > > +    int fd = -1;

> > > > +    char adapterpath[256];

> > > > +    int adapter_num;

> > > > +

> > > > +    qs->fd_display = -1;

> > > > +    qs->va_display = NULL;

> > > > +

> > > > +    //search for valid graphics device

> > > > +    for (adapter_num = 0;adapter_num < 6;adapter_num++) {

> > > > +

> > > > +        if (adapter_num<3) {

> > > > +            snprintf(adapterpath,sizeof(adapterpath),

> > > > +                "/dev/dri/renderD%d", adapter_num+128);

> > > > +        } else {

> > > > +            snprintf(adapterpath,sizeof(adapterpath),

> > > > +                "/dev/dri/card%d", adapter_num-3);

> > > > +        }

> > > > +

> > > > +        fd = open(adapterpath, O_RDWR);

> > > > +        if (fd < 0) {

> > > > +            av_log(avctx, AV_LOG_ERROR,

> > > > +                "mfx init: %s fd open failed\n", adapterpath);

> > > > +            continue;

> > > > +        }

> > > > +

> > > > +        va_dpy = vaGetDisplayDRM(fd);

> > > > +        if (!va_dpy) {

> > > > +            av_log(avctx, AV_LOG_ERROR,

> > > > +                "mfx init: %s vaGetDisplayDRM failed\n", adapterpath);

> > > > +            close(fd);

> > > > +            continue;

> > > > +        }

> > > > +

> > > > +        va_res = vaInitialize(va_dpy, &major_version, &minor_version);

> > > > +        if (VA_STATUS_SUCCESS != va_res) {

> > > > +            av_log(avctx, AV_LOG_ERROR,

> > > > +                "mfx init: %s vaInitialize failed\n", adapterpath);

> > > > +            close(fd);

> > > > +            fd = -1;

> > > > +            continue;

> > > > +        } else {

> > > > +            av_log(avctx, AV_LOG_VERBOSE,

> > > > +            "mfx initialization: %s vaInitialize successful\n",adapterpath);

> > > > +            qs->fd_display = fd;

> > > > +            qs->va_display = va_dpy;

> > > > +            ret = MFXVideoCORE_SetHandle(qs->session,

> > > > +                  (mfxHandleType)MFX_HANDLE_VA_DISPLAY,

> > (mfxHDL)va_dpy);

> > > > +            if (ret < 0) {

> > > > +                return ff_qsv_print_error(avctx, ret, "Error %d

> > > > + during set display

> > > > handle\n");

> > > > +            }

> > > > +            break;

> > > > +        }

> > > > +    }

> > > > +    return 0;

> > > > +}

> > > > +#endif //AVCODEC_QSV_LINUX_SESSION_HANDLE

> > > > +

> > > > +int ff_qsv_init_internal_session(AVCodecContext *avctx,

> > > > +QSVSession *qs,

> > > >                                   const char *load_plugins)  {

> > > >      mfxIMPL impl   = MFX_IMPL_AUTO_ANY;

> > > > @@ -357,18 +429,24 @@ int

> > ff_qsv_init_internal_session(AVCodecContext

> > > > *avctx, mfxSession *session,

> > > >      const char *desc;

> > > >      int ret;

> > > >

> > > > -    ret = MFXInit(impl, &ver, session);

> > > > +    ret = MFXInit(impl, &ver, &qs->session);

> > > >      if (ret < 0)

> > > >          return ff_qsv_print_error(avctx, ret,

> > > >                                    "Error initializing an internal

> > > > MFX session");

> > > >

> > > > -    ret = qsv_load_plugins(*session, load_plugins, avctx);

> > >

> > > > +#ifdef AVCODEC_QSV_LINUX_SESSION_HANDLE

> > > > +    ret = ff_qsv_set_display_handle(avctx, qs);

> > > > +    if (ret < 0)

> > > > +        return ret;

> > > > +#endif

> > >

> > > I think one "#ifdef" check may be good enough for

> > ff_qsv_set_display_handle, but

> > > current version is also ok.

> >

> > If I understand your point, you mean that:

> >

> > #ifdef AVCODEC_QSV_LINUX_SESSION_HANDLE static int

> > ff_qsv_set_display_handle(AVCodecContext *avctx, QSVSession

> >  *qs)

> > ...

> > #endif

> >

> > ret = ff_qsv_set_display_handle(avctx, qs); if (ret < 0) return ret;

> >

> > Right?

> > If so, it will definitely cause compile error on Windows since

> > ff_qsv_set_display_handle is not defined.

> >

> 

> Not really, how about check inside the function:

> 

> Static int  ff_qsv_set_display_handle(AVCodecContext *avctx, QSVSession *qs)

> { #ifdef AVCODEC_QSV_LINUX_SESSION_HANDLE ...

> #endif


This is not efficient for Windows, ff_qsv_set_display_handle will be called but do nothing, thus why I use current way.
Zhong Li Sept. 10, 2019, 7:22 a.m. UTC | #5
> From: Li, Zhong
> Sent: Wednesday, September 4, 2019 11:41 PM
> To: ffmpeg-devel@ffmpeg.org
> Cc: Li, Zhong <zhong.li@intel.com>
> Subject: [PATCH 1/2] lavc/qsv: Fix MSDK initialization failure in system memory
> mode
> 
> MSDK does not create internal acceleration device on Linux, So
> MFXVideoCORE_SetHandle() is necessary.
> It has been added for ff_qsv_init_session_device().
> But missed for ff_qsv_init_internal_session() due to commit
> 1f26a23 overwrited commit db89f45
> 
> Fix #7030
> 
> Signed-off-by: Zhong Li <zhong.li@intel.com>
> ---
>  libavcodec/qsv.c          | 105
> ++++++++++++++++++++++++++++++++++++++++++++--
>  libavcodec/qsv_internal.h |  27 +++++++++++-
>  libavcodec/qsvdec.c       |  29 +++++++------
>  libavcodec/qsvdec.h       |   2 +-
>  libavcodec/qsvenc.c       |  17 ++++----
>  libavcodec/qsvenc.h       |   2 +-
>  6 files changed, 151 insertions(+), 31 deletions(-)
> 
> diff --git a/libavcodec/qsv.c b/libavcodec/qsv.c index 65ad070..126182b 100644
> --- a/libavcodec/qsv.c
> +++ b/libavcodec/qsv.c
> @@ -348,7 +348,79 @@ load_plugin_fail:
> 
>  }
> 
> -int ff_qsv_init_internal_session(AVCodecContext *avctx, mfxSession *session,
> +//This code is only required for Linux since a display handle is required.
> +//For Windows the session is complete and ready to use.
> +//For releases of Media Server Studio >= 2015 R4 the //render nodes
> +interface is preferred (/dev/dri/renderD).
> +//Using Media Server Studio 2015 R4 or newer is recommended //but the
> +older /dev/dri/card interface is also searched for broader compatibility.
> +
> +#ifdef AVCODEC_QSV_LINUX_SESSION_HANDLE static int
> +ff_qsv_set_display_handle(AVCodecContext *avctx, QSVSession *qs) {
> +    // VAAPI display handle
> +    int ret = 0;
> +    VADisplay va_dpy = NULL;
> +    VAStatus va_res = VA_STATUS_SUCCESS;
> +    int major_version = 0, minor_version = 0;
> +    int fd = -1;
> +    char adapterpath[256];
> +    int adapter_num;
> +
> +    qs->fd_display = -1;
> +    qs->va_display = NULL;
> +
> +    //search for valid graphics device
> +    for (adapter_num = 0;adapter_num < 6;adapter_num++) {
> +
> +        if (adapter_num<3) {
> +            snprintf(adapterpath,sizeof(adapterpath),
> +                "/dev/dri/renderD%d", adapter_num+128);
> +        } else {
> +            snprintf(adapterpath,sizeof(adapterpath),
> +                "/dev/dri/card%d", adapter_num-3);
> +        }
> +
> +        fd = open(adapterpath, O_RDWR);
> +        if (fd < 0) {
> +            av_log(avctx, AV_LOG_ERROR,
> +                "mfx init: %s fd open failed\n", adapterpath);
> +            continue;
> +        }
> +
> +        va_dpy = vaGetDisplayDRM(fd);
> +        if (!va_dpy) {
> +            av_log(avctx, AV_LOG_ERROR,
> +                "mfx init: %s vaGetDisplayDRM failed\n", adapterpath);
> +            close(fd);
> +            continue;
> +        }
> +
> +        va_res = vaInitialize(va_dpy, &major_version, &minor_version);
> +        if (VA_STATUS_SUCCESS != va_res) {
> +            av_log(avctx, AV_LOG_ERROR,
> +                "mfx init: %s vaInitialize failed\n", adapterpath);
> +            close(fd);
> +            fd = -1;
> +            continue;
> +        } else {
> +            av_log(avctx, AV_LOG_VERBOSE,
> +            "mfx initialization: %s vaInitialize successful\n",adapterpath);
> +            qs->fd_display = fd;
> +            qs->va_display = va_dpy;
> +            ret = MFXVideoCORE_SetHandle(qs->session,
> +                  (mfxHandleType)MFX_HANDLE_VA_DISPLAY, (mfxHDL)va_dpy);
> +            if (ret < 0) {
> +                return ff_qsv_print_error(avctx, ret, "Error %d during set display
> handle\n");
> +            }
> +            break;
> +        }
> +    }
> +    return 0;
> +}
> +#endif //AVCODEC_QSV_LINUX_SESSION_HANDLE
> +
> +int ff_qsv_init_internal_session(AVCodecContext *avctx, QSVSession *qs,
>                                   const char *load_plugins)  {
>      mfxIMPL impl   = MFX_IMPL_AUTO_ANY;
> @@ -357,18 +429,24 @@ int ff_qsv_init_internal_session(AVCodecContext
> *avctx, mfxSession *session,
>      const char *desc;
>      int ret;
> 
> -    ret = MFXInit(impl, &ver, session);
> +    ret = MFXInit(impl, &ver, &qs->session);
>      if (ret < 0)
>          return ff_qsv_print_error(avctx, ret,
>                                    "Error initializing an internal MFX session");
> 
> -    ret = qsv_load_plugins(*session, load_plugins, avctx);
> +#ifdef AVCODEC_QSV_LINUX_SESSION_HANDLE
> +    ret = ff_qsv_set_display_handle(avctx, qs);
> +    if (ret < 0)
> +        return ret;
> +#endif
> +
> +    ret = qsv_load_plugins(qs->session, load_plugins, avctx);
>      if (ret < 0) {
>          av_log(avctx, AV_LOG_ERROR, "Error loading plugins\n");
>          return ret;
>      }
> 
> -    MFXQueryIMPL(*session, &impl);
> +    MFXQueryIMPL(qs->session, &impl);
> 
>      switch (MFX_IMPL_BASETYPE(impl)) {
>      case MFX_IMPL_SOFTWARE:
> @@ -758,3 +836,22 @@ int ff_qsv_init_session_frames(AVCodecContext *avctx,
> mfxSession *psession,
>      *psession = session;
>      return 0;
>  }
> +
> +int ff_qsv_close_internal_session(QSVSession *qs) {
> +    if (qs->session) {
> +        MFXClose(qs->session);
> +        qs->session = NULL;
> +    }
> +#ifdef AVCODEC_QSV_LINUX_SESSION_HANDLE
> +    if (qs->va_display) {
> +        vaTerminate(qs->va_display);
> +        qs->va_display = NULL;
> +    }
> +    if (qs->fd_display > 0) {
> +        close(qs->fd_display);
> +        qs->fd_display = -1;
> +    }
> +#endif
> +    return 0;
> +}
> diff --git a/libavcodec/qsv_internal.h b/libavcodec/qsv_internal.h index
> c50e9c7..7678114 100644
> --- a/libavcodec/qsv_internal.h
> +++ b/libavcodec/qsv_internal.h
> @@ -21,6 +21,21 @@
>  #ifndef AVCODEC_QSV_INTERNAL_H
>  #define AVCODEC_QSV_INTERNAL_H
> 
> +#if CONFIG_VAAPI
> +#define AVCODEC_QSV_LINUX_SESSION_HANDLE #endif //CONFIG_VAAPI
> +
> +#ifdef AVCODEC_QSV_LINUX_SESSION_HANDLE #include <stdio.h> #include
> +<string.h> #if HAVE_UNISTD_H #include <unistd.h> #endif #include
> +<fcntl.h> #include <va/va.h> #include <va/va_drm.h> #endif
> +
>  #include <mfx/mfxvideo.h>
> 
>  #include "libavutil/frame.h"
> @@ -64,6 +79,14 @@ typedef struct QSVFrame {
>      struct QSVFrame *next;
>  } QSVFrame;
> 
> +typedef struct QSVSession {
> +    mfxSession session;
> +#ifdef AVCODEC_QSV_LINUX_SESSION_HANDLE
> +    int        fd_display;
> +    VADisplay  va_display;
> +#endif
> +} QSVSession;
> +
>  typedef struct QSVFramesContext {
>      AVBufferRef *hw_frames_ctx;
>      void *logctx;
> @@ -99,9 +122,11 @@ enum AVPictureType ff_qsv_map_pictype(int
> mfx_pic_type);
> 
>  enum AVFieldOrder ff_qsv_map_picstruct(int mfx_pic_struct);
> 
> -int ff_qsv_init_internal_session(AVCodecContext *avctx, mfxSession *session,
> +int ff_qsv_init_internal_session(AVCodecContext *avctx, QSVSession *qs,
>                                   const char *load_plugins);
> 
> +int ff_qsv_close_internal_session(QSVSession *qs);
> +
>  int ff_qsv_init_session_device(AVCodecContext *avctx, mfxSession *psession,
>                                 AVBufferRef *device_ref, const char *load_plugins);
> 
> diff --git a/libavcodec/qsvdec.c b/libavcodec/qsvdec.c index eef4fe7..2fce478
> 100644
> --- a/libavcodec/qsvdec.c
> +++ b/libavcodec/qsvdec.c
> @@ -62,9 +62,9 @@ static int qsv_init_session(AVCodecContext *avctx,
> QSVContext *q, mfxSession ses
>      if (session) {
>          q->session = session;
>      } else if (hw_frames_ref) {
> -        if (q->internal_session) {
> -            MFXClose(q->internal_session);
> -            q->internal_session = NULL;
> +        if (q->internal_qs.session) {
> +            MFXClose(q->internal_qs.session);
> +            q->internal_qs.session = NULL;
>          }
>          av_buffer_unref(&q->frames_ctx.hw_frames_ctx);
> 
> @@ -72,7 +72,7 @@ static int qsv_init_session(AVCodecContext *avctx,
> QSVContext *q, mfxSession ses
>          if (!q->frames_ctx.hw_frames_ctx)
>              return AVERROR(ENOMEM);
> 
> -        ret = ff_qsv_init_session_frames(avctx, &q->internal_session,
> +        ret = ff_qsv_init_session_frames(avctx,
> + &q->internal_qs.session,
>                                           &q->frames_ctx, q->load_plugins,
>                                           q->iopattern ==
> MFX_IOPATTERN_OUT_OPAQUE_MEMORY);
>          if (ret < 0) {
> @@ -80,28 +80,28 @@ static int qsv_init_session(AVCodecContext *avctx,
> QSVContext *q, mfxSession ses
>              return ret;
>          }
> 
> -        q->session = q->internal_session;
> +        q->session = q->internal_qs.session;
>      } else if (hw_device_ref) {
> -        if (q->internal_session) {
> -            MFXClose(q->internal_session);
> -            q->internal_session = NULL;
> +        if (q->internal_qs.session) {
> +            MFXClose(q->internal_qs.session);
> +            q->internal_qs.session = NULL;
>          }
> 
> -        ret = ff_qsv_init_session_device(avctx, &q->internal_session,
> +        ret = ff_qsv_init_session_device(avctx,
> + &q->internal_qs.session,
>                                           hw_device_ref, q->load_plugins);
>          if (ret < 0)
>              return ret;
> 
> -        q->session = q->internal_session;
> +        q->session = q->internal_qs.session;
>      } else {
> -        if (!q->internal_session) {
> -            ret = ff_qsv_init_internal_session(avctx, &q->internal_session,
> +        if (!q->internal_qs.session) {
> +            ret = ff_qsv_init_internal_session(avctx, &q->internal_qs,
>                                                 q->load_plugins);
>              if (ret < 0)
>                  return ret;
>          }
> 
> -        q->session = q->internal_session;
> +        q->session = q->internal_qs.session;
>      }
> 
>      /* make sure the decoder is uninitialized */ @@ -529,8 +529,7 @@ int
> ff_qsv_decode_close(QSVContext *q)
>      av_fifo_free(q->async_fifo);
>      q->async_fifo = NULL;
> 
> -    if (q->internal_session)
> -        MFXClose(q->internal_session);
> +    ff_qsv_close_internal_session(&q->internal_qs);
> 
>      av_buffer_unref(&q->frames_ctx.hw_frames_ctx);
>      av_buffer_unref(&q->frames_ctx.mids_buf);
> diff --git a/libavcodec/qsvdec.h b/libavcodec/qsvdec.h index c057bc6..64dc8d2
> 100644
> --- a/libavcodec/qsvdec.h
> +++ b/libavcodec/qsvdec.h
> @@ -42,7 +42,7 @@ typedef struct QSVContext {
> 
>      // the session we allocated internally, in case the caller did not provide
>      // one
> -    mfxSession internal_session;
> +    QSVSession internal_qs;
> 
>      QSVFramesContext frames_ctx;
> 
> diff --git a/libavcodec/qsvenc.c b/libavcodec/qsvenc.c index 9bf8574..207cdc1
> 100644
> --- a/libavcodec/qsvenc.c
> +++ b/libavcodec/qsvenc.c
> @@ -954,7 +954,7 @@ static int qsvenc_init_session(AVCodecContext *avctx,
> QSVEncContext *q)
>          if (!q->frames_ctx.hw_frames_ctx)
>              return AVERROR(ENOMEM);
> 
> -        ret = ff_qsv_init_session_frames(avctx, &q->internal_session,
> +        ret = ff_qsv_init_session_frames(avctx,
> + &q->internal_qs.session,
>                                           &q->frames_ctx, q->load_plugins,
>                                           q->param.IOPattern ==
> MFX_IOPATTERN_IN_OPAQUE_MEMORY);
>          if (ret < 0) {
> @@ -962,21 +962,21 @@ static int qsvenc_init_session(AVCodecContext *avctx,
> QSVEncContext *q)
>              return ret;
>          }
> 
> -        q->session = q->internal_session;
> +        q->session = q->internal_qs.session;
>      } else if (avctx->hw_device_ctx) {
> -        ret = ff_qsv_init_session_device(avctx, &q->internal_session,
> +        ret = ff_qsv_init_session_device(avctx,
> + &q->internal_qs.session,
>                                           avctx->hw_device_ctx, q->load_plugins);
>          if (ret < 0)
>              return ret;
> 
> -        q->session = q->internal_session;
> +        q->session = q->internal_qs.session;
>      } else {
> -        ret = ff_qsv_init_internal_session(avctx, &q->internal_session,
> +        ret = ff_qsv_init_internal_session(avctx, &q->internal_qs,
>                                             q->load_plugins);
>          if (ret < 0)
>              return ret;
> 
> -        q->session = q->internal_session;
> +        q->session = q->internal_qs.session;
>      }
> 
>      return 0;
> @@ -1507,10 +1507,9 @@ int ff_qsv_enc_close(AVCodecContext *avctx,
> QSVEncContext *q)
> 
>      if (q->session)
>          MFXVideoENCODE_Close(q->session);
> -    if (q->internal_session)
> -        MFXClose(q->internal_session);
> +
>      q->session          = NULL;
> -    q->internal_session = NULL;
> +    ff_qsv_close_internal_session(&q->internal_qs);
> 
>      av_buffer_unref(&q->frames_ctx.hw_frames_ctx);
>      av_buffer_unref(&q->frames_ctx.mids_buf);
> diff --git a/libavcodec/qsvenc.h b/libavcodec/qsvenc.h index f2f4d38..ec8b541
> 100644
> --- a/libavcodec/qsvenc.h
> +++ b/libavcodec/qsvenc.h
> @@ -102,7 +102,7 @@ typedef struct QSVEncContext {
>      QSVFrame *work_frames;
> 
>      mfxSession session;
> -    mfxSession internal_session;
> +    QSVSession internal_qs;
> 
>      int packet_size;
>      int width_align;
> --
> 2.7.4

Will apply if no objection.
Mark Thompson Sept. 10, 2019, 10:58 p.m. UTC | #6
On 04/09/2019 16:40, Zhong Li wrote:
> MSDK does not create internal acceleration device on Linux,
> So MFXVideoCORE_SetHandle() is necessary.
> It has been added for ff_qsv_init_session_device().
> But missed for ff_qsv_init_internal_session() due to commit
> 1f26a23 overwrited commit db89f45
> 
> Fix #7030

Huh.  I think I see the problem - the standalone dispatcher does try to create a VA connection to fix common cases on simple devices (<https://github.com/lu-zero/mfx_dispatch/blob/master/src/mfx_va_glue.c>), but that seems to have been lost in the full open source media SDK.

Given that the D3D code does find a device automatically it's tempting to suggest that this should be fixed on the media SDK side instead for consistency, but I don't really mind.

> Signed-off-by: Zhong Li <zhong.li@intel.com>
> ---
>  libavcodec/qsv.c          | 105 ++++++++++++++++++++++++++++++++++++++++++++--
>  libavcodec/qsv_internal.h |  27 +++++++++++-
>  libavcodec/qsvdec.c       |  29 +++++++------
>  libavcodec/qsvdec.h       |   2 +-
>  libavcodec/qsvenc.c       |  17 ++++----
>  libavcodec/qsvenc.h       |   2 +-
>  6 files changed, 151 insertions(+), 31 deletions(-)
> 
> diff --git a/libavcodec/qsv.c b/libavcodec/qsv.c
> index 65ad070..126182b 100644
> --- a/libavcodec/qsv.c
> +++ b/libavcodec/qsv.c
> @@ -348,7 +348,79 @@ load_plugin_fail:
>  
>  }
>  
> -int ff_qsv_init_internal_session(AVCodecContext *avctx, mfxSession *session,
> +//This code is only required for Linux since a display handle is required.
> +//For Windows the session is complete and ready to use.
> +//For releases of Media Server Studio >= 2015 R4 the
> +//render nodes interface is preferred (/dev/dri/renderD).
> +//Using Media Server Studio 2015 R4 or newer is recommended
> +//but the older /dev/dri/card interface is also searched for broader compatibility.
> +
> +#ifdef AVCODEC_QSV_LINUX_SESSION_HANDLE
> +static int ff_qsv_set_display_handle(AVCodecContext *avctx, QSVSession *qs)
> +{
> +    // VAAPI display handle
> +    int ret = 0;
> +    VADisplay va_dpy = NULL;
> +    VAStatus va_res = VA_STATUS_SUCCESS;
> +    int major_version = 0, minor_version = 0;
> +    int fd = -1;
> +    char adapterpath[256];
> +    int adapter_num;
> +
> +    qs->fd_display = -1;
> +    qs->va_display = NULL;
> +
> +    //search for valid graphics device
> +    for (adapter_num = 0;adapter_num < 6;adapter_num++) {
> +
> +        if (adapter_num<3) {
> +            snprintf(adapterpath,sizeof(adapterpath),
> +                "/dev/dri/renderD%d", adapter_num+128);
> +        } else {
> +            snprintf(adapterpath,sizeof(adapterpath),
> +                "/dev/dri/card%d", adapter_num-3);
> +        }
> +
> +        fd = open(adapterpath, O_RDWR);
> +        if (fd < 0) {
> +            av_log(avctx, AV_LOG_ERROR,
> +                "mfx init: %s fd open failed\n", adapterpath);
> +            continue;
> +        }
> +
> +        va_dpy = vaGetDisplayDRM(fd);
> +        if (!va_dpy) {
> +            av_log(avctx, AV_LOG_ERROR,
> +                "mfx init: %s vaGetDisplayDRM failed\n", adapterpath);
> +            close(fd);
> +            continue;
> +        }
> +
> +        va_res = vaInitialize(va_dpy, &major_version, &minor_version);
> +        if (VA_STATUS_SUCCESS != va_res) {
> +            av_log(avctx, AV_LOG_ERROR,
> +                "mfx init: %s vaInitialize failed\n", adapterpath);
> +            close(fd);
> +            fd = -1;
> +            continue;

Just call av_hwdevice_ctx_create(VAAPI, { "kernel_driver": "i915", "driver": "iHD" }) like hwcontext_qsv does rather than writing an incomplete copy.

> +        } else {
> +            av_log(avctx, AV_LOG_VERBOSE,
> +            "mfx initialization: %s vaInitialize successful\n",adapterpath);
> +            qs->fd_display = fd;
> +            qs->va_display = va_dpy;
> +            ret = MFXVideoCORE_SetHandle(qs->session,
> +                  (mfxHandleType)MFX_HANDLE_VA_DISPLAY, (mfxHDL)va_dpy);
> +            if (ret < 0) {
> +                return ff_qsv_print_error(avctx, ret, "Error %d during set display handle\n");
> +            }
> +            break;
> +        }
> +    }
> +    return 0;
> +}
> +#endif //AVCODEC_QSV_LINUX_SESSION_HANDLE
> +
> ...
For the rest, probably ok?

All of the session setup stuff is rather horrible, though - it would be nice if we could push more of it into hwcontext_qsv instead of messing with the sessions like this in lavc.  Can we turn the no-device-provided case into approximately the same as an hw_device_ctx case by just calling av_hwdevice_ctx_create() early on?  (That would avoid this code entirely, since hwcontext_qsv always creates a subdevice.)

- Mark
diff mbox

Patch

diff --git a/libavcodec/qsv.c b/libavcodec/qsv.c
index 65ad070..126182b 100644
--- a/libavcodec/qsv.c
+++ b/libavcodec/qsv.c
@@ -348,7 +348,79 @@  load_plugin_fail:
 
 }
 
-int ff_qsv_init_internal_session(AVCodecContext *avctx, mfxSession *session,
+//This code is only required for Linux since a display handle is required.
+//For Windows the session is complete and ready to use.
+//For releases of Media Server Studio >= 2015 R4 the
+//render nodes interface is preferred (/dev/dri/renderD).
+//Using Media Server Studio 2015 R4 or newer is recommended
+//but the older /dev/dri/card interface is also searched for broader compatibility.
+
+#ifdef AVCODEC_QSV_LINUX_SESSION_HANDLE
+static int ff_qsv_set_display_handle(AVCodecContext *avctx, QSVSession *qs)
+{
+    // VAAPI display handle
+    int ret = 0;
+    VADisplay va_dpy = NULL;
+    VAStatus va_res = VA_STATUS_SUCCESS;
+    int major_version = 0, minor_version = 0;
+    int fd = -1;
+    char adapterpath[256];
+    int adapter_num;
+
+    qs->fd_display = -1;
+    qs->va_display = NULL;
+
+    //search for valid graphics device
+    for (adapter_num = 0;adapter_num < 6;adapter_num++) {
+
+        if (adapter_num<3) {
+            snprintf(adapterpath,sizeof(adapterpath),
+                "/dev/dri/renderD%d", adapter_num+128);
+        } else {
+            snprintf(adapterpath,sizeof(adapterpath),
+                "/dev/dri/card%d", adapter_num-3);
+        }
+
+        fd = open(adapterpath, O_RDWR);
+        if (fd < 0) {
+            av_log(avctx, AV_LOG_ERROR,
+                "mfx init: %s fd open failed\n", adapterpath);
+            continue;
+        }
+
+        va_dpy = vaGetDisplayDRM(fd);
+        if (!va_dpy) {
+            av_log(avctx, AV_LOG_ERROR,
+                "mfx init: %s vaGetDisplayDRM failed\n", adapterpath);
+            close(fd);
+            continue;
+        }
+
+        va_res = vaInitialize(va_dpy, &major_version, &minor_version);
+        if (VA_STATUS_SUCCESS != va_res) {
+            av_log(avctx, AV_LOG_ERROR,
+                "mfx init: %s vaInitialize failed\n", adapterpath);
+            close(fd);
+            fd = -1;
+            continue;
+        } else {
+            av_log(avctx, AV_LOG_VERBOSE,
+            "mfx initialization: %s vaInitialize successful\n",adapterpath);
+            qs->fd_display = fd;
+            qs->va_display = va_dpy;
+            ret = MFXVideoCORE_SetHandle(qs->session,
+                  (mfxHandleType)MFX_HANDLE_VA_DISPLAY, (mfxHDL)va_dpy);
+            if (ret < 0) {
+                return ff_qsv_print_error(avctx, ret, "Error %d during set display handle\n");
+            }
+            break;
+        }
+    }
+    return 0;
+}
+#endif //AVCODEC_QSV_LINUX_SESSION_HANDLE
+
+int ff_qsv_init_internal_session(AVCodecContext *avctx, QSVSession *qs,
                                  const char *load_plugins)
 {
     mfxIMPL impl   = MFX_IMPL_AUTO_ANY;
@@ -357,18 +429,24 @@  int ff_qsv_init_internal_session(AVCodecContext *avctx, mfxSession *session,
     const char *desc;
     int ret;
 
-    ret = MFXInit(impl, &ver, session);
+    ret = MFXInit(impl, &ver, &qs->session);
     if (ret < 0)
         return ff_qsv_print_error(avctx, ret,
                                   "Error initializing an internal MFX session");
 
-    ret = qsv_load_plugins(*session, load_plugins, avctx);
+#ifdef AVCODEC_QSV_LINUX_SESSION_HANDLE
+    ret = ff_qsv_set_display_handle(avctx, qs);
+    if (ret < 0)
+        return ret;
+#endif
+
+    ret = qsv_load_plugins(qs->session, load_plugins, avctx);
     if (ret < 0) {
         av_log(avctx, AV_LOG_ERROR, "Error loading plugins\n");
         return ret;
     }
 
-    MFXQueryIMPL(*session, &impl);
+    MFXQueryIMPL(qs->session, &impl);
 
     switch (MFX_IMPL_BASETYPE(impl)) {
     case MFX_IMPL_SOFTWARE:
@@ -758,3 +836,22 @@  int ff_qsv_init_session_frames(AVCodecContext *avctx, mfxSession *psession,
     *psession = session;
     return 0;
 }
+
+int ff_qsv_close_internal_session(QSVSession *qs)
+{
+    if (qs->session) {
+        MFXClose(qs->session);
+        qs->session = NULL;
+    }
+#ifdef AVCODEC_QSV_LINUX_SESSION_HANDLE
+    if (qs->va_display) {
+        vaTerminate(qs->va_display);
+        qs->va_display = NULL;
+    }
+    if (qs->fd_display > 0) {
+        close(qs->fd_display);
+        qs->fd_display = -1;
+    }
+#endif
+    return 0;
+}
diff --git a/libavcodec/qsv_internal.h b/libavcodec/qsv_internal.h
index c50e9c7..7678114 100644
--- a/libavcodec/qsv_internal.h
+++ b/libavcodec/qsv_internal.h
@@ -21,6 +21,21 @@ 
 #ifndef AVCODEC_QSV_INTERNAL_H
 #define AVCODEC_QSV_INTERNAL_H
 
+#if CONFIG_VAAPI
+#define AVCODEC_QSV_LINUX_SESSION_HANDLE
+#endif //CONFIG_VAAPI
+
+#ifdef AVCODEC_QSV_LINUX_SESSION_HANDLE
+#include <stdio.h>
+#include <string.h>
+#if HAVE_UNISTD_H
+#include <unistd.h>
+#endif
+#include <fcntl.h>
+#include <va/va.h>
+#include <va/va_drm.h>
+#endif
+
 #include <mfx/mfxvideo.h>
 
 #include "libavutil/frame.h"
@@ -64,6 +79,14 @@  typedef struct QSVFrame {
     struct QSVFrame *next;
 } QSVFrame;
 
+typedef struct QSVSession {
+    mfxSession session;
+#ifdef AVCODEC_QSV_LINUX_SESSION_HANDLE
+    int        fd_display;
+    VADisplay  va_display;
+#endif
+} QSVSession;
+
 typedef struct QSVFramesContext {
     AVBufferRef *hw_frames_ctx;
     void *logctx;
@@ -99,9 +122,11 @@  enum AVPictureType ff_qsv_map_pictype(int mfx_pic_type);
 
 enum AVFieldOrder ff_qsv_map_picstruct(int mfx_pic_struct);
 
-int ff_qsv_init_internal_session(AVCodecContext *avctx, mfxSession *session,
+int ff_qsv_init_internal_session(AVCodecContext *avctx, QSVSession *qs,
                                  const char *load_plugins);
 
+int ff_qsv_close_internal_session(QSVSession *qs);
+
 int ff_qsv_init_session_device(AVCodecContext *avctx, mfxSession *psession,
                                AVBufferRef *device_ref, const char *load_plugins);
 
diff --git a/libavcodec/qsvdec.c b/libavcodec/qsvdec.c
index eef4fe7..2fce478 100644
--- a/libavcodec/qsvdec.c
+++ b/libavcodec/qsvdec.c
@@ -62,9 +62,9 @@  static int qsv_init_session(AVCodecContext *avctx, QSVContext *q, mfxSession ses
     if (session) {
         q->session = session;
     } else if (hw_frames_ref) {
-        if (q->internal_session) {
-            MFXClose(q->internal_session);
-            q->internal_session = NULL;
+        if (q->internal_qs.session) {
+            MFXClose(q->internal_qs.session);
+            q->internal_qs.session = NULL;
         }
         av_buffer_unref(&q->frames_ctx.hw_frames_ctx);
 
@@ -72,7 +72,7 @@  static int qsv_init_session(AVCodecContext *avctx, QSVContext *q, mfxSession ses
         if (!q->frames_ctx.hw_frames_ctx)
             return AVERROR(ENOMEM);
 
-        ret = ff_qsv_init_session_frames(avctx, &q->internal_session,
+        ret = ff_qsv_init_session_frames(avctx, &q->internal_qs.session,
                                          &q->frames_ctx, q->load_plugins,
                                          q->iopattern == MFX_IOPATTERN_OUT_OPAQUE_MEMORY);
         if (ret < 0) {
@@ -80,28 +80,28 @@  static int qsv_init_session(AVCodecContext *avctx, QSVContext *q, mfxSession ses
             return ret;
         }
 
-        q->session = q->internal_session;
+        q->session = q->internal_qs.session;
     } else if (hw_device_ref) {
-        if (q->internal_session) {
-            MFXClose(q->internal_session);
-            q->internal_session = NULL;
+        if (q->internal_qs.session) {
+            MFXClose(q->internal_qs.session);
+            q->internal_qs.session = NULL;
         }
 
-        ret = ff_qsv_init_session_device(avctx, &q->internal_session,
+        ret = ff_qsv_init_session_device(avctx, &q->internal_qs.session,
                                          hw_device_ref, q->load_plugins);
         if (ret < 0)
             return ret;
 
-        q->session = q->internal_session;
+        q->session = q->internal_qs.session;
     } else {
-        if (!q->internal_session) {
-            ret = ff_qsv_init_internal_session(avctx, &q->internal_session,
+        if (!q->internal_qs.session) {
+            ret = ff_qsv_init_internal_session(avctx, &q->internal_qs,
                                                q->load_plugins);
             if (ret < 0)
                 return ret;
         }
 
-        q->session = q->internal_session;
+        q->session = q->internal_qs.session;
     }
 
     /* make sure the decoder is uninitialized */
@@ -529,8 +529,7 @@  int ff_qsv_decode_close(QSVContext *q)
     av_fifo_free(q->async_fifo);
     q->async_fifo = NULL;
 
-    if (q->internal_session)
-        MFXClose(q->internal_session);
+    ff_qsv_close_internal_session(&q->internal_qs);
 
     av_buffer_unref(&q->frames_ctx.hw_frames_ctx);
     av_buffer_unref(&q->frames_ctx.mids_buf);
diff --git a/libavcodec/qsvdec.h b/libavcodec/qsvdec.h
index c057bc6..64dc8d2 100644
--- a/libavcodec/qsvdec.h
+++ b/libavcodec/qsvdec.h
@@ -42,7 +42,7 @@  typedef struct QSVContext {
 
     // the session we allocated internally, in case the caller did not provide
     // one
-    mfxSession internal_session;
+    QSVSession internal_qs;
 
     QSVFramesContext frames_ctx;
 
diff --git a/libavcodec/qsvenc.c b/libavcodec/qsvenc.c
index 9bf8574..207cdc1 100644
--- a/libavcodec/qsvenc.c
+++ b/libavcodec/qsvenc.c
@@ -954,7 +954,7 @@  static int qsvenc_init_session(AVCodecContext *avctx, QSVEncContext *q)
         if (!q->frames_ctx.hw_frames_ctx)
             return AVERROR(ENOMEM);
 
-        ret = ff_qsv_init_session_frames(avctx, &q->internal_session,
+        ret = ff_qsv_init_session_frames(avctx, &q->internal_qs.session,
                                          &q->frames_ctx, q->load_plugins,
                                          q->param.IOPattern == MFX_IOPATTERN_IN_OPAQUE_MEMORY);
         if (ret < 0) {
@@ -962,21 +962,21 @@  static int qsvenc_init_session(AVCodecContext *avctx, QSVEncContext *q)
             return ret;
         }
 
-        q->session = q->internal_session;
+        q->session = q->internal_qs.session;
     } else if (avctx->hw_device_ctx) {
-        ret = ff_qsv_init_session_device(avctx, &q->internal_session,
+        ret = ff_qsv_init_session_device(avctx, &q->internal_qs.session,
                                          avctx->hw_device_ctx, q->load_plugins);
         if (ret < 0)
             return ret;
 
-        q->session = q->internal_session;
+        q->session = q->internal_qs.session;
     } else {
-        ret = ff_qsv_init_internal_session(avctx, &q->internal_session,
+        ret = ff_qsv_init_internal_session(avctx, &q->internal_qs,
                                            q->load_plugins);
         if (ret < 0)
             return ret;
 
-        q->session = q->internal_session;
+        q->session = q->internal_qs.session;
     }
 
     return 0;
@@ -1507,10 +1507,9 @@  int ff_qsv_enc_close(AVCodecContext *avctx, QSVEncContext *q)
 
     if (q->session)
         MFXVideoENCODE_Close(q->session);
-    if (q->internal_session)
-        MFXClose(q->internal_session);
+
     q->session          = NULL;
-    q->internal_session = NULL;
+    ff_qsv_close_internal_session(&q->internal_qs);
 
     av_buffer_unref(&q->frames_ctx.hw_frames_ctx);
     av_buffer_unref(&q->frames_ctx.mids_buf);
diff --git a/libavcodec/qsvenc.h b/libavcodec/qsvenc.h
index f2f4d38..ec8b541 100644
--- a/libavcodec/qsvenc.h
+++ b/libavcodec/qsvenc.h
@@ -102,7 +102,7 @@  typedef struct QSVEncContext {
     QSVFrame *work_frames;
 
     mfxSession session;
-    mfxSession internal_session;
+    QSVSession internal_qs;
 
     int packet_size;
     int width_align;