diff mbox

[FFmpeg-devel,v2] libavcodec/vp8dec: fix the multi-thread HWAccel decode error

Message ID 1553794093-19942-1-git-send-email-shaofei.wang@intel.com
State Superseded
Headers show

Commit Message

Shaofei Wang March 28, 2019, 5:28 p.m. UTC
Fix the issue: https://github.com/intel/media-driver/issues/317

the root cause is update_dimensions will be called multple times
when decoder thread number is not only 1, but update_dimensions
call get_pixel_format in each decode thread will trigger the
hwaccel_uninit/hwaccel_init more than once. But only one hwaccel
should be shared with all decode threads.
in current context,
there are 3 situations in the update_dimensions():
1. First time calling. No matter single thread or multithread,
   get_pixel_format() should be called after dimensions were
   set;
2. Dimention changed at the runtime. Dimention need to be
   updated when macroblocks_base is already allocated,
   get_pixel_format() should be called to recreate new frames
   according to updated dimention;
3. Multithread first time calling. After decoder init, the
   other threads will call update_dimensions() at first time
   to allocate macroblocks_base and set dimensions.
   But get_pixel_format() is shouldn't be called due to low
   level frames and context are already created.

In this fix, we only call update_dimensions as need.

Signed-off-by: Wang, Shaofei <shaofei.wang@intel.com>
Reviewed-by: Jun, Zhao <jun.zhao@intel.com>
Reviewed-by: Haihao Xiang <haihao.xiang@intel.com>
---
Previous code reviews:
2019-03-06 9:25 GMT+01:00, Wang, Shaofei <shaofei.wang@intel.com>:
>> -----Original Message-----
>> From: ffmpeg-devel [mailto:ffmpeg-devel-bounces@ffmpeg.org] On Behalf 
>> Of Carl Eugen Hoyos
>> Sent: Wednesday, March 6, 2019 3:49 PM
>> To: FFmpeg development discussions and patches 
>> <ffmpeg-devel@ffmpeg.org>
>> Subject: Re: [FFmpeg-devel] [PATCH] libavcodec/vp8dec: fix the 
>> multi-thread HWAccel decode error
>>
>> 2018-08-09 9:09 GMT+02:00, Jun Zhao <mypopydev@gmail.com>:
>> > the root cause is update_dimentions call get_pixel_format will 
>> > trigger the hwaccel_uninit/hwaccel_init , in current context, there 
>> > are 3 situations in the update_dimentions():
>> > 1. First time calling. No matter single thread or multithread,
>> >    get_pixel_format() should be called after dimentions were
>> >    set;
>> > 2. Dimention changed at the runtime. Dimention need to be
>> >    updated when macroblocks_base is already allocated,
>> >    get_pixel_format() should be called to recreate new frames
>> >    according to updated dimention;
>> > 3. Multithread first time calling. After decoder init, the
>> >    other threads will call update_dimentions() at first time
>> >    to allocate macroblocks_base and set dimentions.
>> >    But get_pixel_format() is shouldn't be called due to low
>> >    level frames and context are already created.
>> > In this fix, we only call update_dimentions as need.
>> >
>> > Signed-off-by: Wang, Shaofei <shaofei.wang@intel.com>
>> > Reviewed-by: Jun, Zhao <jun.zhao@intel.com>
>> > ---
>> >  libavcodec/vp8.c |    7 +++++--
>> >  1 files changed, 5 insertions(+), 2 deletions(-)
>> >
>> > diff --git a/libavcodec/vp8.c b/libavcodec/vp8.c index 
>> > 3adfeac..18d1ada 100644
>> > --- a/libavcodec/vp8.c
>> > +++ b/libavcodec/vp8.c
>> > @@ -187,7 +187,7 @@ static av_always_inline  int 
>> > update_dimensions(VP8Context *s, int width, int height, int is_vp7)  {
>> >      AVCodecContext *avctx = s->avctx;
>> > -    int i, ret;
>> > +    int i, ret, dim_reset = 0;
>> >
>> >      if (width  != s->avctx->width || ((width+15)/16 != s->mb_width 
>> > ||
>> > (height+15)/16 != s->mb_height) && s->macroblocks_base ||
>> >          height != s->avctx->height) { @@ -196,9 +196,12 @@ int 
>> > update_dimensions(VP8Context *s, int width, int height, int is_vp7)
>> >          ret = ff_set_dimensions(s->avctx, width, height);
>> >          if (ret < 0)
>> >              return ret;
>> > +
>> > +        dim_reset = (s->macroblocks_base != NULL);
>> >      }
>> >
>> > -    if (!s->actually_webp && !is_vp7) {
>> > +    if ((s->pix_fmt == AV_PIX_FMT_NONE || dim_reset) &&
>> > +         !s->actually_webp && !is_vp7) {
>>
>> Why is the new variable dim_reset needed?
>> Wouldn't the patch be simpler if you used s->macroblocks_base here?
> Since dim_reset was set in the "if" segment, it equal to (width != 
> s->avctx->width || ((width+15)/16 != s->mb_width ||
> (height+15)/16 != s->mb_height) || height != s->avctx->height) &&
> s->macroblocks_base

Thank you!

Carl Eugen


 libavcodec/vp8.c | 7 +++++--
 1 file changed, 5 insertions(+), 2 deletions(-)

Comments

Xiang, Haihao May 28, 2019, 4:23 a.m. UTC | #1
On Thu, 2019-03-28 at 13:28 -0400, Shaofei Wang wrote:
> Fix the issue: https://github.com/intel/media-driver/issues/317

> 

> the root cause is update_dimensions will be called multple times

> when decoder thread number is not only 1, but update_dimensions

> call get_pixel_format in each decode thread will trigger the

> hwaccel_uninit/hwaccel_init more than once. But only one hwaccel

> should be shared with all decode threads.

> in current context,

> there are 3 situations in the update_dimensions():

> 1. First time calling. No matter single thread or multithread,

>    get_pixel_format() should be called after dimensions were

>    set;

> 2. Dimention changed at the runtime. Dimention need to be

>    updated when macroblocks_base is already allocated,

>    get_pixel_format() should be called to recreate new frames

>    according to updated dimention;


s/Dimention/dimension ?

BTW this version of patch doesn't address the concern provided when reviewing
the first version of patch. 

When (width != s->avctx->width || height != s->avctx->height) is true,
ff_set_dimensions() is called even if s->macroblocks_base is not allocated, so 
why set dim_reset to (s->macroblocks_base != NULL)? I think dim_reset should be
set to 1.

>     if (width  != s->avctx->width || ((width+15)/16 != s->mb_width ||

> (height+15)/16 != s->mb_height) && s->macroblocks_base ||

>          height != s->avctx->height) {

> @@ -196,9 +196,12 @@ int update_dimensions(VP8Context *s, int width, int

> height, int is_vp7)

>          ret = ff_set_dimensions(s->avctx, width, height);

>          if (ret < 0)

>              return ret;

> +

> +        dim_reset = (s->macroblocks_base != NULL);



> 3. Multithread first time calling. After decoder init, the

>    other threads will call update_dimensions() at first time

>    to allocate macroblocks_base and set dimensions.

>    But get_pixel_format() is shouldn't be called due to low

>    level frames and context are already created.

> 

> In this fix, we only call update_dimensions as need.

> 

> Signed-off-by: Wang, Shaofei <shaofei.wang@intel.com>

> Reviewed-by: Jun, Zhao <jun.zhao@intel.com>

> Reviewed-by: Haihao Xiang <haihao.xiang@intel.com>

> ---

> Previous code reviews:

> 2019-03-06 9:25 GMT+01:00, Wang, Shaofei <shaofei.wang@intel.com>:

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

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

> > > Of Carl Eugen Hoyos

> > > Sent: Wednesday, March 6, 2019 3:49 PM

> > > To: FFmpeg development discussions and patches 

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

> > > Subject: Re: [FFmpeg-devel] [PATCH] libavcodec/vp8dec: fix the 

> > > multi-thread HWAccel decode error

> > > 

> > > 2018-08-09 9:09 GMT+02:00, Jun Zhao <mypopydev@gmail.com>:

> > > > the root cause is update_dimentions call get_pixel_format will 

> > > > trigger the hwaccel_uninit/hwaccel_init , in current context, there 

> > > > are 3 situations in the update_dimentions():

> > > > 1. First time calling. No matter single thread or multithread,

> > > >    get_pixel_format() should be called after dimentions were

> > > >    set;

> > > > 2. Dimention changed at the runtime. Dimention need to be

> > > >    updated when macroblocks_base is already allocated,

> > > >    get_pixel_format() should be called to recreate new frames

> > > >    according to updated dimention;

> > > > 3. Multithread first time calling. After decoder init, the

> > > >    other threads will call update_dimentions() at first time

> > > >    to allocate macroblocks_base and set dimentions.

> > > >    But get_pixel_format() is shouldn't be called due to low

> > > >    level frames and context are already created.

> > > > In this fix, we only call update_dimentions as need.

> > > > 

> > > > Signed-off-by: Wang, Shaofei <shaofei.wang@intel.com>

> > > > Reviewed-by: Jun, Zhao <jun.zhao@intel.com>

> > > > ---

> > > >  libavcodec/vp8.c |    7 +++++--

> > > >  1 files changed, 5 insertions(+), 2 deletions(-)

> > > > 

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

> > > > 3adfeac..18d1ada 100644

> > > > --- a/libavcodec/vp8.c

> > > > +++ b/libavcodec/vp8.c

> > > > @@ -187,7 +187,7 @@ static av_always_inline  int 

> > > > update_dimensions(VP8Context *s, int width, int height, int is_vp7)  {

> > > >      AVCodecContext *avctx = s->avctx;

> > > > -    int i, ret;

> > > > +    int i, ret, dim_reset = 0;

> > > > 

> > > >      if (width  != s->avctx->width || ((width+15)/16 != s->mb_width 

> > > > > > 

> > > > 

> > > > (height+15)/16 != s->mb_height) && s->macroblocks_base ||

> > > >          height != s->avctx->height) { @@ -196,9 +196,12 @@ int 

> > > > update_dimensions(VP8Context *s, int width, int height, int is_vp7)

> > > >          ret = ff_set_dimensions(s->avctx, width, height);

> > > >          if (ret < 0)

> > > >              return ret;

> > > > +

> > > > +        dim_reset = (s->macroblocks_base != NULL);

> > > >      }

> > > > 

> > > > -    if (!s->actually_webp && !is_vp7) {

> > > > +    if ((s->pix_fmt == AV_PIX_FMT_NONE || dim_reset) &&

> > > > +         !s->actually_webp && !is_vp7) {

> > > 

> > > Why is the new variable dim_reset needed?

> > > Wouldn't the patch be simpler if you used s->macroblocks_base here?

> > 

> > Since dim_reset was set in the "if" segment, it equal to (width != 

> > s->avctx->width || ((width+15)/16 != s->mb_width ||

> > (height+15)/16 != s->mb_height) || height != s->avctx->height) &&

> > s->macroblocks_base

> 

> Thank you!

> 

> Carl Eugen

> 

> 

>  libavcodec/vp8.c | 7 +++++--

>  1 file changed, 5 insertions(+), 2 deletions(-)

> 

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

> index ba79e5f..0a7f38b 100644

> --- a/libavcodec/vp8.c

> +++ b/libavcodec/vp8.c

> @@ -187,7 +187,7 @@ static av_always_inline

>  int update_dimensions(VP8Context *s, int width, int height, int is_vp7)

>  {

>      AVCodecContext *avctx = s->avctx;

> -    int i, ret;

> +    int i, ret, dim_reset = 0;

>  

>      if (width  != s->avctx->width || ((width+15)/16 != s->mb_width ||

> (height+15)/16 != s->mb_height) && s->macroblocks_base ||

>          height != s->avctx->height) {

> @@ -196,9 +196,12 @@ int update_dimensions(VP8Context *s, int width, int

> height, int is_vp7)

>          ret = ff_set_dimensions(s->avctx, width, height);

>          if (ret < 0)

>              return ret;

> +

> +        dim_reset = (s->macroblocks_base != NULL);

>      }

>  

> -    if (!s->actually_webp && !is_vp7) {

> +    if ((s->pix_fmt == AV_PIX_FMT_NONE || dim_reset) &&

> +         !s->actually_webp && !is_vp7) {

>          s->pix_fmt = get_pixel_format(s);

>          if (s->pix_fmt < 0)

>              return AVERROR(EINVAL);
Shaofei Wang June 4, 2019, 7:21 a.m. UTC | #2
> -----Original Message-----

> From: Xiang, Haihao

> Sent: Tuesday, May 28, 2019 12:23 PM

> To: ffmpeg-devel@ffmpeg.org

> Cc: Wang, Shaofei <shaofei.wang@intel.com>

> Subject: Re: [FFmpeg-devel] [PATCH v2] libavcodec/vp8dec: fix the

> multi-thread HWAccel decode error

> 

> On Thu, 2019-03-28 at 13:28 -0400, Shaofei Wang wrote:

> > Fix the issue: https://github.com/intel/media-driver/issues/317

> >

> > the root cause is update_dimensions will be called multple times when

> > decoder thread number is not only 1, but update_dimensions call

> > get_pixel_format in each decode thread will trigger the

> > hwaccel_uninit/hwaccel_init more than once. But only one hwaccel

> > should be shared with all decode threads.

> > in current context,

> > there are 3 situations in the update_dimensions():

> > 1. First time calling. No matter single thread or multithread,

> >    get_pixel_format() should be called after dimensions were

> >    set;

> > 2. Dimention changed at the runtime. Dimention need to be

> >    updated when macroblocks_base is already allocated,

> >    get_pixel_format() should be called to recreate new frames

> >    according to updated dimention;

> 

> s/Dimention/dimension ?

OK, should be dimension

> BTW this version of patch doesn't address the concern provided when

> reviewing the first version of patch.

> 

> When (width != s->avctx->width || height != s->avctx->height) is true,

> ff_set_dimensions() is called even if s->macroblocks_base is not allocated, so

> why set dim_reset to (s->macroblocks_base != NULL)? I think dim_reset

> should be set to 1.

If s->macroblocks_base is available, it means macroblocks_base of the context 
 has been already allocated by one of threads, so it's a reset operation when
 (width != s->avctx->width...
If s->macroblocks_base is null, it's not allocated yet, and
(width != s->avctx->width..., just dimension need to be updated but it's not a
dim reset operation. Since we only call get_pixel_format() in the first thread or
 in the reset operation

> >     if (width  != s->avctx->width || ((width+15)/16 != s->mb_width ||

> > (height+15)/16 != s->mb_height) && s->macroblocks_base ||

> >          height != s->avctx->height) { @@ -196,9 +196,12 @@ int

> > update_dimensions(VP8Context *s, int width, int height, int is_vp7)

> >          ret = ff_set_dimensions(s->avctx, width, height);

> >          if (ret < 0)

> >              return ret;

> > +

> > +        dim_reset = (s->macroblocks_base != NULL);

> 

> 

> > 3. Multithread first time calling. After decoder init, the

> >    other threads will call update_dimensions() at first time

> >    to allocate macroblocks_base and set dimensions.

> >    But get_pixel_format() is shouldn't be called due to low

> >    level frames and context are already created.

> >

> > In this fix, we only call update_dimensions as need.

> >

> > Signed-off-by: Wang, Shaofei <shaofei.wang@intel.com>

> > Reviewed-by: Jun, Zhao <jun.zhao@intel.com>

> > Reviewed-by: Haihao Xiang <haihao.xiang@intel.com>

> > ---

> > Previous code reviews:

> > 2019-03-06 9:25 GMT+01:00, Wang, Shaofei <shaofei.wang@intel.com>:

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

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

> > > > Behalf Of Carl Eugen Hoyos

> > > > Sent: Wednesday, March 6, 2019 3:49 PM

> > > > To: FFmpeg development discussions and patches

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

> > > > Subject: Re: [FFmpeg-devel] [PATCH] libavcodec/vp8dec: fix the

> > > > multi-thread HWAccel decode error

> > > >

> > > > 2018-08-09 9:09 GMT+02:00, Jun Zhao <mypopydev@gmail.com>:

> > > > > the root cause is update_dimentions call get_pixel_format will

> > > > > trigger the hwaccel_uninit/hwaccel_init , in current context,

> > > > > there are 3 situations in the update_dimentions():

> > > > > 1. First time calling. No matter single thread or multithread,

> > > > >    get_pixel_format() should be called after dimentions were

> > > > >    set;

> > > > > 2. Dimention changed at the runtime. Dimention need to be

> > > > >    updated when macroblocks_base is already allocated,

> > > > >    get_pixel_format() should be called to recreate new frames

> > > > >    according to updated dimention; 3. Multithread first time

> > > > > calling. After decoder init, the

> > > > >    other threads will call update_dimentions() at first time

> > > > >    to allocate macroblocks_base and set dimentions.

> > > > >    But get_pixel_format() is shouldn't be called due to low

> > > > >    level frames and context are already created.

> > > > > In this fix, we only call update_dimentions as need.

> > > > >

> > > > > Signed-off-by: Wang, Shaofei <shaofei.wang@intel.com>

> > > > > Reviewed-by: Jun, Zhao <jun.zhao@intel.com>

> > > > > ---

> > > > >  libavcodec/vp8.c |    7 +++++--

> > > > >  1 files changed, 5 insertions(+), 2 deletions(-)

> > > > >

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

> > > > > 3adfeac..18d1ada 100644

> > > > > --- a/libavcodec/vp8.c

> > > > > +++ b/libavcodec/vp8.c

> > > > > @@ -187,7 +187,7 @@ static av_always_inline  int

> > > > > update_dimensions(VP8Context *s, int width, int height, int is_vp7)  {

> > > > >      AVCodecContext *avctx = s->avctx;

> > > > > -    int i, ret;

> > > > > +    int i, ret, dim_reset = 0;

> > > > >

> > > > >      if (width  != s->avctx->width || ((width+15)/16 !=

> > > > > s->mb_width

> > > > > > >

> > > > >

> > > > > (height+15)/16 != s->mb_height) && s->macroblocks_base ||

> > > > >          height != s->avctx->height) { @@ -196,9 +196,12 @@ int

> > > > > update_dimensions(VP8Context *s, int width, int height, int is_vp7)

> > > > >          ret = ff_set_dimensions(s->avctx, width, height);

> > > > >          if (ret < 0)

> > > > >              return ret;

> > > > > +

> > > > > +        dim_reset = (s->macroblocks_base != NULL);

> > > > >      }

> > > > >

> > > > > -    if (!s->actually_webp && !is_vp7) {

> > > > > +    if ((s->pix_fmt == AV_PIX_FMT_NONE || dim_reset) &&

> > > > > +         !s->actually_webp && !is_vp7) {

> > > >

> > > > Why is the new variable dim_reset needed?

> > > > Wouldn't the patch be simpler if you used s->macroblocks_base here?

> > >

> > > Since dim_reset was set in the "if" segment, it equal to (width !=

> > > s->avctx->width || ((width+15)/16 != s->mb_width ||

> > > (height+15)/16 != s->mb_height) || height != s->avctx->height) &&

> > > s->macroblocks_base

> >

> > Thank you!

> >

> > Carl Eugen

> >

> >

> >  libavcodec/vp8.c | 7 +++++--

> >  1 file changed, 5 insertions(+), 2 deletions(-)

> >

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

> > ba79e5f..0a7f38b 100644

> > --- a/libavcodec/vp8.c

> > +++ b/libavcodec/vp8.c

> > @@ -187,7 +187,7 @@ static av_always_inline  int

> > update_dimensions(VP8Context *s, int width, int height, int is_vp7)  {

> >      AVCodecContext *avctx = s->avctx;

> > -    int i, ret;

> > +    int i, ret, dim_reset = 0;

> >

> >      if (width  != s->avctx->width || ((width+15)/16 != s->mb_width ||

> > (height+15)/16 != s->mb_height) && s->macroblocks_base ||

> >          height != s->avctx->height) { @@ -196,9 +196,12 @@ int

> > update_dimensions(VP8Context *s, int width, int height, int is_vp7)

> >          ret = ff_set_dimensions(s->avctx, width, height);

> >          if (ret < 0)

> >              return ret;

> > +

> > +        dim_reset = (s->macroblocks_base != NULL);

> >      }

> >

> > -    if (!s->actually_webp && !is_vp7) {

> > +    if ((s->pix_fmt == AV_PIX_FMT_NONE || dim_reset) &&

> > +         !s->actually_webp && !is_vp7) {

> >          s->pix_fmt = get_pixel_format(s);

> >          if (s->pix_fmt < 0)

> >              return AVERROR(EINVAL);
Xiang, Haihao June 6, 2019, 3:57 a.m. UTC | #3
On Tue, 2019-06-04 at 15:21 +0800, Wang, Shaofei wrote:
> > -----Original Message-----

> > From: Xiang, Haihao

> > Sent: Tuesday, May 28, 2019 12:23 PM

> > To: ffmpeg-devel@ffmpeg.org

> > Cc: Wang, Shaofei <shaofei.wang@intel.com>

> > Subject: Re: [FFmpeg-devel] [PATCH v2] libavcodec/vp8dec: fix the

> > multi-thread HWAccel decode error

> > 

> > On Thu, 2019-03-28 at 13:28 -0400, Shaofei Wang wrote:

> > > Fix the issue: https://github.com/intel/media-driver/issues/317

> > > 

> > > the root cause is update_dimensions will be called multple times when

> > > decoder thread number is not only 1, but update_dimensions call

> > > get_pixel_format in each decode thread will trigger the

> > > hwaccel_uninit/hwaccel_init more than once. But only one hwaccel

> > > should be shared with all decode threads.

> > > in current context,

> > > there are 3 situations in the update_dimensions():

> > > 1. First time calling. No matter single thread or multithread,

> > >    get_pixel_format() should be called after dimensions were

> > >    set;

> > > 2. Dimention changed at the runtime. Dimention need to be

> > >    updated when macroblocks_base is already allocated,

> > >    get_pixel_format() should be called to recreate new frames

> > >    according to updated dimention;

> > 

> > s/Dimention/dimension ?

> 

> OK, should be dimension

> 

> > BTW this version of patch doesn't address the concern provided when

> > reviewing the first version of patch.

> > 

> > When (width != s->avctx->width || height != s->avctx->height) is true,

> > ff_set_dimensions() is called even if s->macroblocks_base is not allocated,

> > so

> > why set dim_reset to (s->macroblocks_base != NULL)? I think dim_reset

> > should be set to 1.

> 

> If s->macroblocks_base is available, it means macroblocks_base of the context 

>  has been already allocated by one of threads, so it's a reset operation when

>  (width != s->avctx->width...

> If s->macroblocks_base is null, it's not allocated yet, and

> (width != s->avctx->width..., just dimension need to be updated but it's not a

> dim reset operation. Since we only call get_pixel_format() in the first thread

> or

>  in the reset operation


Is it reasonable when dimension is updated however the low level frame still use
stale dimension info? 

Thanks
Haihao


> 

> > >     if (width  != s->avctx->width || ((width+15)/16 != s->mb_width ||

> > > (height+15)/16 != s->mb_height) && s->macroblocks_base ||

> > >          height != s->avctx->height) { @@ -196,9 +196,12 @@ int

> > > update_dimensions(VP8Context *s, int width, int height, int is_vp7)

> > >          ret = ff_set_dimensions(s->avctx, width, height);

> > >          if (ret < 0)

> > >              return ret;

> > > +

> > > +        dim_reset = (s->macroblocks_base != NULL);

> > 

> > 

> > > 3. Multithread first time calling. After decoder init, the

> > >    other threads will call update_dimensions() at first time

> > >    to allocate macroblocks_base and set dimensions.

> > >    But get_pixel_format() is shouldn't be called due to low

> > >    level frames and context are already created.

> > > 

> > > In this fix, we only call update_dimensions as need.

> > > 

> > > Signed-off-by: Wang, Shaofei <shaofei.wang@intel.com>

> > > Reviewed-by: Jun, Zhao <jun.zhao@intel.com>

> > > Reviewed-by: Haihao Xiang <haihao.xiang@intel.com>

> > > ---

> > > Previous code reviews:

> > > 2019-03-06 9:25 GMT+01:00, Wang, Shaofei <shaofei.wang@intel.com>:

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

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

> > > > > Behalf Of Carl Eugen Hoyos

> > > > > Sent: Wednesday, March 6, 2019 3:49 PM

> > > > > To: FFmpeg development discussions and patches

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

> > > > > Subject: Re: [FFmpeg-devel] [PATCH] libavcodec/vp8dec: fix the

> > > > > multi-thread HWAccel decode error

> > > > > 

> > > > > 2018-08-09 9:09 GMT+02:00, Jun Zhao <mypopydev@gmail.com>:

> > > > > > the root cause is update_dimentions call get_pixel_format will

> > > > > > trigger the hwaccel_uninit/hwaccel_init , in current context,

> > > > > > there are 3 situations in the update_dimentions():

> > > > > > 1. First time calling. No matter single thread or multithread,

> > > > > >    get_pixel_format() should be called after dimentions were

> > > > > >    set;

> > > > > > 2. Dimention changed at the runtime. Dimention need to be

> > > > > >    updated when macroblocks_base is already allocated,

> > > > > >    get_pixel_format() should be called to recreate new frames

> > > > > >    according to updated dimention; 3. Multithread first time

> > > > > > calling. After decoder init, the

> > > > > >    other threads will call update_dimentions() at first time

> > > > > >    to allocate macroblocks_base and set dimentions.

> > > > > >    But get_pixel_format() is shouldn't be called due to low

> > > > > >    level frames and context are already created.

> > > > > > In this fix, we only call update_dimentions as need.

> > > > > > 

> > > > > > Signed-off-by: Wang, Shaofei <shaofei.wang@intel.com>

> > > > > > Reviewed-by: Jun, Zhao <jun.zhao@intel.com>

> > > > > > ---

> > > > > >  libavcodec/vp8.c |    7 +++++--

> > > > > >  1 files changed, 5 insertions(+), 2 deletions(-)

> > > > > > 

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

> > > > > > 3adfeac..18d1ada 100644

> > > > > > --- a/libavcodec/vp8.c

> > > > > > +++ b/libavcodec/vp8.c

> > > > > > @@ -187,7 +187,7 @@ static av_always_inline  int

> > > > > > update_dimensions(VP8Context *s, int width, int height, int

> > > > > > is_vp7)  {

> > > > > >      AVCodecContext *avctx = s->avctx;

> > > > > > -    int i, ret;

> > > > > > +    int i, ret, dim_reset = 0;

> > > > > > 

> > > > > >      if (width  != s->avctx->width || ((width+15)/16 !=

> > > > > > s->mb_width

> > > > > > > > 

> > > > > > 

> > > > > > (height+15)/16 != s->mb_height) && s->macroblocks_base ||

> > > > > >          height != s->avctx->height) { @@ -196,9 +196,12 @@ int

> > > > > > update_dimensions(VP8Context *s, int width, int height, int is_vp7)

> > > > > >          ret = ff_set_dimensions(s->avctx, width, height);

> > > > > >          if (ret < 0)

> > > > > >              return ret;

> > > > > > +

> > > > > > +        dim_reset = (s->macroblocks_base != NULL);

> > > > > >      }

> > > > > > 

> > > > > > -    if (!s->actually_webp && !is_vp7) {

> > > > > > +    if ((s->pix_fmt == AV_PIX_FMT_NONE || dim_reset) &&

> > > > > > +         !s->actually_webp && !is_vp7) {

> > > > > 

> > > > > Why is the new variable dim_reset needed?

> > > > > Wouldn't the patch be simpler if you used s->macroblocks_base here?

> > > > 

> > > > Since dim_reset was set in the "if" segment, it equal to (width !=

> > > > s->avctx->width || ((width+15)/16 != s->mb_width ||

> > > > (height+15)/16 != s->mb_height) || height != s->avctx->height) &&

> > > > s->macroblocks_base

> > > 

> > > Thank you!

> > > 

> > > Carl Eugen

> > > 

> > > 

> > >  libavcodec/vp8.c | 7 +++++--

> > >  1 file changed, 5 insertions(+), 2 deletions(-)

> > > 

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

> > > ba79e5f..0a7f38b 100644

> > > --- a/libavcodec/vp8.c

> > > +++ b/libavcodec/vp8.c

> > > @@ -187,7 +187,7 @@ static av_always_inline  int

> > > update_dimensions(VP8Context *s, int width, int height, int is_vp7)  {

> > >      AVCodecContext *avctx = s->avctx;

> > > -    int i, ret;

> > > +    int i, ret, dim_reset = 0;

> > > 

> > >      if (width  != s->avctx->width || ((width+15)/16 != s->mb_width ||

> > > (height+15)/16 != s->mb_height) && s->macroblocks_base ||

> > >          height != s->avctx->height) { @@ -196,9 +196,12 @@ int

> > > update_dimensions(VP8Context *s, int width, int height, int is_vp7)

> > >          ret = ff_set_dimensions(s->avctx, width, height);

> > >          if (ret < 0)

> > >              return ret;

> > > +

> > > +        dim_reset = (s->macroblocks_base != NULL);

> > >      }

> > > 

> > > -    if (!s->actually_webp && !is_vp7) {

> > > +    if ((s->pix_fmt == AV_PIX_FMT_NONE || dim_reset) &&

> > > +         !s->actually_webp && !is_vp7) {

> > >          s->pix_fmt = get_pixel_format(s);

> > >          if (s->pix_fmt < 0)

> > >              return AVERROR(EINVAL);
Shaofei Wang June 6, 2019, 7:21 a.m. UTC | #4
> -----Original Message-----

> From: Xiang, Haihao

> Sent: Thursday, June 6, 2019 11:57 AM

> To: ffmpeg-devel@ffmpeg.org; Wang, Shaofei <shaofei.wang@intel.com>

> Subject: Re: [FFmpeg-devel] [PATCH v2] libavcodec/vp8dec: fix the

> multi-thread HWAccel decode error

> 

> On Tue, 2019-06-04 at 15:21 +0800, Wang, Shaofei wrote:

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

> > > From: Xiang, Haihao

> > > Sent: Tuesday, May 28, 2019 12:23 PM

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

> > > Cc: Wang, Shaofei <shaofei.wang@intel.com>

> > > Subject: Re: [FFmpeg-devel] [PATCH v2] libavcodec/vp8dec: fix the

> > > multi-thread HWAccel decode error

> > >

> > > On Thu, 2019-03-28 at 13:28 -0400, Shaofei Wang wrote:

> > > > Fix the issue: https://github.com/intel/media-driver/issues/317

> > > >

> > > > the root cause is update_dimensions will be called multple times

> > > > when decoder thread number is not only 1, but update_dimensions

> > > > call get_pixel_format in each decode thread will trigger the

> > > > hwaccel_uninit/hwaccel_init more than once. But only one hwaccel

> > > > should be shared with all decode threads.

> > > > in current context,

> > > > there are 3 situations in the update_dimensions():

> > > > 1. First time calling. No matter single thread or multithread,

> > > >    get_pixel_format() should be called after dimensions were

> > > >    set;

> > > > 2. Dimention changed at the runtime. Dimention need to be

> > > >    updated when macroblocks_base is already allocated,

> > > >    get_pixel_format() should be called to recreate new frames

> > > >    according to updated dimention;

> > >

> > > s/Dimention/dimension ?

> >

> > OK, should be dimension

> >

> > > BTW this version of patch doesn't address the concern provided when

> > > reviewing the first version of patch.

> > >

> > > When (width != s->avctx->width || height != s->avctx->height) is

> > > true,

> > > ff_set_dimensions() is called even if s->macroblocks_base is not

> > > allocated, so why set dim_reset to (s->macroblocks_base != NULL)? I

> > > think dim_reset should be set to 1.

> >

> > If s->macroblocks_base is available, it means macroblocks_base of the

> > context  has been already allocated by one of threads, so it's a reset

> > operation when  (width != s->avctx->width...

> > If s->macroblocks_base is null, it's not allocated yet, and (width !=

> > s->avctx->width..., just dimension need to be updated but it's not a

> > dim reset operation. Since we only call get_pixel_format() in the

> > first thread or  in the reset operation

> 

> Is it reasonable when dimension is updated however the low level frame still

> use stale dimension info?

> 

> Thanks

> Haihao


The low level frame, especially hw frame will just need to be updated once.
For example, the init phase of the first thread will call update_dimension and
init hwaccel by get_pixel_format, but not needed to update low level frame for
the follow-up threads.
Xiang, Haihao June 11, 2019, 4:11 a.m. UTC | #5
On Thu, 2019-06-06 at 15:21 +0800, Wang, Shaofei wrote:
> > -----Original Message-----

> > From: Xiang, Haihao

> > Sent: Thursday, June 6, 2019 11:57 AM

> > To: ffmpeg-devel@ffmpeg.org; Wang, Shaofei <shaofei.wang@intel.com>

> > Subject: Re: [FFmpeg-devel] [PATCH v2] libavcodec/vp8dec: fix the

> > multi-thread HWAccel decode error

> > 

> > On Tue, 2019-06-04 at 15:21 +0800, Wang, Shaofei wrote:

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

> > > > From: Xiang, Haihao

> > > > Sent: Tuesday, May 28, 2019 12:23 PM

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

> > > > Cc: Wang, Shaofei <shaofei.wang@intel.com>

> > > > Subject: Re: [FFmpeg-devel] [PATCH v2] libavcodec/vp8dec: fix the

> > > > multi-thread HWAccel decode error

> > > > 

> > > > On Thu, 2019-03-28 at 13:28 -0400, Shaofei Wang wrote:

> > > > > Fix the issue: https://github.com/intel/media-driver/issues/317

> > > > > 

> > > > > the root cause is update_dimensions will be called multple times

> > > > > when decoder thread number is not only 1, but update_dimensions

> > > > > call get_pixel_format in each decode thread will trigger the

> > > > > hwaccel_uninit/hwaccel_init more than once. But only one hwaccel

> > > > > should be shared with all decode threads.

> > > > > in current context,

> > > > > there are 3 situations in the update_dimensions():

> > > > > 1. First time calling. No matter single thread or multithread,

> > > > >    get_pixel_format() should be called after dimensions were

> > > > >    set;

> > > > > 2. Dimention changed at the runtime. Dimention need to be

> > > > >    updated when macroblocks_base is already allocated,

> > > > >    get_pixel_format() should be called to recreate new frames

> > > > >    according to updated dimention;

> > > > 

> > > > s/Dimention/dimension ?

> > > 

> > > OK, should be dimension

> > > 

> > > > BTW this version of patch doesn't address the concern provided when

> > > > reviewing the first version of patch.

> > > > 

> > > > When (width != s->avctx->width || height != s->avctx->height) is

> > > > true,

> > > > ff_set_dimensions() is called even if s->macroblocks_base is not

> > > > allocated, so why set dim_reset to (s->macroblocks_base != NULL)? I

> > > > think dim_reset should be set to 1.

> > > 

> > > If s->macroblocks_base is available, it means macroblocks_base of the

> > > context  has been already allocated by one of threads, so it's a reset

> > > operation when  (width != s->avctx->width...

> > > If s->macroblocks_base is null, it's not allocated yet, and (width !=

> > > s->avctx->width..., just dimension need to be updated but it's not a

> > > dim reset operation. Since we only call get_pixel_format() in the

> > > first thread or  in the reset operation

> > 

> > Is it reasonable when dimension is updated however the low level frame still

> > use stale dimension info?

> > 

> > Thanks

> > Haihao

> 

> The low level frame, especially hw frame will just need to be updated once.

> For example, the init phase of the first thread will call update_dimension and

> init hwaccel by get_pixel_format, but not needed to update low level frame for

> the follow-up threads.


I get your point, thanks for detailed explanation.
diff mbox

Patch

diff --git a/libavcodec/vp8.c b/libavcodec/vp8.c
index ba79e5f..0a7f38b 100644
--- a/libavcodec/vp8.c
+++ b/libavcodec/vp8.c
@@ -187,7 +187,7 @@  static av_always_inline
 int update_dimensions(VP8Context *s, int width, int height, int is_vp7)
 {
     AVCodecContext *avctx = s->avctx;
-    int i, ret;
+    int i, ret, dim_reset = 0;
 
     if (width  != s->avctx->width || ((width+15)/16 != s->mb_width || (height+15)/16 != s->mb_height) && s->macroblocks_base ||
         height != s->avctx->height) {
@@ -196,9 +196,12 @@  int update_dimensions(VP8Context *s, int width, int height, int is_vp7)
         ret = ff_set_dimensions(s->avctx, width, height);
         if (ret < 0)
             return ret;
+
+        dim_reset = (s->macroblocks_base != NULL);
     }
 
-    if (!s->actually_webp && !is_vp7) {
+    if ((s->pix_fmt == AV_PIX_FMT_NONE || dim_reset) &&
+         !s->actually_webp && !is_vp7) {
         s->pix_fmt = get_pixel_format(s);
         if (s->pix_fmt < 0)
             return AVERROR(EINVAL);