[FFmpeg-devel] [PATCH] Implement in lavc a flag which makes avcodec_open() to choose the best framerate

Stefano Sabatini stefano.sabatini-lala
Tue Sep 9 22:51:23 CEST 2008


On date Sunday 2008-08-31 20:58:53 +0200, Stefano Sabatini encoded:
> On date Sunday 2008-08-31 17:09:12 +0200, Michael Niedermayer encoded:
> > On Sun, Aug 31, 2008 at 01:19:31PM +0200, Stefano Sabatini wrote:
> > > On date Sunday 2008-08-31 00:11:03 +0200, Michael Niedermayer encoded:
> > > [...]
> > > > I think we should add a function that takes a list of AVRational and a AVRational
> > > > and finds the closest match for that. Its return value should indicate if the
> > > > match is exact or approximate
> > > > Such function might be usefull for other things as well ...
> > > 
> > > Yes it's the best solution I can see, it's even simpler
> > > application-level-wise, I would like to have thought that!
> > >  
> > > I also thought about to return the comparation code rather than an
> > > "exact" flag like in av_reduce(), I slightly prefer the attached
> > > solution but let me know.
> > 
> > what about returning the actually found value, the user could then run
> > av_cmp_q() over it himself when he needs.
> 
> Mmh, OK it also simplify the interface.
> 
> > > As for the name of the flag to implement in ffmpeg, I'm aware that
> > > -choose_best_framerate may sound too long, suggestions are welcome.
> > 
> > Id say always pick the best framerate that the codec supports, and allow
> > the user with -force-fps to override it.
> 
> OK for it, this has also the advantage that doesn't break backward compatibility.
> 
> > [...]
> > > Index: libavutil/rational.h
> > > ===================================================================
> > > --- libavutil/rational.h	(revision 15120)
> > > +++ libavutil/rational.h	(working copy)
> > > @@ -113,4 +113,13 @@
> > >   */
> > >  AVRational av_d2q(double d, int max) av_const;
> > >  
> > > +/**
> > > + * Finds in \p q_list the rational nearest to \p q.
> > 
> > Finds the nearest value in q_list to q.
> > 
> > 
> > > + * @param nearest_q the pointer to the rational where to copy the
> > > + * nearest rational to \p q found
> > > + * @param q_list NULL-terminated list of rationals
> 
> I realized that it's better to have a {0, 0} terminated list, like
> those the AVCodec supported_ramerates ones. From the practical point
> of view I think they should be exactly the same, that is I think that:
> 
> { {1, 1}, {2, 2}, NULL }
> 
> should be equivalent to:
> 
> { {1, 1}, {2, 2}, { 0, 0} }
> 
> for most compilers, anyway in the doubt I preferred the {0, 0}
> termination in the documentation.
> 
> > > + * @return 1 if the found rational is equivalent to \p q, 0 otherwise
> > > + */
> > > +int av_find_nearest_q(AVRational *nearest_q, AVRational q, AVRational* q_list);
> > > +
> > >  #endif /* AVUTIL_RATIONAL_H */
> > > Index: libavutil/rational.c
> > > ===================================================================
> > > --- libavutil/rational.c	(revision 15119)
> > > +++ libavutil/rational.c	(working copy)
> > > @@ -101,3 +101,60 @@
> > >  
> > >      return a;
> > >  }
> > > +
> > > +int av_find_nearest_q(AVRational *nearest_q, AVRational q, AVRational* q_list)
> > > +{
> > > +    AVRational *p= q_list;
> > 
> > useless temporary variable
> > 
> > 
> > > +    AVRational best_error= (AVRational){INT_MAX, 1};
> > 
> > > +    nearest_q->num = nearest_q->den = 0;
> > 
> > unneeded
> > 
> > 
> > > +    for(; p->den!=0; p++){
> > 
> > the != 0 is superflous
> > 
> > 
> > > +        AVRational error= av_sub_q(q, *p);
> > > +        if(error.num <0) error.num *= -1;
> > > +        if(av_cmp_q(error, best_error) < 0){
> > > +            best_error= error;
> > 
> > > +            nearest_q->num = p->num;
> > > +            nearest_q->den = p->den;
> > 
> > *nearest_q= *p
> 
> Fixed all.
> 
> > > +        }
> > > +    }
> > > +    return !av_cmp_q(*nearest_q, q);
> > > +}
> > > +
> > 
> > > +#if TEST
> > > +int main (void) {
> > > +
> > > +    AVRational list_q[] = {
> > > +        {24000, 1001},
> > > +        {   24,    1},
> > > +        {   25,    1},
> > > +        {30000, 1001},
> > > +        {   30,    1},
> > > +        {   50,    1},
> > > +        {60000, 1001},
> > > +        {   60,    1},
> > > +        // Xing's 15fps: (9)
> > > +        {   15,    1},
> > > +        // libmpeg3's "Unofficial economy rates": (10-13)
> > > +        {    5,    1},
> > > +        {   10,    1},
> > > +        {   12,    1},
> > > +        {   15,    1},
> > > +        {    0,    0},
> > > +    };
> > > +
> > > +    AVRational q = { 5, 1};
> > > +    AVRational nearest_q;
> > > +    int exact= av_find_nearest_q(&nearest_q, q, list_q);
> > > +#undef printf
> > > +    printf ("q=%d/%d(%f), nearest_q=%d/%d(%f), exact=%d\n",
> > > +            q.num, q.den, (double)q.num/q.den,
> > > +            nearest_q.num, nearest_q.den, (double)nearest_q.num/nearest_q.den,
> > > +            exact);
> > > +
> > > +    q.num= 42, q.den = 1;
> > > +    exact= av_find_nearest_q(&q, q, list_q);
> > > +    printf ("q=%d/%d(%f), nearest_q=%d/%d(%f), exact=%d\n",
> > > +            q.num, q.den, (double)q.num/q.den,
> > > +            q.num, q.den, (double)q.num/q.den,
> > > +            exact);
> > > +}
> > > +#endif /* TEST */
> > 
> > hmm, i think if you cant come up with a shorter self test then drop it.
> 
> OK, I'm keeping it for practical and pedagogical reasons, I'm going to
> remove it before the commit.
> 
> Regards.
> -- 
> FFmpeg = Furious & Fostering Multimedia Portable Exuberant Game

