Convert elements to use fractions for their framerate.
authorJan Schmidt <thaytan@mad.scientist.com>
Tue, 22 Nov 2005 16:08:37 +0000 (16:08 +0000)
committerJan Schmidt <thaytan@mad.scientist.com>
Tue, 22 Nov 2005 16:08:37 +0000 (16:08 +0000)
Original commit message from CVS:
* ext/libvisual/visual.c: (gst_visual_src_setcaps), (get_buffer),
(gst_visual_chain):
* ext/ogg/gstogmparse.c: (gst_ogm_parse_chain):
* ext/theora/theoradec.c: (theora_handle_type_packet):
* ext/theora/theoraenc.c: (theora_enc_sink_setcaps),
(theora_enc_chain):
* gst-libs/gst/riff/riff-media.c: (gst_riff_create_video_caps):
* gst-libs/gst/video/video.c: (gst_video_frame_rate):
* gst-libs/gst/video/video.h:
* gst/ffmpegcolorspace/avcodec.h:
* gst/ffmpegcolorspace/gstffmpegcodecmap.c:
(gst_ffmpeg_caps_to_pixfmt):
* gst/ffmpegcolorspace/gstffmpegcolorspace.c:
(gst_ffmpegcsp_set_caps):
* gst/videorate/gstvideorate.c: (gst_videorate_transformcaps),
(gst_videorate_setcaps), (gst_videorate_blank_data),
(gst_videorate_chain):
* gst/videotestsrc/gstvideotestsrc.c:
(gst_videotestsrc_src_fixate), (gst_videotestsrc_getcaps),
(gst_videotestsrc_parse_caps), (gst_videotestsrc_setcaps),
(gst_videotestsrc_event), (gst_videotestsrc_create):
* gst/videotestsrc/gstvideotestsrc.h:
* sys/ximage/ximagesink.c: (gst_ximagesink_xcontext_get),
(gst_ximagesink_setcaps), (gst_ximagesink_change_state),
(gst_ximagesink_get_times), (gst_ximagesink_init):
* sys/ximage/ximagesink.h:
* sys/xvimage/xvimagesink.c: (gst_xvimagesink_get_xv_support),
(gst_xvimagesink_setcaps), (gst_xvimagesink_change_state),
(gst_xvimagesink_get_times), (gst_xvimagesink_init):
* sys/xvimage/xvimagesink.h:
Convert elements to use fractions for their framerate.
V4L elements to come later tonight.

18 files changed:
ChangeLog
ext/libvisual/visual.c
ext/ogg/gstogmparse.c
ext/theora/theoradec.c
ext/theora/theoraenc.c
gst-libs/gst/riff/riff-media.c
gst-libs/gst/video/video.c
gst-libs/gst/video/video.h
gst/ffmpegcolorspace/avcodec.h
gst/ffmpegcolorspace/gstffmpegcodecmap.c
gst/ffmpegcolorspace/gstffmpegcolorspace.c
gst/videorate/gstvideorate.c
gst/videotestsrc/gstvideotestsrc.c
gst/videotestsrc/gstvideotestsrc.h
sys/ximage/ximagesink.c
sys/ximage/ximagesink.h
sys/xvimage/xvimagesink.c
sys/xvimage/xvimagesink.h

index 87f9362..0b173a1 100644 (file)
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,38 @@
+2005-11-22  Jan Schmidt  <thaytan@mad.scientist.com>
+
+       * ext/libvisual/visual.c: (gst_visual_src_setcaps), (get_buffer),
+       (gst_visual_chain):
+       * ext/ogg/gstogmparse.c: (gst_ogm_parse_chain):
+       * ext/theora/theoradec.c: (theora_handle_type_packet):
+       * ext/theora/theoraenc.c: (theora_enc_sink_setcaps),
+       (theora_enc_chain):
+       * gst-libs/gst/riff/riff-media.c: (gst_riff_create_video_caps):
+       * gst-libs/gst/video/video.c: (gst_video_frame_rate):
+       * gst-libs/gst/video/video.h:
+       * gst/ffmpegcolorspace/avcodec.h:
+       * gst/ffmpegcolorspace/gstffmpegcodecmap.c:
+       (gst_ffmpeg_caps_to_pixfmt):
+       * gst/ffmpegcolorspace/gstffmpegcolorspace.c:
+       (gst_ffmpegcsp_set_caps):
+       * gst/videorate/gstvideorate.c: (gst_videorate_transformcaps),
+       (gst_videorate_setcaps), (gst_videorate_blank_data),
+       (gst_videorate_chain):
+       * gst/videotestsrc/gstvideotestsrc.c:
+       (gst_videotestsrc_src_fixate), (gst_videotestsrc_getcaps),
+       (gst_videotestsrc_parse_caps), (gst_videotestsrc_setcaps),
+       (gst_videotestsrc_event), (gst_videotestsrc_create):
+       * gst/videotestsrc/gstvideotestsrc.h:
+       * sys/ximage/ximagesink.c: (gst_ximagesink_xcontext_get),
+       (gst_ximagesink_setcaps), (gst_ximagesink_change_state),
+       (gst_ximagesink_get_times), (gst_ximagesink_init):
+       * sys/ximage/ximagesink.h:
+       * sys/xvimage/xvimagesink.c: (gst_xvimagesink_get_xv_support),
+       (gst_xvimagesink_setcaps), (gst_xvimagesink_change_state),
+       (gst_xvimagesink_get_times), (gst_xvimagesink_init):
+       * sys/xvimage/xvimagesink.h:
+         Convert elements to use fractions for their framerate.
+          V4L elements to come later tonight.
+
 2005-11-22  Thomas Vander Stichele  <thomas at apestaart dot org>
 
        * gst-libs/gst/audio/audio.c:
