2 * Copyright (C) 2008 Jan Schmidt <thaytan@noraisin.net>
10 #include <gst/video/video.h>
13 #include "rsnparsetter.h"
14 #include "rsnwrappedbuffer.h"
16 GST_DEBUG_CATEGORY_STATIC (rsn_parsetter_debug);
17 #define GST_CAT_DEFAULT rsn_parsetter_debug
19 static GstStaticPadTemplate sink_factory = GST_STATIC_PAD_TEMPLATE ("sink",
22 GST_STATIC_CAPS ("video/x-raw-rgb; video/x-raw-yuv")
25 static GstStaticPadTemplate src_factory = GST_STATIC_PAD_TEMPLATE ("src",
28 GST_STATIC_CAPS ("video/x-raw-rgb; video/x-raw-yuv")
31 static void rsn_parsetter_register_extra (GType rsn_parsetter_type);
33 GST_BOILERPLATE_FULL (RsnParSetter, rsn_parsetter, GstElement,
34 GST_TYPE_ELEMENT, rsn_parsetter_register_extra);
36 static void rsn_parsetter_finalize (GObject * object);
37 static GstFlowReturn rsn_parsetter_chain (GstPad * pad, GstBuffer * buf);
38 static gboolean rsn_parsetter_sink_event (GstPad * pad, GstEvent * event);
39 static gboolean rsn_parsetter_sink_setcaps (GstPad * pad, GstCaps * caps);
40 static GstFlowReturn rsn_parsetter_sink_bufferalloc (GstPad * pad,
41 guint64 offset, guint size, GstCaps * caps, GstBuffer ** buf);
43 static GstCaps *rsn_parsetter_src_getcaps (GstPad * pad);
44 static GstCaps *rsn_parsetter_convert_caps (RsnParSetter * parset,
45 GstCaps * caps, gboolean widescreen);
46 static gboolean rsn_parsetter_check_caps (RsnParSetter * parset,
50 rsn_parsetter_register_extra (GType rsn_parsetter_type)
52 GST_DEBUG_CATEGORY_INIT (rsn_parsetter_debug, "rsnparsetter", 0,
53 "Resin DVD aspect ratio adjuster");
57 rsn_parsetter_base_init (gpointer gclass)
60 GstElementClass *element_class = GST_ELEMENT_CLASS (gclass);
62 gst_element_class_add_static_pad_template (element_class, &src_factory);
63 gst_element_class_add_static_pad_template (element_class, &sink_factory);
64 gst_element_class_set_details_simple (element_class,
65 "Resin Aspect Ratio Setter", "Filter/Video",
66 "Overrides caps on video buffers to force a particular display ratio",
67 "Jan Schmidt <thaytan@noraisin.net>");
71 rsn_parsetter_class_init (RsnParSetterClass * klass)
73 GObjectClass *gobject_class;
75 gobject_class = (GObjectClass *) klass;
77 gobject_class->finalize = rsn_parsetter_finalize;
81 rsn_parsetter_init (RsnParSetter * parset, RsnParSetterClass * gclass)
83 parset->sinkpad = gst_pad_new_from_static_template (&sink_factory, "sink");
84 gst_pad_set_getcaps_function (parset->sinkpad,
85 GST_DEBUG_FUNCPTR (gst_pad_proxy_getcaps));
86 gst_pad_set_chain_function (parset->sinkpad,
87 GST_DEBUG_FUNCPTR (rsn_parsetter_chain));
88 gst_pad_set_event_function (parset->sinkpad,
89 GST_DEBUG_FUNCPTR (rsn_parsetter_sink_event));
90 gst_pad_set_setcaps_function (parset->sinkpad,
91 GST_DEBUG_FUNCPTR (rsn_parsetter_sink_setcaps));
92 gst_pad_set_bufferalloc_function (parset->sinkpad,
93 GST_DEBUG_FUNCPTR (rsn_parsetter_sink_bufferalloc));
94 gst_element_add_pad (GST_ELEMENT (parset), parset->sinkpad);
96 parset->srcpad = gst_pad_new_from_static_template (&src_factory, "src");
97 gst_pad_set_getcaps_function (parset->srcpad,
98 GST_DEBUG_FUNCPTR (rsn_parsetter_src_getcaps));
99 gst_element_add_pad (GST_ELEMENT (parset), parset->srcpad);
101 parset->caps_lock = g_mutex_new ();
105 rsn_parsetter_finalize (GObject * object)
107 RsnParSetter *parset = RSN_PARSETTER (object);
109 gst_caps_replace (&parset->outcaps, NULL);
110 gst_caps_replace (&parset->in_caps_last, NULL);
111 gst_caps_replace (&parset->in_caps_converted, NULL);
113 g_mutex_free (parset->caps_lock);
115 G_OBJECT_CLASS (parent_class)->finalize (object);
119 rsn_parsetter_chain (GstPad * pad, GstBuffer * buf)
121 RsnParSetter *parset = RSN_PARSETTER (GST_OBJECT_PARENT (pad));
123 /* If this is a buffer we wrapped up earlier, unwrap it now */
124 if (RSN_IS_WRAPPEDBUFFER (buf)) {
125 RsnWrappedBuffer *wrap_buf = RSN_WRAPPEDBUFFER (buf);
127 if (wrap_buf->owner == GST_ELEMENT (parset)) {
128 buf = rsn_wrappedbuffer_unwrap_and_unref (wrap_buf);
129 GST_DEBUG_OBJECT (parset, "Unwrapping %p yields buffer %p with caps %"
130 GST_PTR_FORMAT, wrap_buf, buf, GST_BUFFER_CAPS (buf));
134 if (parset->outcaps != GST_BUFFER_CAPS (buf)) {
135 if (parset->override_outcaps == FALSE &&
136 gst_caps_is_equal (parset->outcaps, GST_BUFFER_CAPS (buf))) {
137 /* Just update our output caps var */
138 gst_caps_replace (&parset->outcaps, GST_BUFFER_CAPS (buf));
142 /* Replace the caps on the output buffer */
143 buf = gst_buffer_make_metadata_writable (buf);
144 gst_buffer_set_caps (buf, parset->outcaps);
146 GST_DEBUG_OBJECT (parset,
147 "Replacing caps on buffer %p with caps %" GST_PTR_FORMAT,
148 buf, parset->outcaps);
152 return gst_pad_push (parset->srcpad, buf);
156 rsn_parsetter_sink_event (GstPad * pad, GstEvent * event)
158 RsnParSetter *parset = RSN_PARSETTER (gst_pad_get_parent (pad));
159 const GstStructure *structure = gst_event_get_structure (event);
161 if (structure != NULL &&
162 gst_structure_has_name (structure, "application/x-gst-dvd")) {
163 const char *type = gst_structure_get_string (structure, "event");
167 if (strcmp (type, "dvd-video-format") == 0) {
168 gboolean is_widescreen;
170 gst_structure_get_boolean (structure, "video-widescreen", &is_widescreen);
172 GST_DEBUG_OBJECT (parset, "Video is %s",
173 parset->is_widescreen ? "16:9" : "4:3");
175 g_mutex_lock (parset->caps_lock);
176 if (parset->is_widescreen != is_widescreen) {
177 /* Force caps check */
178 gst_caps_replace (&parset->in_caps_last, NULL);
179 gst_caps_replace (&parset->in_caps_converted, NULL);
181 parset->is_widescreen = is_widescreen;
183 /* FIXME: Added for testing: */
184 // parset->is_widescreen = FALSE;
186 g_mutex_unlock (parset->caps_lock);
191 gst_object_unref (GST_OBJECT (parset));
192 return gst_pad_event_default (pad, event);
196 rsn_parsetter_src_getcaps (GstPad * pad)
198 RsnParSetter *parset = RSN_PARSETTER (gst_pad_get_parent (pad));
200 const GstCaps *templ_caps = gst_pad_get_pad_template_caps (pad);
202 ret = gst_pad_peer_get_caps (parset->sinkpad);
204 ret = gst_caps_copy (templ_caps);
207 temp = gst_caps_intersect (templ_caps, ret);
208 gst_caps_unref (ret);
209 ret = rsn_parsetter_convert_caps (parset, temp, parset->is_widescreen);
210 gst_caps_unref (temp);
213 gst_object_unref (parset);
218 rsn_parsetter_check_caps (RsnParSetter * parset, GstCaps * caps)
224 gboolean ret = FALSE;
226 g_mutex_lock (parset->caps_lock);
228 if (caps == parset->in_caps_last ||
229 gst_caps_is_equal (caps, parset->in_caps_last)) {
230 ret = parset->in_caps_was_ok;
234 /* Calculate the DAR from the incoming caps, and return TRUE if it matches
235 * the required DAR, FALSE if not */
236 s = gst_caps_get_structure (caps, 0);
240 if (!gst_structure_get_int (s, "width", &width) ||
241 !gst_structure_get_int (s, "height", &height))
244 if (!gst_structure_get_fraction (s, "pixel-aspect-ratio", &par_n, &par_d))
247 if (!gst_video_calculate_display_ratio (&dar_n, &dar_d, width, height,
251 GST_DEBUG_OBJECT (parset,
252 "Incoming video caps now: w %d h %d PAR %d/%d = DAR %d/%d",
253 width, height, par_n, par_d, dar_n, dar_d);
255 if (parset->is_widescreen) {
256 if (dar_n == 16 && dar_d == 9)
259 if (dar_n == 4 && dar_d == 3)
263 gst_caps_replace (&parset->in_caps_last, caps);
264 gst_caps_replace (&parset->in_caps_converted, NULL);
265 parset->in_caps_was_ok = ret;
268 g_mutex_unlock (parset->caps_lock);
273 rsn_parsetter_convert_caps (RsnParSetter * parset, GstCaps * caps,
276 /* Duplicate the given caps, with a PAR that provides the desired DAR */
284 g_mutex_lock (parset->caps_lock);
285 if (caps == parset->in_caps_last && parset->in_caps_converted) {
286 outcaps = gst_caps_ref (parset->in_caps_converted);
290 outcaps = gst_caps_copy (caps);
292 /* Calculate the DAR from the incoming caps, and return TRUE if it matches
293 * the required DAR, FALSE if not */
294 s = gst_caps_get_structure (outcaps, 0);
298 if (!gst_structure_get_int (s, "width", &width) ||
299 !gst_structure_get_int (s, "height", &height))
310 par_n = dar_n * height;
311 par_d = dar_d * width;
313 g_value_init (&par, GST_TYPE_FRACTION);
314 gst_value_set_fraction (&par, par_n, par_d);
315 gst_structure_set_value (s, "pixel-aspect-ratio", &par);
316 g_value_unset (&par);
318 gst_caps_replace (&parset->in_caps_converted, outcaps);
320 g_mutex_unlock (parset->caps_lock);
325 rsn_parsetter_sink_setcaps (GstPad * pad, GstCaps * caps)
327 /* Check the new incoming caps against our current DAR, and mark
328 * whether the buffers will need adjusting */
329 RsnParSetter *parset = RSN_PARSETTER (gst_pad_get_parent (pad));
331 if (rsn_parsetter_check_caps (parset, caps)) {
332 parset->override_outcaps = FALSE;
333 gst_caps_replace (&parset->outcaps, caps);
335 GstCaps *override_caps = rsn_parsetter_convert_caps (parset, caps,
336 parset->is_widescreen);
338 gst_caps_unref (parset->outcaps);
339 parset->outcaps = override_caps;
341 parset->override_outcaps = TRUE;
344 GST_DEBUG_OBJECT (parset, "caps changed: need_override now = %d",
345 parset->override_outcaps);
347 gst_object_unref (parset);
352 rsn_parsetter_sink_bufferalloc (GstPad * pad, guint64 offset, guint size,
353 GstCaps * caps, GstBuffer ** buf)
355 RsnParSetter *parset = RSN_PARSETTER (gst_pad_get_parent (pad));
358 GST_LOG_OBJECT (parset, "Entering bufferalloc");
360 if (rsn_parsetter_check_caps (parset, caps)) {
361 ret = gst_pad_alloc_buffer (parset->srcpad, offset, size, caps, buf);
362 GST_LOG_OBJECT (parset, "Not wrapping buf %p", *buf);
364 /* Allocate and wrap a downstream buffer */
367 GstCaps *override_caps = rsn_parsetter_convert_caps (parset, caps,
368 parset->is_widescreen);
370 ret = gst_pad_alloc_buffer (parset->srcpad, offset, size,
371 override_caps, &orig_buf);
372 gst_caps_unref (override_caps);
374 if (ret != GST_FLOW_OK)
377 outbuf = (GstBuffer *) rsn_wrapped_buffer_new (orig_buf);
379 /* FIXME: Throw error */
380 return GST_FLOW_ERROR;
383 rsn_wrapped_buffer_set_owner (RSN_WRAPPEDBUFFER (outbuf),
384 GST_ELEMENT (parset));
386 gst_buffer_set_caps (outbuf, caps);
388 GST_LOG_OBJECT (parset,
389 "Wrapped ds buf %p with caps %" GST_PTR_FORMAT
390 " into new buf %p with caps %" GST_PTR_FORMAT,
391 orig_buf, GST_BUFFER_CAPS (orig_buf), outbuf, GST_BUFFER_CAPS (outbuf));
396 gst_object_unref (GST_OBJECT (parset));