]> granicus.if.org Git - handbrake/commitdiff
libhb: Clock/frame rate handling improvements.
authorBradley Sepos <bradley@bradleysepos.com>
Sat, 29 Aug 2015 22:55:32 +0000 (18:55 -0400)
committerBradley Sepos <bradley@bradleysepos.com>
Thu, 10 Sep 2015 19:33:06 +0000 (15:33 -0400)
Allows for arbitrary frame rates between 1 and 1000 fps.
Adds min/max frame rates to CLI help.
Removes hardcoded instances of the internal clock rate in favor of hb_video_framerate_get_limits().

Unfortunately, much of the codebase generally refers to clock rate as frame rate, so a little extra care is still necessary going forward.

libhb/common.c
libhb/common.h
libhb/decavcodec.c
libhb/encavcodec.c
libhb/muxavformat.c
libhb/preset.c
test/test.c

index b63b1cfff9bd51e769373a8f7787a86a2fac6be7..092d6d3060f34a14bf3a151fdbcce37f7535f7af 100644 (file)
@@ -96,6 +96,9 @@ hb_rate_internal_t hb_video_rates[]  =
     { { "60",                   450000, }, NULL, 1, },
 };
 int hb_video_rates_count = sizeof(hb_video_rates) / sizeof(hb_video_rates[0]);
+const int hb_video_rate_clock = 27000000;           // 27MHz clock
+int hb_video_rate_min = hb_video_rate_clock / 1000; // Min clock rate from *max* frame rate
+int hb_video_rate_max = hb_video_rate_clock / 1;    // Max clock rate from *min* frame rate
 
 hb_rate_t *hb_audio_rates_first_item = NULL;
 hb_rate_t *hb_audio_rates_last_item  = NULL;
@@ -670,6 +673,13 @@ const char* hb_video_framerate_sanitize_name(const char *name)
     return hb_video_framerate_get_name(hb_video_framerate_get_from_name(name));
 }
 
