diff mbox

[FFmpeg-devel,2/3] avutil/opt: Add AV_OPT_TYPE_UINT64

Message ID 20161120115744.28351-2-michael@niedermayer.cc
State Accepted
Headers show

Commit Message

Michael Niedermayer Nov. 20, 2016, 11:57 a.m. UTC
Requested-by: wm4 ([FFmpeg-devel] [PATCH] avutil/opt: Support max > INT64_MAX in write_number() with AV_OPT_TYPE_INT64)
Requested-by: ronald ([FFmpeg-devel] [PATCH] avutil/opt: Support max > INT64_MAX in write_number() with AV_OPT_TYPE_INT64)
Signed-off-by: Michael Niedermayer <michael@niedermayer.cc>
---
 libavutil/opt.c | 29 +++++++++++++++++++++++++++++
 libavutil/opt.h |  1 +
 2 files changed, 30 insertions(+)

Comments

Ronald S. Bultje Nov. 20, 2016, 1:56 p.m. UTC | #1
Hi,

On Sun, Nov 20, 2016 at 6:57 AM, Michael Niedermayer <michael@niedermayer.cc
> wrote:

> @@ -131,6 +132,20 @@ static int write_number(void *obj, const AVOption *o,
> void *dst, double num, int
>          if (intnum == 1 && d == (double)INT64_MAX) *(int64_t *)dst =
> INT64_MAX;
>          else                                       *(int64_t *)dst =
> llrint(d) * intnum;
>          break;}
> +    case AV_OPT_TYPE_UINT64:{
> +        double d = num / den;
> +        // We must special case uint64_t here as llrint() does not
> support values
> +        // outside the int64_t range and there is no portable function
> which does
> +        // "INT64_MAX + 1ULL" is used as it is representable exactly as
> IEEE double
> +        // while INT64_MAX is not
> +        if (intnum == 1 && d == (double)UINT64_MAX) {
> +            *(int64_t *)dst = UINT64_MAX;
> +        } else if (o->max > INT64_MAX + 1ULL && d > INT64_MAX + 1ULL) {
> +            *(uint64_t *)dst = (llrint(d - (INT64_MAX + 1ULL)) +
> (INT64_MAX + 1ULL))*intnum;
> +        } else {
> +            *(int64_t *)dst = llrint(d) * intnum;
> +        }
> +        break;}
>      case AV_OPT_TYPE_FLOAT:
>          *(float *)dst = num * intnum / den;
>          break;


For the stupid, like me: what does this do? More specifically, this seems
an integer codepath, but there is a double in there. Why?

Ronald
Michael Niedermayer Nov. 20, 2016, 2:16 p.m. UTC | #2
On Sun, Nov 20, 2016 at 08:56:15AM -0500, Ronald S. Bultje wrote:
> Hi,
> 
> On Sun, Nov 20, 2016 at 6:57 AM, Michael Niedermayer <michael@niedermayer.cc
> > wrote:
> 
> > @@ -131,6 +132,20 @@ static int write_number(void *obj, const AVOption *o,
> > void *dst, double num, int
> >          if (intnum == 1 && d == (double)INT64_MAX) *(int64_t *)dst =
> > INT64_MAX;
> >          else                                       *(int64_t *)dst =
> > llrint(d) * intnum;
> >          break;}
> > +    case AV_OPT_TYPE_UINT64:{
> > +        double d = num / den;
> > +        // We must special case uint64_t here as llrint() does not
> > support values
> > +        // outside the int64_t range and there is no portable function
> > which does
> > +        // "INT64_MAX + 1ULL" is used as it is representable exactly as
> > IEEE double
> > +        // while INT64_MAX is not
> > +        if (intnum == 1 && d == (double)UINT64_MAX) {
> > +            *(int64_t *)dst = UINT64_MAX;
> > +        } else if (o->max > INT64_MAX + 1ULL && d > INT64_MAX + 1ULL) {
> > +            *(uint64_t *)dst = (llrint(d - (INT64_MAX + 1ULL)) +
> > (INT64_MAX + 1ULL))*intnum;
> > +        } else {
> > +            *(int64_t *)dst = llrint(d) * intnum;
> > +        }
> > +        break;}
> >      case AV_OPT_TYPE_FLOAT:
> >          *(float *)dst = num * intnum / den;
> >          break;
> 
> 
> For the stupid, like me: what does this do? More specifically, this seems
> an integer codepath, but there is a double in there. Why?