index 44ea87e..cee88d8 100644 (file)
@@ -56,7 +56,10 @@ struct _GstVisual
 
   /* audio/video state */
   gint rate;                    /* Input samplerate */
-  gdouble fps;
+
+  /* framerate numerator & denominator */
+  gint fps_n;
+  gint fps_d;
   gint width;
   gint height;
 
@@ -268,6 +271,7 @@ gst_visual_src_setcaps (GstPad * pad, GstCaps * caps)
   GstVisual *visual = GST_VISUAL (gst_pad_get_parent (pad));
   GstStructure *structure;
   gint depth;
+  const GValue *fps;
 
   structure = gst_caps_get_structure (caps, 0);
 
@@ -275,10 +279,14 @@ gst_visual_src_setcaps (GstPad * pad, GstCaps * caps)
     return FALSE;
   if (!gst_structure_get_int (structure, "height", &visual->height))
     return FALSE;
-  if (!gst_structure_get_double (structure, "framerate", &visual->fps))
-    return FALSE;
   if (!gst_structure_get_int (structure, "bpp", &depth))
     return FALSE;
+  fps = gst_structure_get_value (structure, "framerate");
+  if (fps == NULL || !GST_VALUE_HOLDS_FRACTION (fps))
+    return FALSE;
+
+  visual->fps_n = gst_value_get_fraction_numerator (fps);
+  visual->fps_d = gst_value_get_fraction_denominator (fps);
 
   visual_video_set_depth (visual->video,
       visual_video_depth_enum_from_value (depth));
@@ -310,6 +318,7 @@ get_buffer (GstVisual * visual, GstBuffer ** outbuf)
     gint width, height, bpp;
     GstStructure *s;
     GstCaps *caps;
+    GValue target_fps = { 0 };
 
     /* No output caps current set up. Try and pick some */
     caps = gst_pad_get_allowed_caps (visual->srcpad);
@@ -328,7 +337,9 @@ get_buffer (GstVisual * visual, GstBuffer ** outbuf)
 
       gst_structure_fixate_field_nearest_int (s, "width", 320);
       gst_structure_fixate_field_nearest_int (s, "height", 240);
-      gst_structure_fixate_field_nearest_double (s, "framerate", 30.0);
+      g_value_init (&target_fps, GST_TYPE_FRACTION);
+      gst_value_set_fraction (&target_fps, 25, 1);
+      gst_structure_fixate_field_nearest_fraction (s, "framerate", &target_fps);
 
       gst_pad_fixate_caps (visual->srcpad, caps);
     } else
@@ -380,11 +391,12 @@ gst_visual_chain (GstPad * pad, GstBuffer * buffer)
     }
   }
 
+  /* Match timestamps from the incoming audio */
   if (GST_BUFFER_TIMESTAMP (buffer) != GST_CLOCK_TIME_NONE)
     visual->next_ts = GST_BUFFER_TIMESTAMP (buffer);
 
   /* spf = samples per frame */
-  spf = visual->rate / visual->fps;
+  spf = ((guint64) (visual->rate) * visual->fps_n) / visual->fps_d;
   gst_adapter_push (visual->adapter, buffer);
 
   while (gst_adapter_available (visual->adapter) > MAX (512, spf) * 4 &&
@@ -410,9 +422,8 @@ gst_visual_chain (GstPad * pad, GstBuffer * buffer)
       visual_audio_analyze (&visual->audio);
       visual_actor_run (visual->actor, &visual->audio);
 
-      /* FIXME: Match timestamps from the incoming audio */
       GST_BUFFER_TIMESTAMP (outbuf) = visual->next_ts;
-      GST_BUFFER_DURATION (outbuf) = GST_SECOND / visual->fps;
+      GST_BUFFER_DURATION (outbuf) = GST_SECOND * visual->fps_n / visual->fps_d;
       visual->next_ts += GST_BUFFER_DURATION (outbuf);
       ret = gst_pad_push (visual->srcpad, outbuf);
       outbuf = NULL;
@@ -420,7 +431,7 @@ gst_visual_chain (GstPad * pad, GstBuffer * buffer)
 
     /* Flush out the number of samples per frame * channels * sizeof (gint16) */
     /* Recompute spf in case caps changed */
-    spf = visual->rate / visual->fps;
+    spf = ((guint64) (visual->rate) * visual->fps_n) / visual->fps_d;
     GST_DEBUG_OBJECT (visual, "finished frame, flushing %u samples from input",
         spf);
     gst_adapter_flush (visual->adapter,
index 0c4d322..2c7d989 100644 (file)
@@ -608,7 +608,8 @@ gst_ogm_parse_chain (GstPad * pad, GstBuffer * buffer)
           gst_caps_set_simple (caps,
               "width", G_TYPE_INT, ogm->hdr.s.video.width,
               "height", G_TYPE_INT, ogm->hdr.s.video.height,
-              "framerate", G_TYPE_DOUBLE, 10000000. / ogm->hdr.time_unit, NULL);
+              "framerate", GST_TYPE_FRACTION, 10000000, ogm->hdr.time_unit,
+              NULL);
           break;
         }
         case 't':
index a7c157f..f6e55ed 100644 (file)
@@ -99,7 +99,7 @@ GST_STATIC_PAD_TEMPLATE ("src",
     GST_PAD_ALWAYS,
     GST_STATIC_CAPS ("video/x-raw-yuv, "
         "format = (fourcc) I420, "
-        "framerate = (double) [0, MAX], "
+        "framerate = (fraction) [0/1, MAX], "
         "width = (int) [ 1, MAX ], " "height = (int) [ 1, MAX ]")
     );
 
