diff mbox

[FFmpeg-devel,1/2] pixdesc: Improve scoring for opaque/unknown pixel formats

Message ID 8ef60c68-b260-83a2-8765-87737879e0b3@jkqxz.net
State Superseded
Headers show

Commit Message

Mark Thompson July 6, 2017, 9:59 p.m. UTC
Hardware pixel formats do not tell you anything about their actual
contents, but should still score higher than formats with completely
unknown properties, which in turn should score higher than invalid
formats.

Do not return an AVERROR code as a score.

Fixes a hang in libavfilter where format negotiation gets stuck in a
loop because AV_PIX_FMT_NONE scores more highly than all other
possibilities.
---
The hang in libavfilter happens when trying to choose a pixfmt for output from a list of software formats when a hardware format is the input (the hwdownload filter does this).  The matching begins with AV_PIX_FMT_NONE as an invalid value and compares against each possibility in turn, but unfortunately it scores -1 when considered as a conversion from an opaque hardware format, higher than the AVERROR(EINVAL) (== -22 on Linux) scored for all of the real formats.  Hence the format selection code chooses AV_PIX_FMT_NONE and thinks it is making forward progress, but actually hasn't and therefore gets stuck in an infinite loop.


 libavutil/pixdesc.c | 10 +++++++---
 1 file changed, 7 insertions(+), 3 deletions(-)

Comments

