diff mbox

[FFmpeg-devel,1/2] avformat/dashenc: Set VP9 codec string with profile, level and bitdepth

Message ID 1524053006-3255-1-git-send-email-kjeyapal@akamai.com
State Superseded
Headers show

Commit Message

Jeyapal, Karthick April 18, 2018, 12:03 p.m. UTC
From: Karthick Jeyapal <kjeyapal@akamai.com>

Otherwise some versions of chrome browser returns "codec not supported" error
---
 libavformat/dashenc.c | 79 ++++++++++++++++++++++++++++++++++++++++++++++++++-
 1 file changed, 78 insertions(+), 1 deletion(-)

Comments

James Almer April 18, 2018, 1:42 p.m. UTC | #1
On 4/18/2018 9:03 AM, Karthick J wrote:
> From: Karthick Jeyapal <kjeyapal@akamai.com>
> 
> Otherwise some versions of chrome browser returns "codec not supported" error
> ---
>  libavformat/dashenc.c | 79 ++++++++++++++++++++++++++++++++++++++++++++++++++-
>  1 file changed, 78 insertions(+), 1 deletion(-)
> 
> diff --git a/libavformat/dashenc.c b/libavformat/dashenc.c
> index 9e72636..5443e31 100644
> --- a/libavformat/dashenc.c
> +++ b/libavformat/dashenc.c
> @@ -170,6 +170,79 @@ static void dashenc_io_close(AVFormatContext *s, AVIOContext **pb, char *filenam
>      }
>  }
>  
> +static void set_vp9_codec_str(AVCodecParameters *par, char *str, int size) {
> +    int profile, level, bitdepth;
> +    int picture_size = par->width * par->height;
> +    switch (par->format) {
> +    case AV_PIX_FMT_YUV420P:
> +    case AV_PIX_FMT_YUVA420P:
> +        bitdepth = 8;
> +        profile = 0;
> +        break;
> +    case AV_PIX_FMT_YUV422P:
> +    case AV_PIX_FMT_YUV440P:
> +    case AV_PIX_FMT_GBRP:
> +    case AV_PIX_FMT_YUV444P:
> +        bitdepth = 8;
> +        profile = 1;
> +        break;
> +    case AV_PIX_FMT_YUV420P10:
> +        bitdepth = 10;
> +        profile = 2;
> +        break;
> +    case AV_PIX_FMT_YUV420P12:
> +        bitdepth = 12;
> +        profile = 2;
> +        break;
> +    case AV_PIX_FMT_YUV422P10:
> +    case AV_PIX_FMT_YUV440P10:
> +    case AV_PIX_FMT_GBRP10:
> +    case AV_PIX_FMT_YUV444P10:
> +        bitdepth = 10;
> +        profile = 3;
> +        break;
> +    case AV_PIX_FMT_YUV422P12:
> +    case AV_PIX_FMT_YUV440P12:
> +    case AV_PIX_FMT_GBRP12:
> +    case AV_PIX_FMT_YUV444P12:
> +        bitdepth = 12;
> +        profile = 3;
> +        break;
> +    default:
> +        goto error;
> +    }

This is too big and unwieldy, you're not looking at par->profile first
(which is more than likely set to the correct value already), also
you're in any case not using the FF_PROFILE constants either.

And you should reuse as much code from vpcc.c as possible here. It will
be needed in other muxers like Matroska soon enough either way.
I'll send a patch in a moment to make that file usable for cases like
this one.

> +    // Finding VP9 level accurately in a ffmpeg muxer is almost impossible.
> +    // Hence we will set approximate levels based on the width and height.

You should check for par->level first, to see if it's not
FF_LEVEL_UNKNOWN (chances are it is, though).
Also, this should be implemented to vpcc.c, so it can be reused there to
write the vpcc atom for mp4 output (it's currently writing 0 when level
is unknown, which is probably wrong).

> +    if (picture_size <= 0) {
> +        goto error;
> +    } else if (picture_size <= 36864) {
> +        level = 0x10;
> +    } else if (picture_size <= 73728) {
> +        level = 0x11;
> +    } else if (picture_size <= 122880) {
> +        level = 0x20;
> +    } else if (picture_size <= 245760) {
> +        level = 0x21;
> +    } else if (picture_size <= 552960) {
> +        level = 0x30;
> +    } else if (picture_size <= 983040) {
> +        level = 0x31;
> +    } else if (picture_size <= 2228224) {
> +        level = 0x40;
> +    } else if (picture_size <= 8912896) {
> +        level = 0x50;
> +    } else if (picture_size <= 35651584) {
> +        level = 0x60;
> +    } else {
> +        goto error;
> +    }
> +    av_strlcatf(str, size, "vp09.%02x.%02x.%02x", profile, level, bitdepth);
> +    return;
> +error:
> +    // Default to just vp9 in case of error while finding out profile or level
> +    av_strlcpy(str, "vp9", size);
> +    return;
> +}
>  static void set_codec_str(AVFormatContext *s, AVCodecParameters *par,
>                            char *str, int size)
>  {
> @@ -180,7 +253,11 @@ static void set_codec_str(AVFormatContext *s, AVCodecParameters *par,
>      // common Webm codecs are not part of RFC 6381
>      for (i = 0; codecs[i].id; i++)
>          if (codecs[i].id == par->codec_id) {
> -            av_strlcpy(str, codecs[i].str, size);
> +            if (codecs[i].id == AV_CODEC_ID_VP9) {
> +                set_vp9_codec_str(par, str, size);
> +            } else {
> +                av_strlcpy(str, codecs[i].str, size);
> +            }
>              return;
>          }
>  
>
Jeyapal, Karthick April 19, 2018, 3:50 a.m. UTC | #2
On 4/18/18 7:12 PM, James Almer wrote:
> On 4/18/2018 9:03 AM, Karthick J wrote:

> > From: Karthick Jeyapal <kjeyapal@akamai.com>

> > 

> > Otherwise some versions of chrome browser returns "codec not supported" error

> > ---

> >  libavformat/dashenc.c | 79 ++++++++++++++++++++++++++++++++++++++++++++++++++-

> >  1 file changed, 78 insertions(+), 1 deletion(-)

> > 

> > diff --git a/libavformat/dashenc.c b/libavformat/dashenc.c

> > index 9e72636..5443e31 100644

> > --- a/libavformat/dashenc.c

> > +++ b/libavformat/dashenc.c

> > @@ -170,6 +170,79 @@ static void dashenc_io_close(AVFormatContext *s, AVIOContext **pb, char *filenam

> >      }

> >  }

> >  

> > +static void set_vp9_codec_str(AVCodecParameters *par, char *str, int size) {

> > +    int profile, level, bitdepth;

> > +    int picture_size = par->width * par->height;

> > +    switch (par->format) {

> > +    case AV_PIX_FMT_YUV420P:

> > +    case AV_PIX_FMT_YUVA420P:

> > +        bitdepth = 8;

> > +        profile = 0;

> > +        break;

> > +    case AV_PIX_FMT_YUV422P:

> > +    case AV_PIX_FMT_YUV440P:

> > +    case AV_PIX_FMT_GBRP:

> > +    case AV_PIX_FMT_YUV444P:

> > +        bitdepth = 8;

> > +        profile = 1;

> > +        break;

> > +    case AV_PIX_FMT_YUV420P10:

> > +        bitdepth = 10;

> > +        profile = 2;

> > +        break;

> > +    case AV_PIX_FMT_YUV420P12:

> > +        bitdepth = 12;

> > +        profile = 2;

> > +        break;

> > +    case AV_PIX_FMT_YUV422P10:

> > +    case AV_PIX_FMT_YUV440P10:

> > +    case AV_PIX_FMT_GBRP10:

> > +    case AV_PIX_FMT_YUV444P10:

> > +        bitdepth = 10;

> > +        profile = 3;

> > +        break;

> > +    case AV_PIX_FMT_YUV422P12:

> > +    case AV_PIX_FMT_YUV440P12:

> > +    case AV_PIX_FMT_GBRP12:

> > +    case AV_PIX_FMT_YUV444P12:

> > +        bitdepth = 12;

> > +        profile = 3;

> > +        break;

> > +    default:

> > +        goto error;

> > +    }

>

> This is too big and unwieldy, you're not looking at par->profile first

> (which is more than likely set to the correct value already), also

> you're in any case not using the FF_PROFILE constants either.

>

> And you should reuse as much code from vpcc.c as possible here. It will

> be needed in other muxers like Matroska soon enough either way.

> I'll send a patch in a moment to make that file usable for cases like

> this one.

>

> > +    // Finding VP9 level accurately in a ffmpeg muxer is almost impossible.

> > +    // Hence we will set approximate levels based on the width and height.

>

> You should check for par->level first, to see if it's not

> FF_LEVEL_UNKNOWN (chances are it is, though).

> Also, this should be implemented to vpcc.c, so it can be reused there to

> write the vpcc atom for mp4 output (it's currently writing 0 when level

> is unknown, which is probably wrong).

Thanks for your excellent comments and the useful patch. 
I wasn't aware of vpcc.c file. 
I will wait for your vpcc patch to be pushed, after which I will rework this patch.
>

> > +    if (picture_size <= 0) {

> > +        goto error;

> > +    } else if (picture_size <= 36864) {

> > +        level = 0x10;

> > +    } else if (picture_size <= 73728) {

> > +        level = 0x11;

> > +    } else if (picture_size <= 122880) {

> > +        level = 0x20;

> > +    } else if (picture_size <= 245760) {

> > +        level = 0x21;

> > +    } else if (picture_size <= 552960) {

> > +        level = 0x30;

> > +    } else if (picture_size <= 983040) {

> > +        level = 0x31;

> > +    } else if (picture_size <= 2228224) {

> > +        level = 0x40;

> > +    } else if (picture_size <= 8912896) {

> > +        level = 0x50;

> > +    } else if (picture_size <= 35651584) {

> > +        level = 0x60;

> > +    } else {

> > +        goto error;

> > +    }

> > +    av_strlcatf(str, size, "vp09.%02x.%02x.%02x", profile, level, bitdepth);

> > +    return;

> > +error:

> > +    // Default to just vp9 in case of error while finding out profile or level

> > +    av_strlcpy(str, "vp9", size);

> > +    return;

> > +}

> >  static void set_codec_str(AVFormatContext *s, AVCodecParameters *par,

> >                            char *str, int size)

> >  {

> > @@ -180,7 +253,11 @@ static void set_codec_str(AVFormatContext *s, AVCodecParameters *par,

> >      // common Webm codecs are not part of RFC 6381

> >      for (i = 0; codecs[i].id; i++)

> >          if (codecs[i].id == par->codec_id) {

> > -            av_strlcpy(str, codecs[i].str, size);

> > +            if (codecs[i].id == AV_CODEC_ID_VP9) {

> > +                set_vp9_codec_str(par, str, size);

> > +            } else {

> > +                av_strlcpy(str, codecs[i].str, size);

> > +            }

> >              return;

> >          }

> >  

> > 

>

> _______________________________________________

> ffmpeg-devel mailing list

> ffmpeg-devel@ffmpeg.org

> http://ffmpeg.org/mailman/listinfo/ffmpeg-devel
diff mbox

Patch

diff --git a/libavformat/dashenc.c b/libavformat/dashenc.c
index 9e72636..5443e31 100644
--- a/libavformat/dashenc.c
+++ b/libavformat/dashenc.c
@@ -170,6 +170,79 @@  static void dashenc_io_close(AVFormatContext *s, AVIOContext **pb, char *filenam
     }
 }
 
+static void set_vp9_codec_str(AVCodecParameters *par, char *str, int size) {
+    int profile, level, bitdepth;
+    int picture_size = par->width * par->height;
+    switch (par->format) {
+    case AV_PIX_FMT_YUV420P:
+    case AV_PIX_FMT_YUVA420P:
+        bitdepth = 8;
+        profile = 0;
+        break;
+    case AV_PIX_FMT_YUV422P:
+    case AV_PIX_FMT_YUV440P:
+    case AV_PIX_FMT_GBRP:
+    case AV_PIX_FMT_YUV444P:
+        bitdepth = 8;
+        profile = 1;
+        break;
+    case AV_PIX_FMT_YUV420P10:
+        bitdepth = 10;
+        profile = 2;
+        break;
+    case AV_PIX_FMT_YUV420P12:
+        bitdepth = 12;
+        profile = 2;
+        break;
+    case AV_PIX_FMT_YUV422P10:
+    case AV_PIX_FMT_YUV440P10:
+    case AV_PIX_FMT_GBRP10:
+    case AV_PIX_FMT_YUV444P10:
+        bitdepth = 10;
+        profile = 3;
+        break;
+    case AV_PIX_FMT_YUV422P12:
+    case AV_PIX_FMT_YUV440P12:
+    case AV_PIX_FMT_GBRP12:
+    case AV_PIX_FMT_YUV444P12:
+        bitdepth = 12;
+        profile = 3;
+        break;
+    default:
+        goto error;
+    }
+    // Finding VP9 level accurately in a ffmpeg muxer is almost impossible.
+    // Hence we will set approximate levels based on the width and height.
+    if (picture_size <= 0) {
+        goto error;
+    } else if (picture_size <= 36864) {
+        level = 0x10;
+    } else if (picture_size <= 73728) {
+        level = 0x11;
+    } else if (picture_size <= 122880) {
+        level = 0x20;
+    } else if (picture_size <= 245760) {
+        level = 0x21;
+    } else if (picture_size <= 552960) {
+        level = 0x30;
+    } else if (picture_size <= 983040) {
+        level = 0x31;
+    } else if (picture_size <= 2228224) {
+        level = 0x40;
+    } else if (picture_size <= 8912896) {
+        level = 0x50;
+    } else if (picture_size <= 35651584) {
+        level = 0x60;
+    } else {
+        goto error;
+    }
+    av_strlcatf(str, size, "vp09.%02x.%02x.%02x", profile, level, bitdepth);
+    return;
+error:
+    // Default to just vp9 in case of error while finding out profile or level
+    av_strlcpy(str, "vp9", size);
+    return;
+}
 static void set_codec_str(AVFormatContext *s, AVCodecParameters *par,
                           char *str, int size)
 {
@@ -180,7 +253,11 @@  static void set_codec_str(AVFormatContext *s, AVCodecParameters *par,
     // common Webm codecs are not part of RFC 6381
     for (i = 0; codecs[i].id; i++)
         if (codecs[i].id == par->codec_id) {
-            av_strlcpy(str, codecs[i].str, size);
+            if (codecs[i].id == AV_CODEC_ID_VP9) {
+                set_vp9_codec_str(par, str, size);
+            } else {
+                av_strlcpy(str, codecs[i].str, size);
+            }
             return;
         }