> Index: libavutil/avutil.h
> ===================================================================
> --- libavutil/avutil.h	(revision 15120)
> +++ libavutil/avutil.h	(working copy)
> @@ -35,7 +35,7 @@
>  #define AV_VERSION(a, b, c) AV_VERSION_DOT(a, b, c)
>  
>  #define LIBAVUTIL_VERSION_MAJOR 49
> -#define LIBAVUTIL_VERSION_MINOR 10
> +#define LIBAVUTIL_VERSION_MINOR 11
>  #define LIBAVUTIL_VERSION_MICRO  0
>  
>  #define LIBAVUTIL_VERSION_INT   AV_VERSION_INT(LIBAVUTIL_VERSION_MAJOR, \
> Index: libavutil/rational.h
> ===================================================================
> --- libavutil/rational.h	(revision 15120)
> +++ libavutil/rational.h	(working copy)
> @@ -113,4 +113,11 @@
>   */
>  AVRational av_d2q(double d, int max) av_const;
>  
> +/**
> + * Finds the nearest value in \p q_list to \p q.
> + * @param q_list an array of rationals terminated by {0, 0}
> + * @return the nearest value found
> + */
> +AVRational av_find_nearest_q(AVRational q, AVRational* q_list);
> +
>  #endif /* AVUTIL_RATIONAL_H */
> Index: libavutil/rational.c
> ===================================================================
> --- libavutil/rational.c	(revision 15119)
> +++ libavutil/rational.c	(working copy)
> @@ -101,3 +101,49 @@
>  
>      return a;
>  }
> +
> +AVRational av_find_nearest_q(AVRational q, AVRational* q_list)
> +{
> +    AVRational nearest_q;
> +    AVRational best_error= (AVRational){INT_MAX, 1};
> +    for(; q_list->den; q_list++){
> +        AVRational error= av_sub_q(q, *q_list);
> +        if(error.num <0) error.num *= -1;
> +        if(av_cmp_q(error, best_error) < 0){
> +            best_error= error;
> +            nearest_q = *q_list;
> +        }
> +    }
> +    return nearest_q;
> +}
> +
> +#if TEST
> +int main (void) {
> +
> +    AVRational list_q[] = {
> +        {24000, 1001},
> +        {   24,    1},
> +        {   25,    1},
> +        {30000, 1001},
> +        {   30,    1},
> +        {   50,    1},
> +        {60000, 1001},
> +        {   60,    1},
> +        // Xing's 15fps: (9)
> +        {   15,    1},
> +        // libmpeg3's "Unofficial economy rates": (10-13)
> +        {    5,    1},
> +        {   10,    1},
> +        {   12,    1},
> +        {   15,    1},
> +        {    0,    0},
> +    };
> +
> +    AVRational q = { 42, 1};
> +    AVRational nearest_q = av_find_nearest_q(q, list_q);
> +#undef printf
> +    printf ("q=%d/%d(%f), nearest_q=%d/%d(%f),\n",
> +            q.num, q.den, (double)q.num/q.den,
> +            nearest_q.num, nearest_q.den, (double)nearest_q.num/nearest_q.den);
> +}
> +#endif /* TEST */

