From 96690aa992f0c0c81c542609d5a21facf72fc8d1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sebastian=20Dr=C3=B6ge?= Date: Sun, 23 Dec 2007 06:22:32 +0000 Subject: Add new plugin rawparse that contains a base class for raw data parsers and the two elements audioparse and videopars... Original commit message from CVS: * configure.ac: * gst/rawparse/Makefile.am: * gst/rawparse/README: * gst/rawparse/gstaudioparse.c: (gst_audio_parse_format_get_type), (gst_audio_parse_endianness_get_type), (gst_audio_parse_base_init), (gst_audio_parse_class_init), (gst_audio_parse_init), (gst_audio_parse_set_property), (gst_audio_parse_get_property), (gst_audio_parse_update_frame_size), (gst_audio_parse_get_caps): * gst/rawparse/gstaudioparse.h: * gst/rawparse/gstrawparse.c: (gst_raw_parse_base_init), (gst_raw_parse_class_init), (gst_raw_parse_init), (gst_raw_parse_dispose), (gst_raw_parse_class_set_src_pad_template), (gst_raw_parse_class_set_multiple_frames_per_buffer), (gst_raw_parse_reset), (gst_raw_parse_chain), (gst_raw_parse_convert), (gst_raw_parse_sink_event), (gst_raw_parse_src_event), (gst_raw_parse_src_query_type), (gst_raw_parse_src_query), (gst_raw_parse_set_framesize), (gst_raw_parse_set_fps), (gst_raw_parse_get_fps), (gst_raw_parse_is_negotiated): * gst/rawparse/gstrawparse.h: * gst/rawparse/gstvideoparse.c: (gst_video_parse_format_get_type), (gst_video_parse_endianness_get_type), (gst_video_parse_base_init), (gst_video_parse_class_init), (gst_video_parse_init), (gst_video_parse_set_property), (gst_video_parse_get_property), (gst_video_parse_format_to_fourcc), (gst_video_parse_update_frame_size), (gst_video_parse_get_caps): * gst/rawparse/gstvideoparse.h: * gst/rawparse/plugin.c: (plugin_init): Add new plugin rawparse that contains a base class for raw data parsers and the two elements audioparse and videoparse that can be used to parse raw audio and video. These are inspired by the old videoparse element which the new rawparse plugin deprecates. --- ChangeLog | 36 +++ configure.ac | 4 +- gst/rawparse/Makefile.am | 8 + gst/rawparse/README | 23 ++ gst/rawparse/gstaudioparse.c | 319 +++++++++++++++++++++++ gst/rawparse/gstaudioparse.h | 66 +++++ gst/rawparse/gstrawparse.c | 598 +++++++++++++++++++++++++++++++++++++++++++ gst/rawparse/gstrawparse.h | 91 +++++++ gst/rawparse/gstvideoparse.c | 422 ++++++++++++++++++++++++++++++ gst/rawparse/gstvideoparse.h | 74 ++++++ gst/rawparse/plugin.c | 26 ++ 11 files changed, 1665 insertions(+), 2 deletions(-) create mode 100644 gst/rawparse/Makefile.am create mode 100644 gst/rawparse/README create mode 100644 gst/rawparse/gstaudioparse.c create mode 100644 gst/rawparse/gstaudioparse.h create mode 100644 gst/rawparse/gstrawparse.c create mode 100644 gst/rawparse/gstrawparse.h create mode 100644 gst/rawparse/gstvideoparse.c create mode 100644 gst/rawparse/gstvideoparse.h create mode 100644 gst/rawparse/plugin.c diff --git a/ChangeLog b/ChangeLog index 1bbfe81a..6aa7694c 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,39 @@ +2007-12-23 Sebastian Dröge + + * configure.ac: + * gst/rawparse/Makefile.am: + * gst/rawparse/README: + * gst/rawparse/gstaudioparse.c: (gst_audio_parse_format_get_type), + (gst_audio_parse_endianness_get_type), (gst_audio_parse_base_init), + (gst_audio_parse_class_init), (gst_audio_parse_init), + (gst_audio_parse_set_property), (gst_audio_parse_get_property), + (gst_audio_parse_update_frame_size), (gst_audio_parse_get_caps): + * gst/rawparse/gstaudioparse.h: + * gst/rawparse/gstrawparse.c: (gst_raw_parse_base_init), + (gst_raw_parse_class_init), (gst_raw_parse_init), + (gst_raw_parse_dispose), + (gst_raw_parse_class_set_src_pad_template), + (gst_raw_parse_class_set_multiple_frames_per_buffer), + (gst_raw_parse_reset), (gst_raw_parse_chain), + (gst_raw_parse_convert), (gst_raw_parse_sink_event), + (gst_raw_parse_src_event), (gst_raw_parse_src_query_type), + (gst_raw_parse_src_query), (gst_raw_parse_set_framesize), + (gst_raw_parse_set_fps), (gst_raw_parse_get_fps), + (gst_raw_parse_is_negotiated): + * gst/rawparse/gstrawparse.h: + * gst/rawparse/gstvideoparse.c: (gst_video_parse_format_get_type), + (gst_video_parse_endianness_get_type), (gst_video_parse_base_init), + (gst_video_parse_class_init), (gst_video_parse_init), + (gst_video_parse_set_property), (gst_video_parse_get_property), + (gst_video_parse_format_to_fourcc), + (gst_video_parse_update_frame_size), (gst_video_parse_get_caps): + * gst/rawparse/gstvideoparse.h: + * gst/rawparse/plugin.c: (plugin_init): + Add new plugin rawparse that contains a base class for raw data + parsers and the two elements audioparse and videoparse that can + be used to parse raw audio and video. These are inspired by the + old videoparse element which the new rawparse plugin deprecates. + 2007-12-21 David Schleef * sys/glsink/glextensions.c: diff --git a/configure.ac b/configure.ac index bea69902..bbc72834 100644 --- a/configure.ac +++ b/configure.ac @@ -100,6 +100,7 @@ GST_PLUGINS_ALL="\ mve \ nsf \ nuvdemux \ + rawparse \ real \ replaygain \ rtpmanager \ @@ -110,7 +111,6 @@ GST_PLUGINS_ALL="\ stereo \ switch \ tta \ - videoparse \ videosignal \ vmnc \ xingheader \ @@ -1078,6 +1078,7 @@ gst/multifile/Makefile gst/mve/Makefile gst/nsf/Makefile gst/nuvdemux/Makefile +gst/rawparse/Makefile gst/replaygain/Makefile gst/rtpmanager/Makefile gst/sdp/Makefile @@ -1087,7 +1088,6 @@ gst/speexresample/Makefile gst/stereo/Makefile gst/switch/Makefile gst/tta/Makefile -gst/videoparse/Makefile gst/videosignal/Makefile gst/vmnc/Makefile gst/xingheader/Makefile diff --git a/gst/rawparse/Makefile.am b/gst/rawparse/Makefile.am new file mode 100644 index 00000000..ba235ea0 --- /dev/null +++ b/gst/rawparse/Makefile.am @@ -0,0 +1,8 @@ + +plugin_LTLIBRARIES = libgstrawparse.la + +libgstrawparse_la_SOURCES = gstrawparse.c gstaudioparse.c gstvideoparse.c plugin.c +libgstrawparse_la_CFLAGS = $(GST_CFLAGS) $(GST_PLUGINS_BASE_CFLAGS) +libgstrawparse_la_LIBADD = $(GST_LIBS) $(GST_BASE_LIBS) +libgstrawparse_la_LDFLAGS = $(GST_PLUGIN_LDFLAGS) + diff --git a/gst/rawparse/README b/gst/rawparse/README new file mode 100644 index 00000000..0a698c90 --- /dev/null +++ b/gst/rawparse/README @@ -0,0 +1,23 @@ + +videoparse +========== + +The videoparse element is used to parse a file containing raw image +data. + + +Creating example data +===================== + +gst-launch videotestsrc num_buffers=300 ! \ + video/x-raw-yuv,format=\(fourcc\)I420,width=320,height=240 ! \ + filesink location=raw + + +Reading example data +==================== + +gst-launch filesrc location=raw ! \ + videoparse format=I420 width=320 height=240 framerate=30/1 ! \ + xvimagesink + diff --git a/gst/rawparse/gstaudioparse.c b/gst/rawparse/gstaudioparse.c new file mode 100644 index 00000000..b8fcd82d --- /dev/null +++ b/gst/rawparse/gstaudioparse.c @@ -0,0 +1,319 @@ +/* GStreamer + * Copyright (C) 2007 Sebastian Dröge + * + * gstaudioparse.c: + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ +/** + * SECTION:element-audioparse + * @short_description: parses a byte stream into audio frames + * + * Converts a byte stream into audio frames. + */ + +#ifdef HAVE_CONFIG_H +# include "config.h" +#endif + +#include "gstaudioparse.h" + +typedef enum +{ + GST_AUDIO_PARSE_FORMAT_INT, + GST_AUDIO_PARSE_FORMAT_FLOAT +} GstAudioParseFormat; + +typedef enum +{ + GST_AUDIO_PARSE_ENDIANNESS_LITTLE = 1234, + GST_AUDIO_PARSE_ENDIANNESS_BIG = 4321 +} GstAudioParseEndianness; + +static void gst_audio_parse_set_property (GObject * object, guint prop_id, + const GValue * value, GParamSpec * pspec); +static void gst_audio_parse_get_property (GObject * object, guint prop_id, + GValue * value, GParamSpec * pspec); + +static GstCaps *gst_audio_parse_get_caps (GstRawParse * rp); + +static void gst_audio_parse_update_frame_size (GstAudioParse * ap); + +GST_DEBUG_CATEGORY_STATIC (gst_audio_parse_debug); +#define GST_CAT_DEFAULT gst_audio_parse_debug + +static const GstElementDetails gst_audio_parse_details = +GST_ELEMENT_DETAILS ("Audio Parse", + "Filter/Audio", + "Converts stream into audio frames", + "Sebastian Dröge "); + +enum +{ + ARG_0, + ARG_FORMAT, + ARG_RATE, + ARG_CHANNELS, + ARG_ENDIANNESS, + ARG_WIDTH, + ARG_DEPTH, + ARG_SIGNED, +}; + + +#define GST_AUDIO_PARSE_FORMAT (gst_audio_parse_format_get_type ()) +static GType +gst_audio_parse_format_get_type (void) +{ + static GType audio_parse_format_type = 0; + static const GEnumValue format_types[] = { + {GST_AUDIO_PARSE_FORMAT_INT, "Integer", "int"}, + {GST_AUDIO_PARSE_FORMAT_FLOAT, "Floating Point", "float"}, + {0, NULL, NULL} + }; + + if (!audio_parse_format_type) { + audio_parse_format_type = + g_enum_register_static ("GstAudioParseFormat", format_types); + } + + return audio_parse_format_type; +} + +#define GST_AUDIO_PARSE_ENDIANNESS (gst_audio_parse_endianness_get_type ()) +static GType +gst_audio_parse_endianness_get_type (void) +{ + static GType audio_parse_endianness_type = 0; + static const GEnumValue endian_types[] = { + {GST_AUDIO_PARSE_ENDIANNESS_LITTLE, "Little Endian", "little"}, + {GST_AUDIO_PARSE_ENDIANNESS_BIG, "Big Endian", "big"}, + {0, NULL, NULL} + }; + + if (!audio_parse_endianness_type) { + audio_parse_endianness_type = + g_enum_register_static ("GstAudioParseEndianness", endian_types); + } + + return audio_parse_endianness_type; +} + +GST_BOILERPLATE (GstAudioParse, gst_audio_parse, GstRawParse, + GST_TYPE_RAW_PARSE); + +static void +gst_audio_parse_base_init (gpointer g_class) +{ + GstRawParseClass *rp_class = GST_RAW_PARSE_CLASS (g_class); + GstElementClass *gstelement_class = GST_ELEMENT_CLASS (g_class); + GstCaps *caps; + + GST_DEBUG_CATEGORY_INIT (gst_audio_parse_debug, "audioparse", 0, + "audioparse element"); + + gst_element_class_set_details (gstelement_class, &gst_audio_parse_details); + + caps = + gst_caps_from_string ("audio/x-raw-int," + " depth=(int) [ 1, 32 ]," + " width=(int) { 8, 16, 24, 32 }," + " endianness=(int) { LITTLE_ENDIAN, BIG_ENDIAN }, " + " signed=(bool) { TRUE, FALSE }," + " rate=(int) [ 1, MAX ]," + " channels=(int) [ 1, MAX ]; " + "audio/x-raw-float," + " width=(int) { 32, 64 }," + " endianness=(int) { LITTLE_ENDIAN, BIG_ENDIAN }, " + " rate=(int)[1,MAX]," " channels=(int)[1,MAX]"); + + gst_raw_parse_class_set_src_pad_template (rp_class, caps); + gst_raw_parse_class_set_multiple_frames_per_buffer (rp_class, TRUE); + gst_caps_unref (caps); +} + +static void +gst_audio_parse_class_init (GstAudioParseClass * klass) +{ + GObjectClass *gobject_class = G_OBJECT_CLASS (klass); + GstRawParseClass *rp_class = GST_RAW_PARSE_CLASS (klass); + + gobject_class->set_property = gst_audio_parse_set_property; + gobject_class->get_property = gst_audio_parse_get_property; + + rp_class->get_caps = gst_audio_parse_get_caps; + + g_object_class_install_property (gobject_class, ARG_FORMAT, + g_param_spec_enum ("format", "Format", + "Format of audio samples in raw stream", GST_AUDIO_PARSE_FORMAT, + GST_AUDIO_PARSE_FORMAT_INT, G_PARAM_READWRITE)); + + g_object_class_install_property (gobject_class, ARG_RATE, + g_param_spec_int ("rate", "Rate", "Rate of audio samples in raw stream", + 1, INT_MAX, 44100, G_PARAM_READWRITE)); + + g_object_class_install_property (gobject_class, ARG_CHANNELS, + g_param_spec_int ("channels", "Channels", + "Number of channels in raw stream", 1, INT_MAX, 2, + G_PARAM_READWRITE)); + + g_object_class_install_property (gobject_class, ARG_WIDTH, + g_param_spec_int ("width", "Width", + "Width of audio samples in raw stream", 1, INT_MAX, 16, + G_PARAM_READWRITE)); + + g_object_class_install_property (gobject_class, ARG_DEPTH, + g_param_spec_int ("depth", "Depth", + "Depth of audio samples in raw stream", 1, INT_MAX, 16, + G_PARAM_READWRITE)); + + g_object_class_install_property (gobject_class, ARG_SIGNED, + g_param_spec_boolean ("signed", "signed", + "Sign of audio samples in raw stream", TRUE, G_PARAM_READWRITE)); + + g_object_class_install_property (gobject_class, ARG_ENDIANNESS, + g_param_spec_enum ("endianness", "Endianness", + "Endianness of audio samples in raw stream", + GST_AUDIO_PARSE_ENDIANNESS, G_BYTE_ORDER, G_PARAM_READWRITE)); +} + +static void +gst_audio_parse_init (GstAudioParse * ap, GstAudioParseClass * g_class) +{ + ap->format = GST_AUDIO_PARSE_FORMAT_INT; + ap->channels = 2; + ap->width = 16; + ap->depth = 16; + ap->signedness = TRUE; + ap->endianness = G_BYTE_ORDER; + + gst_audio_parse_update_frame_size (ap); + gst_raw_parse_set_fps (GST_RAW_PARSE (ap), 44100, 1); +} + +static void +gst_audio_parse_set_property (GObject * object, guint prop_id, + const GValue * value, GParamSpec * pspec) +{ + GstAudioParse *ap = GST_AUDIO_PARSE (object); + + g_return_if_fail (!gst_raw_parse_is_negotiated (GST_RAW_PARSE (ap))); + + switch (prop_id) { + case ARG_FORMAT: + ap->format = g_value_get_enum (value); + break; + case ARG_RATE: + gst_raw_parse_set_fps (GST_RAW_PARSE (ap), g_value_get_int (value), 1); + break; + case ARG_CHANNELS: + ap->channels = g_value_get_int (value); + break; + case ARG_WIDTH: + ap->width = g_value_get_int (value); + break; + case ARG_DEPTH: + ap->depth = g_value_get_int (value); + break; + case ARG_SIGNED: + ap->signedness = g_value_get_boolean (value); + break; + case ARG_ENDIANNESS: + ap->endianness = g_value_get_enum (value); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); + break; + } + + gst_audio_parse_update_frame_size (ap); +} + +static void +gst_audio_parse_get_property (GObject * object, guint prop_id, GValue * value, + GParamSpec * pspec) +{ + GstAudioParse *ap = GST_AUDIO_PARSE (object); + + switch (prop_id) { + case ARG_FORMAT: + g_value_set_enum (value, ap->format); + break; + case ARG_RATE:{ + gint fps_n, fps_d; + + gst_raw_parse_get_fps (GST_RAW_PARSE (ap), &fps_n, &fps_d); + g_value_set_int (value, fps_n); + break; + } + case ARG_CHANNELS: + g_value_set_int (value, ap->channels); + break; + case ARG_WIDTH: + g_value_set_int (value, ap->width); + break; + case ARG_DEPTH: + g_value_set_int (value, ap->depth); + break; + case ARG_SIGNED: + g_value_set_boolean (value, ap->signedness); + break; + case ARG_ENDIANNESS: + g_value_set_enum (value, ap->endianness); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); + break; + } +} + +void +gst_audio_parse_update_frame_size (GstAudioParse * ap) +{ + gint framesize; + + framesize = (ap->width / 8) * ap->channels; + + gst_raw_parse_set_framesize (GST_RAW_PARSE (ap), framesize); +} + +static GstCaps * +gst_audio_parse_get_caps (GstRawParse * rp) +{ + GstAudioParse *ap = GST_AUDIO_PARSE (rp); + GstCaps *caps; + + gint fps_n, fps_d; + + gst_raw_parse_get_fps (rp, &fps_n, &fps_d); + + if (ap->format == GST_AUDIO_PARSE_FORMAT_INT) { + caps = gst_caps_new_simple ("audio/x-raw-int", + "rate", G_TYPE_INT, fps_n, + "channels", G_TYPE_INT, ap->channels, + "width", G_TYPE_INT, ap->width, + "depth", G_TYPE_INT, ap->depth, + "signed", G_TYPE_BOOLEAN, ap->signedness, + "endianness", G_TYPE_INT, ap->endianness, NULL); + } else { + caps = gst_caps_new_simple ("audio/x-raw-float", + "rate", G_TYPE_INT, fps_n, + "channels", G_TYPE_INT, ap->channels, + "width", G_TYPE_INT, ap->width, + "endianness", G_TYPE_INT, ap->endianness, NULL); + } + return caps; +} diff --git a/gst/rawparse/gstaudioparse.h b/gst/rawparse/gstaudioparse.h new file mode 100644 index 00000000..86c8fe2a --- /dev/null +++ b/gst/rawparse/gstaudioparse.h @@ -0,0 +1,66 @@ +/* GStreamer + * Copyright (C) 2007 Sebastian Dröge + * + * gstaudioparse.h: + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + +#ifndef __GST_AUDIO_PARSE_H__ +#define __GST_AUDIO_PARSE_H__ + +#include +#include +#include + +#include "gstrawparse.h" + +#define GST_TYPE_AUDIO_PARSE \ + (gst_audio_parse_get_type()) +#define GST_AUDIO_PARSE(obj) \ + (G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_AUDIO_PARSE,GstAudioParse)) +#define GST_AUDIO_PARSE_CLASS(klass) \ + (G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_AUDIO_PARSE,GstAudioParseClass)) +#define GST_IS_AUDIO_PARSE(obj) \ + (G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_AUDIO_PARSE)) +#define GST_IS_AUDIO_PARSE_CLASS(klass) \ + (G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_AUDIO_PARSE)) + +typedef struct _GstAudioParse GstAudioParse; +typedef struct _GstAudioParseClass GstAudioParseClass; + +struct _GstAudioParse +{ + GstRawParse parent; + + /* properties */ + gint format; + gint channels; + gint width; + gint depth; + gint signedness; + gint endianness; +}; + +struct _GstAudioParseClass +{ + GstRawParseClass parent_class; +}; + + +GType gst_audio_parse_get_type (void); + +#endif /* __GST_AUDIO_PARSE_H__ */ diff --git a/gst/rawparse/gstrawparse.c b/gst/rawparse/gstrawparse.c new file mode 100644 index 00000000..9714bba2 --- /dev/null +++ b/gst/rawparse/gstrawparse.c @@ -0,0 +1,598 @@ +/* GStreamer + * Copyright (C) 2006 David A. Schleef + * Copyright (C) 2007 Sebastian Dröge + * + * gstrawparse.c: + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + +/* TODO: - Add locking where appropiate + */ + +#ifdef HAVE_CONFIG_H +# include "config.h" +#endif + +#include +#include +#include + +#include "gstrawparse.h" + +static void gst_raw_parse_dispose (GObject * object); + +static GstFlowReturn gst_raw_parse_chain (GstPad * pad, GstBuffer * buffer); +static gboolean gst_raw_parse_sink_event (GstPad * pad, GstEvent * event); +static gboolean gst_raw_parse_src_event (GstPad * pad, GstEvent * event); +static const GstQueryType *gst_raw_parse_src_query_type (GstPad * pad); +static gboolean gst_raw_parse_src_query (GstPad * pad, GstQuery * query); +static gboolean gst_raw_parse_convert (GstRawParse * rp, + GstFormat src_format, gint64 src_value, + GstFormat dest_format, gint64 * dest_value); + +static GstStaticPadTemplate gst_raw_parse_sink_pad_template = +GST_STATIC_PAD_TEMPLATE ("sink", + GST_PAD_SINK, + GST_PAD_ALWAYS, + GST_STATIC_CAPS_ANY); + +GST_DEBUG_CATEGORY_STATIC (gst_raw_parse_debug); +#define GST_CAT_DEFAULT gst_raw_parse_debug + +static const GstElementDetails raw_parse_details = +GST_ELEMENT_DETAILS ("Raw parser base class", + "Filter/Raw", + "Parses byte streams into raw frames", + "Sebastian Dröge "); + +GST_BOILERPLATE (GstRawParse, gst_raw_parse, GstElement, GST_TYPE_ELEMENT); + +static void +gst_raw_parse_base_init (gpointer g_class) +{ + GstElementClass *gstelement_class = GST_ELEMENT_CLASS (g_class); + + GST_DEBUG_CATEGORY_INIT (gst_raw_parse_debug, "rawparse", 0, + "rawparse element"); + + gst_element_class_add_pad_template (gstelement_class, + gst_static_pad_template_get (&gst_raw_parse_sink_pad_template)); + gst_element_class_set_details (gstelement_class, &raw_parse_details); +} + +static void +gst_raw_parse_class_init (GstRawParseClass * klass) +{ + GObjectClass *gobject_class = G_OBJECT_CLASS (klass); + + gobject_class->dispose = gst_raw_parse_dispose; +} + +static void +gst_raw_parse_init (GstRawParse * rp, GstRawParseClass * g_class) +{ + GstPadTemplate *src_pad_template; + GstElementClass *element_class = GST_ELEMENT_CLASS (g_class); + + rp->sinkpad = + gst_pad_new_from_static_template (&gst_raw_parse_sink_pad_template, + "sink"); + gst_element_add_pad (GST_ELEMENT (rp), rp->sinkpad); + + gst_pad_set_chain_function (rp->sinkpad, gst_raw_parse_chain); + gst_pad_set_event_function (rp->sinkpad, gst_raw_parse_sink_event); + + src_pad_template = gst_element_class_get_pad_template (element_class, "src"); + + if (src_pad_template) { + rp->srcpad = gst_pad_new_from_template (src_pad_template, "src"); + } else { + GstCaps *caps; + + GST_WARNING ("Subclass didn't specify a src pad template, using ANY caps"); + rp->srcpad = gst_pad_new ("src", GST_PAD_SRC); + caps = gst_caps_new_any (); + gst_pad_set_caps (rp->srcpad, caps); + gst_caps_unref (caps); + } + + gst_element_add_pad (GST_ELEMENT (rp), rp->srcpad); + g_object_unref (src_pad_template); + + gst_pad_set_event_function (rp->srcpad, gst_raw_parse_src_event); + + gst_pad_set_query_type_function (rp->srcpad, gst_raw_parse_src_query_type); + gst_pad_set_query_function (rp->srcpad, gst_raw_parse_src_query); + + rp->adapter = gst_adapter_new (); + + rp->fps_n = 1; + rp->fps_d = 0; + rp->framesize = 1; +} + +static void +gst_raw_parse_dispose (GObject * object) +{ + GstRawParse *rp = GST_RAW_PARSE (object); + + if (rp->adapter) { + g_object_unref (rp->adapter); + rp->adapter = NULL; + } + + G_OBJECT_CLASS (parent_class)->dispose (object); +} + +void +gst_raw_parse_class_set_src_pad_template (GstRawParseClass * klass, + const GstCaps * allowed_caps) +{ + GstElementClass *element_class = GST_ELEMENT_CLASS (klass); + + g_return_if_fail (GST_IS_RAW_PARSE_CLASS (klass)); + g_return_if_fail (allowed_caps != NULL); + g_return_if_fail (GST_IS_CAPS (allowed_caps)); + + gst_element_class_add_pad_template (element_class, + gst_pad_template_new ("src", GST_PAD_SRC, GST_PAD_ALWAYS, + gst_caps_copy (allowed_caps))); +} + +void +gst_raw_parse_class_set_multiple_frames_per_buffer (GstRawParseClass * klass, + gboolean multiple_frames) +{ + g_return_if_fail (GST_IS_RAW_PARSE_CLASS (klass)); + + klass->multiple_frames_per_buffer = multiple_frames; +} + +static void +gst_raw_parse_reset (GstRawParse * rp) +{ + rp->n_frames = 0; + rp->discont = TRUE; + + gst_segment_init (&rp->segment, GST_FORMAT_TIME); + gst_adapter_clear (rp->adapter); +} + +static GstFlowReturn +gst_raw_parse_chain (GstPad * pad, GstBuffer * buffer) +{ + GstRawParse *rp = GST_RAW_PARSE (gst_pad_get_parent (pad)); + GstFlowReturn ret = GST_FLOW_OK; + GstRawParseClass *rp_class = GST_RAW_PARSE_GET_CLASS (rp); + guint buffersize, nframes; + + if (G_UNLIKELY (GST_BUFFER_FLAG_IS_SET (buffer, GST_BUFFER_FLAG_DISCONT))) { + GST_DEBUG_OBJECT (rp, "received DISCONT buffer"); + + rp->discont = TRUE; + } + + if (!rp->negotiated) { + GstCaps *caps; + + if (rp_class->get_caps) { + caps = rp_class->get_caps (rp); + } else { + GST_WARNING + ("Subclass doesn't implement get_caps() method, using ANY caps"); + caps = gst_caps_new_any (); + } + + rp->negotiated = gst_pad_set_caps (rp->srcpad, caps); + } + + g_return_val_if_fail (rp->negotiated, GST_FLOW_ERROR); + + gst_adapter_push (rp->adapter, buffer); + + if (rp_class->multiple_frames_per_buffer) { + buffersize = gst_adapter_available (rp->adapter); + buffersize -= buffersize % rp->framesize; + nframes = buffersize / rp->framesize; + } else { + buffersize = rp->framesize; + nframes = 1; + } + + while (gst_adapter_available (rp->adapter) >= buffersize) { + buffer = gst_adapter_take_buffer (rp->adapter, buffersize); + + if (rp->fps_n) { + GST_BUFFER_TIMESTAMP (buffer) = rp->segment.start + + gst_util_uint64_scale (rp->n_frames, GST_SECOND * rp->fps_d, + rp->fps_n); + GST_BUFFER_DURATION (buffer) = + gst_util_uint64_scale (nframes * GST_SECOND, rp->fps_d, rp->fps_n); + } else { + GST_BUFFER_TIMESTAMP (buffer) = rp->segment.start; + GST_BUFFER_DURATION (buffer) = GST_CLOCK_TIME_NONE; + } + gst_buffer_set_caps (buffer, GST_PAD_CAPS (rp->srcpad)); + if (rp->discont) { + GST_BUFFER_FLAG_SET (buffer, GST_BUFFER_FLAG_DISCONT); + rp->discont = FALSE; + } + + rp->n_frames += nframes; + + ret = gst_pad_push (rp->srcpad, buffer); + if (ret != GST_FLOW_OK) + break; + } + + gst_object_unref (rp); + return ret; +} + +static gboolean +gst_raw_parse_convert (GstRawParse * rp, + GstFormat src_format, gint64 src_value, + GstFormat dest_format, gint64 * dest_value) +{ + gboolean ret = FALSE; + + GST_DEBUG ("converting value %" G_GINT64_FORMAT " from %s to %s", + src_value, gst_format_get_name (src_format), + gst_format_get_name (dest_format)); + + if (src_format == dest_format) { + *dest_value = src_value; + ret = TRUE; + goto done; + } + + if (src_value == -1) { + *dest_value = -1; + ret = TRUE; + goto done; + } + + /* bytes to frames */ + if (src_format == GST_FORMAT_BYTES && dest_format == GST_FORMAT_DEFAULT) { + if (rp->framesize != 0) { + *dest_value = gst_util_uint64_scale_int (src_value, 1, rp->framesize); + } else { + GST_ERROR ("framesize is 0"); + *dest_value = 0; + } + ret = TRUE; + goto done; + } + + /* frames to bytes */ + if (src_format == GST_FORMAT_DEFAULT && dest_format == GST_FORMAT_BYTES) { + *dest_value = gst_util_uint64_scale_int (src_value, rp->framesize, 1); + ret = TRUE; + goto done; + } + + /* time to frames */ + if (src_format == GST_FORMAT_TIME && dest_format == GST_FORMAT_DEFAULT) { + if (rp->fps_d != 0) { + *dest_value = gst_util_uint64_scale (src_value, + rp->fps_n, GST_SECOND * rp->fps_d); + } else { + GST_ERROR ("framerate denominator is 0"); + *dest_value = 0; + } + ret = TRUE; + goto done; + } + + /* frames to time */ + if (src_format == GST_FORMAT_DEFAULT && dest_format == GST_FORMAT_TIME) { + if (rp->fps_n != 0) { + *dest_value = gst_util_uint64_scale (src_value, + GST_SECOND * rp->fps_d, rp->fps_n); + } else { + GST_ERROR ("framerate numerator is 0"); + *dest_value = 0; + } + ret = TRUE; + goto done; + } + + /* time to bytes */ + if (src_format == GST_FORMAT_TIME && dest_format == GST_FORMAT_BYTES) { + if (rp->fps_d != 0) { + *dest_value = gst_util_uint64_scale (src_value, + rp->fps_n * rp->framesize, GST_SECOND * rp->fps_d); + } else { + GST_ERROR ("framerate denominator is 0"); + *dest_value = 0; + } + ret = TRUE; + goto done; + } + + /* bytes to time */ + if (src_format == GST_FORMAT_BYTES && dest_format == GST_FORMAT_TIME) { + if (rp->fps_n != 0 && rp->framesize != 0) { + *dest_value = gst_util_uint64_scale (src_value, + GST_SECOND * rp->fps_d, rp->fps_n * rp->framesize); + } else { + GST_ERROR ("framerate denominator and/or framesize is 0"); + *dest_value = 0; + } + ret = TRUE; + } + +done: + + GST_DEBUG ("ret=%d result %" G_GINT64_FORMAT, ret, *dest_value); + + return ret; +} + + +static gboolean +gst_raw_parse_sink_event (GstPad * pad, GstEvent * event) +{ + GstRawParse *rp = GST_RAW_PARSE (gst_pad_get_parent (pad)); + gboolean ret; + + switch (GST_EVENT_TYPE (event)) { + case GST_EVENT_FLUSH_STOP: + gst_raw_parse_reset (rp); + ret = gst_pad_push_event (rp->srcpad, event); + break; + case GST_EVENT_NEWSEGMENT: + { + GstClockTimeDiff start, stop, time; + gdouble rate, arate; + gboolean update; + GstFormat format; + + gst_event_parse_new_segment_full (event, &update, &rate, &arate, &format, + &start, &stop, &time); + + if (format == GST_FORMAT_TIME) { + ret = gst_pad_push_event (rp->srcpad, event); + gst_segment_set_newsegment_full (&rp->segment, update, rate, arate, + GST_FORMAT_TIME, start, stop, time); + } else { + + gst_event_unref (event); + + ret = + gst_raw_parse_convert (rp, format, start, GST_FORMAT_TIME, &start); + ret &= gst_raw_parse_convert (rp, format, time, GST_FORMAT_TIME, &time); + ret &= gst_raw_parse_convert (rp, format, stop, GST_FORMAT_TIME, &stop); + if (!ret) { + GST_ERROR_OBJECT (rp, + "Failed converting to GST_FORMAT_TIME format (%d)", format); + break; + } + + gst_segment_set_newsegment_full (&rp->segment, update, rate, arate, + GST_FORMAT_TIME, start, stop, time); + event = gst_event_new_new_segment (FALSE, rp->segment.rate, + GST_FORMAT_TIME, start, stop, time); + + ret = gst_pad_push_event (rp->srcpad, event); + } + + if (ret) { + rp->n_frames = 0; + rp->discont = TRUE; + gst_adapter_clear (rp->adapter); + } + break; + } + default: + ret = gst_pad_event_default (rp->sinkpad, event); + break; + } + + gst_object_unref (rp); + + return ret; +} + +static gboolean +gst_raw_parse_src_event (GstPad * pad, GstEvent * event) +{ + GstRawParse *rp = GST_RAW_PARSE (gst_pad_get_parent (pad)); + gboolean ret; + + switch (GST_EVENT_TYPE (event)) { + case GST_EVENT_SEEK:{ + GstFormat format; + gdouble rate; + GstSeekFlags flags; + GstSeekType start_type, stop_type; + gint64 start, stop; + + gst_event_parse_seek (event, &rate, &format, &flags, &start_type, &start, + &stop_type, &stop); + + /* First try if upstream handles the seek */ + ret = gst_pad_push_event (rp->sinkpad, event); + if (ret) + goto done; + + /* Otherwise convert to bytes and push upstream */ + if (format == GST_FORMAT_TIME || format == GST_FORMAT_DEFAULT) { + gst_event_unref (event); + + ret = + gst_raw_parse_convert (rp, format, start, GST_FORMAT_BYTES, &start); + ret &= + gst_raw_parse_convert (rp, format, stop, GST_FORMAT_BYTES, &stop); + + if (ret) { + event = + gst_event_new_seek (rate, GST_FORMAT_BYTES, flags, start_type, + start, stop_type, stop); + + ret = gst_pad_push_event (rp->sinkpad, event); + } + } + break; + } + default: + ret = gst_pad_event_default (rp->srcpad, event); + break; + } + +done: + gst_object_unref (rp); + + return ret; +} + +static const GstQueryType * +gst_raw_parse_src_query_type (GstPad * pad) +{ + static const GstQueryType types[] = { + GST_QUERY_POSITION, + GST_QUERY_DURATION, + GST_QUERY_CONVERT, + 0 + }; + + return types; +} + +static gboolean +gst_raw_parse_src_query (GstPad * pad, GstQuery * query) +{ + GstRawParse *rp = GST_RAW_PARSE (gst_pad_get_parent (pad)); + gboolean ret = FALSE; + + GST_DEBUG ("src_query %s", gst_query_type_get_name (GST_QUERY_TYPE (query))); + + switch (GST_QUERY_TYPE (query)) { + case GST_QUERY_POSITION: + { + GstFormat format; + gint64 time, value; + + GST_LOG ("query position"); + + gst_query_parse_position (query, &format, NULL); + + time = gst_util_uint64_scale (rp->n_frames, + GST_SECOND * rp->fps_d, rp->fps_n); + ret = gst_raw_parse_convert (rp, GST_FORMAT_TIME, time, format, &value); + + gst_query_set_position (query, format, value); + + break; + } + case GST_QUERY_DURATION:{ + gint64 duration; + GstFormat format; + GstQuery *bquery; + + GST_LOG ("query duration"); + ret = gst_pad_peer_query (rp->srcpad, query); + if (ret) + goto done; + + gst_query_parse_duration (query, &format, NULL); + /* We only handle TIME and DEFAULT format */ + if (format != GST_FORMAT_TIME && format != GST_FORMAT_DEFAULT) + goto error; + + bquery = gst_query_new_duration (GST_FORMAT_BYTES); + ret = gst_pad_peer_query (rp->srcpad, bquery); + + if (!ret) { + gst_query_unref (bquery); + goto error; + } + + gst_query_parse_duration (bquery, NULL, &duration); + gst_query_unref (bquery); + + ret = + gst_raw_parse_convert (rp, GST_FORMAT_BYTES, duration, format, + &duration); + if (ret) + gst_query_set_duration (query, format, duration); + + break; + } + case GST_QUERY_CONVERT: + { + GstFormat src_fmt, dest_fmt; + gint64 src_val, dest_val; + + GST_LOG ("query convert"); + + gst_query_parse_convert (query, &src_fmt, &src_val, &dest_fmt, &dest_val); + ret = gst_raw_parse_convert (rp, src_fmt, src_val, dest_fmt, &dest_val); + if (!ret) + goto error; + gst_query_set_convert (query, src_fmt, src_val, dest_fmt, dest_val); + break; + } + default: + /* else forward upstream */ + ret = gst_pad_peer_query (rp->sinkpad, query); + break; + } + +done: + gst_object_unref (rp); + return ret; +error: + GST_DEBUG_OBJECT (rp, "query failed"); + goto done; +} + +void +gst_raw_parse_set_framesize (GstRawParse * rp, int framesize) +{ + g_return_if_fail (GST_IS_RAW_PARSE (rp)); + g_return_if_fail (!rp->negotiated); + + rp->framesize = framesize; +} + +void +gst_raw_parse_set_fps (GstRawParse * rp, int fps_n, int fps_d) +{ + g_return_if_fail (GST_IS_RAW_PARSE (rp)); + g_return_if_fail (!rp->negotiated); + + rp->fps_n = fps_n; + rp->fps_d = fps_d; +} + +void +gst_raw_parse_get_fps (GstRawParse * rp, int *fps_n, int *fps_d) +{ + g_return_if_fail (GST_IS_RAW_PARSE (rp)); + + *fps_n = rp->fps_n; + *fps_d = rp->fps_d; +} + +gboolean +gst_raw_parse_is_negotiated (GstRawParse * rp) +{ + g_return_val_if_fail (GST_IS_RAW_PARSE (rp), FALSE); + + return rp->negotiated; +} diff --git a/gst/rawparse/gstrawparse.h b/gst/rawparse/gstrawparse.h new file mode 100644 index 00000000..dd486c34 --- /dev/null +++ b/gst/rawparse/gstrawparse.h @@ -0,0 +1,91 @@ +/* GStreamer + * Copyright (C) 2006 David A. Schleef + * Copyright (C) 2007 Sebastian Dröge + * + * gstrawparse.h: + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + +#ifndef __GST_RAW_PARSE_H__ +#define __GST_RAW_PARSE_H__ + +#include +#include +#include + +G_BEGIN_DECLS + +#define GST_TYPE_RAW_PARSE \ + (gst_raw_parse_get_type()) +#define GST_RAW_PARSE(obj) \ + (G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_RAW_PARSE,GstRawParse)) +#define GST_RAW_PARSE_CLASS(klass) \ + (G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_RAW_PARSE,GstRawParseClass)) +#define GST_RAW_PARSE_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj),GST_TYPE_RAW_PARSE,GstRawParseClass)) +#define GST_IS_RAW_PARSE(obj) \ + (G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_RAW_PARSE)) +#define GST_IS_RAW_PARSE_CLASS(klass) \ + (G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_RAW_PARSE)) + +typedef struct _GstRawParse GstRawParse; +typedef struct _GstRawParseClass GstRawParseClass; + +struct _GstRawParse +{ + GstElement parent; + + /* private */ + GstPad *sinkpad; + GstPad *srcpad; + + GstAdapter *adapter; + + int framesize; + int fps_d; + int fps_n; + + gboolean discont; + guint64 n_frames; + + GstSegment segment; + + gboolean negotiated; + gboolean have_new_segment; +}; + +struct _GstRawParseClass +{ + GstElementClass parent_class; + + GstCaps * (*get_caps) (GstRawParse *rp); + + gboolean multiple_frames_per_buffer; +}; + +GType gst_raw_parse_get_type (void); + +void gst_raw_parse_class_set_src_pad_template (GstRawParseClass *klass, const GstCaps * allowed_caps); +void gst_raw_parse_class_set_multiple_frames_per_buffer (GstRawParseClass *klass, gboolean multiple_frames); + +void gst_raw_parse_set_framesize (GstRawParse *rp, int framesize); +void gst_raw_parse_set_fps (GstRawParse *rp, int fps_n, int fps_d); +void gst_raw_parse_get_fps (GstRawParse *rp, int *fps_n, int *fps_d); +gboolean gst_raw_parse_is_negotiated (GstRawParse *rp); + +G_END_DECLS + +#endif /* __GST_RAW_PARSE_H__ */ diff --git a/gst/rawparse/gstvideoparse.c b/gst/rawparse/gstvideoparse.c new file mode 100644 index 00000000..8f090f72 --- /dev/null +++ b/gst/rawparse/gstvideoparse.c @@ -0,0 +1,422 @@ +/* GStreamer + * Copyright (C) 2006 David A. Schleef + * Copyright (C) 2007 Sebastian Dröge + * + * gstvideoparse.c: + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ +/** + * SECTION:element-videoparse + * @short_description: parses a byte stream into video frames + * + * Converts a byte stream into video frames. + */ + +#ifdef HAVE_CONFIG_H +# include "config.h" +#endif + +#include "gstvideoparse.h" + +typedef enum +{ + GST_VIDEO_PARSE_FORMAT_I420, + GST_VIDEO_PARSE_FORMAT_YV12, + GST_VIDEO_PARSE_FORMAT_YUY2, + GST_VIDEO_PARSE_FORMAT_UYVY, + GST_VIDEO_PARSE_FORMAT_RGB = 10, + GST_VIDEO_PARSE_FORMAT_GRAY +} GstVideoParseFormat; + +typedef enum +{ + GST_VIDEO_PARSE_ENDIANNESS_LITTLE = 1234, + GST_VIDEO_PARSE_ENDIANNESS_BIG = 4321 +} GstVideoParseEndianness; + +static void gst_video_parse_set_property (GObject * object, guint prop_id, + const GValue * value, GParamSpec * pspec); +static void gst_video_parse_get_property (GObject * object, guint prop_id, + GValue * value, GParamSpec * pspec); + +static GstCaps *gst_video_parse_get_caps (GstRawParse * rp); + +static void gst_video_parse_update_frame_size (GstVideoParse * vp); + +GST_DEBUG_CATEGORY_STATIC (gst_video_parse_debug); +#define GST_CAT_DEFAULT gst_video_parse_debug + +static const GstElementDetails gst_video_parse_details = +GST_ELEMENT_DETAILS ("Video Parse", + "Filter/Video", + "Converts stream into video frames", + "David Schleef , " + "Sebastian Dröge "); + +enum +{ + ARG_0, + ARG_WIDTH, + ARG_HEIGHT, + ARG_FORMAT, + ARG_PAR, + ARG_FRAMERATE, + ARG_BPP, + ARG_DEPTH, + ARG_ENDIANNESS, + ARG_RED_MASK, + ARG_GREEN_MASK, + ARG_BLUE_MASK, + ARG_ALPHA_MASK +}; + + +#define GST_VIDEO_PARSE_FORMAT (gst_video_parse_format_get_type ()) +static GType +gst_video_parse_format_get_type (void) +{ + static GType video_parse_format_type = 0; + static const GEnumValue format_types[] = { + {GST_VIDEO_PARSE_FORMAT_I420, "I420", "I420"}, + {GST_VIDEO_PARSE_FORMAT_YV12, "YV12", "YV12"}, + {GST_VIDEO_PARSE_FORMAT_YUY2, "YUY2", "YUY2"}, + {GST_VIDEO_PARSE_FORMAT_UYVY, "UYVY", "UYVY"}, + {GST_VIDEO_PARSE_FORMAT_RGB, "RGB", "RGB"}, + {GST_VIDEO_PARSE_FORMAT_GRAY, "GRAY", "GRAY"}, + {0, NULL, NULL} + }; + + if (!video_parse_format_type) { + video_parse_format_type = + g_enum_register_static ("GstVideoParseFormat", format_types); + } + + return video_parse_format_type; +} + +#define GST_VIDEO_PARSE_ENDIANNESS (gst_video_parse_endianness_get_type ()) +static GType +gst_video_parse_endianness_get_type (void) +{ + static GType video_parse_endianness_type = 0; + static const GEnumValue endian_types[] = { + {GST_VIDEO_PARSE_ENDIANNESS_LITTLE, "Little Endian", "little"}, + {GST_VIDEO_PARSE_ENDIANNESS_BIG, "Big Endian", "big"}, + {0, NULL, NULL} + }; + + if (!video_parse_endianness_type) { + video_parse_endianness_type = + g_enum_register_static ("GstVideoParseEndianness", endian_types); + } + + return video_parse_endianness_type; +} + +GST_BOILERPLATE (GstVideoParse, gst_video_parse, GstRawParse, + GST_TYPE_RAW_PARSE); + +static void +gst_video_parse_base_init (gpointer g_class) +{ + GstRawParseClass *rp_class = GST_RAW_PARSE_CLASS (g_class); + GstElementClass *gstelement_class = GST_ELEMENT_CLASS (g_class); + GstCaps *caps; + + GST_DEBUG_CATEGORY_INIT (gst_video_parse_debug, "videoparse", 0, + "videoparse element"); + + gst_element_class_set_details (gstelement_class, &gst_video_parse_details); + + caps = + gst_caps_from_string (GST_VIDEO_CAPS_YUV + ("{ I420, YV12, YUY2, UYVY }") ";" "video/x-raw-rgb; video/x-raw-gray"); + + gst_raw_parse_class_set_src_pad_template (rp_class, caps); + gst_raw_parse_class_set_multiple_frames_per_buffer (rp_class, FALSE); + gst_caps_unref (caps); +} + +static void +gst_video_parse_class_init (GstVideoParseClass * klass) +{ + GObjectClass *gobject_class = G_OBJECT_CLASS (klass); + GstRawParseClass *rp_class = GST_RAW_PARSE_CLASS (klass); + + gobject_class->set_property = gst_video_parse_set_property; + gobject_class->get_property = gst_video_parse_get_property; + + rp_class->get_caps = gst_video_parse_get_caps; + + g_object_class_install_property (gobject_class, ARG_WIDTH, + g_param_spec_int ("width", "Width", "Width of images in raw stream", + 0, INT_MAX, 320, G_PARAM_READWRITE)); + g_object_class_install_property (gobject_class, ARG_HEIGHT, + g_param_spec_int ("height", "Height", "Height of images in raw stream", + 0, INT_MAX, 240, G_PARAM_READWRITE)); + g_object_class_install_property (gobject_class, ARG_FORMAT, + g_param_spec_enum ("format", "Format", "Format of images in raw stream", + GST_VIDEO_PARSE_FORMAT, GST_VIDEO_PARSE_FORMAT_I420, + G_PARAM_READWRITE)); + g_object_class_install_property (gobject_class, ARG_FRAMERATE, + gst_param_spec_fraction ("framerate", "Frame Rate", + "Frame rate of images in raw stream", 0, 1, 100, 1, 25, 1, + G_PARAM_READWRITE)); + g_object_class_install_property (gobject_class, ARG_PAR, + gst_param_spec_fraction ("pixel_aspect_ratio", "Pixel Aspect Ratio", + "Pixel aspect ratio of images in raw stream", 1, 100, 100, 1, 1, 1, + G_PARAM_READWRITE)); + g_object_class_install_property (gobject_class, ARG_BPP, + g_param_spec_int ("bpp", "Bpp", "Bits per pixel of images in raw stream", + 0, INT_MAX, 24, G_PARAM_READWRITE)); + g_object_class_install_property (gobject_class, ARG_DEPTH, + g_param_spec_int ("depth", "Depth", "Depth of images in raw stream", + 0, INT_MAX, 24, G_PARAM_READWRITE)); + g_object_class_install_property (gobject_class, ARG_ENDIANNESS, + g_param_spec_enum ("endianness", "Endianness", + "Endianness of images in raw stream", GST_VIDEO_PARSE_ENDIANNESS, + G_BYTE_ORDER, G_PARAM_READWRITE)); + g_object_class_install_property (gobject_class, ARG_RED_MASK, + g_param_spec_int ("red-mask", "Red mask", + "Red mask of images in raw stream", 0, INT_MAX, + GST_VIDEO_BYTE1_MASK_24_INT, G_PARAM_READWRITE)); + g_object_class_install_property (gobject_class, ARG_GREEN_MASK, + g_param_spec_int ("green-mask", "Green mask", + "Green mask of images in raw stream", 0, INT_MAX, + GST_VIDEO_BYTE2_MASK_24_INT, G_PARAM_READWRITE)); + g_object_class_install_property (gobject_class, ARG_BLUE_MASK, + g_param_spec_int ("blue-mask", "Blue mask", + "Blue mask of images in raw stream", 0, INT_MAX, + GST_VIDEO_BYTE3_MASK_24_INT, G_PARAM_READWRITE)); + g_object_class_install_property (gobject_class, ARG_ALPHA_MASK, + g_param_spec_int ("alpha-mask", "Alpha mask", + "Alpha mask of images in raw stream", 0, INT_MAX, 0, + G_PARAM_READWRITE)); +} + +static void +gst_video_parse_init (GstVideoParse * vp, GstVideoParseClass * g_class) +{ + vp->width = 320; + vp->height = 240; + vp->format = GST_VIDEO_PARSE_FORMAT_I420; + vp->par_n = 1; + vp->par_d = 1; + vp->bpp = 24; + vp->depth = 24; + vp->endianness = G_BYTE_ORDER; + vp->red_mask = GST_VIDEO_BYTE1_MASK_24_INT; + vp->green_mask = GST_VIDEO_BYTE2_MASK_24_INT; + vp->blue_mask = GST_VIDEO_BYTE3_MASK_24_INT; + vp->alpha_mask = 0; + + gst_video_parse_update_frame_size (vp); + gst_raw_parse_set_fps (GST_RAW_PARSE (vp), 25, 1); +} + +static void +gst_video_parse_set_property (GObject * object, guint prop_id, + const GValue * value, GParamSpec * pspec) +{ + GstVideoParse *vp = GST_VIDEO_PARSE (object); + + g_return_if_fail (!gst_raw_parse_is_negotiated (GST_RAW_PARSE (vp))); + + switch (prop_id) { + case ARG_WIDTH: + vp->width = g_value_get_int (value); + break; + case ARG_HEIGHT: + vp->height = g_value_get_int (value); + break; + case ARG_FORMAT: + vp->format = g_value_get_enum (value); + break; + case ARG_FRAMERATE: + gst_raw_parse_set_fps (GST_RAW_PARSE (vp), + gst_value_get_fraction_numerator (value), + gst_value_get_fraction_denominator (value)); + break; + case ARG_PAR: + vp->par_n = gst_value_get_fraction_numerator (value); + vp->par_d = gst_value_get_fraction_denominator (value); + break; + case ARG_BPP: + vp->bpp = g_value_get_int (value); + break; + case ARG_DEPTH: + vp->depth = g_value_get_int (value); + break; + case ARG_ENDIANNESS: + vp->endianness = g_value_get_enum (value); + break; + case ARG_RED_MASK: + vp->red_mask = g_value_get_int (value); + break; + case ARG_GREEN_MASK: + vp->green_mask = g_value_get_int (value); + break; + case ARG_BLUE_MASK: + vp->blue_mask = g_value_get_int (value); + break; + case ARG_ALPHA_MASK: + vp->alpha_mask = g_value_get_int (value); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); + break; + } + + gst_video_parse_update_frame_size (vp); +} + +static void +gst_video_parse_get_property (GObject * object, guint prop_id, GValue * value, + GParamSpec * pspec) +{ + GstVideoParse *vp = GST_VIDEO_PARSE (object); + + switch (prop_id) { + case ARG_WIDTH: + g_value_set_int (value, vp->width); + break; + case ARG_HEIGHT: + g_value_set_int (value, vp->height); + break; + case ARG_FORMAT: + g_value_set_enum (value, vp->format); + break; + case ARG_FRAMERATE:{ + gint fps_n, fps_d; + + gst_raw_parse_get_fps (GST_RAW_PARSE (vp), &fps_n, &fps_d); + gst_value_set_fraction (value, fps_n, fps_d); + break; + } + case ARG_PAR: + gst_value_set_fraction (value, vp->par_n, vp->par_d); + break; + case ARG_BPP: + g_value_set_int (value, vp->bpp); + break; + case ARG_DEPTH: + g_value_set_int (value, vp->depth); + break; + case ARG_ENDIANNESS: + g_value_set_enum (value, vp->endianness); + break; + case ARG_RED_MASK: + g_value_set_int (value, vp->red_mask); + break; + case ARG_GREEN_MASK: + g_value_set_int (value, vp->green_mask); + break; + case ARG_BLUE_MASK: + g_value_set_int (value, vp->blue_mask); + break; + case ARG_ALPHA_MASK: + g_value_set_int (value, vp->alpha_mask); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); + break; + } +} + +static guint32 +gst_video_parse_format_to_fourcc (GstVideoParseFormat format) +{ + switch (format) { + case GST_VIDEO_PARSE_FORMAT_I420: + return GST_MAKE_FOURCC ('I', '4', '2', '0'); + case GST_VIDEO_PARSE_FORMAT_YV12: + return GST_MAKE_FOURCC ('Y', 'V', '1', '2'); + case GST_VIDEO_PARSE_FORMAT_YUY2: + return GST_MAKE_FOURCC ('Y', 'U', 'Y', '2'); + case GST_VIDEO_PARSE_FORMAT_UYVY: + return GST_MAKE_FOURCC ('U', 'Y', 'V', 'Y'); + default: + g_assert_not_reached (); + } + return 0; +} + +void +gst_video_parse_update_frame_size (GstVideoParse * vp) +{ + gint framesize; + + if (vp->format == GST_VIDEO_PARSE_FORMAT_I420 || + vp->format == GST_VIDEO_PARSE_FORMAT_YV12) { + framesize = GST_ROUND_UP_4 (vp->width) * GST_ROUND_UP_2 (vp->height) + + + 2 * (GST_ROUND_UP_8 (vp->width) / 2) * (GST_ROUND_UP_2 (vp->height) / + 2); + } else if (vp->format == GST_VIDEO_PARSE_FORMAT_YUY2 + || vp->format == GST_VIDEO_PARSE_FORMAT_UYVY) { + framesize = GST_ROUND_UP_4 (vp->width * 2) * vp->height; + } else if (vp->format == GST_VIDEO_PARSE_FORMAT_RGB) { + framesize = GST_ROUND_UP_4 (vp->width * vp->bpp) * vp->height; + } else { + framesize = GST_ROUND_UP_4 (vp->width * vp->bpp) * vp->height; + } + + gst_raw_parse_set_framesize (GST_RAW_PARSE (vp), framesize); +} + +static GstCaps * +gst_video_parse_get_caps (GstRawParse * rp) +{ + GstVideoParse *vp = GST_VIDEO_PARSE (rp); + GstCaps *caps; + + gint fps_n, fps_d; + + gst_raw_parse_get_fps (rp, &fps_n, &fps_d); + + if (vp->format < GST_VIDEO_PARSE_FORMAT_RGB) { + caps = gst_caps_new_simple ("video/x-raw-yuv", + "width", G_TYPE_INT, vp->width, + "height", G_TYPE_INT, vp->height, + "format", GST_TYPE_FOURCC, + gst_video_parse_format_to_fourcc (vp->format), "framerate", + GST_TYPE_FRACTION, fps_n, fps_d, "pixel_aspect_ratio", + GST_TYPE_FRACTION, vp->par_n, vp->par_d, NULL); + } else if (vp->format == GST_VIDEO_PARSE_FORMAT_RGB) { + caps = gst_caps_new_simple ("video/x-raw-rgb", + "width", G_TYPE_INT, vp->width, + "height", G_TYPE_INT, vp->height, + "bpp", G_TYPE_INT, vp->bpp, + "depth", G_TYPE_INT, vp->depth, + "framerate", GST_TYPE_FRACTION, fps_n, fps_d, + "pixel_aspect_ratio", GST_TYPE_FRACTION, vp->par_n, vp->par_d, + "red_mask", G_TYPE_INT, vp->red_mask, + "green_mask", G_TYPE_INT, vp->green_mask, + "blue_mask", G_TYPE_INT, vp->blue_mask, + "alpha_mask", G_TYPE_INT, vp->alpha_mask, + "endianness", G_TYPE_INT, vp->endianness, NULL); + } else { + caps = gst_caps_new_simple ("video/x-raw-gray", + "width", G_TYPE_INT, vp->width, + "height", G_TYPE_INT, vp->height, + "bpp", G_TYPE_INT, vp->bpp, + "depth", G_TYPE_INT, vp->depth, + "framerate", GST_TYPE_FRACTION, fps_n, fps_d, + "pixel_aspect_ratio", GST_TYPE_FRACTION, vp->par_n, vp->par_d, NULL); + } + return caps; +} diff --git a/gst/rawparse/gstvideoparse.h b/gst/rawparse/gstvideoparse.h new file mode 100644 index 00000000..a7163161 --- /dev/null +++ b/gst/rawparse/gstvideoparse.h @@ -0,0 +1,74 @@ +/* GStreamer + * Copyright (C) 2006 David A. Schleef + * Copyright (C) 2007 Sebastian Dröge + * + * gstvideoparse.h: + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + +#ifndef __GST_VIDEO_PARSE_H__ +#define __GST_VIDEO_PARSE_H__ + +#include +#include +#include +#include + +#include "gstrawparse.h" + +#define GST_TYPE_VIDEO_PARSE \ + (gst_video_parse_get_type()) +#define GST_VIDEO_PARSE(obj) \ + (G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_VIDEO_PARSE,GstVideoParse)) +#define GST_VIDEO_PARSE_CLASS(klass) \ + (G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_VIDEO_PARSE,GstVideoParseClass)) +#define GST_IS_VIDEO_PARSE(obj) \ + (G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_VIDEO_PARSE)) +#define GST_IS_VIDEO_PARSE_CLASS(klass) \ + (G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_VIDEO_PARSE)) + +typedef struct _GstVideoParse GstVideoParse; +typedef struct _GstVideoParseClass GstVideoParseClass; + +struct _GstVideoParse +{ + GstRawParse parent; + + /* properties */ + int width; + int height; + guint32 format; + int par_n; + int par_d; + int bpp; + int depth; + int endianness; + int red_mask; + int blue_mask; + int green_mask; + int alpha_mask; +}; + +struct _GstVideoParseClass +{ + GstRawParseClass parent_class; +}; + + +GType gst_video_parse_get_type (void); + +#endif /* __GST_VIDEO_PARSE_H__ */ diff --git a/gst/rawparse/plugin.c b/gst/rawparse/plugin.c new file mode 100644 index 00000000..250be6de --- /dev/null +++ b/gst/rawparse/plugin.c @@ -0,0 +1,26 @@ +#ifdef HAVE_CONFIG_H +# include "config.h" +#endif + +#include +#include "gstaudioparse.h" +#include "gstvideoparse.h" + +static gboolean +plugin_init (GstPlugin * plugin) +{ + gboolean ret; + + ret = gst_element_register (plugin, "videoparse", GST_RANK_NONE, + gst_video_parse_get_type ()); + ret &= gst_element_register (plugin, "audioparse", GST_RANK_NONE, + gst_audio_parse_get_type ()); + + return ret; +} + +GST_PLUGIN_DEFINE (GST_VERSION_MAJOR, + GST_VERSION_MINOR, + "rawparse", + "Parses byte streams into raw frames", + plugin_init, VERSION, "LGPL", GST_PACKAGE_NAME, GST_PACKAGE_ORIGIN); -- cgit v1.2.1