From ec6e7c42e2be29611a7e824b78d0be3e46476f0b Mon Sep 17 00:00:00 2001 From: David Schleef Date: Tue, 14 Sep 2010 11:30:33 -0700 Subject: sdi: Add raw SDI muxing/demuxing elements --- gst/sdi/Makefile.am | 14 ++ gst/sdi/gstsdi.c | 44 ++++ gst/sdi/gstsdidemux.c | 553 ++++++++++++++++++++++++++++++++++++++++++++++++++ gst/sdi/gstsdidemux.h | 76 +++++++ gst/sdi/gstsdimux.c | 324 +++++++++++++++++++++++++++++ gst/sdi/gstsdimux.h | 54 +++++ 6 files changed, 1065 insertions(+) create mode 100644 gst/sdi/Makefile.am create mode 100644 gst/sdi/gstsdi.c create mode 100644 gst/sdi/gstsdidemux.c create mode 100644 gst/sdi/gstsdidemux.h create mode 100644 gst/sdi/gstsdimux.c create mode 100644 gst/sdi/gstsdimux.h (limited to 'gst/sdi') diff --git a/gst/sdi/Makefile.am b/gst/sdi/Makefile.am new file mode 100644 index 000000000..160ad85c2 --- /dev/null +++ b/gst/sdi/Makefile.am @@ -0,0 +1,14 @@ +plugin_LTLIBRARIES = libgstsdi.la + +libgstsdi_la_SOURCES = gstsdi.c \ + gstsdidemux.c \ + gstsdimux.c + +libgstsdi_la_CFLAGS = $(GST_PLUGINS_BASE_CFLAGS) $(GST_CFLAGS) +libgstsdi_la_LIBADD = $(GST_PLUGINS_BASE_LIBS) $(GST_BASE_LIBS) \ + $(GST_LIBS) +libgstsdi_la_LDFLAGS = $(GST_PLUGIN_LDFLAGS) +libgstsdi_la_LIBTOOLFLAGS = --tag=disable-static + +noinst_HEADERS = gstsdidemux.h gstsdimux.h + diff --git a/gst/sdi/gstsdi.c b/gst/sdi/gstsdi.c new file mode 100644 index 000000000..30101ebaf --- /dev/null +++ b/gst/sdi/gstsdi.c @@ -0,0 +1,44 @@ +/* GStreamer + * Copyright (C) 2010 David Schleef + * + * 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. + */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "gstsdidemux.h" +#include "gstsdimux.h" + + +static gboolean +plugin_init (GstPlugin * plugin) +{ + + gst_element_register (plugin, "sdidemux", GST_RANK_NONE, + gst_sdi_demux_get_type ()); + gst_element_register (plugin, "sdimux", GST_RANK_NONE, + gst_sdi_mux_get_type ()); + + return TRUE; +} + +GST_PLUGIN_DEFINE (GST_VERSION_MAJOR, + GST_VERSION_MINOR, + "sdi", + "SDI elements", plugin_init, VERSION, "LGPL", PACKAGE_NAME, + GST_PACKAGE_ORIGIN) diff --git a/gst/sdi/gstsdidemux.c b/gst/sdi/gstsdidemux.c new file mode 100644 index 000000000..bc0b76635 --- /dev/null +++ b/gst/sdi/gstsdidemux.c @@ -0,0 +1,553 @@ +/* GStreamer + * Copyright (C) 2010 David Schleef + * + * 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-gstsdidemux + * + * The gstsdidemux element does FIXME stuff. + * + * + * Example launch line + * |[ + * gst-launch -v fakesrc ! gstsdidemux ! FIXME ! fakesink + * ]| + * FIXME Describe what the pipeline does. + * + */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include +#include +#include +#include "gstsdidemux.h" + +/* prototypes */ + + +static void gst_sdi_demux_set_property (GObject * object, + guint property_id, const GValue * value, GParamSpec * pspec); +static void gst_sdi_demux_get_property (GObject * object, + guint property_id, GValue * value, GParamSpec * pspec); +static void gst_sdi_demux_dispose (GObject * object); +static void gst_sdi_demux_finalize (GObject * object); + +static GstStateChangeReturn +gst_sdi_demux_change_state (GstElement * element, GstStateChange transition); +static GstFlowReturn gst_sdi_demux_chain (GstPad * pad, GstBuffer * buffer); +static gboolean gst_sdi_demux_sink_event (GstPad * pad, GstEvent * event); +static gboolean gst_sdi_demux_src_event (GstPad * pad, GstEvent * event); +static GstCaps *gst_sdi_demux_src_getcaps (GstPad * pad); + + +enum +{ + PROP_0 +}; + +/* pad templates */ + +#define GST_VIDEO_CAPS_NTSC(fourcc) \ + "video/x-raw-yuv,format=(fourcc)" fourcc ",width=720,height=480," \ + "framerate=30000/1001,interlaced=TRUE,pixel-aspect-ratio=10/11," \ + "chroma-site=mpeg2,color-matrix=sdtv" +#define GST_VIDEO_CAPS_NTSC_WIDE(fourcc) \ + "video/x-raw-yuv,format=(fourcc)" fourcc ",width=720,height=480," \ + "framerate=30000/1001,interlaced=TRUE,pixel-aspect-ratio=40/33," \ + "chroma-site=mpeg2,color-matrix=sdtv" +#define GST_VIDEO_CAPS_PAL(fourcc) \ + "video/x-raw-yuv,format=(fourcc)" fourcc ",width=720,height=576," \ + "framerate=25/1,interlaced=TRUE,pixel-aspect-ratio=12/11," \ + "chroma-site=mpeg2,color-matrix=sdtv" +#define GST_VIDEO_CAPS_PAL_WIDE(fourcc) \ + "video/x-raw-yuv,format=(fourcc)" fourcc ",width=720,height=576," \ + "framerate=25/1,interlaced=TRUE,pixel-aspect-ratio=16/11," \ + "chroma-site=mpeg2,color-matrix=sdtv" + +static GstStaticPadTemplate gst_sdi_demux_sink_template = +GST_STATIC_PAD_TEMPLATE ("sink", + GST_PAD_SINK, + GST_PAD_ALWAYS, + GST_STATIC_CAPS ("application/x-raw-sdi") + ); + +static GstStaticPadTemplate gst_sdi_demux_src_template = + GST_STATIC_PAD_TEMPLATE ("src", + GST_PAD_SRC, + GST_PAD_ALWAYS, + GST_STATIC_CAPS (GST_VIDEO_CAPS_NTSC ("UYVY") ";" + GST_VIDEO_CAPS_PAL ("UYVY")) + ); + +/* class initialization */ + +GST_BOILERPLATE (GstSdiDemux, gst_sdi_demux, GstElement, GST_TYPE_ELEMENT); + +static void +gst_sdi_demux_base_init (gpointer g_class) +{ + GstElementClass *element_class = GST_ELEMENT_CLASS (g_class); + + gst_element_class_add_pad_template (element_class, + gst_static_pad_template_get (&gst_sdi_demux_src_template)); + gst_element_class_add_pad_template (element_class, + gst_static_pad_template_get (&gst_sdi_demux_sink_template)); + + gst_element_class_set_details_simple (element_class, + "SDI Demuxer", + "Demuxer", + "Demultiplex SDI streams into raw audio and video", + "David Schleef "); +} + +static void +gst_sdi_demux_class_init (GstSdiDemuxClass * klass) +{ + GObjectClass *gobject_class = G_OBJECT_CLASS (klass); + GstElementClass *element_class = GST_ELEMENT_CLASS (klass); + + gobject_class->set_property = gst_sdi_demux_set_property; + gobject_class->get_property = gst_sdi_demux_get_property; + gobject_class->dispose = gst_sdi_demux_dispose; + gobject_class->finalize = gst_sdi_demux_finalize; + if (0) + element_class->change_state = + GST_DEBUG_FUNCPTR (gst_sdi_demux_change_state); + +} + +static void +gst_sdi_demux_init (GstSdiDemux * sdidemux, GstSdiDemuxClass * sdidemux_class) +{ + + sdidemux->sinkpad = + gst_pad_new_from_static_template (&gst_sdi_demux_sink_template, "sink"); + gst_pad_set_event_function (sdidemux->sinkpad, + GST_DEBUG_FUNCPTR (gst_sdi_demux_sink_event)); + gst_pad_set_chain_function (sdidemux->sinkpad, + GST_DEBUG_FUNCPTR (gst_sdi_demux_chain)); + gst_element_add_pad (GST_ELEMENT (sdidemux), sdidemux->sinkpad); + + sdidemux->srcpad = + gst_pad_new_from_static_template (&gst_sdi_demux_src_template, "src"); + gst_pad_set_event_function (sdidemux->srcpad, + GST_DEBUG_FUNCPTR (gst_sdi_demux_src_event)); + gst_pad_set_getcaps_function (sdidemux->srcpad, + GST_DEBUG_FUNCPTR (gst_sdi_demux_src_getcaps)); + gst_element_add_pad (GST_ELEMENT (sdidemux), sdidemux->srcpad); + + +} + +void +gst_sdi_demux_set_property (GObject * object, guint property_id, + const GValue * value, GParamSpec * pspec) +{ + GstSdiDemux *sdidemux; + + g_return_if_fail (GST_IS_SDI_DEMUX (object)); + sdidemux = GST_SDI_DEMUX (object); + + switch (property_id) { + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec); + break; + } +} + +void +gst_sdi_demux_get_property (GObject * object, guint property_id, + GValue * value, GParamSpec * pspec) +{ + GstSdiDemux *sdidemux; + + g_return_if_fail (GST_IS_SDI_DEMUX (object)); + sdidemux = GST_SDI_DEMUX (object); + + switch (property_id) { + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec); + break; + } +} + +void +gst_sdi_demux_dispose (GObject * object) +{ + GstSdiDemux *sdidemux; + + g_return_if_fail (GST_IS_SDI_DEMUX (object)); + sdidemux = GST_SDI_DEMUX (object); + + /* clean up as possible. may be called multiple times */ + + G_OBJECT_CLASS (parent_class)->dispose (object); +} + +void +gst_sdi_demux_finalize (GObject * object) +{ + GstSdiDemux *sdidemux; + + g_return_if_fail (GST_IS_SDI_DEMUX (object)); + sdidemux = GST_SDI_DEMUX (object); + + /* clean up object here */ + + G_OBJECT_CLASS (parent_class)->finalize (object); +} + + +static GstStateChangeReturn +gst_sdi_demux_change_state (GstElement * element, GstStateChange transition) +{ + + return GST_STATE_CHANGE_SUCCESS; +} + +static GstCaps * +gst_sdi_demux_src_getcaps (GstPad * pad) +{ + return gst_caps_from_string (GST_VIDEO_CAPS_NTSC ("UYVY")); +} + +static void +gst_sdi_demux_get_output_buffer (GstSdiDemux * sdidemux) +{ + sdidemux->output_buffer = + gst_buffer_new_and_alloc (720 * sdidemux->format->active_lines * 2); + gst_buffer_set_caps (sdidemux->output_buffer, + gst_caps_from_string (GST_VIDEO_CAPS_PAL ("UYVY"))); + GST_BUFFER_TIMESTAMP (sdidemux->output_buffer) = + GST_SECOND * sdidemux->frame_number; + sdidemux->frame_number++; +} + +static guint32 +get_word10 (guint8 * ptr) +{ + guint32 a; + + a = (((ptr[0] >> 2) | (ptr[1] << 6)) & 0xff) << 24; + a |= (((ptr[1] >> 4) | (ptr[2] << 4)) & 0xff) << 16; + a |= (((ptr[2] >> 6) | (ptr[3] << 2)) & 0xff) << 8; + a |= ptr[4]; + + return a; +} + +static void +line10_copy (guint8 * dest, guint8 * src, int n) +{ + int i; + guint32 a; + for (i = 0; i < n; i++) { + a = get_word10 (src); + GST_WRITE_UINT32_BE (dest, a); + src += 5; + dest += 4; + } + +} + + +static GstFlowReturn +copy_line (GstSdiDemux * sdidemux, guint8 * line) +{ + guint8 *output_data; + GstFlowReturn ret = GST_FLOW_OK; + GstSdiFormat *format = sdidemux->format; + + output_data = GST_BUFFER_DATA (sdidemux->output_buffer); + + /* line is one less than the video line */ + if (sdidemux->line >= format->start0 - 1 && + sdidemux->line < format->start0 - 1 + format->active_lines / 2) { +#if 0 + memcpy (output_data + 720 * 2 * ((sdidemux->line - + (format->start0 - 1)) * 2 + (!format->tff)), + line + (format->width - 720) * 2, 720 * 2); +#else + line10_copy (output_data + 720 * 2 * ((sdidemux->line - + (format->start0 - 1)) * 2 + (!format->tff)), + line + (format->width - 720) / 2 * 5, 720 / 2); +#endif + } + if (sdidemux->line >= format->start1 - 1 && + sdidemux->line < format->start1 - 1 + format->active_lines / 2) { +#if 0 + memcpy (output_data + 720 * 2 * ((sdidemux->line - + (format->start1 - 1)) * 2 + (format->tff)), + line + (format->width - 720) * 2, 720 * 2); +#else + line10_copy (output_data + 720 * 2 * ((sdidemux->line - + (format->start1 - 1)) * 2 + (format->tff)), + line + (format->width - 720) / 2 * 5, 720 / 2); +#endif + } + + sdidemux->offset = 0; + sdidemux->line++; + if (sdidemux->line == format->lines) { + ret = gst_pad_push (sdidemux->srcpad, sdidemux->output_buffer); + gst_sdi_demux_get_output_buffer (sdidemux); + output_data = GST_BUFFER_DATA (sdidemux->output_buffer); + sdidemux->line = 0; + } + + return ret; +} + +#define SDI_IS_SYNC(a) (((a)&0xffffff80) == 0xff000080) +#define SDI_SYNC_F(a) (((a)>>6)&1) +#define SDI_SYNC_V(a) (((a)>>5)&1) +#define SDI_SYNC_H(a) (((a)>>4)&1) + +GstSdiFormat sd_ntsc = { 525, 480, 858, 20, 283, 0 }; +GstSdiFormat sd_pal = { 625, 576, 864, 23, 336, 1 }; + +static GstFlowReturn +gst_sdi_demux_chain (GstPad * pad, GstBuffer * buffer) +{ + GstSdiDemux *sdidemux; + int offset = 0; + guint8 *data = GST_BUFFER_DATA (buffer); + int size = GST_BUFFER_SIZE (buffer); + guint8 *output_data; + GstFlowReturn ret = GST_FLOW_OK; + GstSdiFormat *format; + + sdidemux = GST_SDI_DEMUX (gst_pad_get_parent (pad)); + sdidemux->format = &sd_pal; + format = sdidemux->format; + + GST_DEBUG_OBJECT (sdidemux, "chain"); + + if (GST_BUFFER_IS_DISCONT (buffer)) { + sdidemux->have_hsync = FALSE; + sdidemux->have_vsync = FALSE; + } + + if (!sdidemux->have_hsync) { +#if 0 + for (offset = 0; offset < size; offset += 4) { + guint32 sync = READ_UINT32_BE (data + offset); + GST_ERROR ("sync value %08x", sync); + if (SDI_IS_SYNC (sync) && SDI_SYNC_H (sync)) { + sdidemux->have_hsync = TRUE; + sdidemux->line = 0; + sdidemux->offset = 0; + break; + } + } +#else + for (offset = 0; offset < size; offset += 5) { + guint32 sync = get_word10 (data + offset); + //GST_ERROR("sync value %08x", sync); + if (SDI_IS_SYNC (sync) && SDI_SYNC_H (sync)) { + sdidemux->have_hsync = TRUE; + sdidemux->line = 0; + sdidemux->offset = 0; + break; + } + } +#endif + if (!sdidemux->have_hsync) { + GST_ERROR ("no sync"); + goto out; + } + } + + if (sdidemux->output_buffer == NULL) { + gst_sdi_demux_get_output_buffer (sdidemux); + } + output_data = GST_BUFFER_DATA (sdidemux->output_buffer); + +#if 0 + if (sdidemux->offset) { + int n; + + /* second half of a line */ + n = MIN (size - offset, format->width * 2 - sdidemux->offset); + + memcpy (sdidemux->stored_line + sdidemux->offset, data + offset, n); + + offset += n; + sdidemux->offset += n; + + if (sdidemux->offset == format->width * 2) { + guint32 sync = + GST_READ_UINT32_BE (data + offset + (format->width - 720 - 2) * 2); + + //GST_ERROR("%08x", sync); + if (!sdidemux->have_vsync) { + //GST_ERROR("%08x", GST_READ_UINT32_BE(data+offset)); + if (SDI_IS_SYNC (sync) && !SDI_SYNC_F (sync) && + SDI_SYNC_F (sdidemux->last_sync)) { + sdidemux->have_vsync = TRUE; + } + sdidemux->line = 0; + } + + ret = copy_line (sdidemux, sdidemux->stored_line); + + sdidemux->last_sync = sync; + } + } + + while (size - offset >= format->width * 2) { + guint32 sync = + GST_READ_UINT32_BE (data + offset + (format->width - 720 - 2) * 2); + + //GST_ERROR("%08x", sync); + if (!sdidemux->have_vsync) { + if (SDI_IS_SYNC (sync) && !SDI_SYNC_F (sync) && + SDI_SYNC_F (sdidemux->last_sync)) { + sdidemux->have_vsync = TRUE; + } + sdidemux->line = 0; + } + + ret = copy_line (sdidemux, data + offset); + offset += format->width * 2; + + sdidemux->last_sync = sync; + } + + if (size - offset > 0) { + memcpy (sdidemux->stored_line, data + offset, size - offset); + sdidemux->offset = size - offset; + } +#else + if (sdidemux->offset) { + int n; + + /* second half of a line */ + n = MIN (size - offset, format->width / 2 * 5 - sdidemux->offset); + + memcpy (sdidemux->stored_line + sdidemux->offset, data + offset, n); + + offset += n; + sdidemux->offset += n; + + if (sdidemux->offset == (format->width / 2) * 5) { + guint32 sync = + get_word10 (data + offset + ((format->width - 720 - 2) / 2) * 5); + + if (!sdidemux->have_vsync) { + //GST_ERROR("%08x", GST_READ_UINT32_BE(data+offset)); + if (SDI_IS_SYNC (sync) && !SDI_SYNC_F (sync) && + SDI_SYNC_F (sdidemux->last_sync)) { + sdidemux->have_vsync = TRUE; + } + sdidemux->line = 0; + } + + ret = copy_line (sdidemux, sdidemux->stored_line); + + sdidemux->last_sync = sync; + } + } + + while (size - offset >= format->width / 2 * 5) { + guint32 sync = + get_word10 (data + offset + ((format->width - 720 - 2) / 2) * 5); + + //GST_ERROR("%08x", sync); + if (!sdidemux->have_vsync) { + if (SDI_IS_SYNC (sync) && !SDI_SYNC_F (sync) && + SDI_SYNC_F (sdidemux->last_sync)) { + sdidemux->have_vsync = TRUE; + } + sdidemux->line = 0; + } + + ret = copy_line (sdidemux, data + offset); + offset += (format->width / 2) * 5; + + sdidemux->last_sync = sync; + } + + if (size - offset > 0) { + memcpy (sdidemux->stored_line, data + offset, size - offset); + sdidemux->offset = size - offset; + } +#endif + +out: + gst_buffer_unref (buffer); + gst_object_unref (sdidemux); + return ret; +} + +static gboolean +gst_sdi_demux_sink_event (GstPad * pad, GstEvent * event) +{ + gboolean res; + GstSdiDemux *sdidemux; + + sdidemux = GST_SDI_DEMUX (gst_pad_get_parent (pad)); + + GST_DEBUG_OBJECT (sdidemux, "event"); + + switch (GST_EVENT_TYPE (event)) { + case GST_EVENT_FLUSH_START: + res = gst_pad_push_event (sdidemux->srcpad, event); + break; + case GST_EVENT_FLUSH_STOP: + res = gst_pad_push_event (sdidemux->srcpad, event); + break; + case GST_EVENT_NEWSEGMENT: + res = gst_pad_push_event (sdidemux->srcpad, event); + break; + case GST_EVENT_EOS: + res = gst_pad_push_event (sdidemux->srcpad, event); + break; + default: + res = gst_pad_push_event (sdidemux->srcpad, event); + break; + } + + gst_object_unref (sdidemux); + return TRUE; +} + +static gboolean +gst_sdi_demux_src_event (GstPad * pad, GstEvent * event) +{ + gboolean res; + GstSdiDemux *sdidemux; + + sdidemux = GST_SDI_DEMUX (gst_pad_get_parent (pad)); + + GST_DEBUG_OBJECT (sdidemux, "event"); + + switch (GST_EVENT_TYPE (event)) { + case GST_EVENT_SEEK: + res = gst_pad_push_event (sdidemux->sinkpad, event); + break; + default: + res = gst_pad_push_event (sdidemux->sinkpad, event); + break; + } + + gst_object_unref (sdidemux); + return TRUE; +} diff --git a/gst/sdi/gstsdidemux.h b/gst/sdi/gstsdidemux.h new file mode 100644 index 000000000..5c6425ad2 --- /dev/null +++ b/gst/sdi/gstsdidemux.h @@ -0,0 +1,76 @@ +/* GStreamer + * Copyright (C) 2010 REAL_NAME + * + * 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_SDI_DEMUX_H_ +#define _GST_SDI_DEMUX_H_ + +#include +#include + +G_BEGIN_DECLS + +#define GST_TYPE_SDI_DEMUX (gst_sdi_demux_get_type()) +#define GST_SDI_DEMUX(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_SDI_DEMUX,GstSdiDemux)) +#define GST_SDI_DEMUX_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_SDI_DEMUX,GstSdiDemuxClass)) +#define GST_IS_SDI_DEMUX(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_SDI_DEMUX)) +#define GST_IS_SDI_DEMUX_CLASS(obj) (G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_SDI_DEMUX)) + +typedef struct _GstSdiDemux GstSdiDemux; +typedef struct _GstSdiDemuxClass GstSdiDemuxClass; +typedef struct _GstSdiFormat GstSdiFormat; + +struct _GstSdiDemux +{ + GstElement base_sdidemux; + GstPad *sinkpad; + GstPad *srcpad; + + GstBuffer *output_buffer; + int line; + int offset; + + gboolean have_hsync; + gboolean have_vsync; + guchar stored_line[2160]; /* 864/2*5 */ + + int frame_number; + guint32 last_sync; + GstSdiFormat *format; +}; + +struct _GstSdiFormat +{ + int lines; + int active_lines; + int width; + int start0; + int start1; + int tff; +}; + +struct _GstSdiDemuxClass +{ + GstElementClass base_sdidemux_class; +}; + +GType gst_sdi_demux_get_type (void); + +G_END_DECLS + +#endif diff --git a/gst/sdi/gstsdimux.c b/gst/sdi/gstsdimux.c new file mode 100644 index 000000000..d2c4ef7c6 --- /dev/null +++ b/gst/sdi/gstsdimux.c @@ -0,0 +1,324 @@ +/* GStreamer + * Copyright (C) 2010 David Schleef + * + * 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-gstsdimux + * + * The gstsdimux element does FIXME stuff. + * + * + * Example launch line + * |[ + * gst-launch -v fakesrc ! gstsdimux ! FIXME ! fakesink + * ]| + * FIXME Describe what the pipeline does. + * + */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include +#include +#include "gstsdimux.h" + +/* prototypes */ + + +static void gst_sdi_mux_set_property (GObject * object, + guint property_id, const GValue * value, GParamSpec * pspec); +static void gst_sdi_mux_get_property (GObject * object, + guint property_id, GValue * value, GParamSpec * pspec); +static void gst_sdi_mux_dispose (GObject * object); +static void gst_sdi_mux_finalize (GObject * object); + +static GstPad *gst_sdi_mux_request_new_pad (GstElement * element, + GstPadTemplate * templ, const gchar * name); +static void gst_sdi_mux_release_pad (GstElement * element, GstPad * pad); +static GstStateChangeReturn +gst_sdi_mux_change_state (GstElement * element, GstStateChange transition); +static const GstQueryType *gst_sdi_mux_get_query_types (GstElement * element); +static gboolean gst_sdi_mux_query (GstElement * element, GstQuery * query); +static GstFlowReturn gst_sdi_mux_chain (GstPad * pad, GstBuffer * buffer); +static gboolean gst_sdi_mux_sink_event (GstPad * pad, GstEvent * event); +static gboolean gst_sdi_mux_src_event (GstPad * pad, GstEvent * event); + +enum +{ + PROP_0 +}; + +/* pad templates */ + +#define GST_VIDEO_CAPS_NTSC(fourcc) \ + "video/x-raw-yuv,format=(fourcc)" fourcc ",width=720,height=480," \ + "framerate=30000/1001,interlaced=TRUE,pixel-aspect-ratio=10/11," \ + "chroma-site=mpeg2,color-matrix=sdtv" +#define GST_VIDEO_CAPS_NTSC_WIDE(fourcc) \ + "video/x-raw-yuv,format=(fourcc)" fourcc ",width=720,height=480," \ + "framerate=30000/1001,interlaced=TRUE,pixel-aspect-ratio=40/33," \ + "chroma-site=mpeg2,color-matrix=sdtv" +#define GST_VIDEO_CAPS_PAL(fourcc) \ + "video/x-raw-yuv,format=(fourcc)" fourcc ",width=720,height=576," \ + "framerate=25/1,interlaced=TRUE,pixel-aspect-ratio=12/11," \ + "chroma-site=mpeg2,color-matrix=sdtv" +#define GST_VIDEO_CAPS_PAL_WIDE(fourcc) \ + "video/x-raw-yuv,format=(fourcc)" fourcc ",width=720,height=576," \ + "framerate=25/1,interlaced=TRUE,pixel-aspect-ratio=16/11," \ + "chroma-site=mpeg2,color-matrix=sdtv" + +static GstStaticPadTemplate gst_sdi_mux_sink_template = + GST_STATIC_PAD_TEMPLATE ("sink", + GST_PAD_SINK, + GST_PAD_ALWAYS, + GST_STATIC_CAPS (GST_VIDEO_CAPS_NTSC ("{UYVY,v210}") ";" + GST_VIDEO_CAPS_PAL ("{UYVY,v210}")) + ); + +static GstStaticPadTemplate gst_sdi_mux_src_template = +GST_STATIC_PAD_TEMPLATE ("src", + GST_PAD_SRC, + GST_PAD_ALWAYS, + GST_STATIC_CAPS + ("application/x-raw-sdi,rate=270,format=(fourcc){UYVY,v210}") + ); + +/* class initialization */ + +GST_BOILERPLATE (GstSdiMux, gst_sdi_mux, GstElement, GST_TYPE_ELEMENT); + +static void +gst_sdi_mux_base_init (gpointer g_class) +{ + GstElementClass *element_class = GST_ELEMENT_CLASS (g_class); + + gst_element_class_add_pad_template (element_class, + gst_static_pad_template_get (&gst_sdi_mux_src_template)); + gst_element_class_add_pad_template (element_class, + gst_static_pad_template_get (&gst_sdi_mux_sink_template)); + + gst_element_class_set_details_simple (element_class, "SDI Muxer", + "Muxer", + "Multiplex raw audio and video into SDI", + "David Schleef "); +} + +static void +gst_sdi_mux_class_init (GstSdiMuxClass * klass) +{ + GObjectClass *gobject_class = G_OBJECT_CLASS (klass); + GstElementClass *element_class = GST_ELEMENT_CLASS (klass); + + gobject_class->set_property = gst_sdi_mux_set_property; + gobject_class->get_property = gst_sdi_mux_get_property; + gobject_class->dispose = gst_sdi_mux_dispose; + gobject_class->finalize = gst_sdi_mux_finalize; + element_class->request_new_pad = + GST_DEBUG_FUNCPTR (gst_sdi_mux_request_new_pad); + element_class->release_pad = GST_DEBUG_FUNCPTR (gst_sdi_mux_release_pad); + element_class->change_state = GST_DEBUG_FUNCPTR (gst_sdi_mux_change_state); + element_class->get_query_types = + GST_DEBUG_FUNCPTR (gst_sdi_mux_get_query_types); + element_class->query = GST_DEBUG_FUNCPTR (gst_sdi_mux_query); + +} + +static void +gst_sdi_mux_init (GstSdiMux * sdimux, GstSdiMuxClass * sdimux_class) +{ + + sdimux->sinkpad = + gst_pad_new_from_static_template (&gst_sdi_mux_sink_template, "sink"); + gst_pad_set_event_function (sdimux->sinkpad, + GST_DEBUG_FUNCPTR (gst_sdi_mux_sink_event)); + gst_pad_set_chain_function (sdimux->sinkpad, + GST_DEBUG_FUNCPTR (gst_sdi_mux_chain)); + gst_element_add_pad (GST_ELEMENT (sdimux), sdimux->sinkpad); + + sdimux->srcpad = gst_pad_new_from_static_template (&gst_sdi_mux_src_template, + "src"); + gst_pad_set_event_function (sdimux->srcpad, + GST_DEBUG_FUNCPTR (gst_sdi_mux_src_event)); + gst_element_add_pad (GST_ELEMENT (sdimux), sdimux->srcpad); + +} + +void +gst_sdi_mux_set_property (GObject * object, guint property_id, + const GValue * value, GParamSpec * pspec) +{ + GstSdiMux *sdimux; + + g_return_if_fail (GST_IS_SDI_MUX (object)); + sdimux = GST_SDI_MUX (object); + + switch (property_id) { + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec); + break; + } +} + +void +gst_sdi_mux_get_property (GObject * object, guint property_id, + GValue * value, GParamSpec * pspec) +{ + GstSdiMux *sdimux; + + g_return_if_fail (GST_IS_SDI_MUX (object)); + sdimux = GST_SDI_MUX (object); + + switch (property_id) { + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec); + break; + } +} + +void +gst_sdi_mux_dispose (GObject * object) +{ + GstSdiMux *sdimux; + + g_return_if_fail (GST_IS_SDI_MUX (object)); + sdimux = GST_SDI_MUX (object); + + /* clean up as possible. may be called multiple times */ + + G_OBJECT_CLASS (parent_class)->dispose (object); +} + +void +gst_sdi_mux_finalize (GObject * object) +{ + GstSdiMux *sdimux; + + g_return_if_fail (GST_IS_SDI_MUX (object)); + sdimux = GST_SDI_MUX (object); + + /* clean up object here */ + + G_OBJECT_CLASS (parent_class)->finalize (object); +} + + + +static GstPad * +gst_sdi_mux_request_new_pad (GstElement * element, GstPadTemplate * templ, + const gchar * name) +{ + + return NULL; +} + +static void +gst_sdi_mux_release_pad (GstElement * element, GstPad * pad) +{ + +} + +static GstStateChangeReturn +gst_sdi_mux_change_state (GstElement * element, GstStateChange transition) +{ + + return GST_STATE_CHANGE_SUCCESS; +} + +static const GstQueryType * +gst_sdi_mux_get_query_types (GstElement * element) +{ + + return NULL; +} + +static gboolean +gst_sdi_mux_query (GstElement * element, GstQuery * query) +{ + + return FALSE; +} + +static GstFlowReturn +gst_sdi_mux_chain (GstPad * pad, GstBuffer * buffer) +{ + GstSdiMux *sdimux; + + sdimux = GST_SDI_MUX (gst_pad_get_parent (pad)); + + GST_DEBUG_OBJECT (sdimux, "chain"); + + + gst_object_unref (sdimux); + return GST_FLOW_OK; +} + +static gboolean +gst_sdi_mux_sink_event (GstPad * pad, GstEvent * event) +{ + gboolean res; + GstSdiMux *sdimux; + + sdimux = GST_SDI_MUX (gst_pad_get_parent (pad)); + + GST_DEBUG_OBJECT (sdimux, "event"); + + switch (GST_EVENT_TYPE (event)) { + case GST_EVENT_FLUSH_START: + res = gst_pad_push_event (sdimux->srcpad, event); + break; + case GST_EVENT_FLUSH_STOP: + res = gst_pad_push_event (sdimux->srcpad, event); + break; + case GST_EVENT_NEWSEGMENT: + res = gst_pad_push_event (sdimux->srcpad, event); + break; + case GST_EVENT_EOS: + res = gst_pad_push_event (sdimux->srcpad, event); + break; + default: + res = gst_pad_push_event (sdimux->srcpad, event); + break; + } + + gst_object_unref (sdimux); + return TRUE; +} + +static gboolean +gst_sdi_mux_src_event (GstPad * pad, GstEvent * event) +{ + gboolean res; + GstSdiMux *sdimux; + + sdimux = GST_SDI_MUX (gst_pad_get_parent (pad)); + + GST_DEBUG_OBJECT (sdimux, "event"); + + switch (GST_EVENT_TYPE (event)) { + case GST_EVENT_SEEK: + res = gst_pad_push_event (sdimux->sinkpad, event); + break; + default: + res = gst_pad_push_event (sdimux->sinkpad, event); + break; + } + + gst_object_unref (sdimux); + return TRUE; +} diff --git a/gst/sdi/gstsdimux.h b/gst/sdi/gstsdimux.h new file mode 100644 index 000000000..5955810d5 --- /dev/null +++ b/gst/sdi/gstsdimux.h @@ -0,0 +1,54 @@ +/* GStreamer + * Copyright (C) 2010 REAL_NAME + * + * 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_SDI_MUX_H_ +#define _GST_SDI_MUX_H_ + +#include +#include + +G_BEGIN_DECLS + +#define GST_TYPE_SDI_MUX (gst_sdi_mux_get_type()) +#define GST_SDI_MUX(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_SDI_MUX,GstSdiMux)) +#define GST_SDI_MUX_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_SDI_MUX,GstSdiMuxClass)) +#define GST_IS_SDI_MUX(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_SDI_MUX)) +#define GST_IS_SDI_MUX_CLASS(obj) (G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_SDI_MUX)) + +typedef struct _GstSdiMux GstSdiMux; +typedef struct _GstSdiMuxClass GstSdiMuxClass; + +struct _GstSdiMux +{ + GstElement base_sdimux; + + GstPad *srcpad; + GstPad *sinkpad; +}; + +struct _GstSdiMuxClass +{ + GstElementClass base_sdimux_class; +}; + +GType gst_sdi_mux_get_type (void); + +G_END_DECLS + +#endif -- cgit v1.2.1