mirror of
https://gitlab.freedesktop.org/gstreamer/gstreamer.git
synced 2024-12-24 01:00:37 +00:00
pixel aspect ratio handling
Original commit message from CVS: pixel aspect ratio handling
This commit is contained in:
parent
da7a7b47e1
commit
cc2e1fab44
11 changed files with 574 additions and 51 deletions
33
ChangeLog
33
ChangeLog
|
@ -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:
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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;
|
||||
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
|
||||
|
|
Loading…
Reference in a new issue