2004-07-27 Thomas Vander Stichele <thomas at apestaart dot org>
+ * gst/matroska/matroska-demux.c:
+ (gst_matroska_demux_parse_metadata),
+ (gst_matroska_demux_video_caps), (gst_matroska_demux_plugin_init):
+ * gst/mpegaudio/common.c:
+ * gst/videoscale/gstvideoscale.c: (gst_videoscale_class_init),
+ (gst_videoscale_getcaps), (gst_videoscale_link),
+ (gst_videoscale_src_fixate), (gst_videoscale_init),
+ (gst_videoscale_finalize):
+ * gst/videoscale/gstvideoscale.h:
+ * gst/videotestsrc/gstvideotestsrc.c:
+ (gst_videotestsrc_get_capslist):
+ * gst/wavenc/gstwavenc.c:
+ * sys/oss/gstossmixer.c: (fill_labels):
+ * sys/ximage/ximagesink.c: (gst_ximagesink_renegotiate_size),
+ (gst_ximagesink_handle_xevents),
+ (gst_ximagesink_calculate_pixel_aspect_ratio),
+ (gst_ximagesink_xcontext_get), (gst_ximagesink_fixate),
+ (gst_ximagesink_getcaps), (gst_ximagesink_sink_link),
+ (gst_ximagesink_chain), (gst_ximagesink_set_xwindow_id),
+ (gst_ximagesink_set_property), (gst_ximagesink_get_property),
+ (gst_ximagesink_init), (gst_ximagesink_class_init):
+ * sys/ximage/ximagesink.h:
+ * sys/xvimage/xvimagesink.c:
+ (gst_xvimagesink_calculate_pixel_aspect_ratio),
+ (gst_xvimagesink_xcontext_get), (gst_xvimagesink_sink_link),
+ (gst_xvimagesink_chain), (gst_xvimagesink_buffer_alloc),
+ (gst_xvimagesink_set_property), (gst_xvimagesink_get_property),
+ (gst_xvimagesink_init), (gst_xvimagesink_class_init):
+ * sys/xvimage/xvimagesink.h:
+ first batch of pixel aspect ratio commits.
+
+2004-07-27 Thomas Vander Stichele <thomas at apestaart dot org>
+
* gst/ffmpegcolorspace/gstffmpegcolorspace.c:
(gst_ffmpegcolorspace_class_init), (gst_ffmpegcolorspace_chain):
* gst/ffmpegcolorspace/imgconvert.c: (avpicture_fill):
gst_element_found_tags_for_pad (GST_ELEMENT (dec), dec->srcpad, 0, list);
} else if (packet.packetno == 2) {
GstCaps *caps;
+ gint par_num, par_den;
+
+ GST_DEBUG_OBJECT (dec, "fps %d/%d, PAR %d/%d",
+ dec->info.fps_numerator, dec->info.fps_denominator,
+ dec->info.aspect_numerator, dec->info.aspect_denominator);
+
+ /* calculate par
+ * the info.aspect_* values reflect PAR;
+ * 0:0 is allowed and can be interpreted as 1:1, so correct for it */
+ par_num = dec->info.aspect_numerator;
+ par_den = dec->info.aspect_denominator;
+ if (par_num == 0 && par_den == 0) {
+ par_num = par_den = 1;
+ }
+ GST_DEBUG_OBJECT (dec, "video %dx%d, PAR %d/%d", dec->info.width,
+ dec->info.height, par_num, par_den);
/* done */
theora_decode_init (&dec->state, &dec->info);
"format", GST_TYPE_FOURCC, GST_MAKE_FOURCC ('I', '4', '2', '0'),
"framerate", G_TYPE_DOUBLE,
((gdouble) dec->info.fps_numerator) / dec->info.fps_denominator,
+ "pixel-aspect-ratio", GST_TYPE_FRACTION, par_num, par_den,
"width", G_TYPE_INT, dec->info.width, "height", G_TYPE_INT,
dec->info.height, NULL);
gst_pad_set_explicit_caps (dec->srcpad, caps);
{
GstStructure *structure = gst_caps_get_structure (caps, 0);
GstTheoraEnc *enc = GST_THEORA_ENC (gst_pad_get_parent (pad));
+ const GValue *par;
if (!gst_caps_is_fixed (caps))
return GST_PAD_LINK_DELAYED;
gst_structure_get_int (structure, "width", &enc->width);
gst_structure_get_int (structure, "height", &enc->height);
gst_structure_get_double (structure, "framerate", &enc->fps);
+ par = gst_structure_get_value (structure, "pixel-aspect-ratio");
/* Theora has a divisible-by-sixteen restriction for the encoded video size */
if ((enc->width & 0x0f) != 0 || (enc->height & 0x0f) != 0)
/* do some scaling, we really need fractions in structures... */
enc->info.fps_numerator = enc->fps * 10000000;
enc->info.fps_denominator = 10000000;
- enc->info.aspect_numerator = 1;
- enc->info.aspect_denominator = 1;
- /* */
+ if (par) {
+ enc->info.aspect_numerator = gst_value_get_fraction_numerator (par);
+ enc->info.aspect_denominator = gst_value_get_fraction_denominator (par);
+ } else {
+ /* setting them to 0 indicates that the decoder can chose a good aspect
+ * ratio, defaulting to 1/1 */
+ enc->info.aspect_numerator = 0;
+ enc->info.aspect_denominator = 0;
+ }
enc->info.colorspace = OC_CS_UNSPECIFIED;
enc->info.target_bitrate = enc->video_bitrate;
enum PixelFormat pix_fmt;
int height, width;
double framerate;
+ const GValue *par = NULL;
space = GST_FFMPEGCOLORSPACE (gst_pad_get_parent (pad));
+ GST_DEBUG_OBJECT (space, "pad_link on %s:%s with caps %" GST_PTR_FORMAT,
+ GST_DEBUG_PAD_NAME (pad), caps);
structure = gst_caps_get_structure (caps, 0);
-
gst_structure_get_int (structure, "width", &width);
gst_structure_get_int (structure, "height", &height);
gst_structure_get_double (structure, "framerate", &framerate);
+ par = gst_structure_get_value (structure, "pixel-aspect-ratio");
+ if (par) {
+ GST_DEBUG_OBJECT (space, "setting PAR %d/%d",
+ gst_value_get_fraction_numerator (par),
+ gst_value_get_fraction_denominator (par));
+ }
otherpad = (pad == space->srcpad) ? space->sinkpad : space->srcpad;
- GST_DEBUG_OBJECT (space, "pad_link on %s:%s with caps %" GST_PTR_FORMAT,
- GST_DEBUG_PAD_NAME (pad), caps);
-
/* FIXME attempt and/or check for passthru */
/* loop over all possibilities and select the first one we can convert and
return GST_PAD_LINK_REFUSED;
}
-
/* set the size on the otherpad */
othercaps = gst_pad_get_negotiated_caps (otherpad);
if (othercaps) {
"width", G_TYPE_INT, width,
"height", G_TYPE_INT, height,
"framerate", G_TYPE_DOUBLE, framerate, NULL);
+ if (par) {
+ GST_DEBUG_OBJECT (space, "setting PAR %d/%d",
+ gst_value_get_fraction_numerator (par),
+ gst_value_get_fraction_denominator (par));
+ gst_caps_set_simple (newothercaps,
+ "pixel-aspect-ratio", GST_TYPE_FRACTION,
+ gst_value_get_fraction_numerator (par),
+ gst_value_get_fraction_denominator (par), NULL);
+ }
ret = gst_pad_try_set_caps (otherpad, newothercaps);
if (GST_PAD_LINK_FAILED (ret)) {
return ret;
const GValue * value, GParamSpec * pspec);
static void gst_videoscale_get_property (GObject * object, guint prop_id,
GValue * value, GParamSpec * pspec);
+static void gst_videoscale_finalize (GObject * object);
static void gst_videoscale_chain (GstPad * pad, GstData * _data);
static GstCaps *gst_videoscale_get_capslist (void);
parent_class = g_type_class_ref (GST_TYPE_ELEMENT);
+ gobject_class->finalize = gst_videoscale_finalize;
gobject_class->set_property = gst_videoscale_set_property;
gobject_class->get_property = gst_videoscale_get_property;
GstPad *otherpad;
int i;
- GST_DEBUG ("gst_videoscale_getcaps");
videoscale = GST_VIDEOSCALE (gst_pad_get_parent (pad));
otherpad = (pad == videoscale->srcpad) ? videoscale->sinkpad :
videoscale->srcpad;
othercaps = gst_pad_get_allowed_caps (otherpad);
- GST_DEBUG ("othercaps are: %" GST_PTR_FORMAT, othercaps);
+ GST_DEBUG_OBJECT (pad, "othercaps of otherpad %s:%s are: %" GST_PTR_FORMAT,
+ GST_DEBUG_PAD_NAME (otherpad), othercaps);
caps = gst_caps_copy (othercaps);
for (i = 0; i < gst_caps_get_size (caps); i++) {
gst_structure_set (structure,
"width", GST_TYPE_INT_RANGE, 16, G_MAXINT,
"height", GST_TYPE_INT_RANGE, 16, G_MAXINT, NULL);
+ gst_structure_remove_field (structure, "pixel-aspect-ratio");
}
- GST_DEBUG ("returning caps: %" GST_PTR_FORMAT, caps);
-
+ GST_DEBUG_OBJECT (pad, "returning caps: %" GST_PTR_FORMAT, caps);
return caps;
}
GstVideoscale *videoscale;
GstPadLinkReturn ret;
GstPad *otherpad;
+ GstCaps *othercaps;
+ GstStructure *otherstructure;
GstStructure *structure;
struct videoscale_format_struct *format;
- int height, width;
+ int height = 0, width = 0;
+ const GValue *par = NULL;
+ const GValue *otherpar;
GST_DEBUG_OBJECT (pad, "_link with caps %" GST_PTR_FORMAT, caps);
videoscale = GST_VIDEOSCALE (gst_pad_get_parent (pad));
structure = gst_caps_get_structure (caps, 0);
ret = gst_structure_get_int (structure, "width", &width);
ret &= gst_structure_get_int (structure, "height", &height);
+ par = gst_structure_get_value (structure, "pixel-aspect-ratio");
format = videoscale_find_by_structure (structure);
if (!ret || format == NULL)
return GST_PAD_LINK_REFUSED;
+ GST_DEBUG_OBJECT (videoscale,
+ "trying to set caps %" GST_PTR_FORMAT " on pad %s:%s for passthru",
+ caps, GST_DEBUG_PAD_NAME (otherpad));
+
ret = gst_pad_try_set_caps (otherpad, caps);
if (ret == GST_PAD_LINK_OK) {
/* cool, we can use passthru */
+ GST_DEBUG_OBJECT (videoscale, "passthru works");
videoscale->format = format;
videoscale->to_width = width;
videoscale->from_width = width;
videoscale->from_height = height;
- gst_videoscale_setup (videoscale);
-
- return GST_PAD_LINK_OK;
+ goto beach;
}
+ /* no passthru, so try to convert */
+ GST_DEBUG_OBJECT (videoscale, "no passthru");
+
if (gst_pad_is_negotiated (otherpad)) {
GstCaps *newcaps = gst_caps_copy (caps);
+ GST_DEBUG_OBJECT (videoscale, "otherpad %s:%s is negotiated",
+ GST_DEBUG_PAD_NAME (otherpad));
+
if (pad == videoscale->srcpad) {
gst_caps_set_simple (newcaps,
"width", G_TYPE_INT, videoscale->from_width,
"height", G_TYPE_INT, videoscale->from_height, NULL);
+ GST_DEBUG_OBJECT (videoscale, "from par %d/%d",
+ gst_value_get_fraction_numerator (videoscale->from_par),
+ gst_value_get_fraction_denominator (videoscale->from_par));
+ if (videoscale->from_par) {
+ gst_structure_set (gst_caps_get_structure (newcaps, 0),
+ "pixel-aspect-ratio", GST_TYPE_FRACTION,
+ gst_value_get_fraction_numerator (videoscale->from_par),
+ gst_value_get_fraction_denominator (videoscale->from_par), NULL);
+ }
} else {
+ GST_DEBUG_OBJECT (videoscale, "negotiating, checking PAR's");
+ /* sink pad is being negotiated, so if there is a PAR,
+ * convert w/h/PAR to new src
+ * values and try to set them */
+ if (par && videoscale->to_par) {
+ GValue to_ratio = { 0, };
+ gint from_par_n, from_par_d;
+ gint to_par_n, to_par_d;
+ gint num, den;
+
+ GST_DEBUG_OBJECT (videoscale, "both pads have PAR, calculating");
+ from_par_n = gst_value_get_fraction_numerator (par);
+ from_par_d = gst_value_get_fraction_denominator (par);
+ to_par_n = gst_value_get_fraction_numerator (videoscale->to_par);
+ to_par_d = gst_value_get_fraction_denominator (videoscale->to_par);
+ g_value_init (&to_ratio, GST_TYPE_FRACTION);
+ gst_value_set_fraction (&to_ratio,
+ width * from_par_n * to_par_d, height * from_par_d * to_par_n);
+ num = gst_value_get_fraction_numerator (&to_ratio);
+ den = gst_value_get_fraction_denominator (&to_ratio);
+ GST_DEBUG_OBJECT (videoscale, "need to scale to a ratio of %d/%d",
+ num, den);
+ if (height % den == 0) {
+ GST_DEBUG_OBJECT (videoscale, "keeping height %d constant", height);
+ videoscale->to_width = height * num / den;
+ videoscale->to_height = height;
+ } else if (width % num == 0) {
+ GST_DEBUG_OBJECT (videoscale, "keeping width %d constant", height);
+ videoscale->to_width = width;
+ videoscale->to_height = width * den / num;
+ } else {
+ /* approximate keeping height constant */
+ GST_DEBUG_OBJECT (videoscale,
+ "approximating while keeping height %d constant", height);
+ videoscale->to_width = height * num / den;
+ videoscale->to_height = height;
+ }
+ }
+
+ GST_DEBUG_OBJECT (videoscale, "scaling to %dx%d", videoscale->to_width,
+ videoscale->to_height);
gst_caps_set_simple (newcaps,
"width", G_TYPE_INT, videoscale->to_width,
"height", G_TYPE_INT, videoscale->to_height, NULL);
+ if (videoscale->to_par) {
+ GST_DEBUG_OBJECT (videoscale, "to par %d/%d",
+ gst_value_get_fraction_numerator (videoscale->to_par),
+ gst_value_get_fraction_denominator (videoscale->to_par));
+ gst_structure_set (gst_caps_get_structure (newcaps, 0),
+ "pixel-aspect-ratio", GST_TYPE_FRACTION,
+ gst_value_get_fraction_numerator (videoscale->to_par),
+ gst_value_get_fraction_denominator (videoscale->to_par), NULL);
+ }
}
+ GST_DEBUG_OBJECT (videoscale, "trying to set caps %" GST_PTR_FORMAT
+ " on pad %s:%s", newcaps, GST_DEBUG_PAD_NAME (otherpad));
ret = gst_pad_try_set_caps (otherpad, newcaps);
if (GST_PAD_LINK_FAILED (ret)) {
return GST_PAD_LINK_REFUSED;
}
videoscale->passthru = FALSE;
+ GST_DEBUG_OBJECT (videoscale,
+ "no passthru, otherpad %s:%s is not negotiated",
+ GST_DEBUG_PAD_NAME (otherpad));
+
+beach:
+ /* since we're accepting these caps on this pad, we can store the
+ * values we're using in conversion, like from/to w,h,PAR */
+ othercaps = gst_pad_get_caps (otherpad);
+ otherstructure = gst_caps_get_structure (othercaps, 0);
+ structure = gst_caps_get_structure (caps, 0);
+ par = gst_structure_get_value (structure, "pixel-aspect-ratio");
+ otherpar = gst_structure_get_value (otherstructure, "pixel-aspect-ratio");
+ GST_DEBUG ("othercaps: %" GST_PTR_FORMAT, othercaps);
+ if (par && otherpar) {
+ GST_DEBUG_OBJECT (videoscale, "par %d/%d, otherpar %d/%d",
+ gst_value_get_fraction_numerator (par),
+ gst_value_get_fraction_denominator (par),
+ gst_value_get_fraction_numerator (otherpar),
+ gst_value_get_fraction_denominator (otherpar));
+ }
if (pad == videoscale->srcpad) {
videoscale->to_width = width;
videoscale->to_height = height;
+ if (par) {
+ g_free (videoscale->to_par);
+ videoscale->to_par = g_new0 (GValue, 1);
+ gst_value_init_and_copy (videoscale->to_par, par);
+ }
} else {
videoscale->from_width = width;
videoscale->from_height = height;
+ if (par) {
+ g_free (videoscale->from_par);
+ videoscale->from_par = g_new0 (GValue, 1);
+ gst_value_init_and_copy (videoscale->from_par, par);
+ }
}
videoscale->format = format;
if (gst_pad_is_negotiated (otherpad)) {
gst_videoscale_setup (videoscale);
}
-
return GST_PAD_LINK_OK;
}
+static GstCaps *
+gst_videoscale_src_fixate (GstPad * pad, const GstCaps * caps)
+{
+ GstVideoscale *videoscale;
+ GstCaps *newcaps;
+ int i;
+ gboolean ret = TRUE;
+
+ videoscale = GST_VIDEOSCALE (gst_pad_get_parent (pad));
+
+ GST_DEBUG_OBJECT (pad, "asked to fixate caps %" GST_PTR_FORMAT, caps);
+
+ /* don't mess with fixation if we don't have a sink pad PAR */
+ if (!videoscale->from_par) {
+ GST_DEBUG_OBJECT (videoscale, "no PAR to scale from, not fixating");
+ return NULL;
+ }
+
+ /* for each structure, if it contains a pixel aspect ratio,
+ * fix width and height */
+
+ newcaps = gst_caps_copy (caps);
+ for (i = 0; i < gst_caps_get_size (newcaps); i++) {
+ const GValue *to_par;
+
+ GstStructure *structure = gst_caps_get_structure (newcaps, i);
+
+ to_par = gst_structure_get_value (structure, "pixel-aspect-ratio");
+ if (to_par) {
+ GValue to_ratio = { 0, }; /* w/h of output video */
+ int from_w, from_h, from_par_n, from_par_d, to_par_n, to_par_d;
+ int count = 0;
+
+ int w = 0, h = 0;
+ int num, den;
+
+ /* if both width and height are already fixed, we can't do anything
+ * about it anymore */
+ if (gst_structure_get_int (structure, "width", &w))
+ ++count;
+ if (gst_structure_get_int (structure, "height", &h))
+ ++count;
+ if (count == 2) {
+ GST_DEBUG_OBJECT (videoscale,
+ "dimensions already set to %dx%d, not fixating", w, h);
+ return NULL;
+ }
+
+ from_w = videoscale->from_width;
+ from_h = videoscale->from_height;
+ from_par_n = gst_value_get_fraction_numerator (videoscale->from_par);
+ from_par_d = gst_value_get_fraction_denominator (videoscale->from_par);
+ to_par_n = gst_value_get_fraction_numerator (to_par);
+ to_par_d = gst_value_get_fraction_denominator (to_par);
+
+ g_value_init (&to_ratio, GST_TYPE_FRACTION);
+ gst_value_set_fraction (&to_ratio, from_w * from_par_n * to_par_d,
+ from_h * from_par_d * to_par_n);
+ num = gst_value_get_fraction_numerator (&to_ratio);
+ den = gst_value_get_fraction_denominator (&to_ratio);
+ GST_DEBUG_OBJECT (videoscale,
+ "scaling input with %dx%d and PAR %d/%d to output PAR %d/%d",
+ from_w, from_h, from_par_n, from_par_d, to_par_n, to_par_d);
+ GST_DEBUG_OBJECT (videoscale,
+ "resulting output should respect ratio of %d/%d", num, den);
+
+ /* now find a width x height that respects this display ratio.
+ * prefer those that have one of w/h the same as the incoming video
+ * using wd / hd = num / den */
+
+ /* start with same height, because of interlaced video */
+ /* check hd / den is an integer scale factor, and scale wd with the PAR */
+ if (from_h % den == 0) {
+ GST_DEBUG_OBJECT (videoscale, "keeping video height");
+ h = from_h;
+ w = h * num / den;
+ } else if (from_w % num == 0) {
+ GST_DEBUG_OBJECT (videoscale, "keeping video width");
+ w = from_w;
+ h = w * den / num;
+ } else {
+ GST_DEBUG_OBJECT (videoscale, "approximating but keeping video height");
+ h = from_h;
+ w = h * num / den;
+ }
+ GST_DEBUG_OBJECT (videoscale, "scaling to %dx%d", w, h);
+
+ /* now fixate */
+ ret &=
+ gst_caps_structure_fixate_field_nearest_int (structure, "width", w);
+ ret &=
+ gst_caps_structure_fixate_field_nearest_int (structure, "height", h);
+ }
+ }
+
+ if (ret)
+ return newcaps;
+
+ gst_caps_free (newcaps);
+ return NULL;
+}
+
static void
gst_videoscale_init (GstVideoscale * videoscale)
{
gst_videoscale_handle_src_event);
gst_pad_set_link_function (videoscale->srcpad, gst_videoscale_link);
gst_pad_set_getcaps_function (videoscale->srcpad, gst_videoscale_getcaps);
+ gst_pad_set_fixate_function (videoscale->srcpad, gst_videoscale_src_fixate);
videoscale->inited = FALSE;
}
}
+/* maybe these free's should go in a state change instead;
+ * in that case, we'd probably also want to clear from/to width/height there. */
+static void
+gst_videoscale_finalize (GObject * object)
+{
+ GstVideoscale *videoscale;
+
+ videoscale = GST_VIDEOSCALE (object);
+
+ g_free (videoscale->from_par);
+ g_free (videoscale->to_par);
+
+ G_OBJECT_CLASS (parent_class)->finalize (object);
+}
static gboolean
plugin_init (GstPlugin * plugin)
gint to_height;
gint from_width;
gint from_height;
+ GValue *to_par; /* pixel aspect ratio of sink pad */
+ GValue *from_par; /* pixel aspect ratio of src pad */
gboolean passthru;
float framerate;
gst_structure_set (structure,
"width", GST_TYPE_INT_RANGE, 1, G_MAXINT,
"height", GST_TYPE_INT_RANGE, 1, G_MAXINT,
+ "pixel-aspect-ratio", GST_TYPE_FRACTION, 1, 1,
"framerate", GST_TYPE_DOUBLE_RANGE, 0.0, G_MAXDOUBLE, NULL);
gst_caps_append_structure (caps, structure);
}
{
ARG_0,
ARG_DISPLAY,
- ARG_SYNCHRONOUS
+ ARG_SYNCHRONOUS,
+ ARG_PIXEL_ASPECT_RATIO
/* FILL ME */
};
"blue_mask", G_TYPE_INT, ximagesink->xcontext->visual->blue_mask,
"width", G_TYPE_INT, ximagesink->xwindow->width,
"height", G_TYPE_INT, ximagesink->xwindow->height,
+ /* for now we use the object-set value for par */
+ "pixel-aspect-ratio", GST_TYPE_FRACTION,
+ gst_value_get_fraction_numerator (&ximagesink->par),
+ gst_value_get_fraction_denominator (&ximagesink->par),
"framerate", G_TYPE_DOUBLE, ximagesink->framerate, NULL));
if ((r == GST_PAD_LINK_OK) || (r == GST_PAD_LINK_DONE)) {
default:
GST_DEBUG ("ximagesink unhandled X event (%d)", e.type);
}
-
g_mutex_lock (ximagesink->x_lock);
}
g_mutex_unlock (ximagesink->x_lock);
}
+/* This function calculates the pixel aspect ratio based on the properties
+ * in the xcontext structure and stores it there. */
+static void
+gst_ximagesink_calculate_pixel_aspect_ratio (GstXContext * xcontext)
+{
+ gint par[][2] = {
+ {1, 1}, /* regular screen */
+ {16, 15}, /* PAL TV */
+ {11, 10}, /* 525 line Rec.601 video */
+ {54, 59} /* 625 line Rec.601 video */
+ };
+ gint i;
+ gint index;
+ gdouble ratio;
+ gdouble delta;
+
+#define DELTA(idx) (ABS (ratio - ((gdouble) par[idx][0] / par[idx][1])))
+
+ /* first calculate the "real" ratio based on the X values;
+ * which is the "physical" w/h divided by the w/h in pixels of the display */
+ ratio = xcontext->widthmm * xcontext->height
+ / (xcontext->heightmm * xcontext->width);
+ GST_DEBUG ("calculated pixel aspect ratio: %f", ratio);
+
+ /* now find the one from par[][2] with the lowest delta to the real one */
+ delta = DELTA (0);
+ index = 0;
+
+ for (i = 1; i < sizeof (par) / (sizeof (gint) * 2); ++i) {
+ gdouble this_delta = DELTA (i);
+
+ if (this_delta < delta) {
+ index = i;
+ delta = this_delta;
+ }
+ }
+
+ GST_DEBUG ("Decided on index %d (%d/%d)", index,
+ par[index][0], par[index][1]);
+
+ g_value_init (&xcontext->par, GST_TYPE_FRACTION);
+ gst_value_set_fraction (&xcontext->par, par[index][0], par[index][1]);
+}
+
/* This function gets the X Display and global info about it. Everything is
stored in our object and will be cleaned when the object is disposed. Note
here that caps for supported format are generated without any window or
xcontext->black = XBlackPixel (xcontext->disp, xcontext->screen_num);
xcontext->depth = DefaultDepthOfScreen (xcontext->screen);
+ xcontext->width = DisplayWidth (xcontext->disp, xcontext->screen_num);
+ xcontext->height = DisplayHeight (xcontext->disp, xcontext->screen_num);
+ xcontext->widthmm = DisplayWidthMM (xcontext->disp, xcontext->screen_num);
+ xcontext->heightmm = DisplayHeightMM (xcontext->disp, xcontext->screen_num);
+
+ gst_ximagesink_calculate_pixel_aspect_ratio (xcontext);
+
/* We get supported pixmap formats at supported depth */
px_formats = XListPixmapFormats (xcontext->disp, &nb_formats);
"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,
+ /* for now we use the object-set value for par */
+ "pixel-aspect-ratio", GST_TYPE_FRACTION,
+ gst_value_get_fraction_numerator (&ximagesink->par),
+ gst_value_get_fraction_denominator (&ximagesink->par),
"framerate", GST_TYPE_DOUBLE_RANGE, 0.0, G_MAXDOUBLE, NULL);
g_mutex_unlock (ximagesink->x_lock);
newcaps = gst_caps_copy (caps);
structure = gst_caps_get_structure (newcaps, 0);
+ /* if par is set and either w or h is set, we can set the other */
+
if (gst_caps_structure_fixate_field_nearest_int (structure, "width", 320)) {
return newcaps;
}
gst_ximagesink_getcaps (GstPad * pad)
{
GstXImageSink *ximagesink;
+ GstCaps *caps;
+ int i;
ximagesink = GST_XIMAGESINK (gst_pad_get_parent (pad));
if (ximagesink->xcontext)
return gst_caps_copy (ximagesink->xcontext->caps);
- return gst_caps_copy (gst_pad_get_pad_template_caps (pad));
+ /* get a template copy and add the pixel aspect ratio */
+ caps = gst_caps_copy (gst_pad_get_pad_template_caps (pad));
+ for (i = 0; i < gst_caps_get_size (caps); ++i) {
+ GstStructure *structure = gst_caps_get_structure (caps, i);
+
+ gst_structure_set (structure, "pixel-aspect-ratio", GST_TYPE_FRACTION,
+ gst_value_get_fraction_numerator (&ximagesink->par),
+ gst_value_get_fraction_denominator (&ximagesink->par), NULL);
+ }
+ return caps;
}
static GstPadLinkReturn
GstXImageSink *ximagesink;
gboolean ret;
GstStructure *structure;
+ const GValue *par;
ximagesink = GST_XIMAGESINK (gst_pad_get_parent (pad));
if (!ret)
return GST_PAD_LINK_REFUSED;
- ximagesink->pixel_width = 1;
- gst_structure_get_int (structure, "pixel_width", &ximagesink->pixel_width);
-
- ximagesink->pixel_height = 1;
- gst_structure_get_int (structure, "pixel_height", &ximagesink->pixel_height);
+ /* if the caps contain pixel-aspect-ratio, they have to match ours,
+ * otherwise linking should fail */
+ par = gst_structure_get_value (structure, "pixel-aspect-ratio");
+ if (par) {
+ if (gst_value_compare (par, &ximagesink->par) != GST_VALUE_EQUAL) {
+ GST_INFO_OBJECT (ximagesink, "pixel aspect ratio does not match");
+ return GST_PAD_LINK_REFUSED;
+ }
+ }
/* Creating our window and our image */
g_assert (GST_VIDEOSINK_WIDTH (ximagesink) > 0);
/* If this buffer has been allocated using our buffer management we simply
put the ximage which is in the PRIVATE pointer */
if (GST_BUFFER_FREE_DATA_FUNC (buf) == gst_ximagesink_buffer_free) {
+ GST_LOG_OBJECT (ximagesink, "buffer from our pool, writing directly");
gst_ximagesink_ximage_put (ximagesink, GST_BUFFER_PRIVATE (buf));
} else {
/* Else we have to copy the data into our private image, */
/* if we have one... */
+ GST_LOG_OBJECT (ximagesink, "normal buffer, copying from it");
if (!ximagesink->ximage) {
GST_DEBUG_OBJECT (ximagesink, "creating our ximage");
ximagesink->ximage = gst_ximagesink_ximage_new (ximagesink,
"endianness", G_TYPE_INT, ximagesink->xcontext->endianness,
"red_mask", G_TYPE_INT, ximagesink->xcontext->visual->red_mask,
"green_mask", G_TYPE_INT,
- ximagesink->xcontext->visual->green_mask, "blue_mask", G_TYPE_INT,
- ximagesink->xcontext->visual->blue_mask, "width", G_TYPE_INT,
- xwindow->width, "height", G_TYPE_INT, xwindow->height,
+ ximagesink->xcontext->visual->green_mask,
+ "blue_mask", G_TYPE_INT,
+ ximagesink->xcontext->visual->blue_mask,
+ "width", G_TYPE_INT, xwindow->width,
+ "height", G_TYPE_INT, xwindow->height,
+ /* for now we use the object-set value for par */
+ "pixel-aspect-ratio", GST_TYPE_FRACTION,
+ gst_value_get_fraction_numerator (&ximagesink->par),
+ gst_value_get_fraction_denominator (&ximagesink->par),
"framerate", G_TYPE_DOUBLE, ximagesink->framerate, NULL));
/* If caps nego succeded updating our size */
XSynchronize (ximagesink->xcontext->disp, ximagesink->synchronous);
}
break;
+ case ARG_PIXEL_ASPECT_RATIO:
+ if (!g_value_transform (value, &ximagesink->par))
+ g_warning ("Could not transform string to aspect ratio");
+ GST_DEBUG_OBJECT (ximagesink, "set PAR to %d/%d",
+ gst_value_get_fraction_numerator (&ximagesink->par),
+ gst_value_get_fraction_denominator (&ximagesink->par));
+ break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
break;
case ARG_SYNCHRONOUS:
g_value_set_boolean (value, ximagesink->synchronous);
break;
+ case ARG_PIXEL_ASPECT_RATIO:
+ g_value_transform (&ximagesink->par, value);
+ break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
break;
ximagesink->x_lock = g_mutex_new ();
- ximagesink->pixel_width = ximagesink->pixel_height = 1;
ximagesink->image_pool = NULL;
ximagesink->pool_lock = g_mutex_new ();
ximagesink->sw_scaling_failed = FALSE;
ximagesink->synchronous = FALSE;
+ g_value_init (&ximagesink->par, GST_TYPE_FRACTION);
+ gst_value_set_fraction (&ximagesink->par, 1, 1);
+
GST_FLAG_SET (ximagesink, GST_ELEMENT_THREAD_SUGGESTED);
GST_FLAG_SET (ximagesink, GST_ELEMENT_EVENT_AWARE);
}
g_param_spec_boolean ("synchronous", "Synchronous", "When enabled, runs "
"the X display in synchronous mode. (used only for debugging)", FALSE,
G_PARAM_READWRITE));
+ g_object_class_install_property (gobject_class, ARG_PIXEL_ASPECT_RATIO,
+ g_param_spec_string ("pixel-aspect-ratio", "Pixel Aspect Ratio",
+ "The pixel aspect ratio of the device", "1/1", G_PARAM_READWRITE));
gobject_class->finalize = gst_ximagesink_finalize;
gobject_class->set_property = gst_ximagesink_set_property;
gint bpp;
gint endianness;
+ gint width, height;
+ gint widthmm, heightmm;
+ GValue par; /* calculated pixel aspect ratio */
+
gboolean use_xshm;
GstCaps *caps;
/* Unused */
gint pixel_width, pixel_height;
+ GValue par; /* object-set pixel aspect ratio */
GstClockTime time;
ARG_HUE,
ARG_SATURATION,
ARG_DISPLAY,
- ARG_SYNCHRONOUS
+ ARG_SYNCHRONOUS,
+ ARG_PIXEL_ASPECT_RATIO
/* FILL ME */
};
return TRUE;
}
-/* This function handles a GstXWindow creation */
+/* This function handles a GstXWindow creation
+ * The width and height are the actual pixel size on the display */
static GstXWindow *
gst_xvimagesink_xwindow_new (GstXvImageSink * xvimagesink,
gint width, gint height)
g_free (xwindow);
}
-/* This function resizes a GstXWindow */
+/* This function resizes a GstXWindow.
+ * The width and height are the actual pixel size on the display. */
static void
gst_xvimagesink_xwindow_resize (GstXvImageSink * xvimagesink,
GstXWindow * xwindow, guint width, guint height)
return caps;
}
+/* This function calculates the pixel aspect ratio based on the properties
+ * in the xcontext structure and stores it there. */
+static void
+gst_xvimagesink_calculate_pixel_aspect_ratio (GstXContext * xcontext)
+{
+ gint par[][2] = {
+ {1, 1}, /* regular screen */
+ {16, 15}, /* PAL TV */
+ {11, 10}, /* 525 line Rec.601 video */
+ {54, 59} /* 625 line Rec.601 video */
+ };
+ gint i;
+ gint index;
+ gdouble ratio;
+ gdouble delta;
+
+#define DELTA(idx) (ABS (ratio - ((gdouble) par[idx][0] / par[idx][1])))
+
+ /* first calculate the "real" ratio based on the X values;
+ * which is the "physical" w/h divided by the w/h in pixels of the display */
+ ratio = xcontext->widthmm * xcontext->height
+ / (xcontext->heightmm * xcontext->width);
+ GST_DEBUG ("calculated pixel aspect ratio: %f", ratio);
+ /* now find the one from par[][2] with the lowest delta to the real one */
+ delta = DELTA (0);
+ index = 0;
+
+ for (i = 1; i < sizeof (par) / (sizeof (gint) * 2); ++i) {
+ gdouble this_delta = DELTA (i);
+
+ if (this_delta < delta) {
+ index = i;
+ delta = this_delta;
+ }
+ }
+
+ GST_DEBUG ("Decided on index %d (%d/%d)", index,
+ par[index][0], par[index][1]);
+
+ g_value_init (&xcontext->par, GST_TYPE_FRACTION);
+ gst_value_set_fraction (&xcontext->par, par[index][0], par[index][1]);
+}
+
/* This function gets the X Display and global info about it. Everything is
stored in our object and will be cleaned when the object is disposed. Note
here that caps for supported format are generated without any window or
xcontext->black = XBlackPixel (xcontext->disp, xcontext->screen_num);
xcontext->depth = DefaultDepthOfScreen (xcontext->screen);
+ xcontext->width = DisplayWidth (xcontext->disp, xcontext->screen_num);
+ xcontext->height = DisplayHeight (xcontext->disp, xcontext->screen_num);
+ xcontext->widthmm = DisplayWidthMM (xcontext->disp, xcontext->screen_num);
+ xcontext->heightmm = DisplayHeightMM (xcontext->disp, xcontext->screen_num);
+
+ gst_xvimagesink_calculate_pixel_aspect_ratio (xcontext);
/* We get supported pixmap formats at supported depth */
px_formats = XListPixmapFormats (xcontext->disp, &nb_formats);
GstStructure *structure;
gint im_format = 0;
gboolean ret;
+ gint video_width, video_height;
+ gint video_par_n, video_par_d; /* video's PAR */
+ gint display_par_n, display_par_d; /* display's PAR */
+ GValue display_ratio = { 0, }; /* display w/h ratio */
+ const GValue *caps_par;
+ gint num, den;
xvimagesink = GST_XVIMAGESINK (gst_pad_get_parent (pad));
GST_PTR_FORMAT, xvimagesink->xcontext->caps, caps);
structure = gst_caps_get_structure (caps, 0);
- ret = gst_structure_get_int (structure, "width",
- &(GST_VIDEOSINK_WIDTH (xvimagesink)));
- ret &= gst_structure_get_int (structure, "height",
- &(GST_VIDEOSINK_HEIGHT (xvimagesink)));
+ 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);
if (!ret)
return GST_PAD_LINK_REFUSED;
+ xvimagesink->video_width = video_width;
+ xvimagesink->video_height = video_height;
if (!gst_structure_get_fourcc (structure, "format", &im_format)) {
im_format =
gst_xvimagesink_get_fourcc_from_caps (xvimagesink,
return GST_PAD_LINK_REFUSED;
}
- xvimagesink->pixel_width = 1;
- gst_structure_get_int (structure, "pixel_width", &xvimagesink->pixel_width);
+ /* get aspect ratio from caps if it's present, and
+ * convert video width and height to a display width and height
+ * using wd / hd = wv / hv * PARv / PARd
+ * the ratio wd / hd will be stored in display_ratio */
+ g_value_init (&display_ratio, GST_TYPE_FRACTION);
+
+ /* get video's PAR */
+ caps_par = gst_structure_get_value (structure, "pixel-aspect-ratio");
+ if (caps_par) {
+ video_par_n = gst_value_get_fraction_numerator (caps_par);
+ video_par_d = gst_value_get_fraction_denominator (caps_par);
+ } else {
+ video_par_n = 1;
+ video_par_d = 1;
+ }
+ /* get display's PAR */
+ display_par_n = gst_value_get_fraction_numerator (&xvimagesink->par);
+ display_par_d = gst_value_get_fraction_denominator (&xvimagesink->par);
+
+ gst_value_set_fraction (&display_ratio,
+ video_width * video_par_n * display_par_d,
+ video_height * video_par_d * display_par_n);
- xvimagesink->pixel_height = 1;
- gst_structure_get_int (structure, "pixel_height", &xvimagesink->pixel_height);
+ num = gst_value_get_fraction_numerator (&display_ratio);
+ den = gst_value_get_fraction_denominator (&display_ratio);
+ GST_DEBUG_OBJECT (xvimagesink,
+ "video width/height: %dx%d, calculated display ratio: %d/%d",
+ video_width, video_height, num, den);
+
+ /* now find a width x height that respects this display ratio.
+ * prefer those that have one of w/h the same as the incoming video
+ * using wd / hd = num / den */
+
+ /* start with same height, because of interlaced video */
+ /* check hd / den is an integer scale factor, and scale wd with the PAR */
+ if (video_height % den == 0) {
+ GST_DEBUG_OBJECT (xvimagesink, "keeping video height");
+ GST_VIDEOSINK_WIDTH (xvimagesink) = video_height * num / den;
+ GST_VIDEOSINK_HEIGHT (xvimagesink) = video_height;
+ } else if (video_width % num == 0) {
+ GST_DEBUG_OBJECT (xvimagesink, "keeping video width");
+ GST_VIDEOSINK_WIDTH (xvimagesink) = video_width;
+ GST_VIDEOSINK_HEIGHT (xvimagesink) = video_width * den / num;
+ } else {
+ GST_DEBUG_OBJECT (xvimagesink, "approximating while keeping video height");
+ GST_VIDEOSINK_WIDTH (xvimagesink) = video_height * num / den;
+ GST_VIDEOSINK_HEIGHT (xvimagesink) = video_height;
+ }
+ GST_DEBUG_OBJECT (xvimagesink, "scaling to %dx%d",
+ GST_VIDEOSINK_WIDTH (xvimagesink), GST_VIDEOSINK_HEIGHT (xvimagesink));
- /* Creating our window and our image */
+ /* Creating our window and our image with the display size in pixels */
g_assert (GST_VIDEOSINK_WIDTH (xvimagesink) > 0);
g_assert (GST_VIDEOSINK_HEIGHT (xvimagesink) > 0);
if (!xvimagesink->xwindow)
GST_VIDEOSINK_HEIGHT (xvimagesink));
}
- /* We renew our xvimage only if size or format changed */
+ /* We renew our xvimage only if size or format changed;
+ * the xvimage is the same size as the video pixel size */
if ((xvimagesink->xvimage) &&
((im_format != xvimagesink->xvimage->im_format) ||
- (GST_VIDEOSINK_WIDTH (xvimagesink) != xvimagesink->xvimage->width) ||
- (GST_VIDEOSINK_HEIGHT (xvimagesink) !=
- xvimagesink->xvimage->height))) {
+ (video_width != xvimagesink->xvimage->width) ||
+ (video_height != xvimagesink->xvimage->height))) {
GST_DEBUG_OBJECT (xvimagesink,
"old format " GST_FOURCC_FORMAT ", new format " GST_FOURCC_FORMAT,
GST_FOURCC_ARGS (xvimagesink->xcontext->im_format),
if (!xvimagesink->xvimage) {
GST_DEBUG_OBJECT (xvimagesink, "creating our xvimage");
xvimagesink->xvimage = gst_xvimagesink_xvimage_new (xvimagesink,
- GST_VIDEOSINK_WIDTH (xvimagesink),
- GST_VIDEOSINK_HEIGHT (xvimagesink));
+ xvimagesink->video_width, xvimagesink->video_height);
if (!xvimagesink->xvimage) {
/* No image available. That's very bad ! */
gst_buffer_unref (buf);
/* We found no suitable image in the pool. Creating... */
GST_DEBUG_OBJECT (xvimagesink, "no usable image in pool, creating xvimage");
xvimage = gst_xvimagesink_xvimage_new (xvimagesink,
- GST_VIDEOSINK_WIDTH (xvimagesink), GST_VIDEOSINK_HEIGHT (xvimagesink));
+ xvimagesink->video_width, xvimagesink->video_height);
}
if (xvimage) {
xvimagesink->synchronous ? "TRUE" : "FALSE");
}
break;
+ case ARG_PIXEL_ASPECT_RATIO:
+ if (!g_value_transform (value, &xvimagesink->par))
+ g_warning ("Could not transform string to aspect ratio");
+ GST_DEBUG_OBJECT (xvimagesink, "set PAR to %d/%d",
+ gst_value_get_fraction_numerator (&xvimagesink->par),
+ gst_value_get_fraction_denominator (&xvimagesink->par));
+ break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
break;
case ARG_SYNCHRONOUS:
g_value_set_boolean (value, xvimagesink->synchronous);
break;
+ case ARG_PIXEL_ASPECT_RATIO:
+ g_value_transform (&xvimagesink->par, value);
+ break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
break;
xvimagesink->x_lock = g_mutex_new ();
- xvimagesink->pixel_width = xvimagesink->pixel_height = 1;
+ g_value_init (&xvimagesink->par, GST_TYPE_FRACTION);
+ gst_value_set_fraction (&xvimagesink->par, 1, 1);
xvimagesink->image_pool = NULL;
xvimagesink->pool_lock = g_mutex_new ();
"When enabled, runs "
"the X display in synchronous mode. (used only for debugging)", FALSE,
G_PARAM_READWRITE));
+ g_object_class_install_property (gobject_class, ARG_PIXEL_ASPECT_RATIO,
+ g_param_spec_string ("pixel-aspect-ratio", "Pixel Aspect Ratio",
+ "The pixel aspect ratio of the device", "1/1", G_PARAM_READWRITE));
gobject_class->finalize = gst_xvimagesink_finalize;
gobject_class->set_property = gst_xvimagesink_set_property;
gint bpp;
gint endianness;
+ gint width, height;
+ gint widthmm, heightmm;
+ GValue par; /* calculated pixel aspect ratio */
+
gboolean use_xshm;
XvPortID xv_port_id;
GMutex *x_lock;
- /* Unused */
- gint pixel_width, pixel_height;
+ guint video_width, video_height; /* size of incoming video;
+ * used as the size for XvImage */
+ GValue par; /* object-set pixel aspect ratio */
GstClockTime time;