pixel aspect ratio handling

Original commit message from CVS:
pixel aspect ratio handling
This commit is contained in:
Thomas Vander Stichele 2004-07-27 16:43:24 +00:00
parent da7a7b47e1
commit cc2e1fab44
11 changed files with 574 additions and 51 deletions

View file

@ -1,3 +1,36 @@
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:

View file

@ -532,6 +532,22 @@ theora_dec_chain (GstPad * pad, GstData * data)
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);
@ -539,6 +555,7 @@ theora_dec_chain (GstPad * pad, GstData * data)
"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);

View file

@ -234,6 +234,7 @@ theora_enc_sink_link (GstPad * pad, const GstCaps * 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;
@ -241,6 +242,7 @@ theora_enc_sink_link (GstPad * pad, const GstCaps * caps)
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)
@ -257,9 +259,15 @@ theora_enc_sink_link (GstPad * pad, const GstCaps * caps)
/* 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;

View file

@ -175,20 +175,25 @@ gst_ffmpegcolorspace_pad_link (GstPad * pad, const GstCaps * caps)
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
@ -205,7 +210,6 @@ gst_ffmpegcolorspace_pad_link (GstPad * pad, const GstCaps * caps)
return GST_PAD_LINK_REFUSED;
}
/* set the size on the otherpad */
othercaps = gst_pad_get_negotiated_caps (otherpad);
if (othercaps) {
@ -215,6 +219,15 @@ gst_ffmpegcolorspace_pad_link (GstPad * pad, const GstCaps * caps)
"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;

View file

@ -108,6 +108,7 @@ static void gst_videoscale_set_property (GObject * object, guint prop_id,
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);
@ -166,6 +167,7 @@ gst_videoscale_class_init (GstVideoscaleClass * klass)
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;
@ -180,14 +182,14 @@ gst_videoscale_getcaps (GstPad * pad)
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++) {
@ -196,10 +198,10 @@ gst_videoscale_getcaps (GstPad * pad)
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;
}
@ -210,9 +212,13 @@ gst_videoscale_link (GstPad * pad, const GstCaps * 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));
@ -223,15 +229,21 @@ gst_videoscale_link (GstPad * pad, const GstCaps * caps)
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;
@ -239,23 +251,88 @@ gst_videoscale_link (GstPad * pad, const GstCaps * caps)
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;
@ -263,23 +340,154 @@ gst_videoscale_link (GstPad * pad, const GstCaps * caps)
}
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)
{
@ -299,6 +507,7 @@ 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;
@ -439,6 +648,20 @@ gst_videoscale_get_property (GObject * object, guint prop_id, GValue * value,
}
}
/* 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)

View file

@ -66,6 +66,8 @@ struct _GstVideoscale {
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;

View file

@ -304,6 +304,7 @@ gst_videotestsrc_get_capslist (void)
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);
}

View file

@ -71,7 +71,8 @@ enum
{
ARG_0,
ARG_DISPLAY,
ARG_SYNCHRONOUS
ARG_SYNCHRONOUS,
ARG_PIXEL_ASPECT_RATIO
/* FILL ME */
};
@ -541,6 +542,10 @@ gst_ximagesink_renegotiate_size (GstXImageSink * ximagesink)
"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)) {
@ -652,12 +657,55 @@ gst_ximagesink_handle_xevents (GstXImageSink * ximagesink, GstPad * pad)
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
@ -693,6 +741,13 @@ gst_ximagesink_xcontext_get (GstXImageSink * ximagesink)
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);
@ -750,6 +805,10 @@ 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,
/* 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);
@ -805,6 +864,8 @@ gst_ximagesink_fixate (GstPad * pad, const GstCaps * caps)
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;
}
@ -824,13 +885,24 @@ static GstCaps *
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
@ -839,6 +911,7 @@ gst_ximagesink_sink_link (GstPad * pad, const GstCaps * caps)
GstXImageSink *ximagesink;
gboolean ret;
GstStructure *structure;
const GValue *par;
ximagesink = GST_XIMAGESINK (gst_pad_get_parent (pad));
@ -859,11 +932,15 @@ gst_ximagesink_sink_link (GstPad * pad, const GstCaps * caps)
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);
@ -985,10 +1062,12 @@ gst_ximagesink_chain (GstPad * pad, GstData * data)
/* 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,
@ -1232,9 +1311,15 @@ gst_ximagesink_set_xwindow_id (GstXOverlay * overlay, XID xwindow_id)
"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 */
@ -1316,6 +1401,13 @@ gst_ximagesink_set_property (GObject * object, guint prop_id,
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;
@ -1339,6 +1431,9 @@ gst_ximagesink_get_property (GObject * object, guint prop_id,
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;
@ -1394,7 +1489,6 @@ gst_ximagesink_init (GstXImageSink * ximagesink)
ximagesink->x_lock = g_mutex_new ();
ximagesink->pixel_width = ximagesink->pixel_height = 1;
ximagesink->image_pool = NULL;
ximagesink->pool_lock = g_mutex_new ();
@ -1402,6 +1496,9 @@ gst_ximagesink_init (GstXImageSink * ximagesink)
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);
}
@ -1435,6 +1532,9 @@ gst_ximagesink_class_init (GstXImageSinkClass * klass)
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;