+void hb_video_framerate_get_limits(int *low, int *high, int *clock)
+{
+    *low   = hb_video_rate_min;
+    *high  = hb_video_rate_max;
+    *clock = hb_video_rate_clock;
+}
+
 const hb_rate_t* hb_video_framerate_get_next(const hb_rate_t *last)
 {
     if (last == NULL)
index d1fe733352099844b4ab0e0a7a3a28f8b7e47393..9cf51b3e270e832d3f2afac17308e1150e9a3c94 100644 (file)
@@ -339,6 +339,7 @@ void hb_common_global_init();
 int              hb_video_framerate_get_from_name(const char *name);
 const char*      hb_video_framerate_get_name(int framerate);
 const char*      hb_video_framerate_sanitize_name(const char *name);
+void             hb_video_framerate_get_limits(int *low, int *high, int *clock);
 const hb_rate_t* hb_video_framerate_get_next(const hb_rate_t *last);
 
 int              hb_audio_samplerate_get_best(uint32_t codec, int samplerate, int *sr_shift);
index f81205ada76ee0aa71e2eaacb61ef836a64df442..ae9806f95b2b9a5ee4551ca441dcfe65cf6a8bf9 100644 (file)
@@ -2019,6 +2019,9 @@ static int decavcodecvInfo( hb_work_object_t *w, hb_work_info_t *info )
 {
     hb_work_private_t *pv = w->private_data;
 
+    int clock_min, clock_max, clock;
+    hb_video_framerate_get_limits(&clock_min, &clock_max, &clock);
+
     memset( info, 0, sizeof(*info) );
 
     if (pv->context == NULL)
@@ -2035,8 +2038,8 @@ static int decavcodecvInfo( hb_work_object_t *w, hb_work_info_t *info )
     info->geometry.par.den = pv->context->sample_aspect_ratio.den;
 
     compute_frame_duration( pv );
-    info->rate.num = 27000000;
-    info->rate.den = pv->duration * 300.;
+    info->rate.num = clock;
+    info->rate.den = pv->duration * (clock / 90000.);
 
     info->profile = pv->context->profile;
     info->level = pv->context->level;
index 856fff31a9940f51e9698b8572b9db63bd0a7661..5063e43f1cd29d866719130ee14206dc5d9932de 100644 (file)
@@ -64,9 +64,11 @@ int encavcodecInit( hb_work_object_t * w, hb_job_t * job )
 
     hb_work_private_t * pv = calloc( 1, sizeof( hb_work_private_t ) );
     w->private_data = pv;
-
     pv->job = job;
 
+    int clock_min, clock_max, clock;
+    hb_video_framerate_get_limits(&clock_min, &clock_max, &clock);
+
     switch ( w->codec_param )
     {
         case AV_CODEC_ID_MPEG4:
@@ -111,13 +113,13 @@ int encavcodecInit( hb_work_object_t * w, hb_job_t * job )
         fps.num = job->vrate.num;
     }
 
-    // If the fps.num is 27000000, there's a good chance this is
-    // a standard rate that we have in our hb_video_rates table.
+    // If the fps.num is the internal clock rate, there's a good chance
+    // this is a standard rate that we have in our hb_video_rates table.
     // Because of rounding errors and approximations made while 
     // measuring framerate, the actual value may not be exact.  So
     // we look for rates that are "close" and make an adjustment
     // to fps.den.
-    if (fps.num == 27000000)
+    if (fps.num == clock)
     {
         const hb_rate_t *video_framerate = NULL;
         while ((video_framerate = hb_video_framerate_get_next(video_framerate)) != NULL)
index d54200e1a66366731f9054756d2dc2e7072d6c3c..e6ad4ae23bdc9f029c077bbd5fc4c7f9686f0d14 100644 (file)
@@ -123,6 +123,9 @@ static int avformatInit( hb_mux_object_t * m )
     int max_tracks;
     int ii, ret;
 
+    int clock_min, clock_max, clock;
+    hb_video_framerate_get_limits(&clock_min, &clock_max, &clock);
+
     const char *muxer_name = NULL;
 
     uint8_t         default_track_flag = 1;
@@ -362,13 +365,13 @@ static int avformatInit( hb_mux_object_t * m )
         vrate = job->vrate;
     }
 
-    // If the vrate is 27000000, there's a good chance this is
-    // a standard rate that we have in our hb_video_rates table.
+    // If the vrate is the internal clock rate, there's a good chance
+    // this is a standard rate that we have in our hb_video_rates table.
     // Because of rounding errors and approximations made while
     // measuring framerate, the actual value may not be exact.  So
     // we look for rates that are "close" and make an adjustment
     // to fps.den.
-    if (vrate.num == 27000000)
+    if (vrate.num == clock)
     {
         const hb_rate_t *video_framerate = NULL;
         while ((video_framerate = hb_video_framerate_get_next(video_framerate)) != NULL)
index ec0c9b26ca354877749e65859352afec2e7a6b45..b7074feb03770ab3f4e8b1482e2b6f29abd6a7f7 100644 (file)
@@ -1018,39 +1018,47 @@ int hb_preset_job_add_subtitles(hb_handle_t *h, int title_index,
 
 static int get_video_framerate(hb_value_t *rate_value)
 {
-    int rate = 0;
-    if (hb_value_type(rate_value) != HB_VALUE_TYPE_STRING)
+    // Predefined by name
+    if (hb_value_type(rate_value) == HB_VALUE_TYPE_STRING)
     {
-        double d;
-        d = hb_value_get_double(rate_value);
-        if (d != 0 && d <= 600)
+        int rate = 0;
+        const char *rate_name = hb_value_get_string(rate_value);
+        if (!strcasecmp(rate_name, "source") ||
+            !strcasecmp(rate_name, "auto") ||
+            !strcasecmp(rate_name, "same as source"))
         {
-            // Assume the value is an actual framerate and compute
-            // 27Mhz based denominator
-            rate = (int)(27000000 / d);
+            return rate;
         }
         else
-        {
-            // Assume the value is a 27Mhz based denominator
-            rate = (int)d;
-        }
-    }
-    else
-    {
-        const char *rate_name = hb_value_get_string(rate_value);
-        if (strcasecmp(rate_name, "source") &&
-            strcasecmp(rate_name, "auto") &&
-            strcasecmp(rate_name, "same as source"))
         {
             rate = hb_video_framerate_get_from_name(rate_name);
-            if (rate < 0)
+            if (rate != -1)
             {
-                // No matching rate found. Error out.
-                rate = -1;
+                return rate;
             }
         }
     }
-    return rate;
+
+    // Arbitrary
+    int clock_min, clock_max, clock,
+        frame_min, frame_max;
+    hb_video_framerate_get_limits(&clock_min, &clock_max, &clock);
+    frame_min = clock / clock_max;
+    frame_max = clock / clock_min;
+    double rate_d = hb_value_get_double(rate_value);
+    if (rate_d >= frame_min && rate_d <= frame_max)
+    {
+        // Value is a framerate, return clockrate
+        return (int)(clock / rate_d);
+    }
+    else if (rate_d >= clock_min && rate_d <= clock_max)
+    {
+        // Value is already a clockrate
+        return (int)(rate_d);
+    }
+
+    // Value out of bounds
+    return -1;
 }
 
 int hb_preset_apply_filters(const hb_dict_t *preset, hb_dict_t *job_dict)
@@ -1058,6 +1066,9 @@ int hb_preset_apply_filters(const hb_dict_t *preset, hb_dict_t *job_dict)
     hb_value_t *filters_dict, *filter_list, *filter_dict;
     char *filter_str;
 
+    int clock_min, clock_max, clock;
+    hb_video_framerate_get_limits(&clock_min, &clock_max, &clock);
+
     // Create new filters
     filters_dict = hb_dict_init();
     hb_dict_set(job_dict, "Filters", filters_dict);
@@ -1282,7 +1293,7 @@ int hb_preset_apply_filters(const hb_dict_t *preset, hb_dict_t *job_dict)
     if (vrate_den == 0)
         filter_str = hb_strdup_printf("%d", fr_mode);
     else
-        filter_str = hb_strdup_printf("%d:%d:%d", fr_mode, 27000000, vrate_den);
+        filter_str = hb_strdup_printf("%d:%d:%d", fr_mode, clock, vrate_den);
 
     filter_dict = hb_dict_init();
     hb_dict_set(filter_dict, "ID", hb_value_int(HB_FILTER_VFR));
index 1efaa17b1c70cb2f32816dc34c34969a3b827079..5463f8d9598776b23100f55d94ccb06de8a46590 100644 (file)
@@ -901,7 +901,7 @@ void SigHandler( int i_signal )
  ****************************************************************************/
 static void ShowHelp()
 {
-    int i;
+    int i, clock_min, clock_max, clock;
     const hb_rate_t *rate;
     const hb_dither_t *dither;
     const hb_mixdown_t *mixdown;
@@ -1042,7 +1042,11 @@ static void ShowHelp()
             fprintf(out, "/");
         }
     }
-    fprintf( out, ")\n"
+    fprintf( out, "\n"
+"                           or a number between " );
+    hb_video_framerate_get_limits(&clock_min, &clock_max, &clock);
+    fprintf(out, "%i and %i", (clock / clock_max), (clock / clock_min));
+    fprintf( out, ").\n"
 "                           Be aware that not specifying a framerate lets\n"
 "                           HandBrake preserve a source's time stamps,\n"
 "                           potentially creating variable framerate video\n"