> Index: ffmpeg.c
> ===================================================================
> --- ffmpeg.c	(revision 15119)
> +++ ffmpeg.c	(working copy)
> @@ -207,6 +207,7 @@
>  static int nb_frames_drop = 0;
>  static int input_sync;
>  static uint64_t limit_filesize = 0; //
> +static int force_fps = 0;
>  
>  static int pgmyuv_compatibility_hack=0;
>  static float dts_delta_threshold = 10;
> @@ -3043,23 +3044,10 @@
>  
>          set_context_opts(video_enc, avctx_opts[CODEC_TYPE_VIDEO], AV_OPT_FLAG_VIDEO_PARAM | AV_OPT_FLAG_ENCODING_PARAM);
>  
> +        if (codec && codec->supported_framerates && !force_fps)
> +            fps = av_find_nearest_q(fps, codec->supported_framerates);
>          video_enc->time_base.den = fps.num;
>          video_enc->time_base.num = fps.den;
> -        if(codec && codec->supported_framerates){
> -            const AVRational *p= codec->supported_framerates;
> -            const AVRational *best=NULL;
> -            AVRational best_error= (AVRational){INT_MAX, 1};
> -            for(; p->den!=0; p++){
> -                AVRational error= av_sub_q(fps, *p);
> -                if(error.num <0) error.num *= -1;
> -                if(av_cmp_q(error, best_error) < 0){
> -                    best_error= error;
> -                    best= p;
> -                }
> -            }
> -            video_enc->time_base.den= best->num;
> -            video_enc->time_base.num= best->den;
> -        }
>  
>          video_enc->width = frame_width + frame_padright + frame_padleft;
>          video_enc->height = frame_height + frame_padtop + frame_padbottom;
> @@ -3857,6 +3845,7 @@
>      { "vtag", HAS_ARG | OPT_EXPERT | OPT_VIDEO, {(void*)opt_video_tag}, "force video tag/fourcc", "fourcc/tag" },
>      { "newvideo", OPT_VIDEO, {(void*)opt_new_video_stream}, "add a new video stream to the current output stream" },
>      { "qphist", OPT_BOOL | OPT_EXPERT | OPT_VIDEO, { (void *)&qp_hist }, "show QP histogram" },
> +    { "force_fps", OPT_BOOL | OPT_VIDEO, {(void*)&force_fps}, "force the selected framerate, disable the best supported framerate selection" },
>  
>      /* audio options */
>      { "ab", OPT_FUNC2 | HAS_ARG | OPT_AUDIO, {(void*)opt_bitrate}, "set bitrate (in bits/s)", "bitrate" },

Ping?

Regards.
-- 
FFmpeg = Frenzy Frightening Multimedia Problematic Everlasting Gorilla




More information about the ffmpeg-devel mailing list