View file

@ -75,6 +75,10 @@ struct _GstXContext {
gint bpp;
gint endianness;
gint width, height;
gint widthmm, heightmm;
GValue par; /* calculated pixel aspect ratio */
gboolean use_xshm;
GstCaps *caps;
@ -118,6 +122,7 @@ struct _GstXImageSink {
/* Unused */
gint pixel_width, pixel_height;
GValue par; /* object-set pixel aspect ratio */
GstClockTime time;

View file

@ -81,7 +81,8 @@ enum
ARG_HUE,
ARG_SATURATION,
ARG_DISPLAY,
ARG_SYNCHRONOUS
ARG_SYNCHRONOUS,
ARG_PIXEL_ASPECT_RATIO
/* FILL ME */
};
@ -390,7 +391,8 @@ gst_xvimagesink_xwindow_decorate (GstXvImageSink * xvimagesink,
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)
@ -458,7 +460,8 @@ gst_xvimagesink_xwindow_destroy (GstXvImageSink * xvimagesink,
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)
@ -815,6 +818,49 @@ gst_xvimagesink_get_xv_support (GstXvImageSink * xvimagesink,
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
@ -855,6 +901,12 @@ gst_xvimagesink_xcontext_get (GstXvImageSink * xvimagesink)
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);
@ -1112,6 +1164,12 @@ gst_xvimagesink_sink_link (GstPad * pad, const GstCaps * caps)
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));
@ -1120,15 +1178,15 @@ gst_xvimagesink_sink_link (GstPad * pad, const GstCaps * caps)
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,
@ -1138,13 +1196,58 @@ gst_xvimagesink_sink_link (GstPad * pad, const GstCaps * caps)
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);
xvimagesink->pixel_height = 1;
gst_structure_get_int (structure, "pixel_height", &xvimagesink->pixel_height);
/* 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);
/* Creating our window and our image */
gst_value_set_fraction (&display_ratio,
video_width * video_par_n * display_par_d,
video_height * video_par_d * display_par_n);
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 with the display size in pixels */
g_assert (GST_VIDEOSINK_WIDTH (xvimagesink) > 0);
g_assert (GST_VIDEOSINK_HEIGHT (xvimagesink) > 0);
if (!xvimagesink->xwindow)
@ -1157,12 +1260,12 @@ gst_xvimagesink_sink_link (GstPad * pad, const GstCaps * caps)
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),
@ -1278,8 +1381,7 @@ gst_xvimagesink_chain (GstPad * pad, GstData * data)
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);
@ -1373,7 +1475,7 @@ gst_xvimagesink_buffer_alloc (GstPad * pad, guint64 offset, guint size)
/* 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) {
@ -1680,6 +1782,13 @@ gst_xvimagesink_set_property (GObject * object, guint prop_id,
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;
@ -1715,6 +1824,9 @@ gst_xvimagesink_get_property (GObject * object, guint prop_id,
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;
@ -1777,7 +1889,8 @@ gst_xvimagesink_init (GstXvImageSink * xvimagesink)
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 ();
@ -1830,6 +1943,9 @@ gst_xvimagesink_class_init (GstXvImageSinkClass * klass)
"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;

View file

@ -79,6 +79,10 @@ struct _GstXContext {
gint bpp;
gint endianness;
gint width, height;
gint widthmm, heightmm;
GValue par; /* calculated pixel aspect ratio */
gboolean use_xshm;
XvPortID xv_port_id;
@ -139,8 +143,9 @@ struct _GstXvImageSink {
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;