From 0e82871285a50bf546192d24daeb0d088f3f40d1 Mon Sep 17 00:00:00 2001 From: Jan Schmidt Date: Tue, 22 Nov 2005 16:08:37 +0000 Subject: [PATCH] Convert elements to use fractions for their framerate. 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. --- ChangeLog | 35 +++++++++++++++ ext/libvisual/visual.c | 27 ++++++++---- ext/ogg/gstogmparse.c | 3 +- ext/theora/theoradec.c | 6 +-- ext/theora/theoraenc.c | 20 ++++----- gst-libs/gst/riff/riff-media.c | 7 ++- gst-libs/gst/video/video.c | 26 +++++++---- gst-libs/gst/video/video.h | 4 +- gst/ffmpegcolorspace/avcodec.h | 2 - gst/ffmpegcolorspace/gstffmpegcodecmap.c | 23 +++++----- gst/ffmpegcolorspace/gstffmpegcolorspace.c | 24 +++++++++-- gst/videorate/gstvideorate.c | 50 ++++++++++++++-------- gst/videotestsrc/gstvideotestsrc.c | 50 ++++++++++++++++------ gst/videotestsrc/gstvideotestsrc.h | 3 +- sys/ximage/ximagesink.c | 22 ++++++---- sys/ximage/ximagesink.h | 5 ++- sys/xvimage/xvimagesink.c | 27 +++++++----- sys/xvimage/xvimagesink.h | 3 +- 18 files changed, 230 insertions(+), 107 deletions(-) diff --git a/ChangeLog b/ChangeLog index 87f9362fa9..0b173a14c1 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,38 @@ +2005-11-22 Jan Schmidt + + * 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 * gst-libs/gst/audio/audio.c: diff --git a/ext/libvisual/visual.c b/ext/libvisual/visual.c index 44ea87e1cd..cee88d8ee0 100644 --- a/ext/libvisual/visual.c +++ b/ext/libvisual/visual.c @@ -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, diff --git a/ext/ogg/gstogmparse.c b/ext/ogg/gstogmparse.c index 0c4d322247..2c7d9899f9 100644 --- a/ext/ogg/gstogmparse.c +++ b/ext/ogg/gstogmparse.c @@ -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': diff --git a/ext/theora/theoradec.c b/ext/theora/theoradec.c index a7c157f399..f6e55ed1fd 100644 --- a/ext/theora/theoradec.c +++ b/ext/theora/theoradec.c @@ -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); diff --git a/ext/theora/theoraenc.c b/ext/theora/theoraenc.c index ee40edfbad..b60e10ce65 100644 --- a/ext/theora/theoraenc.c +++ b/ext/theora/theoraenc.c @@ -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) { diff --git a/gst-libs/gst/riff/riff-media.c b/gst-libs/gst/riff/riff-media.c index 7bf8c4f649..cae90069ec 100644 --- a/gst-libs/gst/riff/riff-media.c +++ b/gst-libs/gst/riff/riff-media.c @@ -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) { diff --git a/gst-libs/gst/video/video.c b/gst-libs/gst/video/video.c index 67214b8bc4..3dad3d00a0 100644 --- a/gst-libs/gst/video/video.c +++ b/gst-libs/gst/video/video.c @@ -25,11 +25,12 @@ #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; } diff --git a/gst-libs/gst/video/video.h b/gst-libs/gst/video/video.h index 60efe3ec08..6c3cd8419d 100644 --- a/gst-libs/gst/video/video.h +++ b/gst-libs/gst/video/video.h @@ -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); diff --git a/gst/ffmpegcolorspace/avcodec.h b/gst/ffmpegcolorspace/avcodec.h index 3bf14c703e..e25f8e52cb 100644 --- a/gst/ffmpegcolorspace/avcodec.h +++ b/gst/ffmpegcolorspace/avcodec.h @@ -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 */ diff --git a/gst/ffmpegcolorspace/gstffmpegcodecmap.c b/gst/ffmpegcolorspace/gstffmpegcodecmap.c index 1c114eb39c..f87159e115 100644 --- a/gst/ffmpegcolorspace/gstffmpegcodecmap.c +++ b/gst/ffmpegcolorspace/gstffmpegcodecmap.c @@ -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; diff --git a/gst/ffmpegcolorspace/gstffmpegcolorspace.c b/gst/ffmpegcolorspace/gstffmpegcolorspace.c index ca6ff13915..3cf3cb8bdf 100644 --- a/gst/ffmpegcolorspace/gstffmpegcolorspace.c +++ b/gst/ffmpegcolorspace/gstffmpegcolorspace.c @@ -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"); diff --git a/gst/videorate/gstvideorate.c b/gst/videorate/gstvideorate.c index c115304b09..0ca1fe131d 100644 --- a/gst/videorate/gstvideorate.c +++ b/gst/videorate/gstvideorate.c @@ -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); - gst_structure_get_double (structure, "framerate", &fps); + rate = gst_structure_get_value (structure, "framerate"); + + 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 */ diff --git a/gst/videotestsrc/gstvideotestsrc.c b/gst/videotestsrc/gstvideotestsrc.c index e947e25323..25318d953c 100644 --- a/gst/videotestsrc/gstvideotestsrc.c +++ b/gst/videotestsrc/gstvideotestsrc.c @@ -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; diff --git a/gst/videotestsrc/gstvideotestsrc.h b/gst/videotestsrc/gstvideotestsrc.h index 9718c26299..bce97c864e 100644 --- a/gst/videotestsrc/gstvideotestsrc.h +++ b/gst/videotestsrc/gstvideotestsrc.h @@ -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 */ diff --git a/sys/ximage/ximagesink.c b/sys/ximage/ximagesink.c index f9679b2dd1..d468f4a1ec 100644 --- a/sys/ximage/ximagesink.c +++ b/sys/ximage/ximagesink.c @@ -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 (); diff --git a/sys/ximage/ximagesink.h b/sys/ximage/ximagesink.h index b5c35adc28..58a38ac16d 100644 --- a/sys/ximage/ximagesink.h +++ b/sys/ximage/ximagesink.h @@ -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; diff --git a/sys/xvimage/xvimagesink.c b/sys/xvimage/xvimagesink.c index 8fa63a802f..102bd112bd 100644 --- a/sys/xvimage/xvimagesink.c +++ b/sys/xvimage/xvimagesink.c @@ -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; diff --git a/sys/xvimage/xvimagesink.h b/sys/xvimage/xvimagesink.h index 41062f20e7..38ecdaa403 100644 --- a/sys/xvimage/xvimagesink.h +++ b/sys/xvimage/xvimagesink.h @@ -136,7 +136,8 @@ struct _GstXvImageSink { GstXvImageBuffer *xvimage; GstXvImageBuffer *cur_image; - gdouble framerate; + gint fps_n; + gint fps_d; gint brightness; gint contrast;