write_number() has a num/den double argument. If this is used to
set a uint64_t to UINT64_MAX things fail as double cannot exactly
represent UINT64_MAX.  (the closest it can represent is "UINT64_MAX + 1"
So it needs to be handled as a special case. Otherwise it turns into 0


[...]
Ronald S. Bultje Nov. 20, 2016, 5 p.m. UTC | #3
Hi,

On Sun, Nov 20, 2016 at 9:16 AM, Michael Niedermayer <michael@niedermayer.cc
> wrote:

> On Sun, Nov 20, 2016 at 08:56:15AM -0500, Ronald S. Bultje wrote:
> > Hi,
> >
> > On Sun, Nov 20, 2016 at 6:57 AM, Michael Niedermayer
> <michael@niedermayer.cc
> > > wrote:
> >
> > > @@ -131,6 +132,20 @@ static int write_number(void *obj, const AVOption
> *o,
> > > void *dst, double num, int
> > >          if (intnum == 1 && d == (double)INT64_MAX) *(int64_t *)dst =
> > > INT64_MAX;
> > >          else                                       *(int64_t *)dst =
> > > llrint(d) * intnum;
> > >          break;}
> > > +    case AV_OPT_TYPE_UINT64:{
> > > +        double d = num / den;
> > > +        // We must special case uint64_t here as llrint() does not
> > > support values
> > > +        // outside the int64_t range and there is no portable function
> > > which does
> > > +        // "INT64_MAX + 1ULL" is used as it is representable exactly
> as
> > > IEEE double
> > > +        // while INT64_MAX is not
> > > +        if (intnum == 1 && d == (double)UINT64_MAX) {
> > > +            *(int64_t *)dst = UINT64_MAX;
> > > +        } else if (o->max > INT64_MAX + 1ULL && d > INT64_MAX + 1ULL)
> {
> > > +            *(uint64_t *)dst = (llrint(d - (INT64_MAX + 1ULL)) +
> > > (INT64_MAX + 1ULL))*intnum;
> > > +        } else {
> > > +            *(int64_t *)dst = llrint(d) * intnum;
> > > +        }
> > > +        break;}
> > >      case AV_OPT_TYPE_FLOAT:
> > >          *(float *)dst = num * intnum / den;
> > >          break;
> >
> >
> > For the stupid, like me: what does this do? More specifically, this seems
> > an integer codepath, but there is a double in there. Why?
>
> write_number() has a num/den double argument. If this is used to
> set a uint64_t to UINT64_MAX things fail as double cannot exactly
> represent UINT64_MAX.  (the closest it can represent is "UINT64_MAX + 1"
> So it needs to be handled as a special case. Otherwise it turns into 0


This sounds incredibly shaky. Is write_number() so fringe that we don't
need an integer codepath?

Ronald
Michael Niedermayer Nov. 20, 2016, 6:40 p.m. UTC | #4
On Sun, Nov 20, 2016 at 12:00:49PM -0500, Ronald S. Bultje wrote:
> Hi,
> 
> On Sun, Nov 20, 2016 at 9:16 AM, Michael Niedermayer <michael@niedermayer.cc
> > wrote:
> 
> > On Sun, Nov 20, 2016 at 08:56:15AM -0500, Ronald S. Bultje wrote:
> > > Hi,
> > >
> > > On Sun, Nov 20, 2016 at 6:57 AM, Michael Niedermayer
> > <michael@niedermayer.cc
> > > > wrote:
> > >
> > > > @@ -131,6 +132,20 @@ static int write_number(void *obj, const AVOption
> > *o,
> > > > void *dst, double num, int
> > > >          if (intnum == 1 && d == (double)INT64_MAX) *(int64_t *)dst =
> > > > INT64_MAX;
> > > >          else                                       *(int64_t *)dst =
> > > > llrint(d) * intnum;
> > > >          break;}
> > > > +    case AV_OPT_TYPE_UINT64:{
> > > > +        double d = num / den;
> > > > +        // We must special case uint64_t here as llrint() does not
> > > > support values
> > > > +        // outside the int64_t range and there is no portable function
> > > > which does
> > > > +        // "INT64_MAX + 1ULL" is used as it is representable exactly
> > as
> > > > IEEE double
> > > > +        // while INT64_MAX is not
> > > > +        if (intnum == 1 && d == (double)UINT64_MAX) {
> > > > +            *(int64_t *)dst = UINT64_MAX;
> > > > +        } else if (o->max > INT64_MAX + 1ULL && d > INT64_MAX + 1ULL)
> > {
> > > > +            *(uint64_t *)dst = (llrint(d - (INT64_MAX + 1ULL)) +
> > > > (INT64_MAX + 1ULL))*intnum;
> > > > +        } else {
> > > > +            *(int64_t *)dst = llrint(d) * intnum;
> > > > +        }
> > > > +        break;}
> > > >      case AV_OPT_TYPE_FLOAT:
> > > >          *(float *)dst = num * intnum / den;
> > > >          break;
> > >
> > >
> > > For the stupid, like me: what does this do? More specifically, this seems
> > > an integer codepath, but there is a double in there. Why?
> >
> > write_number() has a num/den double argument. If this is used to
> > set a uint64_t to UINT64_MAX things fail as double cannot exactly
> > represent UINT64_MAX.  (the closest it can represent is "UINT64_MAX + 1"
> > So it needs to be handled as a special case. Otherwise it turns into 0
> 
> 
> This sounds incredibly shaky. Is write_number() so fringe that we don't
> need an integer codepath?

write_number() can take int64_t, double and 32/32bit rationals.
Its done compactly by representing the value as a
num/den * intnum
for integer input num/den == 1
for double or rational input intnum == 1
doubles can represent int32 exactly so it can be used simplifying the
code
so there is a integer codepath basically

Ive written this 11 years ago
(860a40c8a7756a3e63e7f9bb0d9caaf742d26402 av_set_number())
which also means it had 11 years of testing on many platforms

[...]
Andreas Cadhalpun Nov. 20, 2016, 7:55 p.m. UTC | #5
On 20.11.2016 12:57, Michael Niedermayer wrote:
> Requested-by: wm4 ([FFmpeg-devel] [PATCH] avutil/opt: Support max > INT64_MAX in write_number() with AV_OPT_TYPE_INT64)
> Requested-by: ronald ([FFmpeg-devel] [PATCH] avutil/opt: Support max > INT64_MAX in write_number() with AV_OPT_TYPE_INT64)
> Signed-off-by: Michael Niedermayer <michael@niedermayer.cc>
> ---
>  libavutil/opt.c | 29 +++++++++++++++++++++++++++++
>  libavutil/opt.h |  1 +
>  2 files changed, 30 insertions(+)
> 
> diff --git a/libavutil/opt.c b/libavutil/opt.c
> index 6669356..b6b4d9f 100644
> --- a/libavutil/opt.c
> +++ b/libavutil/opt.c
> @@ -74,6 +74,7 @@ static int read_number(const AVOption *o, const void *dst, double *num, int *den
>      case AV_OPT_TYPE_CHANNEL_LAYOUT:
>      case AV_OPT_TYPE_DURATION:
>      case AV_OPT_TYPE_INT64:
> +    case AV_OPT_TYPE_UINT64:
>          *intnum = *(int64_t *)dst;
>          return 0;
>      case AV_OPT_TYPE_FLOAT:
> @@ -131,6 +132,20 @@ static int write_number(void *obj, const AVOption *o, void *dst, double num, int
>          if (intnum == 1 && d == (double)INT64_MAX) *(int64_t *)dst = INT64_MAX;
>          else                                       *(int64_t *)dst = llrint(d) * intnum;
>          break;}
> +    case AV_OPT_TYPE_UINT64:{
> +        double d = num / den;
> +        // We must special case uint64_t here as llrint() does not support values
> +        // outside the int64_t range and there is no portable function which does
> +        // "INT64_MAX + 1ULL" is used as it is representable exactly as IEEE double
> +        // while INT64_MAX is not
> +        if (intnum == 1 && d == (double)UINT64_MAX) {
> +            *(int64_t *)dst = UINT64_MAX;

Is there a reason why this uses int64_t, 

> +        } else if (o->max > INT64_MAX + 1ULL && d > INT64_MAX + 1ULL) {
> +            *(uint64_t *)dst = (llrint(d - (INT64_MAX + 1ULL)) + (INT64_MAX + 1ULL))*intnum;

but this uint64_t,

> +        } else {
> +            *(int64_t *)dst = llrint(d) * intnum;

and this again int64_t?

Best regards,
Andreas
Michael Niedermayer Nov. 20, 2016, 8:52 p.m. UTC | #6
On Sun, Nov 20, 2016 at 08:55:44PM +0100, Andreas Cadhalpun wrote:
> On 20.11.2016 12:57, Michael Niedermayer wrote:
> > Requested-by: wm4 ([FFmpeg-devel] [PATCH] avutil/opt: Support max > INT64_MAX in write_number() with AV_OPT_TYPE_INT64)
> > Requested-by: ronald ([FFmpeg-devel] [PATCH] avutil/opt: Support max > INT64_MAX in write_number() with AV_OPT_TYPE_INT64)
> > Signed-off-by: Michael Niedermayer <michael@niedermayer.cc>
> > ---
> >  libavutil/opt.c | 29 +++++++++++++++++++++++++++++
> >  libavutil/opt.h |  1 +
> >  2 files changed, 30 insertions(+)
> > 
> > diff --git a/libavutil/opt.c b/libavutil/opt.c
> > index 6669356..b6b4d9f 100644
> > --- a/libavutil/opt.c
> > +++ b/libavutil/opt.c
> > @@ -74,6 +74,7 @@ static int read_number(const AVOption *o, const void *dst, double *num, int *den
> >      case AV_OPT_TYPE_CHANNEL_LAYOUT:
> >      case AV_OPT_TYPE_DURATION:
> >      case AV_OPT_TYPE_INT64:
> > +    case AV_OPT_TYPE_UINT64:
> >          *intnum = *(int64_t *)dst;
> >          return 0;
> >      case AV_OPT_TYPE_FLOAT:
> > @@ -131,6 +132,20 @@ static int write_number(void *obj, const AVOption *o, void *dst, double num, int
> >          if (intnum == 1 && d == (double)INT64_MAX) *(int64_t *)dst = INT64_MAX;
> >          else                                       *(int64_t *)dst = llrint(d) * intnum;
> >          break;}
> > +    case AV_OPT_TYPE_UINT64:{
> > +        double d = num / den;
> > +        // We must special case uint64_t here as llrint() does not support values
> > +        // outside the int64_t range and there is no portable function which does
> > +        // "INT64_MAX + 1ULL" is used as it is representable exactly as IEEE double
> > +        // while INT64_MAX is not
> > +        if (intnum == 1 && d == (double)UINT64_MAX) {
> > +            *(int64_t *)dst = UINT64_MAX;
> 
> Is there a reason why this uses int64_t, 
> 
> > +        } else if (o->max > INT64_MAX + 1ULL && d > INT64_MAX + 1ULL) {
> > +            *(uint64_t *)dst = (llrint(d - (INT64_MAX + 1ULL)) + (INT64_MAX + 1ULL))*intnum;
> 
> but this uint64_t,
> 
> > +        } else {
> > +            *(int64_t *)dst = llrint(d) * intnum;
> 
> and this again int64_t?

these are left over from the year old patch this is based on
fixed locally

[...]
Andreas Cadhalpun Nov. 21, 2016, 11:29 p.m. UTC | #7
On 20.11.2016 21:52, Michael Niedermayer wrote:
> On Sun, Nov 20, 2016 at 08:55:44PM +0100, Andreas Cadhalpun wrote:
>> On 20.11.2016 12:57, Michael Niedermayer wrote:
>>> +        if (intnum == 1 && d == (double)UINT64_MAX) {
>>> +            *(int64_t *)dst = UINT64_MAX;
>>
>> Is there a reason why this uses int64_t, 
>>
>>> +        } else if (o->max > INT64_MAX + 1ULL && d > INT64_MAX + 1ULL) {
>>> +            *(uint64_t *)dst = (llrint(d - (INT64_MAX + 1ULL)) + (INT64_MAX + 1ULL))*intnum;
>>
>> but this uint64_t,
>>
>>> +        } else {
>>> +            *(int64_t *)dst = llrint(d) * intnum;
>>
>> and this again int64_t?
> 
> these are left over from the year old patch this is based on
> fixed locally

OK. Now I've another question. Why does the check involve o->max?
Is the out-of-range check at the beginning of write_number not
sufficient?

Best regards,
Andreas
Michael Niedermayer Nov. 22, 2016, 11:06 a.m. UTC | #8
On Tue, Nov 22, 2016 at 12:29:02AM +0100, Andreas Cadhalpun wrote:
> On 20.11.2016 21:52, Michael Niedermayer wrote:
> > On Sun, Nov 20, 2016 at 08:55:44PM +0100, Andreas Cadhalpun wrote:
> >> On 20.11.2016 12:57, Michael Niedermayer wrote:
> >>> +        if (intnum == 1 && d == (double)UINT64_MAX) {
> >>> +            *(int64_t *)dst = UINT64_MAX;
> >>
> >> Is there a reason why this uses int64_t, 
> >>
> >>> +        } else if (o->max > INT64_MAX + 1ULL && d > INT64_MAX + 1ULL) {
> >>> +            *(uint64_t *)dst = (llrint(d - (INT64_MAX + 1ULL)) + (INT64_MAX + 1ULL))*intnum;
> >>
> >> but this uint64_t,
> >>
> >>> +        } else {
> >>> +            *(int64_t *)dst = llrint(d) * intnum;
> >>
> >> and this again int64_t?
> > 
> > these are left over from the year old patch this is based on
> > fixed locally
> 
> OK. Now I've another question. Why does the check involve o->max?
> Is the out-of-range check at the beginning of write_number not
> sufficient?

removed, this too came from the old patch

thx

[...]
Andreas Cadhalpun Nov. 22, 2016, 10:06 p.m. UTC | #9
On 22.11.2016 12:06, Michael Niedermayer wrote:
> On Tue, Nov 22, 2016 at 12:29:02AM +0100, Andreas Cadhalpun wrote:
>> OK. Now I've another question. Why does the check involve o->max?
>> Is the out-of-range check at the beginning of write_number not
>> sufficient?
> 
> removed, this too came from the old patch

Thanks. The patch should be OK then.

Best regards,
Andreas
Michael Niedermayer Nov. 23, 2016, 12:29 a.m. UTC | #10
On Tue, Nov 22, 2016 at 11:06:49PM +0100, Andreas Cadhalpun wrote:
> On 22.11.2016 12:06, Michael Niedermayer wrote:
> > On Tue, Nov 22, 2016 at 12:29:02AM +0100, Andreas Cadhalpun wrote:
> >> OK. Now I've another question. Why does the check involve o->max?
> >> Is the out-of-range check at the beginning of write_number not
> >> sufficient?
> > 
> > removed, this too came from the old patch
> 
> Thanks. The patch should be OK then.

applied

thx

[...]
diff mbox

Patch

diff --git a/libavutil/opt.c b/libavutil/opt.c
index 6669356..b6b4d9f 100644
--- a/libavutil/opt.c
+++ b/libavutil/opt.c
@@ -74,6 +74,7 @@  static int read_number(const AVOption *o, const void *dst, double *num, int *den
     case AV_OPT_TYPE_CHANNEL_LAYOUT:
     case AV_OPT_TYPE_DURATION:
     case AV_OPT_TYPE_INT64:
+    case AV_OPT_TYPE_UINT64:
         *intnum = *(int64_t *)dst;
         return 0;
     case AV_OPT_TYPE_FLOAT:
@@ -131,6 +132,20 @@  static int write_number(void *obj, const AVOption *o, void *dst, double num, int
         if (intnum == 1 && d == (double)INT64_MAX) *(int64_t *)dst = INT64_MAX;
         else                                       *(int64_t *)dst = llrint(d) * intnum;
         break;}
+    case AV_OPT_TYPE_UINT64:{
+        double d = num / den;
+        // We must special case uint64_t here as llrint() does not support values
+        // outside the int64_t range and there is no portable function which does
+        // "INT64_MAX + 1ULL" is used as it is representable exactly as IEEE double
+        // while INT64_MAX is not
+        if (intnum == 1 && d == (double)UINT64_MAX) {
+            *(int64_t *)dst = UINT64_MAX;
+        } else if (o->max > INT64_MAX + 1ULL && d > INT64_MAX + 1ULL) {
+            *(uint64_t *)dst = (llrint(d - (INT64_MAX + 1ULL)) + (INT64_MAX + 1ULL))*intnum;
+        } else {
+            *(int64_t *)dst = llrint(d) * intnum;
+        }
+        break;}
     case AV_OPT_TYPE_FLOAT:
         *(float *)dst = num * intnum / den;
         break;
@@ -202,6 +217,7 @@  static int set_string(void *obj, const AVOption *o, const char *val, uint8_t **d
 }
 
 #define DEFAULT_NUMVAL(opt) ((opt->type == AV_OPT_TYPE_INT64 || \
+                              opt->type == AV_OPT_TYPE_UINT64 || \
                               opt->type == AV_OPT_TYPE_CONST || \
                               opt->type == AV_OPT_TYPE_FLAGS || \
                               opt->type == AV_OPT_TYPE_INT)     \
@@ -458,6 +474,7 @@  int av_opt_set(void *obj, const char *name, const char *val, int search_flags)
     case AV_OPT_TYPE_FLAGS:
     case AV_OPT_TYPE_INT:
     case AV_OPT_TYPE_INT64:
+    case AV_OPT_TYPE_UINT64:
     case AV_OPT_TYPE_FLOAT:
     case AV_OPT_TYPE_DOUBLE:
     case AV_OPT_TYPE_RATIONAL:
@@ -758,6 +775,9 @@  int av_opt_get(void *obj, const char *name, int search_flags, uint8_t **out_val)
     case AV_OPT_TYPE_INT64:
         ret = snprintf(buf, sizeof(buf), "%"PRId64, *(int64_t *)dst);
         break;
+    case AV_OPT_TYPE_UINT64:
+        ret = snprintf(buf, sizeof(buf), "%"PRIu64, *(uint64_t *)dst);
+        break;
     case AV_OPT_TYPE_FLOAT:
         ret = snprintf(buf, sizeof(buf), "%f", *(float *)dst);
         break;
@@ -1106,6 +1126,9 @@  static void opt_list(void *obj, void *av_log_obj, const char *unit,
             case AV_OPT_TYPE_INT64:
                 av_log(av_log_obj, AV_LOG_INFO, "%-12s ", "<int64>");
                 break;
+            case AV_OPT_TYPE_UINT64:
+                av_log(av_log_obj, AV_LOG_INFO, "%-12s ", "<uint64>");
+                break;
             case AV_OPT_TYPE_DOUBLE:
                 av_log(av_log_obj, AV_LOG_INFO, "%-12s ", "<double>");
                 break;
@@ -1166,6 +1189,7 @@  static void opt_list(void *obj, void *av_log_obj, const char *unit,
             switch (opt->type) {
             case AV_OPT_TYPE_INT:
             case AV_OPT_TYPE_INT64:
+            case AV_OPT_TYPE_UINT64:
             case AV_OPT_TYPE_DOUBLE:
             case AV_OPT_TYPE_FLOAT:
             case AV_OPT_TYPE_RATIONAL:
@@ -1210,6 +1234,7 @@  static void opt_list(void *obj, void *av_log_obj, const char *unit,
                 break;
             }
             case AV_OPT_TYPE_INT:
+            case AV_OPT_TYPE_UINT64:
             case AV_OPT_TYPE_INT64: {
                 const char *def_const = get_opt_const_name(obj, opt->unit, opt->default_val.i64);
                 if (def_const)
@@ -1288,6 +1313,7 @@  void av_opt_set_defaults2(void *s, int mask, int flags)
             case AV_OPT_TYPE_FLAGS:
             case AV_OPT_TYPE_INT:
             case AV_OPT_TYPE_INT64:
+            case AV_OPT_TYPE_UINT64:
             case AV_OPT_TYPE_DURATION:
             case AV_OPT_TYPE_CHANNEL_LAYOUT:
             case AV_OPT_TYPE_PIXEL_FMT:
@@ -1648,6 +1674,7 @@  static int opt_size(enum AVOptionType type)
     case AV_OPT_TYPE_DURATION:
     case AV_OPT_TYPE_CHANNEL_LAYOUT:
     case AV_OPT_TYPE_INT64:
+    case AV_OPT_TYPE_UINT64:
         return sizeof(int64_t);
     case AV_OPT_TYPE_DOUBLE:
         return sizeof(double);
@@ -1777,6 +1804,7 @@  int av_opt_query_ranges_default(AVOptionRanges **ranges_arg, void *obj, const ch
     case AV_OPT_TYPE_BOOL:
     case AV_OPT_TYPE_INT:
     case AV_OPT_TYPE_INT64:
+    case AV_OPT_TYPE_UINT64:
     case AV_OPT_TYPE_PIXEL_FMT:
     case AV_OPT_TYPE_SAMPLE_FMT:
     case AV_OPT_TYPE_FLOAT:
@@ -1866,6 +1894,7 @@  int av_opt_is_set_to_default(void *obj, const AVOption *o)
     case AV_OPT_TYPE_CHANNEL_LAYOUT:
     case AV_OPT_TYPE_DURATION:
     case AV_OPT_TYPE_INT64:
+    case AV_OPT_TYPE_UINT64:
         read_number(o, dst, NULL, NULL, &i64);
         return o->default_val.i64 == i64;
     case AV_OPT_TYPE_STRING:
diff --git a/libavutil/opt.h b/libavutil/opt.h
index 9430b98..0d89379 100644
--- a/libavutil/opt.h
+++ b/libavutil/opt.h
@@ -228,6 +228,7 @@  enum AVOptionType{
     AV_OPT_TYPE_RATIONAL,
     AV_OPT_TYPE_BINARY,  ///< offset must point to a pointer immediately followed by an int for the length
     AV_OPT_TYPE_DICT,
+    AV_OPT_TYPE_UINT64,
     AV_OPT_TYPE_CONST = 128,
     AV_OPT_TYPE_IMAGE_SIZE = MKBETAG('S','I','Z','E'), ///< offset must point to two consecutive integers
     AV_OPT_TYPE_PIXEL_FMT  = MKBETAG('P','F','M','T'),