@@ -747,8 +747,8 @@ theora_handle_type_packet (GstTheoraDec * dec, ogg_packet * packet)
 
   caps = gst_caps_new_simple ("video/x-raw-yuv",
       "format", GST_TYPE_FOURCC, GST_MAKE_FOURCC ('I', '4', '2', '0'),
-      "framerate", G_TYPE_DOUBLE,
-      ((gdouble) dec->info.fps_numerator) / dec->info.fps_denominator,
+      "framerate", GST_TYPE_FRACTION,
+      dec->info.fps_numerator, dec->info.fps_denominator,
       "pixel-aspect-ratio", GST_TYPE_FRACTION, par_num, par_den,
       "width", G_TYPE_INT, dec->width, "height", G_TYPE_INT, dec->height, NULL);
   gst_pad_set_caps (dec->srcpad, caps);
index ee40edf..b60e10c 100644 (file)
@@ -113,7 +113,7 @@ GST_STATIC_PAD_TEMPLATE ("sink",
     GST_PAD_ALWAYS,
     GST_STATIC_CAPS ("video/x-raw-yuv, "
         "format = (fourcc) I420, "
-        "framerate = (double) [0, MAX], "
+        "framerate = (fraction) [0/1, MAX], "
         "width = (int) [ 1, MAX ], " "height = (int) [ 1, MAX ]")
     );
 
@@ -244,12 +244,11 @@ theora_enc_sink_setcaps (GstPad * pad, GstCaps * caps)
   GstStructure *structure = gst_caps_get_structure (caps, 0);
   GstTheoraEnc *enc = GST_THEORA_ENC (gst_pad_get_parent (pad));
   const GValue *par;
-  GValue fps = { 0 };
-  GValue framerate = { 0 };
+  const GValue *framerate;
 
   gst_structure_get_int (structure, "width", &enc->width);
   gst_structure_get_int (structure, "height", &enc->height);
-  gst_structure_get_double (structure, "framerate", &enc->fps);
+  framerate = gst_structure_get_value (structure, "framerate");
   par = gst_structure_get_value (structure, "pixel-aspect-ratio");
 
   theora_info_init (&enc->info);
@@ -272,14 +271,8 @@ theora_enc_sink_setcaps (GstPad * pad, GstCaps * caps)
   enc->info.offset_x = enc->offset_x;
   enc->info.offset_y = enc->offset_y;
 
