diff --git a/Makefile.am b/Makefile.am index 17a124f..97102d4 100644 --- a/Makefile.am +++ b/Makefile.am @@ -1,6 +1,13 @@ bin_PROGRAMS = omvs -omvs_SOURCES = omvs_main.c omvs_gst.h omvs_gst.c +omvs_SOURCES = \ + omvs_main.c \ + omvs_gst.h \ + omvs_gst.c \ + omvs_gst_plugin.h \ + omvs_gst_plugin.c \ + omvs_gst_plugin_rtpsrc.h \ + omvs_gst_plugin_rtpsrc.c omvs_CFLAGS = $(GLIB_CFLAGS) $(GIO_CFLAGS) $(GSTREAMER_CFLAGS) omvs_CFLAGS += -std=gnu99 -W -Wall -Wno-unused-result -pedantic omvs_LDADD = $(GLIB_LIBS) $(GIO_LIBS) $(GSTREAMER_LIBS) -ACLOCAL_AMFLAGS= -I m4 +ACLOCAL_AMFLAGS = -I m4 diff --git a/Makefile.in b/Makefile.in index d5c14c1..9f963f3 100644 --- a/Makefile.in +++ b/Makefile.in @@ -100,7 +100,9 @@ CONFIG_CLEAN_FILES = CONFIG_CLEAN_VPATH_FILES = am__installdirs = "$(DESTDIR)$(bindir)" PROGRAMS = $(bin_PROGRAMS) -am_omvs_OBJECTS = omvs-omvs_main.$(OBJEXT) omvs-omvs_gst.$(OBJEXT) +am_omvs_OBJECTS = omvs-omvs_main.$(OBJEXT) omvs-omvs_gst.$(OBJEXT) \ + omvs-omvs_gst_plugin.$(OBJEXT) \ + omvs-omvs_gst_plugin_rtpsrc.$(OBJEXT) omvs_OBJECTS = $(am_omvs_OBJECTS) am__DEPENDENCIES_1 = omvs_DEPENDENCIES = $(am__DEPENDENCIES_1) $(am__DEPENDENCIES_1) \ @@ -316,7 +318,15 @@ target_alias = @target_alias@ top_build_prefix = @top_build_prefix@ top_builddir = @top_builddir@ top_srcdir = @top_srcdir@ -omvs_SOURCES = omvs_main.c omvs_gst.h omvs_gst.c +omvs_SOURCES = \ + omvs_main.c \ + omvs_gst.h \ + omvs_gst.c \ + omvs_gst_plugin.h \ + omvs_gst_plugin.c \ + omvs_gst_plugin_rtpsrc.h \ + omvs_gst_plugin_rtpsrc.c + omvs_CFLAGS = $(GLIB_CFLAGS) $(GIO_CFLAGS) $(GSTREAMER_CFLAGS) \ -std=gnu99 -W -Wall -Wno-unused-result -pedantic omvs_LDADD = $(GLIB_LIBS) $(GIO_LIBS) $(GSTREAMER_LIBS) @@ -436,6 +446,8 @@ distclean-compile: -rm -f *.tab.c @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/omvs-omvs_gst.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/omvs-omvs_gst_plugin.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/omvs-omvs_gst_plugin_rtpsrc.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/omvs-omvs_main.Po@am__quote@ .c.o: @@ -487,6 +499,34 @@ omvs-omvs_gst.obj: omvs_gst.c @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(omvs_CFLAGS) $(CFLAGS) -c -o omvs-omvs_gst.obj `if test -f 'omvs_gst.c'; then $(CYGPATH_W) 'omvs_gst.c'; else $(CYGPATH_W) '$(srcdir)/omvs_gst.c'; fi` +omvs-omvs_gst_plugin.o: omvs_gst_plugin.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(omvs_CFLAGS) $(CFLAGS) -MT omvs-omvs_gst_plugin.o -MD -MP -MF $(DEPDIR)/omvs-omvs_gst_plugin.Tpo -c -o omvs-omvs_gst_plugin.o `test -f 'omvs_gst_plugin.c' || echo '$(srcdir)/'`omvs_gst_plugin.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/omvs-omvs_gst_plugin.Tpo $(DEPDIR)/omvs-omvs_gst_plugin.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='omvs_gst_plugin.c' object='omvs-omvs_gst_plugin.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(omvs_CFLAGS) $(CFLAGS) -c -o omvs-omvs_gst_plugin.o `test -f 'omvs_gst_plugin.c' || echo '$(srcdir)/'`omvs_gst_plugin.c + +omvs-omvs_gst_plugin.obj: omvs_gst_plugin.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(omvs_CFLAGS) $(CFLAGS) -MT omvs-omvs_gst_plugin.obj -MD -MP -MF $(DEPDIR)/omvs-omvs_gst_plugin.Tpo -c -o omvs-omvs_gst_plugin.obj `if test -f 'omvs_gst_plugin.c'; then $(CYGPATH_W) 'omvs_gst_plugin.c'; else $(CYGPATH_W) '$(srcdir)/omvs_gst_plugin.c'; fi` +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/omvs-omvs_gst_plugin.Tpo $(DEPDIR)/omvs-omvs_gst_plugin.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='omvs_gst_plugin.c' object='omvs-omvs_gst_plugin.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(omvs_CFLAGS) $(CFLAGS) -c -o omvs-omvs_gst_plugin.obj `if test -f 'omvs_gst_plugin.c'; then $(CYGPATH_W) 'omvs_gst_plugin.c'; else $(CYGPATH_W) '$(srcdir)/omvs_gst_plugin.c'; fi` + +omvs-omvs_gst_plugin_rtpsrc.o: omvs_gst_plugin_rtpsrc.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(omvs_CFLAGS) $(CFLAGS) -MT omvs-omvs_gst_plugin_rtpsrc.o -MD -MP -MF $(DEPDIR)/omvs-omvs_gst_plugin_rtpsrc.Tpo -c -o omvs-omvs_gst_plugin_rtpsrc.o `test -f 'omvs_gst_plugin_rtpsrc.c' || echo '$(srcdir)/'`omvs_gst_plugin_rtpsrc.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/omvs-omvs_gst_plugin_rtpsrc.Tpo $(DEPDIR)/omvs-omvs_gst_plugin_rtpsrc.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='omvs_gst_plugin_rtpsrc.c' object='omvs-omvs_gst_plugin_rtpsrc.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(omvs_CFLAGS) $(CFLAGS) -c -o omvs-omvs_gst_plugin_rtpsrc.o `test -f 'omvs_gst_plugin_rtpsrc.c' || echo '$(srcdir)/'`omvs_gst_plugin_rtpsrc.c + +omvs-omvs_gst_plugin_rtpsrc.obj: omvs_gst_plugin_rtpsrc.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(omvs_CFLAGS) $(CFLAGS) -MT omvs-omvs_gst_plugin_rtpsrc.obj -MD -MP -MF $(DEPDIR)/omvs-omvs_gst_plugin_rtpsrc.Tpo -c -o omvs-omvs_gst_plugin_rtpsrc.obj `if test -f 'omvs_gst_plugin_rtpsrc.c'; then $(CYGPATH_W) 'omvs_gst_plugin_rtpsrc.c'; else $(CYGPATH_W) '$(srcdir)/omvs_gst_plugin_rtpsrc.c'; fi` +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/omvs-omvs_gst_plugin_rtpsrc.Tpo $(DEPDIR)/omvs-omvs_gst_plugin_rtpsrc.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='omvs_gst_plugin_rtpsrc.c' object='omvs-omvs_gst_plugin_rtpsrc.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(omvs_CFLAGS) $(CFLAGS) -c -o omvs-omvs_gst_plugin_rtpsrc.obj `if test -f 'omvs_gst_plugin_rtpsrc.c'; then $(CYGPATH_W) 'omvs_gst_plugin_rtpsrc.c'; else $(CYGPATH_W) '$(srcdir)/omvs_gst_plugin_rtpsrc.c'; fi` + mostlyclean-libtool: -rm -f *.lo diff --git a/omvs_gst.c b/omvs_gst.c index 8eb2328..4cc5d26 100644 --- a/omvs_gst.c +++ b/omvs_gst.c @@ -18,6 +18,7 @@ along with this program. If not, see . */ +#include #include #include "omvs_gst.h" @@ -29,6 +30,9 @@ typedef struct _OMVSGstImpl { OMVSGst omvs_gst_open(const gchar *uri, const gchar *filename) { guint flags; OMVSGstImpl *gst_impl; + gchar *protocol; + gchar *location; + gchar *real_uri; GstElement *play; GstElement *conv; GstElement *png; @@ -37,9 +41,34 @@ OMVSGst omvs_gst_open(const gchar *uri, const gchar *filename) { GstPad *pad; GstPad *ghostpad; + if (gst_uri_is_valid(uri)) { + protocol = gst_uri_get_protocol(uri); + if (protocol) { + location = gst_uri_get_location(uri); + if (location) { + if (!gst_uri_protocol_is_supported(GST_URI_SRC, protocol)) { + if (strcmp(protocol, "rtp") == 0) { + g_free(protocol); + protocol = g_strdup("ortp"); + } + } + real_uri = g_strdup_printf("%s://%s", protocol, location); + g_free(location); + } else { + real_uri = g_strdup(uri); + } + g_free(protocol); + } else { + real_uri = g_strdup(uri); + } + } else { + real_uri = g_strdup(uri); + } + gst_impl = g_malloc0(sizeof(OMVSGstImpl)); gst_impl->play = play = gst_element_factory_make("playbin", "play"); - g_object_set(G_OBJECT(play), "uri", uri, NULL); + g_object_set(G_OBJECT(play), "uri", real_uri, NULL); + g_free(real_uri); g_object_get(play, "flags", &flags, NULL); flags &= (~0x00000002); g_object_set(play, "flags", flags, NULL); diff --git a/omvs_gst_plugin.c b/omvs_gst_plugin.c new file mode 100644 index 0000000..d68ef91 --- /dev/null +++ b/omvs_gst_plugin.c @@ -0,0 +1,53 @@ +/* + Oh! Multicast Video Scanner + Copyright (C) 2016 Taeho Oh + + This file is part of Oh! Multicast Video Scanner. + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program 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 General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . +*/ + +#include "config.h" +#include "omvs_gst_plugin.h" +#include "omvs_gst_plugin_rtpsrc.h" + +#if 0 + +static gboolean omvs_gst_plugin_init(GstPlugin *plugin); + +static gboolean omvs_gst_plugin_init(GstPlugin *plugin) { + if (!omvs_gst_plugin_rtpsrc_init(plugin)) { + return FALSE; + } + + return TRUE; +} + +GST_PLUGIN_DEFINE(GST_VERSION_MAJOR, GST_VERSION_MINOR, omvprtp, + "RTP protocol for " PACKAGE, omvs_gst_plugin_init, PACKAGE_VERSION, "GPL", + PACKAGE, PACKAGE_URL) + +#else + +gboolean omvs_gst_plugin_register(void) { + gboolean ret; + + ret = gst_plugin_register_static(GST_VERSION_MAJOR, GST_VERSION_MINOR, + "omvsrtpsrc", "RTP protocol for " PACKAGE, omvs_gst_plugin_rtpsrc_init, + PACKAGE_VERSION, "GPL", PACKAGE, PACKAGE, PACKAGE_URL); + + return ret; +} + +#endif diff --git a/omvs_gst_plugin.h b/omvs_gst_plugin.h new file mode 100644 index 0000000..6c7417f --- /dev/null +++ b/omvs_gst_plugin.h @@ -0,0 +1,28 @@ +/* + Oh! Multicast Video Scanner + Copyright (C) 2016 Taeho Oh + + This file is part of Oh! Multicast Video Scanner. + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program 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 General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . +*/ + +#ifndef _OMVS_GST_PLUGIN_H_ +#define _OMVS_GST_PLUGIN_H_ + +#include + +extern gboolean omvs_gst_plugin_register(void); + +#endif /* _OMVS_GST_PLUGIN_H_ */ diff --git a/omvs_gst_plugin_rtpsrc.c b/omvs_gst_plugin_rtpsrc.c new file mode 100644 index 0000000..01bbb64 --- /dev/null +++ b/omvs_gst_plugin_rtpsrc.c @@ -0,0 +1,398 @@ +/* + Oh! Multicast Video Scanner + Copyright (C) 2016 Taeho Oh + + This file is part of Oh! Multicast Video Scanner. + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program 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 General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . +*/ + +#include +#include "config.h" +#include "omvs_gst_plugin_rtpsrc.h" + +GST_DEBUG_CATEGORY_STATIC(omvs_rtpsrc_debug); +#define GST_CAT_DEFAULT omvs_rtpsrc_debug + +enum { + PROP_0, + PROP_URI, + PROP_LAST +}; + +#define DEFAULT_PROP_URI (NULL) + +static GstStaticPadTemplate src_template = GST_STATIC_PAD_TEMPLATE("src", + GST_PAD_SRC, GST_PAD_SOMETIMES, GST_STATIC_CAPS("application/x-rtp")); + +static gboolean gst_omvs_rtpsrc_parse_uri(const gchar *uristr, gchar **host, + guint16 *port); +static GstURIType gst_omvs_rtpsrc_uri_get_type(GType type); +static const gchar *const *gst_omvs_rtpsrc_uri_get_protocols(GType type); +static gchar *gst_omvs_rtpsrc_uri_get_uri(GstURIHandler *handler); +static gboolean gst_omvs_rtpsrc_uri_set_uri(GstURIHandler *handler, + const gchar *uri, GError **error); +static void gst_omvs_rtpsrc_uri_handler_init(gpointer g_iface, + gpointer iface_data); +static void gst_omvs_rtpsrc_set_property(GObject *object, guint prop_id, + const GValue *value, GParamSpec *pspec); +static void gst_omvs_rtpsrc_get_property(GObject *object, guint prop_id, + GValue *value, GParamSpec *pspec); +static void gst_omvs_rtpsrc_finalize(GObject *gobject); +static void gst_omvs_rtpsrc_rtpbin_pad_added_cb(GstElement *element, + GstPad *pad, gpointer data); +static gboolean gst_omvs_rtpsrc_start(GstOMVSRtpSrc *rtpsrc); +static GstStateChangeReturn gst_omvs_rtpsrc_change_state(GstElement *element, + GstStateChange transition); + +static gboolean gst_omvs_rtpsrc_parse_uri(const gchar *uristr, gchar **host, + guint16 *port) { + gchar *protocol, *location_start; + gchar *location, *location_end; + gchar *colptr; + + protocol = gst_uri_get_protocol(uristr); + if (!protocol) { + goto no_protocol; + } + if (strcmp(protocol, "ortp") != 0) { + goto wrong_protocol; + } + g_free(protocol); + + location_start = gst_uri_get_location(uristr); + if (!location_start) { + return FALSE; + } + + GST_DEBUG("got location '%s'", location_start); + + location = g_strstr_len(location_start, -1, "@"); + if (location == NULL) { + location = location_start; + } + else { + location += 1; + } + + if (location[0] == '[') { + GST_DEBUG("parse IPV6 address '%s'", location); + location_end = strchr(location, ']'); + if (location_end == NULL) { + goto wrong_address; + } + + *host = g_strndup(location + 1, location_end - location - 1); + colptr = strrchr(location_end, ':'); + } else { + GST_DEBUG("parse IPV4 address '%s'", location); + colptr = strrchr(location, ':'); + + if (colptr != NULL) { + *host = g_strndup(location, colptr - location); + } else { + *host = g_strdup(location); + } + } + GST_DEBUG("host set to '%s'", *host); + + if (colptr != NULL) { + *port = g_ascii_strtoll(colptr + 1, NULL, 10); + } else { + *port = 0; + } + g_free(location_start); + + return TRUE; + +no_protocol: + { + GST_ERROR("error parsing uri %s: no protocol", uristr); + return FALSE; + } +wrong_protocol: + { + GST_ERROR("error parsing uri %s: wrong protocol (%s != ortp)", uristr, + protocol); + g_free(protocol); + return FALSE; + } +wrong_address: + { + GST_ERROR("error parsing uri %s", uristr); + g_free(location); + return FALSE; + } +} + +#define gst_omvs_rtpsrc_parent_class parent_class +G_DEFINE_TYPE_WITH_CODE(GstOMVSRtpSrc, gst_omvs_rtpsrc, GST_TYPE_BIN, + G_IMPLEMENT_INTERFACE(GST_TYPE_URI_HANDLER, + gst_omvs_rtpsrc_uri_handler_init)) + +static void gst_omvs_rtpsrc_class_init(GstOMVSRtpSrcClass *klass) { + GObjectClass *oclass = G_OBJECT_CLASS(klass); + GstElementClass *gstelement_class = GST_ELEMENT_CLASS(klass); + + oclass->set_property = gst_omvs_rtpsrc_set_property; + oclass->get_property = gst_omvs_rtpsrc_get_property; + oclass->finalize = gst_omvs_rtpsrc_finalize; + + g_object_class_install_property(oclass, PROP_URI, + g_param_spec_string("uri", "URI", "URI of the media to play", + DEFAULT_PROP_URI, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); + + gst_element_class_add_pad_template(gstelement_class, + gst_static_pad_template_get(&src_template)); + + gstelement_class->change_state = + GST_DEBUG_FUNCPTR(gst_omvs_rtpsrc_change_state); + + gst_element_class_set_static_metadata(gstelement_class, "omvsrtpsrc", + "Generic/Bin/Src", "OMVS RTP Src", "Taeho Oh "); + + GST_DEBUG_CATEGORY_INIT(omvs_rtpsrc_debug, "omvsrtpsrc", 0, "OMVS RTP Src"); +} + +static void gst_omvs_rtpsrc_init(GstOMVSRtpSrc *rtpsrc) { + rtpsrc->uri = NULL; + rtpsrc->udpsrc = NULL; + rtpsrc->rtpbin = NULL; + rtpsrc->n_pads = 0; + + GST_DEBUG_OBJECT(rtpsrc, "omvsrtpsrc initialized"); +} + +static GstURIType gst_omvs_rtpsrc_uri_get_type(GType type) { + (void)type; + return GST_URI_SRC; +} + +static const gchar *const *gst_omvs_rtpsrc_uri_get_protocols(GType type) { + static const gchar *protocols[] = { "ortp", NULL }; + + (void)type; + + return protocols; +} + +static gchar *gst_omvs_rtpsrc_uri_get_uri(GstURIHandler *handler) { + GstOMVSRtpSrc *rtpsrc = GST_OMVS_RTPSRC(handler); + + return g_strdup(rtpsrc->uri); +} + +static gboolean gst_omvs_rtpsrc_uri_set_uri(GstURIHandler *handler, + const gchar *uri, GError **error) { + GstOMVSRtpSrc *rtpsrc = (GstOMVSRtpSrc *)handler; + + (void)error; + + g_object_set(G_OBJECT(rtpsrc), "uri", uri, NULL); + + return TRUE; +} + +static void gst_omvs_rtpsrc_uri_handler_init(gpointer g_iface, + gpointer iface_data) { + GstURIHandlerInterface *iface = (GstURIHandlerInterface *)g_iface; + + (void)iface_data; + + iface->get_type = gst_omvs_rtpsrc_uri_get_type; + iface->get_protocols = gst_omvs_rtpsrc_uri_get_protocols; + iface->get_uri = gst_omvs_rtpsrc_uri_get_uri; + iface->set_uri = gst_omvs_rtpsrc_uri_set_uri; +} + +static void gst_omvs_rtpsrc_set_property(GObject *object, guint prop_id, + const GValue *value, GParamSpec *pspec) { + GstOMVSRtpSrc *rtpsrc = GST_OMVS_RTPSRC(object); + + switch (prop_id) { + case PROP_URI: + g_free(rtpsrc->uri); + rtpsrc->uri = g_strdup(g_value_get_string(value)); + if (rtpsrc->udpsrc) { + gchar *host; + guint16 port; + if (gst_omvs_rtpsrc_parse_uri(rtpsrc->uri, &host, &port)) { + gchar *udpsrc_uri; + udpsrc_uri = g_strdup_printf("udp://%s:%u", host, port); + g_object_set(G_OBJECT(rtpsrc->udpsrc), "uri", udpsrc_uri, NULL); + g_free(host); + g_free(udpsrc_uri); + } + } + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID(object, prop_id, pspec); + break; + } +} + +static void gst_omvs_rtpsrc_get_property(GObject *object, guint prop_id, + GValue *value, GParamSpec *pspec) { + GstOMVSRtpSrc *rtpsrc = GST_OMVS_RTPSRC(object); + + switch (prop_id) { + case PROP_URI: + g_value_set_string(value, rtpsrc->uri); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID(object, prop_id, pspec); + break; + } +} + +static void gst_omvs_rtpsrc_finalize(GObject *gobject) { + GstOMVSRtpSrc *rtpsrc = GST_OMVS_RTPSRC(gobject); + + g_free(rtpsrc->uri); + rtpsrc->uri = NULL; + rtpsrc->udpsrc = NULL; + rtpsrc->rtpbin = NULL; + rtpsrc->n_pads = 0; + + G_OBJECT_CLASS(parent_class)->finalize(gobject); +} + +static void gst_omvs_rtpsrc_rtpbin_pad_added_cb(GstElement *element, + GstPad *pad, gpointer data) { + gchar *name; + GstOMVSRtpSrc *rtpsrc = (GstOMVSRtpSrc *)data; + + (void)element; + + name = gst_pad_get_name(pad); + GST_DEBUG_OBJECT(rtpsrc, "adding a pad %s", name); + + if (strncmp(name, "recv_rtp_src_", strlen("recv_rtp_src_")) != 0) { + g_free(name); + GST_DEBUG_OBJECT(rtpsrc, "Pad name does not start with recv_rtp_src_"); + return; + } + g_free(name); + + if (GST_PAD_DIRECTION(pad) == GST_PAD_SINK) { + GST_DEBUG_OBJECT(rtpsrc, "Pad is not src pad"); + return; + } + + gst_object_ref(pad); + + if (rtpsrc->n_pads) { + GST_DEBUG_OBJECT(rtpsrc, "Ignore SSRC"); + gst_ghost_pad_set_target(GST_GHOST_PAD(rtpsrc->ghostpad), pad); + gst_object_unref(pad); + return; + } + + rtpsrc->ghostpad = gst_ghost_pad_new("src", pad); + gst_pad_set_active(rtpsrc->ghostpad, TRUE); + gst_element_add_pad(GST_ELEMENT(rtpsrc), rtpsrc->ghostpad); + gst_object_unref(pad); + + rtpsrc->n_pads++; + + gst_element_no_more_pads(GST_ELEMENT(rtpsrc)); + + return; +} + +static gboolean gst_omvs_rtpsrc_start(GstOMVSRtpSrc *rtpsrc) { + gchar *host; + guint16 port; + GstCaps *caps; + + GST_DEBUG_OBJECT(rtpsrc, "Creating elements"); + + rtpsrc->udpsrc = gst_element_factory_make("udpsrc", NULL); + if (!rtpsrc->udpsrc) { + return FALSE; + } + + rtpsrc->rtpbin = gst_element_factory_make("rtpbin", NULL); + if (!rtpsrc->rtpbin) { + gst_object_unref(rtpsrc->udpsrc); + rtpsrc->udpsrc = NULL; + return FALSE; + } + + caps = gst_caps_new_simple("application/x-rtp", + "media", G_TYPE_STRING, "video", + "clock-rate", G_TYPE_INT, 90000, + "payload", G_TYPE_INT, 33, + NULL); + g_object_set(G_OBJECT(rtpsrc->udpsrc), "caps", caps, NULL); + gst_caps_unref(caps); + + if (gst_omvs_rtpsrc_parse_uri(rtpsrc->uri, &host, &port)) { + gchar *udpsrc_uri; + udpsrc_uri = g_strdup_printf("udp://%s:%u", host, port); + g_object_set(G_OBJECT(rtpsrc->udpsrc), "uri", udpsrc_uri, NULL); + g_free(host); + g_free(udpsrc_uri); + } + + gst_bin_add_many(GST_BIN(rtpsrc), rtpsrc->udpsrc, rtpsrc->rtpbin, NULL); + gst_element_link_pads(rtpsrc->udpsrc, "src", rtpsrc->rtpbin, + "recv_rtp_sink_0"); + + g_signal_connect(rtpsrc->rtpbin, "pad-added", + G_CALLBACK(gst_omvs_rtpsrc_rtpbin_pad_added_cb), rtpsrc); + + if (!gst_element_sync_state_with_parent(rtpsrc->udpsrc)) { + GST_ERROR_OBJECT(rtpsrc, "Could not set udpsrc to playing"); + } + if (!gst_element_sync_state_with_parent(rtpsrc->rtpbin)) { + GST_ERROR_OBJECT(rtpsrc, "Could not set rtpbin to playing"); + } + + return TRUE; +} + +static GstStateChangeReturn gst_omvs_rtpsrc_change_state(GstElement *element, + GstStateChange transition) { + GstOMVSRtpSrc *rtpsrc = GST_OMVS_RTPSRC(element); + + switch (transition) { + case GST_STATE_CHANGE_READY_TO_PAUSED: + GST_DEBUG_OBJECT(rtpsrc, "Configuring omvsrtpsrc"); + if (!gst_omvs_rtpsrc_start(rtpsrc)) { + GST_DEBUG_OBJECT(rtpsrc, "Start failed"); + return GST_STATE_CHANGE_FAILURE; + } + break; + case GST_STATE_CHANGE_PAUSED_TO_PLAYING: + break; + case GST_STATE_CHANGE_PLAYING_TO_PAUSED: + break; + case GST_STATE_CHANGE_PAUSED_TO_READY: + break; + default: + break; + } + + return GST_ELEMENT_CLASS(parent_class)->change_state(element, transition); +} + +gboolean omvs_gst_plugin_rtpsrc_init(GstPlugin *plugin) { + gboolean ret; + + ret = gst_element_register(plugin, "omvsrtpsrc", GST_RANK_NONE, + GST_TYPE_OMVS_RTPSRC); + + return ret; +} diff --git a/omvs_gst_plugin_rtpsrc.h b/omvs_gst_plugin_rtpsrc.h new file mode 100644 index 0000000..b5ec75f --- /dev/null +++ b/omvs_gst_plugin_rtpsrc.h @@ -0,0 +1,58 @@ +/* + Oh! Multicast Video Scanner + Copyright (C) 2016 Taeho Oh + + This file is part of Oh! Multicast Video Scanner. + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program 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 General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . +*/ + +#ifndef _OMVS_GST_PLUGIN_RTPSRC_H_ +#define _OMVS_GST_PLUGIN_RTPSRC_H_ + +#include + +#define GST_TYPE_OMVS_RTPSRC (gst_omvs_rtpsrc_get_type()) +#define GST_OMVS_RTPSRC(obj) \ + (G_TYPE_CHECK_INSTANCE_CAST((obj), GST_TYPE_OMVS_RTPSRC, GstOMVSRtpSrc)) +#define GST_OMVS_RTPSRC_CLASS(klass) \ + (G_TYPE_CHECK_CLASS_CAST((klass), GST_TYPE_OMVS_RTPSRC, GstOMVSRtpSrcClass)) +#define GST_IS_OMVS_RTPSRC(obj) \ + (G_TYPE_CHECK_INSTANCE_TYPE((obj), GST_TYPE_OMVS_RTPSRC)) +#define GST_IS_OMVS_RTPSRC_CLASS(klass) \ + (G_TYPE_CHECK_CLASS_TYPE((klass), GST_TYPE_OMVS_RTPSRC)) +#define GST_OMVS_RTPSRC_GET_CLASS(obj) \ + (G_TYPE_INSTANCE_GET_CLASS((obj), GST_TYPE_OMVS_RTPSRC, GstOMVSRtpSrcClass)) + +typedef struct _GstOMVSRtpSrcClass GstOMVSRtpSrcClass; +typedef struct _GstOMVSRtpSrc GstOMVSRtpSrc; + +struct _GstOMVSRtpSrcClass { + GstBinClass parent_class; +}; + +struct _GstOMVSRtpSrc { + GstBin parent_instance; + + gchar *uri; + GstElement *udpsrc; + GstElement *rtpbin; + GstPad *ghostpad; + gint n_pads; +}; + +extern GType gst_omvs_rtpsrc_get_type(void); +extern gboolean omvs_gst_plugin_rtpsrc_init(GstPlugin *plugin); + +#endif /* _OMVS_GST_PLUGIN_RTPSRC_H_ */ diff --git a/omvs_main.c b/omvs_main.c index 2ae6a29..3382a82 100644 --- a/omvs_main.c +++ b/omvs_main.c @@ -27,6 +27,7 @@ #include "config.h" #include "omvs_gst.h" +#include "omvs_gst_plugin.h" #define _OMVS_IPPROTO_UDP 17 @@ -308,7 +309,7 @@ static gpointer _omvs_start_scan_job(gpointer data) { if (!is_udp_port_found) { gchar *uri; gchar *filename; - uri = g_strdup_printf("udp://%s:%d", addr_str, udp_port); + uri = g_strdup_printf("rtp://%s:%d", addr_str, udp_port); filename = g_strdup_printf("%s/%s-%d.png", _omvs_outdir, addr_str, udp_port); if (!_omvs_quiet) { @@ -533,7 +534,7 @@ static gint _omvs_wait_for_multicast_packet(void) { (haddr >> 16) & 0xff, (haddr >> 8) & 0xff, (haddr >> 0) & 0xff); - uri = g_strdup_printf("udp://%s:%u", addr_str, udp_port); + uri = g_strdup_printf("rtp://%s:%u", addr_str, udp_port); filename = g_strdup_printf("%s/%s-%d.png", _omvs_outdir, addr_str, udp_port); g_free(addr_str); @@ -609,6 +610,8 @@ int main(int argc, char *argv[]) { goto finish_return; } + omvs_gst_plugin_register(); + g_mkdir(_omvs_outdir, 0755); if (_omvs_wait) {