2 * Copyright (C) <1999> Erik Walthinsen <omega@cse.ogi.edu>
3 * Copyright (C) <2006> Mark Nauwelaerts <mnauw@skynet.be>
5 * This library is free software; you can redistribute it and/or
6 * modify it under the terms of the GNU Library General Public
7 * License as published by the Free Software Foundation; either
8 * version 2 of the License, or (at your option) any later version.
10 * This library is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 * Library General Public License for more details.
15 * You should have received a copy of the GNU Library General Public
16 * License along with this library; if not, write to the
17 * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
18 * Boston, MA 02111-1307, USA.
21 /* see mjpegtools/yuv4mpeg.h for yuv4mpeg format */
28 #include <gst/video/video.h>
29 #include "gsty4mencode.h"
31 static const GstElementDetails y4mencode_details =
32 GST_ELEMENT_DETAILS ("YUV4MPEG video encoder",
33 "Codec/Encoder/Video",
34 "Encodes a YUV frame into the yuv4mpeg format (mjpegtools)",
35 "Wim Taymans <wim.taymans@chello.be>");
38 /* Filter signals and args */
50 static GstStaticPadTemplate y4mencode_src_factory =
51 GST_STATIC_PAD_TEMPLATE ("src",
54 GST_STATIC_CAPS ("application/x-yuv4mpeg, " "y4mversion = (int) 2")
57 static GstStaticPadTemplate y4mencode_sink_factory =
58 GST_STATIC_PAD_TEMPLATE ("sink",
61 GST_STATIC_CAPS (GST_VIDEO_CAPS_YUV ("{ IYUV, I420 }"))
65 static void gst_y4m_encode_set_property (GObject * object,
66 guint prop_id, const GValue * value, GParamSpec * pspec);
67 static void gst_y4m_encode_get_property (GObject * object,
68 guint prop_id, GValue * value, GParamSpec * pspec);
70 static void gst_y4m_encode_reset (GstY4mEncode * filter);
72 static gboolean gst_y4m_encode_setcaps (GstPad * pad, GstCaps * vscaps);
73 static GstFlowReturn gst_y4m_encode_chain (GstPad * pad, GstBuffer * buf);
74 static GstStateChangeReturn gst_y4m_encode_change_state (GstElement * element,
75 GstStateChange transition);
77 GST_BOILERPLATE (GstY4mEncode, gst_y4m_encode, GstElement, GST_TYPE_ELEMENT);
81 gst_y4m_encode_base_init (gpointer g_class)
83 GstElementClass *element_class = GST_ELEMENT_CLASS (g_class);
85 gst_element_class_add_pad_template (element_class,
86 gst_static_pad_template_get (&y4mencode_src_factory));
87 gst_element_class_add_pad_template (element_class,
88 gst_static_pad_template_get (&y4mencode_sink_factory));
89 gst_element_class_set_details (element_class, &y4mencode_details);
93 gst_y4m_encode_class_init (GstY4mEncodeClass * klass)
95 GObjectClass *gobject_class;
96 GstElementClass *gstelement_class;
98 gobject_class = (GObjectClass *) klass;
99 gstelement_class = (GstElementClass *) klass;
101 gstelement_class->change_state =
102 GST_DEBUG_FUNCPTR (gst_y4m_encode_change_state);
104 gobject_class->set_property = gst_y4m_encode_set_property;
105 gobject_class->get_property = gst_y4m_encode_get_property;
109 gst_y4m_encode_init (GstY4mEncode * filter, GstY4mEncodeClass * klass)
112 gst_pad_new_from_template (gst_static_pad_template_get
113 (&y4mencode_sink_factory), "sink");
114 gst_element_add_pad (GST_ELEMENT (filter), filter->sinkpad);
115 gst_pad_set_chain_function (filter->sinkpad,
116 GST_DEBUG_FUNCPTR (gst_y4m_encode_chain));
117 gst_pad_set_setcaps_function (filter->sinkpad,
118 GST_DEBUG_FUNCPTR (gst_y4m_encode_setcaps));
121 gst_pad_new_from_template (gst_static_pad_template_get
122 (&y4mencode_src_factory), "src");
123 gst_element_add_pad (GST_ELEMENT (filter), filter->srcpad);
124 gst_pad_use_fixed_caps (filter->srcpad);
126 /* init properties */
127 gst_y4m_encode_reset (filter);
131 gst_y4m_encode_reset (GstY4mEncode * filter)
133 filter->width = filter->height = -1;
134 filter->fps_num = filter->fps_den = 1;
135 filter->par_num = filter->par_den = 1;
139 gst_y4m_encode_setcaps (GstPad * pad, GstCaps * vscaps)
141 GstY4mEncode *filter;
142 GstStructure *structure;
144 const GValue *fps, *par;
146 filter = GST_Y4M_ENCODE (GST_PAD_PARENT (pad));
148 structure = gst_caps_get_structure (vscaps, 0);
150 g_return_val_if_fail (gst_structure_get_int (structure, "width", &w), FALSE);
151 g_return_val_if_fail (gst_structure_get_int (structure, "height", &h), FALSE);
152 fps = gst_structure_get_value (structure, "framerate");
153 g_return_val_if_fail (w > 0 && h > 0
154 && fps != NULL && GST_VALUE_HOLDS_FRACTION (fps), FALSE);
155 /* optional par info */
156 par = gst_structure_get_value (structure, "pixel-aspect-ratio");
160 filter->fps_num = gst_value_get_fraction_numerator (fps);
161 filter->fps_den = gst_value_get_fraction_denominator (fps);
162 if ((par != NULL) && GST_VALUE_HOLDS_FRACTION (par)) {
163 filter->par_num = gst_value_get_fraction_numerator (par);
164 filter->par_den = gst_value_get_fraction_denominator (par);
165 } else { /* indicates unknown */
170 /* the template caps will do for the src pad, should always accept */
171 return gst_pad_set_caps (filter->srcpad,
172 gst_caps_copy (gst_pad_get_pad_template_caps (filter->srcpad)));
175 static inline GstBuffer *
176 gst_y4m_encode_get_stream_header (GstY4mEncode * filter)
181 header = g_strdup_printf ("YUV4MPEG2 W%d H%d I? F%d:%d A%d:%d\n",
182 filter->width, filter->height,
183 filter->fps_num, filter->fps_den, filter->par_num, filter->par_den);
185 buf = gst_buffer_new ();
186 gst_buffer_set_data (buf, header, strlen (header));
187 /* so it gets free'd when needed */
188 GST_BUFFER_MALLOCDATA (buf) = header;
193 static inline GstBuffer *
194 gst_y4m_encode_get_frame_header (GstY4mEncode * filter)
199 header = g_strdup_printf ("FRAME\n");
201 buf = gst_buffer_new ();
202 gst_buffer_set_data (buf, header, strlen (header));
203 /* so it gets free'd when needed */
204 GST_BUFFER_MALLOCDATA (buf) = header;
210 gst_y4m_encode_chain (GstPad * pad, GstBuffer * buf)
212 GstY4mEncode *filter = GST_Y4M_ENCODE (GST_PAD_PARENT (pad));
215 /* check we got some decent info from caps */
216 if (filter->width < 0) {
217 GST_ELEMENT_ERROR ("filter", CORE, NEGOTIATION, (NULL),
218 ("format wasn't negotiated before chain function"));
219 gst_buffer_unref (buf);
220 return GST_FLOW_NOT_NEGOTIATED;
223 if (G_UNLIKELY (!filter->header)) {
224 outbuf = gst_y4m_encode_get_stream_header (filter);
225 filter->header = TRUE;
226 outbuf = gst_buffer_join (outbuf, gst_y4m_encode_get_frame_header (filter));
228 outbuf = gst_y4m_encode_get_frame_header (filter);
231 outbuf = gst_buffer_join (outbuf, buf);
233 gst_buffer_make_metadata_writable (outbuf);
234 gst_buffer_set_caps (outbuf, GST_PAD_CAPS (filter->srcpad));
235 /* strip to avoid sink dropping on time-base, decorate and send */
236 GST_BUFFER_TIMESTAMP (outbuf) = GST_CLOCK_TIME_NONE;
237 return gst_pad_push (filter->srcpad, outbuf);
241 gst_y4m_encode_set_property (GObject * object, guint prop_id,
242 const GValue * value, GParamSpec * pspec)
244 GstY4mEncode *filter;
246 g_return_if_fail (GST_IS_Y4M_ENCODE (object));
247 filter = GST_Y4M_ENCODE (object);
256 gst_y4m_encode_get_property (GObject * object, guint prop_id, GValue * value,
259 GstY4mEncode *filter;
261 g_return_if_fail (GST_IS_Y4M_ENCODE (object));
262 filter = GST_Y4M_ENCODE (object);
266 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
271 static GstStateChangeReturn
272 gst_y4m_encode_change_state (GstElement * element, GstStateChange transition)
274 GstY4mEncode *filter = GST_Y4M_ENCODE (element);
275 GstStateChangeReturn ret;
277 switch (transition) {
278 case GST_STATE_CHANGE_NULL_TO_READY:
279 case GST_STATE_CHANGE_READY_TO_PAUSED:
285 ret = GST_CALL_PARENT_WITH_DEFAULT (GST_ELEMENT_CLASS, change_state,
286 (element, transition), GST_STATE_CHANGE_SUCCESS);
287 if (ret != GST_STATE_CHANGE_SUCCESS)
290 switch (transition) {
291 case GST_STATE_CHANGE_PAUSED_TO_READY:
292 gst_y4m_encode_reset (filter);
298 return GST_STATE_CHANGE_SUCCESS;
302 plugin_init (GstPlugin * plugin)
304 return gst_element_register (plugin, "y4menc", GST_RANK_NONE,
305 GST_TYPE_Y4M_ENCODE);
308 GST_PLUGIN_DEFINE (GST_VERSION_MAJOR,
311 "Encodes a YUV frame into the yuv4mpeg format (mjpegtools)",
312 plugin_init, VERSION, GST_LICENSE, GST_PACKAGE_NAME, GST_PACKAGE_ORIGIN)