-  /* convert double to fraction for the framerate */
-  g_value_init (&fps, G_TYPE_DOUBLE);
-  g_value_init (&framerate, GST_TYPE_FRACTION);
-  g_value_set_double (&fps, enc->fps);
-  g_value_transform (&fps, &framerate);
-
-  enc->info.fps_numerator = gst_value_get_fraction_numerator (&framerate);
-  enc->info.fps_denominator = gst_value_get_fraction_denominator (&framerate);
+  enc->info.fps_numerator = gst_value_get_fraction_numerator (framerate);
+  enc->info.fps_denominator = gst_value_get_fraction_denominator (framerate);
 
   if (par) {
     enc->info.aspect_numerator = gst_value_get_fraction_numerator (par);
@@ -471,6 +464,9 @@ theora_enc_chain (GstPad * pad, GstBuffer * buffer)
 
     /* create the remaining theora headers */
     theora_comment_init (&enc->comment);
+    /* Currently leaks due to libtheora API brokenness, I don't think we can
+     * portably work around it. Leaks ~50 bytes per encoder instance, so not a
+     * huge problem. */
     theora_encode_comment (&enc->comment, &op);
     ret = theora_buffer_from_packet (enc, &op, 0, 0, &buf2);
     if (ret != GST_FLOW_OK) {
index 7bf8c4f..cae9006 100644 (file)
@@ -363,12 +363,11 @@ gst_riff_create_video_caps (guint32 codec_fcc,
   }
 
   if (strh != NULL) {
-    gdouble fps = 1. * strh->rate / strh->scale;
-
-    gst_caps_set_simple (caps, "framerate", G_TYPE_DOUBLE, fps, NULL);
+    gst_caps_set_simple (caps, "framerate", GST_TYPE_FRACTION,
+        strh->rate, strh->scale, NULL);
   } else {
     gst_caps_set_simple (caps,
-        "framerate", GST_TYPE_DOUBLE_RANGE, 0., G_MAXDOUBLE, NULL);
+        "framerate", GST_TYPE_FRACTION_RANGE, 0, 1, G_MAXINT, 1, NULL);
   }
 
   if (strf != NULL) {
index 67214b8..3dad3d0 100644 (file)
 #include "video.h"
 
 /* This is simply a convenience function, nothing more or less */
-
-gdouble
+const GValue *
 gst_video_frame_rate (GstPad * pad)
 {
-  gdouble fps = 0.;
+  const GValue *fps;
+  gchar *fps_string;
+
   const GstCaps *caps = NULL;
   GstStructure *structure;
 
@@ -38,18 +39,27 @@ gst_video_frame_rate (GstPad * pad)
   if (caps == NULL) {
     g_warning ("gstvideo: failed to get caps of pad %s:%s",
         GST_ELEMENT_NAME (gst_pad_get_parent (pad)), GST_PAD_NAME (pad));
-    return 0.;
+    return NULL;
   }
 
   structure = gst_caps_get_structure (caps, 0);
-  if (!gst_structure_get_double (structure, "framerate", &fps)) {
+  if ((fps = gst_structure_get_value (structure, "framerate")) == NULL) {
     g_warning ("gstvideo: failed to get framerate property of pad %s:%s",
         GST_ELEMENT_NAME (gst_pad_get_parent (pad)), GST_PAD_NAME (pad));
-    return 0.;
+    return NULL;
+  }
+  if (!GST_VALUE_HOLDS_FRACTION (fps)) {
+    g_warning
+        ("gstvideo: framerate property of pad %s:%s is not of type Fraction",
+        GST_ELEMENT_NAME (gst_pad_get_parent (pad)), GST_PAD_NAME (pad));
+    return NULL;
   }
 
-  GST_DEBUG ("Framerate request on pad %s:%s: %f",
-      GST_ELEMENT_NAME (gst_pad_get_parent (pad)), GST_PAD_NAME (pad), fps);
+  fps_string = gst_value_serialize (fps);
+  GST_DEBUG ("Framerate request on pad %s:%s: %s",
+      GST_ELEMENT_NAME (gst_pad_get_parent (pad)), GST_PAD_NAME (pad),
+      fps_string);
+  g_free (fps_string);
 
   return fps;
 }
index 60efe3e..6c3cd84 100644 (file)
@@ -60,7 +60,7 @@ G_BEGIN_DECLS
 #define GST_VIDEO_BLUE_MASK_15_INT 0x001f
 
 #define GST_VIDEO_SIZE_RANGE "(int) [ 1, max ]"
-#define GST_VIDEO_FPS_RANGE "(double) [ 0.0, max ]"
+#define GST_VIDEO_FPS_RANGE "(fraction) [ 0, max ]"
 
 /* consider the next 2 protected */
 #define __GST_VIDEO_CAPS_MAKE_32A(R, G, B, A)                          \
@@ -184,7 +184,7 @@ G_BEGIN_DECLS
        "framerate = " GST_VIDEO_FPS_RANGE
 
 /* functions */
-gdouble  gst_video_frame_rate (GstPad *pad);
+const GValue *gst_video_frame_rate (GstPad *pad);
 gboolean gst_video_get_size   (GstPad *pad,
                                gint   *width,
                                gint   *height);
index 3bf14c7..e25f8e5 100644 (file)
@@ -88,8 +88,6 @@ enum SampleFormat {
     SAMPLE_FMT_S16 = 0,         ///< signed 16 bits
 };
 
-#define DEFAULT_FRAME_RATE_BASE 1001000
-
 /* thomas: extracted from imgconvert.c since it's also used in
  * gstffmpegcodecmap.c */
 
index 1c114eb..f87159e 100644 (file)
@@ -83,14 +83,14 @@ gst_ffmpeg_set_palette (GstCaps * caps, AVCodecContext * context)
     gst_caps_new_simple (mimetype,                             \
        "width",     G_TYPE_INT,   context->width,              \
        "height",    G_TYPE_INT,   context->height,             \
-       "framerate", G_TYPE_DOUBLE, 1. * context->frame_rate /  \
-                                  context->frame_rate_base,    \
+       "framerate", GST_TYPE_FRACTION,                         \
+        (gint) context->frame_rate, (gint) context->frame_rate_base, \
        __VA_ARGS__, NULL)                                      \
     :                                                          \
     gst_caps_new_simple (mimetype,                             \
        "width",     GST_TYPE_INT_RANGE, 1, G_MAXINT,           \
        "height",    GST_TYPE_INT_RANGE, 1, G_MAXINT,           \
-       "framerate", GST_TYPE_DOUBLE_RANGE, 0.0, G_MAXDOUBLE,   \
+       "framerate", GST_TYPE_FRACTION_RANGE, 0, 1, G_MAXINT, 1,\
        __VA_ARGS__, NULL)
 
 /* same for audio - now with channels/sample rate
@@ -447,19 +447,22 @@ gst_ffmpeg_caps_to_pixfmt (const GstCaps * caps,
     AVCodecContext * context, gboolean raw)
 {
   GstStructure *structure;
-  gdouble fps;
+  const GValue *fps;
+  gboolean ret;
 
   g_return_if_fail (gst_caps_get_size (caps) == 1);
   structure = gst_caps_get_structure (caps, 0);
 
-  gst_structure_get_int (structure, "width", &context->width);
-  gst_structure_get_int (structure, "height", &context->height);
+  ret = gst_structure_get_int (structure, "width", &context->width);
+  ret &= gst_structure_get_int (structure, "height", &context->height);
+  g_return_if_fail (ret == TRUE);
+
+  fps = gst_structure_get_value (structure, "framerate");
+  g_return_if_fail (GST_VALUE_HOLDS_FRACTION (fps));
 
   /* framerate does not really matter */
-  if (gst_structure_get_double (structure, "framerate", &fps)) {
-    context->frame_rate = fps * DEFAULT_FRAME_RATE_BASE;
-    context->frame_rate_base = DEFAULT_FRAME_RATE_BASE;
-  }
+  context->frame_rate = gst_value_get_fraction_numerator (fps);
+  context->frame_rate_base = gst_value_get_fraction_denominator (fps);
 
   if (!raw)
     return;
index ca6ff13..3cf3cb8 100644 (file)
@@ -163,7 +163,8 @@ gst_ffmpegcsp_set_caps (GstBaseTransform * btrans, GstCaps * incaps,
   GstStructure *structure;
   gint in_height, in_width;
   gint out_height, out_width;
-  gdouble in_framerate, out_framerate;
+  const GValue *in_framerate = NULL;
+  const GValue *out_framerate = NULL;
   const GValue *in_par = NULL;
   const GValue *out_par = NULL;
   AVCodecContext *ctx;
@@ -177,10 +178,14 @@ gst_ffmpegcsp_set_caps (GstBaseTransform * btrans, GstCaps * incaps,
   /* we have to have width and height */
   res = gst_structure_get_int (structure, "width", &in_width);
   res &= gst_structure_get_int (structure, "height", &in_height);
-  res &= gst_structure_get_double (structure, "framerate", &in_framerate);
   if (!res)
     goto no_width_height;
 
+  /* and framerate */
+  in_framerate = gst_structure_get_value (structure, "framerate");
+  if (in_framerate == NULL || !GST_VALUE_HOLDS_FRACTION (in_framerate))
+    goto no_framerate;
+
   /* this is optional */
   in_par = gst_structure_get_value (structure, "pixel-aspect-ratio");
 
@@ -189,16 +194,20 @@ gst_ffmpegcsp_set_caps (GstBaseTransform * btrans, GstCaps * incaps,
   /* we have to have width and height */
   res = gst_structure_get_int (structure, "width", &out_width);
   res &= gst_structure_get_int (structure, "height", &out_height);
-  res &= gst_structure_get_double (structure, "framerate", &out_framerate);
   if (!res)
     goto no_width_height;
 
+  /* and framerate */
+  out_framerate = gst_structure_get_value (structure, "framerate");
+  if (out_framerate == NULL || !GST_VALUE_HOLDS_FRACTION (out_framerate))
+    goto no_framerate;
+
   /* this is optional */
   out_par = gst_structure_get_value (structure, "pixel-aspect-ratio");
 
   /* these must match */
   if (in_width != out_width || in_height != out_height ||
-      in_framerate != out_framerate)
+      gst_value_compare (in_framerate, out_framerate) != GST_VALUE_EQUAL)
     goto format_mismatch;
 
   /* if present, these must match too */
@@ -244,6 +253,13 @@ no_width_height:
     space->to_pixfmt = PIX_FMT_NB;
     return FALSE;
   }
+no_framerate:
+  {
+    GST_DEBUG ("did not specify framerate");
+    space->from_pixfmt = PIX_FMT_NB;
+    space->to_pixfmt = PIX_FMT_NB;
+    return FALSE;
+  }
 format_mismatch:
   {
     GST_DEBUG ("input and output formats do not match");
index c115304..0ca1fe1 100644 (file)
@@ -47,7 +47,8 @@ struct _GstVideorate
   GstPad *sinkpad, *srcpad;
 
   /* video state */
-  gdouble from_fps, to_fps;
+  gint from_rate_numerator, from_rate_denominator;
+  gint to_rate_numerator, to_rate_denominator;
   guint64 next_ts;              /* Timestamp of next buffer to output */
   guint64 first_ts;             /* Timestamp of first buffer */
   GstBuffer *prevbuf;
@@ -220,7 +221,7 @@ gst_videorate_transformcaps (GstPad * in_pad, GstCaps * in_caps,
     structure = gst_caps_get_structure (intersect, i);
 
     gst_structure_set (structure,
-        "framerate", GST_TYPE_DOUBLE_RANGE, 0.0, G_MAXDOUBLE, NULL);
+        "framerate", GST_TYPE_FRACTION_RANGE, 0, 1, G_MAXINT, 1, NULL);
   }
   *out_caps = intersect;
 
@@ -261,20 +262,27 @@ gst_videorate_setcaps (GstPad * pad, GstCaps * caps)
   GstVideorate *videorate;
   GstStructure *structure;
   gboolean ret = TRUE;
-  double fps;
   GstPad *otherpad, *opeer;
+  const GValue *rate;
+  gint rate_numerator, rate_denominator;
 
   videorate = GST_VIDEORATE (GST_PAD_PARENT (pad));
 
   structure = gst_caps_get_structure (caps, 0);
-  if (!(ret = gst_structure_get_double (structure, "framerate", &fps)))
+  rate = gst_structure_get_value (structure, "framerate");
+  if (!rate)
     goto done;
 
+  rate_numerator = gst_value_get_fraction_numerator (rate);
+  rate_denominator = gst_value_get_fraction_denominator (rate);
+
   if (pad == videorate->srcpad) {
-    videorate->to_fps = fps;
+    videorate->to_rate_numerator = rate_numerator;
+    videorate->to_rate_denominator = rate_denominator;
     otherpad = videorate->sinkpad;
   } else {
-    videorate->from_fps = fps;
+    videorate->from_rate_numerator = rate_numerator;
+    videorate->from_rate_denominator = rate_denominator;
     otherpad = videorate->srcpad;
   }
   /* now try to find something for the peer */
@@ -315,14 +323,20 @@ gst_videorate_setcaps (GstPad * pad, GstCaps * caps)
       structure = gst_caps_get_structure (caps, 0);
 
       /* and fixate */
-      gst_structure_fixate_field_nearest_int (structure, "framerate", fps);
+      gst_structure_fixate_field_nearest_fraction (structure, "framerate",
+          rate);
+
+      rate = gst_structure_get_value (structure, "framerate");
 
-      gst_structure_get_double (structure, "framerate", &fps);
+      rate_numerator = gst_value_get_fraction_numerator (rate);
+      rate_denominator = gst_value_get_fraction_denominator (rate);
 
       if (otherpad == videorate->srcpad) {
-        videorate->to_fps = fps;
+        videorate->to_rate_numerator = rate_numerator;
+        videorate->to_rate_denominator = rate_denominator;
       } else {
-        videorate->from_fps = fps;
+        videorate->from_rate_numerator = rate_numerator;
+        videorate->from_rate_denominator = rate_denominator;
       }
       gst_pad_set_caps (otherpad, caps);
       ret = TRUE;
@@ -341,8 +355,10 @@ gst_videorate_blank_data (GstVideorate * videorate)
     gst_buffer_unref (videorate->prevbuf);
   videorate->prevbuf = NULL;
 
-  videorate->from_fps = 0;
-  videorate->to_fps = 0;
+  videorate->from_rate_numerator = 0;
+  videorate->from_rate_denominator = 0;
+  videorate->to_rate_numerator = 0;
+  videorate->to_rate_denominator = 0;
   videorate->in = 0;
   videorate->out = 0;
   videorate->drop = 0;
@@ -435,10 +451,9 @@ gst_videorate_chain (GstPad * pad, GstBuffer * buffer)
 
   videorate = GST_VIDEORATE (GST_PAD_PARENT (pad));
 
-  if (videorate->from_fps == 0)
-    return GST_FLOW_NOT_NEGOTIATED;
-
-  if (videorate->to_fps == 0)
+  if (videorate->from_rate_numerator == 0 ||
+      videorate->from_rate_denominator == 0 ||
+      videorate->to_rate_denominator == 0 || videorate->to_rate_numerator == 0)
     return GST_FLOW_NOT_NEGOTIATED;
 
   /* pull in 2 buffers */
@@ -494,7 +509,8 @@ gst_videorate_chain (GstPad * pad, GstBuffer * buffer)
         videorate->out++;
         videorate->next_ts =
             videorate->first_ts +
-            (videorate->out / videorate->to_fps * GST_SECOND);
+            (videorate->out * GST_SECOND *
+            videorate->to_rate_denominator / videorate->to_rate_numerator);
         GST_BUFFER_DURATION (outbuf) =
             videorate->next_ts - GST_BUFFER_TIMESTAMP (outbuf);
         /* adapt for looping */
index e947e25..25318d9 100644 (file)
@@ -173,12 +173,16 @@ static void
 gst_videotestsrc_src_fixate (GstPad * pad, GstCaps * caps)
 {
   GstStructure *structure;
+  GValue value = { 0 };
+
+  g_value_init (&value, GST_TYPE_FRACTION);
+  gst_value_set_fraction (&value, 30, 1);
 
   structure = gst_caps_get_structure (caps, 0);
 
   gst_structure_fixate_field_nearest_int (structure, "width", 320);
   gst_structure_fixate_field_nearest_int (structure, "height", 240);
-  gst_structure_fixate_field_nearest_double (structure, "framerate", 30.0);
+  gst_structure_fixate_field_nearest_fraction (structure, "framerate", &value);
 }
 
 static void
@@ -263,7 +267,7 @@ gst_videotestsrc_getcaps (GstBaseSrc * unused)
       gst_structure_set (structure,
           "width", GST_TYPE_INT_RANGE, 1, G_MAXINT,
           "height", GST_TYPE_INT_RANGE, 1, G_MAXINT,
-          "framerate", GST_TYPE_DOUBLE_RANGE, 0.0, G_MAXDOUBLE, NULL);
+          "framerate", GST_TYPE_FRACTION_RANGE, 0, 1, G_MAXINT, 1, NULL);
       gst_caps_append_structure (caps, structure);
     }
 
@@ -275,11 +279,12 @@ gst_videotestsrc_getcaps (GstBaseSrc * unused)
 
 static gboolean
 gst_videotestsrc_parse_caps (const GstCaps * caps,
-    gint * width, gint * height, gdouble * rate,
+    gint * width, gint * height, gint * rate_numerator, gint * rate_denominator,
     struct fourcc_list_struct **fourcc)
 {
   const GstStructure *structure;
   GstPadLinkReturn ret;
+  const GValue *framerate;
 
   GST_DEBUG ("parsing caps");
 
@@ -296,7 +301,14 @@ gst_videotestsrc_parse_caps (const GstCaps * caps,
 
   ret = gst_structure_get_int (structure, "width", width);
   ret &= gst_structure_get_int (structure, "height", height);
-  ret &= gst_structure_get_double (structure, "framerate", rate);
+
+  framerate = gst_structure_get_value (structure, "framerate");
+
+  if (framerate) {
+    *rate_numerator = gst_value_get_fraction_numerator (framerate);
+    *rate_denominator = gst_value_get_fraction_denominator (framerate);
+  } else
+    ret = FALSE;
 
   return ret;
 }
@@ -305,24 +317,26 @@ static gboolean
 gst_videotestsrc_setcaps (GstBaseSrc * bsrc, GstCaps * caps)
 {
   gboolean res;
-  gint width, height;
-  gdouble rate;
+  gint width, height, rate_denominator, rate_numerator;
   struct fourcc_list_struct *fourcc;
   GstVideoTestSrc *videotestsrc;
 
   videotestsrc = GST_VIDEOTESTSRC (bsrc);
 
-  res = gst_videotestsrc_parse_caps (caps, &width, &height, &rate, &fourcc);
+  res = gst_videotestsrc_parse_caps (caps, &width, &height,
+      &rate_numerator, &rate_denominator, &fourcc);
   if (res) {
     /* looks ok here */
     videotestsrc->fourcc = fourcc;
     videotestsrc->width = width;
     videotestsrc->height = height;
-    videotestsrc->rate = rate;
+    videotestsrc->rate_numerator = rate_numerator;
+    videotestsrc->rate_denominator = rate_denominator;
     videotestsrc->bpp = videotestsrc->fourcc->bitspp;
 
-    GST_DEBUG_OBJECT (videotestsrc, "size %dx%d, %f fps", videotestsrc->width,
-        videotestsrc->height, videotestsrc->rate);
+    GST_DEBUG_OBJECT (videotestsrc, "size %dx%d, %d/%d fps",
+        videotestsrc->width, videotestsrc->height,
+        videotestsrc->rate_numerator, videotestsrc->rate_denominator);
   }
   return res;
 }
@@ -350,10 +364,12 @@ gst_videotestsrc_event (GstBaseSrc * bsrc, GstEvent * event)
 
       switch (format) {
         case GST_FORMAT_TIME:
-          new_n_frames = cur * (double) videotestsrc->rate / GST_SECOND;
+          new_n_frames = cur * videotestsrc->rate_numerator /
+              (videotestsrc->rate_denominator * GST_SECOND);
           videotestsrc->segment_start_frame = new_n_frames;
           videotestsrc->segment_end_frame =
-              stop * (double) videotestsrc->rate / GST_SECOND;
+              stop * videotestsrc->rate_numerator /
+              (videotestsrc->rate_denominator * GST_SECOND);
           videotestsrc->segment = flags & GST_SEEK_FLAG_SEGMENT;
           break;
         case GST_FORMAT_DEFAULT:
@@ -442,10 +458,16 @@ gst_videotestsrc_create (GstPushSrc * psrc, GstBuffer ** buffer)
       src->width, src->height);
 
   GST_BUFFER_TIMESTAMP (outbuf) = src->timestamp_offset + src->running_time;
-  GST_BUFFER_DURATION (outbuf) = GST_SECOND / (double) src->rate;
+  if (src->rate_numerator != 0) {
+    GST_BUFFER_DURATION (outbuf) = GST_SECOND * src->rate_denominator /
+        src->rate_numerator;
+  }
 
   src->n_frames++;
-  src->running_time += GST_BUFFER_DURATION (outbuf);
+  if (src->rate_numerator != 0) {
+    src->running_time = src->n_frames * GST_SECOND * src->rate_denominator /
+        src->rate_numerator;
+  }
 
   *buffer = outbuf;
 
index 9718c26..bce97c8 100644 (file)
@@ -58,7 +58,8 @@ struct _GstVideoTestSrc {
   gint height;
   struct fourcc_list_struct *fourcc;
   gint bpp;
-  gdouble rate;
+  gint rate_numerator;
+  gint rate_denominator;
 
   /* private */
   gint64 timestamp_offset;             /* base offset */
index f9679b2..d468f4a 100644 (file)
@@ -64,7 +64,7 @@ GST_STATIC_PAD_TEMPLATE ("sink",
     GST_PAD_SINK,
     GST_PAD_ALWAYS,
     GST_STATIC_CAPS ("video/x-raw-rgb, "
-        "framerate = (double) [ 0.0, MAX ], "
+        "framerate = (fraction) [ 0, MAX ], "
         "width = (int) [ 1, MAX ], " "height = (int) [ 1, MAX ]")
     );
 
@@ -968,7 +968,7 @@ gst_ximagesink_xcontext_get (GstXImageSink * ximagesink)
       "blue_mask", G_TYPE_INT, xcontext->visual->blue_mask,
       "width", GST_TYPE_INT_RANGE, 1, G_MAXINT,
       "height", GST_TYPE_INT_RANGE, 1, G_MAXINT,
-      "framerate", GST_TYPE_DOUBLE_RANGE, 0.0, G_MAXDOUBLE, NULL);
+      "framerate", GST_TYPE_FRACTION_RANGE, 0, 1, G_MAXINT, 1, NULL);
   if (ximagesink->par) {
     int nom, den;
 
@@ -1076,7 +1076,7 @@ gst_ximagesink_setcaps (GstBaseSink * bsink, GstCaps * caps)
   GstCaps *intersection;
   const GValue *par;
   gint new_width, new_height;
-  gdouble fps;
+  const GValue *fps;
 
   ximagesink = GST_XIMAGESINK (bsink);
 
@@ -1101,7 +1101,8 @@ gst_ximagesink_setcaps (GstBaseSink * bsink, GstCaps * caps)
 
   ret &= gst_structure_get_int (structure, "width", &new_width);
   ret &= gst_structure_get_int (structure, "height", &new_height);
-  ret &= gst_structure_get_double (structure, "framerate", &fps);
+  fps = gst_structure_get_value (structure, "framerate");
+  ret &= (fps != NULL);
   if (!ret)
     return FALSE;
 
@@ -1122,7 +1123,8 @@ gst_ximagesink_setcaps (GstBaseSink * bsink, GstCaps * caps)
 
   GST_VIDEO_SINK_WIDTH (ximagesink) = new_width;
   GST_VIDEO_SINK_HEIGHT (ximagesink) = new_height;
-  ximagesink->framerate = fps;
+  ximagesink->fps_n = gst_value_get_fraction_numerator (fps);
+  ximagesink->fps_d = gst_value_get_fraction_denominator (fps);
 
   /* Notify application to set xwindow id now */
   if (!ximagesink->xwindow) {
@@ -1199,7 +1201,8 @@ gst_ximagesink_change_state (GstElement * element, GstStateChange transition)
     case GST_STATE_CHANGE_PAUSED_TO_READY:
       if (ximagesink->xwindow)
         gst_ximagesink_xwindow_clear (ximagesink, ximagesink->xwindow);
-      ximagesink->framerate = 0;
+      ximagesink->fps_n = 0;
+      ximagesink->fps_d = 1;
       GST_VIDEO_SINK_WIDTH (ximagesink) = 0;
       GST_VIDEO_SINK_HEIGHT (ximagesink) = 0;
       break;
@@ -1247,8 +1250,8 @@ gst_ximagesink_get_times (GstBaseSink * bsink, GstBuffer * buf,
     if (GST_BUFFER_DURATION_IS_VALID (buf)) {
       *end = *start + GST_BUFFER_DURATION (buf);
     } else {
-      if (ximagesink->framerate > 0) {
-        *end = *start + GST_SECOND / ximagesink->framerate;
+      if (ximagesink->fps_n > 0) {
+        *end = *start + (GST_SECOND * ximagesink->fps_d) / ximagesink->fps_n;
       }
     }
   }
@@ -1736,7 +1739,8 @@ gst_ximagesink_init (GstXImageSink * ximagesink)
   ximagesink->event_thread = NULL;
   ximagesink->running = FALSE;
 
-  ximagesink->framerate = 0;
+  ximagesink->fps_n = 0;
+  ximagesink->fps_d = 1;
 
   ximagesink->x_lock = g_mutex_new ();
   ximagesink->flow_lock = g_mutex_new ();
index b5c35ad..58a38ac 100644 (file)
@@ -125,7 +125,10 @@ struct _GstXImageSink {
   GThread *event_thread;
   gboolean running;
 
-  gdouble framerate;
+  /* Framerate numerator and denominator */
+  gint fps_n;
+  gint fps_d;
+
   GMutex *x_lock;
   GMutex *flow_lock;
 
index 8fa63a8..102bd11 100644 (file)
@@ -70,11 +70,11 @@ static GstStaticPadTemplate gst_xvimagesink_sink_template_factory =
     GST_PAD_SINK,
     GST_PAD_ALWAYS,
     GST_STATIC_CAPS ("video/x-raw-rgb, "
-        "framerate = (double) [ 0.0, MAX ], "
+        "framerate = (fraction) [ 0, MAX ], "
         "width = (int) [ 1, MAX ], "
         "height = (int) [ 1, MAX ]; "
         "video/x-raw-yuv, "
-        "framerate = (double) [ 0.0, MAX ], "
+        "framerate = (fraction) [ 0, MAX ], "
         "width = (int) [ 1, MAX ], " "height = (int) [ 1, MAX ]")
     );
 
@@ -998,7 +998,7 @@ gst_xvimagesink_get_xv_support (GstXvImageSink * xvimagesink,
             "red_mask", G_TYPE_INT, formats[i].blue_mask,
             "width", GST_TYPE_INT_RANGE, 1, G_MAXINT,
             "height", GST_TYPE_INT_RANGE, 1, G_MAXINT,
-            "framerate", GST_TYPE_DOUBLE_RANGE, 0.0, G_MAXDOUBLE, NULL);
+            "framerate", GST_TYPE_FRACTION_RANGE, 0, 1, G_MAXINT, 1, NULL);
         break;
       }
       case XvYUV:
@@ -1006,7 +1006,7 @@ gst_xvimagesink_get_xv_support (GstXvImageSink * xvimagesink,
             "format", GST_TYPE_FOURCC, formats[i].id,
             "width", GST_TYPE_INT_RANGE, 1, G_MAXINT,
             "height", GST_TYPE_INT_RANGE, 1, G_MAXINT,
-            "framerate", GST_TYPE_DOUBLE_RANGE, 0.0, G_MAXDOUBLE, NULL);
+            "framerate", GST_TYPE_FRACTION_RANGE, 0, 1, G_MAXINT, 1, NULL);
         break;
       default:
         g_assert_not_reached ();
@@ -1415,6 +1415,7 @@ gst_xvimagesink_setcaps (GstBaseSink * bsink, GstCaps * caps)
   gint display_par_n, display_par_d;    /* display's PAR */
   GValue display_ratio = { 0, };        /* display w/h ratio */
   const GValue *caps_par;
+  const GValue *fps;
   gint num, den;
 
   xvimagesink = GST_XVIMAGESINK (bsink);
@@ -1435,11 +1436,15 @@ gst_xvimagesink_setcaps (GstBaseSink * bsink, GstCaps * caps)
   structure = gst_caps_get_structure (caps, 0);
   ret = gst_structure_get_int (structure, "width", &video_width);
   ret &= gst_structure_get_int (structure, "height", &video_height);
-  ret &= gst_structure_get_double (structure, "framerate",
-      &xvimagesink->framerate);
+  fps = gst_structure_get_value (structure, "framerate");
+  ret &= (fps != NULL);
+
   if (!ret)
     return FALSE;
 
+  xvimagesink->fps_n = gst_value_get_fraction_numerator (fps);
+  xvimagesink->fps_d = gst_value_get_fraction_denominator (fps);
+
   xvimagesink->video_width = video_width;
   xvimagesink->video_height = video_height;
   im_format = gst_xvimagesink_get_format_from_caps (xvimagesink, caps);
@@ -1581,7 +1586,8 @@ gst_xvimagesink_change_state (GstElement * element, GstStateChange transition)
     case GST_STATE_CHANGE_PLAYING_TO_PAUSED:
       break;
     case GST_STATE_CHANGE_PAUSED_TO_READY:
-      xvimagesink->framerate = 0;
+      xvimagesink->fps_n = 0;
+      xvimagesink->fps_d = 1;
       GST_VIDEO_SINK_WIDTH (xvimagesink) = 0;
       GST_VIDEO_SINK_HEIGHT (xvimagesink) = 0;
       break;
@@ -1625,8 +1631,8 @@ gst_xvimagesink_get_times (GstBaseSink * bsink, GstBuffer * buf,
     if (GST_BUFFER_DURATION_IS_VALID (buf)) {
       *end = *start + GST_BUFFER_DURATION (buf);
     } else {
-      if (xvimagesink->framerate > 0) {
-        *end = *start + GST_SECOND / xvimagesink->framerate;
+      if (xvimagesink->fps_n > 0) {
+        *end = *start + (GST_SECOND * xvimagesink->fps_d) / xvimagesink->fps_n;
       }
     }
   }
@@ -2147,7 +2153,8 @@ gst_xvimagesink_init (GstXvImageSink * xvimagesink)
   xvimagesink->contrast = xvimagesink->brightness = 0;
   xvimagesink->cb_changed = FALSE;
 
-  xvimagesink->framerate = 0;
+  xvimagesink->fps_n = 0;
+  xvimagesink->fps_d = 0;
   xvimagesink->video_width = 0;
   xvimagesink->video_height = 0;
 
index 41062f2..38ecdaa 100644 (file)
@@ -136,7 +136,8 @@ struct _GstXvImageSink {
   GstXvImageBuffer *xvimage;
   GstXvImageBuffer *cur_image;
 
-  gdouble framerate;
+  gint fps_n;
+  gint fps_d;
 
   gint brightness;
   gint contrast;