Michael Niedermayer July 7, 2017, 12:14 a.m. UTC | #1
On Thu, Jul 06, 2017 at 10:59:24PM +0100, Mark Thompson wrote:
> Hardware pixel formats do not tell you anything about their actual
> contents, but should still score higher than formats with completely
> unknown properties, which in turn should score higher than invalid
> formats.
> 
> Do not return an AVERROR code as a score.
> 
> Fixes a hang in libavfilter where format negotiation gets stuck in a
> loop because AV_PIX_FMT_NONE scores more highly than all other
> possibilities.
> ---
> The hang in libavfilter happens when trying to choose a pixfmt for output from a list of software formats when a hardware format is the input (the hwdownload filter does this).  The matching begins with AV_PIX_FMT_NONE as an invalid value and compares against each possibility in turn, but unfortunately it scores -1 when considered as a conversion from an opaque hardware format, higher than the AVERROR(EINVAL) (== -22 on Linux) scored for all of the real formats.  Hence the format selection code chooses AV_PIX_FMT_NONE and thinks it is making forward progress, but actually hasn't and therefore gets stuck in an infinite loop.
> 
> 
>  libavutil/pixdesc.c | 10 +++++++---
>  1 file changed, 7 insertions(+), 3 deletions(-)
> 
> diff --git a/libavutil/pixdesc.c b/libavutil/pixdesc.c
> index 46a7eff06d..35b63f43c6 100644
> --- a/libavutil/pixdesc.c
> +++ b/libavutil/pixdesc.c
> @@ -2512,7 +2512,11 @@ static int get_pix_fmt_score(enum AVPixelFormat dst_pix_fmt,
>      int score = INT_MAX - 1;
>  
>      if (dst_pix_fmt >= AV_PIX_FMT_NB || dst_pix_fmt <= AV_PIX_FMT_NONE)
> -        return ~0;
> +        return -2;
> +

> +    if ((src_desc->flags & AV_PIX_FMT_FLAG_HWACCEL) ||
> +        (dst_desc->flags & AV_PIX_FMT_FLAG_HWACCEL))
> +        return 0;

this breaks ffmpegs choose_pixel_fmt()
src_desc being NULL


>  
>      /* compute loss */
>      *lossp = loss = 0;

shouldnt this be set on a 0 return ?

i also wonder if src and dst being identical should score different
than if not if either is AV_PIX_FMT_FLAG_HWACCEL

[...]
wm4 July 7, 2017, 8:16 a.m. UTC | #2
On Thu, 6 Jul 2017 22:59:24 +0100
Mark Thompson <sw@jkqxz.net> wrote:

> Hardware pixel formats do not tell you anything about their actual
> contents, but should still score higher than formats with completely
> unknown properties, which in turn should score higher than invalid
> formats.
> 
> Do not return an AVERROR code as a score.
> 
> Fixes a hang in libavfilter where format negotiation gets stuck in a
> loop because AV_PIX_FMT_NONE scores more highly than all other
> possibilities.
> ---
> The hang in libavfilter happens when trying to choose a pixfmt for output from a list of software formats when a hardware format is the input (the hwdownload filter does this).  The matching begins with AV_PIX_FMT_NONE as an invalid value and compares against each possibility in turn, but unfortunately it scores -1 when considered as a conversion from an opaque hardware format, higher than the AVERROR(EINVAL) (== -22 on Linux) scored for all of the real formats.  Hence the format selection code chooses AV_PIX_FMT_NONE and thinks it is making forward progress, but actually hasn't and therefore gets stuck in an infinite loop.
> 
> 
>  libavutil/pixdesc.c | 10 +++++++---
>  1 file changed, 7 insertions(+), 3 deletions(-)
> 
> diff --git a/libavutil/pixdesc.c b/libavutil/pixdesc.c
> index 46a7eff06d..35b63f43c6 100644
> --- a/libavutil/pixdesc.c
> +++ b/libavutil/pixdesc.c
> @@ -2512,7 +2512,11 @@ static int get_pix_fmt_score(enum AVPixelFormat dst_pix_fmt,
>      int score = INT_MAX - 1;
>  
>      if (dst_pix_fmt >= AV_PIX_FMT_NB || dst_pix_fmt <= AV_PIX_FMT_NONE)
> -        return ~0;
> +        return -2;
> +
> +    if ((src_desc->flags & AV_PIX_FMT_FLAG_HWACCEL) ||
> +        (dst_desc->flags & AV_PIX_FMT_FLAG_HWACCEL))
> +        return 0;
>  
>      /* compute loss */
>      *lossp = loss = 0;
> @@ -2521,9 +2525,9 @@ static int get_pix_fmt_score(enum AVPixelFormat dst_pix_fmt,
>          return INT_MAX;
>  
>      if ((ret = get_pix_fmt_depth(&src_min_depth, &src_max_depth, src_pix_fmt)) < 0)
> -        return ret;
> +        return -1;
>      if ((ret = get_pix_fmt_depth(&dst_min_depth, &dst_max_depth, dst_pix_fmt)) < 0)
> -        return ret;
> +        return -1;
>  
>      src_color = get_color_type(src_desc);
>      dst_color = get_color_type(dst_desc);

I don't think it makes any sense to prefer one hw format over an
another without additional information, but I guess that also means
returning a random one doesn't do any harms.

Wouldn't it be better to fix the lavfi code, though?
diff mbox

Patch

diff --git a/libavutil/pixdesc.c b/libavutil/pixdesc.c
index 46a7eff06d..35b63f43c6 100644
--- a/libavutil/pixdesc.c
+++ b/libavutil/pixdesc.c
@@ -2512,7 +2512,11 @@  static int get_pix_fmt_score(enum AVPixelFormat dst_pix_fmt,
     int score = INT_MAX - 1;
 
     if (dst_pix_fmt >= AV_PIX_FMT_NB || dst_pix_fmt <= AV_PIX_FMT_NONE)
-        return ~0;
+        return -2;
+
+    if ((src_desc->flags & AV_PIX_FMT_FLAG_HWACCEL) ||
+        (dst_desc->flags & AV_PIX_FMT_FLAG_HWACCEL))
+        return 0;
 
     /* compute loss */
     *lossp = loss = 0;
@@ -2521,9 +2525,9 @@  static int get_pix_fmt_score(enum AVPixelFormat dst_pix_fmt,
         return INT_MAX;
 
     if ((ret = get_pix_fmt_depth(&src_min_depth, &src_max_depth, src_pix_fmt)) < 0)
-        return ret;
+        return -1;
     if ((ret = get_pix_fmt_depth(&dst_min_depth, &dst_max_depth, dst_pix_fmt)) < 0)
-        return ret;
+        return -1;
 
     src_color = get_color_type(src_desc);
     dst_color = get_color_type(dst_desc);