Merge branch 'master' into 0.11

Conflicts:
	common
	configure.ac
This commit is contained in:
Wim Taymans 2011-04-26 19:07:13 +02:00
commit 6959ebd8e8
52 changed files with 3117 additions and 586 deletions

4
.gitignore vendored
View file

@ -10,6 +10,7 @@
*~ *~
.deps .deps
.libs .libs
ABOUT-NLS
INSTALL INSTALL
Makefile Makefile
Makefile.in Makefile.in
@ -21,6 +22,7 @@ config.guess
config.h config.h
config.h.in config.h.in
config.log config.log
config.rpath
config.status config.status
config.sub config.sub
configure configure
@ -34,3 +36,5 @@ bindings/python/rtspserver.c
tags tags
gst-rtsp.spec gst-rtsp.spec
stamp-h.in stamp-h.in
/m4/*m4

View file

@ -3,11 +3,11 @@ DISTCHECK_CONFIGURE_FLAGS=--enable-gtk-doc
SUBDIRS = \ SUBDIRS = \
gst \ gst \
bindings \ bindings \
m4 \
common \ common \
pkgconfig \ pkgconfig \
docs \ docs \
examples examples \
tests
DIST_SUBDIRS = $(SUBDIRS) DIST_SUBDIRS = $(SUBDIRS)
@ -16,13 +16,15 @@ EXTRA_DIST = \
AUTHORS COPYING NEWS README RELEASE REQUIREMENTS \ AUTHORS COPYING NEWS README RELEASE REQUIREMENTS \
gst-rtsp.spec docs/design/gst-rtp-server-design gst-rtsp.spec docs/design/gst-rtp-server-design
ACLOCAL_AMFLAGS = -I common/m4 -I m4 ACLOCAL_AMFLAGS = -I m4 -I common/m4
DISTCLEANFILES = _stdint.h gst-rtsp.spec DISTCLEANFILES = _stdint.h gst-rtsp.spec
include $(top_srcdir)/common/release.mak include $(top_srcdir)/common/release.mak
include $(top_srcdir)/common/po.mak include $(top_srcdir)/common/po.mak
include $(top_srcdir)/common/coverage/lcov.mak
check-valgrind: check-valgrind:
cd tests/check && make check-valgrind cd tests/check && make check-valgrind
@ -37,7 +39,41 @@ endif
# cruft: plugins that have been merged or moved or renamed # cruft: plugins that have been merged or moved or renamed
CRUFT_FILES = \ CRUFT_FILES = \
$(top_builddir)/common/shave \ $(top_builddir)/common/shave \
$(top_builddir)/common/shave-libtool $(top_builddir)/common/shave-libtool \
$(top_builddir)/common/m4/codeset.m4 \
$(top_builddir)/common/m4/gettext.m4 \
$(top_builddir)/common/m4/glibc2.m4 \
$(top_builddir)/common/m4/glibc21.m4 \
$(top_builddir)/common/m4/iconv.m4 \
$(top_builddir)/common/m4/intdiv0.m4 \
$(top_builddir)/common/m4/intl.m4 \
$(top_builddir)/common/m4/intldir.m4 \
$(top_builddir)/common/m4/intlmacosx.m4 \
$(top_builddir)/common/m4/intmax.m4 \
$(top_builddir)/common/m4/inttypes-pri.m4 \
$(top_builddir)/common/m4/inttypes_h.m4 \
$(top_builddir)/common/m4/lcmessage.m4 \
$(top_builddir)/common/m4/lib-ld.m4 \
$(top_builddir)/common/m4/lib-link.m4 \
$(top_builddir)/common/m4/lib-prefix.m4 \
$(top_builddir)/common/m4/libtool.m4 \
$(top_builddir)/common/m4/lock.m4 \
$(top_builddir)/common/m4/longlong.m4 \
$(top_builddir)/common/m4/ltoptions.m4 \
$(top_builddir)/common/m4/ltsugar.m4 \
$(top_builddir)/common/m4/ltversion.m4 \
$(top_builddir)/common/m4/lt~obsolete.m4 \
$(top_builddir)/common/m4/nls.m4 \
$(top_builddir)/common/m4/po.m4 \
$(top_builddir)/common/m4/printf-posix.m4 \
$(top_builddir)/common/m4/progtest.m4 \
$(top_builddir)/common/m4/size_max.m4 \
$(top_builddir)/common/m4/stdint_h.m4 \
$(top_builddir)/common/m4/uintmax_t.m4 \
$(top_builddir)/common/m4/visibility.m4 \
$(top_builddir)/common/m4/wchar_t.m4 \
$(top_builddir)/common/m4/wint_t.m4 \
$(top_builddir)/common/m4/xsize.m4
include $(top_srcdir)/common/cruft.mak include $(top_srcdir)/common/cruft.mak

View file

@ -83,7 +83,7 @@ tool_run "$libtoolize" "--copy --force"
tool_run "$aclocal" "-I m4 -I common/m4 $ACLOCAL_FLAGS" tool_run "$aclocal" "-I m4 -I common/m4 $ACLOCAL_FLAGS"
tool_run "$autoheader" tool_run "$autoheader"
# touch the stamp-h.in build stamp so we don't re-run autoheader in maintainer mode -- wingo # touch the stamp-h.in build stamp so we don't re-run autoheader in maintainer mode
echo timestamp > stamp-h.in 2> /dev/null echo timestamp > stamp-h.in 2> /dev/null
tool_run "$autoconf" tool_run "$autoconf"

View file

@ -37,6 +37,7 @@ rtspserver.c: $(DEFS) $(OVERRIDES) arg-types.py
($(PYTHON) $(srcdir)/codegen/codegen.py \ ($(PYTHON) $(srcdir)/codegen/codegen.py \
--load-types $(srcdir)/arg-types.py \ --load-types $(srcdir)/arg-types.py \
--register $(srcdir)/rtspserver-types.defs \ --register $(srcdir)/rtspserver-types.defs \
--register $(PYGST_DEFSDIR)/gst-types.defs \
--override $(srcdir)/$*.override \ --override $(srcdir)/$*.override \
--extendpath $(top_builddir)/gst/ \ --extendpath $(top_builddir)/gst/ \
--extendpath $(srcdir)/ \ --extendpath $(srcdir)/ \

View file

@ -145,6 +145,54 @@ class GstIteratorArg(ArgType):
info.varlist.add('GstIterator', '*ret') info.varlist.add('GstIterator', '*ret')
info.codeafter.append(' return pygst_iterator_new(ret);') info.codeafter.append(' return pygst_iterator_new(ret);')
class GstRTSPUrlArg(ArgType):
"""GstRTSPUrl node generator"""
before = (' parse_result = gst_rtsp_url_parse (py_%(name)s, &%(name)s);\n'
' if (parse_result != GST_RTSP_OK) {\n'
' PyErr_SetString(PyExc_TypeError, "invalid url");\n'
' return NULL;\n'
' }')
beforenull = (' if (py_%(name)s == NULL)\n'
' %(name)s = NULL;\n'
' else\n'
' ' + before)
after = (' if (%(name)s)\n'
' gst_rtsp_url_free (%(name)s);\n')
def write_param(self, ptype, pname, pdflt, pnull, keeprefcount, info):
if ptype in ('const-GstRTSPUrl*', 'GstRTSPUrl*'):
self.write_normal_param(pname, pdflt, pnull, info)
else:
raise RuntimeError, "write_param not implemented for %s" % ptype
def write_normal_param(self, pname, pdflt, pnull, info):
info.varlist.add('GstRTSPResult', 'parse_result')
if pdflt:
assert pdflt == 'NULL'
info.varlist.add('const char', '*py_' + pname + ' = NULL')
else:
info.varlist.add('const char', '*py_' + pname)
info.varlist.add('GstRTSPUrl', '*'+pname)
info.add_parselist('s', ['&py_'+pname], [pname])
info.arglist.append(pname)
if pnull:
info.codebefore.append (self.beforenull % { 'name' : pname })
else:
info.codebefore.append (self.before % { 'name' : pname })
info.codeafter.append (self.after % { 'name' : pname })
def write_return(self, ptype, ownsreturn, info):
if ptype == 'GstRTSPUrl*':
info.varlist.add('GstRTSPUrl', '*ret')
copyval = 'FALSE'
elif ptype == 'const-GstRTSPUrl*':
info.varlist.add('const GstRTSPUrl', '*ret')
copyval = 'TRUE'
else:
raise RuntimeError, "write_return not implemented for %s" % ptype
info.codeafter.append(' return pyg_boxed_new (GST_TYPE_RTSP_URL, ret, '+copyval+', TRUE);')
class GstMiniObjectParam(Parameter): class GstMiniObjectParam(Parameter):
def get_c_type(self): def get_c_type(self):
@ -165,6 +213,31 @@ class GstMiniObjectParam(Parameter):
matcher.register_reverse('GstMiniObject*', GstMiniObjectParam) matcher.register_reverse('GstMiniObject*', GstMiniObjectParam)
class GstRTSPUrlParam(Parameter):
def get_c_type(self):
c_type = self.props.get('c_type', None)
if c_type and c_type.startswith('const'):
return 'const GstRTSPUrl *'
return 'GstRTSPUrl *'
def convert_c2py(self):
self.wrapper.add_declaration("char *%s_str = NULL;" % self.name)
self.wrapper.add_declaration("PyObject *py_%s = NULL;" % self.name)
self.wrapper.write_code(code=("if (%(name)s) {\n"
" %(name)s_str = gst_rtsp_url_get_request_uri ((GstRTSPUrl*) %(name)s);\n"
" py_%(name)s = PyString_FromString (%(name)s_str);\n"
" g_free (%(name)s_str);\n"
"} else {\n"
" Py_INCREF(Py_None);\n"
" py_%(name)s = Py_None;\n"
"}" % {'name': self.name}),
cleanup=("Py_DECREF(py_%s);" % self.name))
self.wrapper.add_pyargv_item("py_%s" % self.name)
matcher.register_reverse('const-GstRTSPUrl*', GstRTSPUrlParam)
matcher.register_reverse('GstRTSPUrl*', GstRTSPUrlParam)
class GstMiniObjectReturn(ReturnType): class GstMiniObjectReturn(ReturnType):
def get_c_type(self): def get_c_type(self):
@ -343,6 +416,8 @@ matcher.register('GstCaps', GstCapsArg()) #FIXME: does this work?
matcher.register('GstCaps*', GstCapsArg()) #FIXME: does this work? matcher.register('GstCaps*', GstCapsArg()) #FIXME: does this work?
matcher.register('const-GstCaps*', GstCapsArg()) matcher.register('const-GstCaps*', GstCapsArg())
matcher.register('GstIterator*', GstIteratorArg()) matcher.register('GstIterator*', GstIteratorArg())
matcher.register('const-GstRTSPUrl*', GstRTSPUrlArg())
matcher.register('GstRTSPUrl*', GstRTSPUrlArg())
arg = PointerArg('gpointer', 'G_TYPE_POINTER') arg = PointerArg('gpointer', 'G_TYPE_POINTER')
matcher.register('GstClockID', arg) matcher.register('GstClockID', arg)

View file

@ -1,6 +1,63 @@
;; From gst/rtsp-server/rtsp-server.h
(define-object Server (define-object Server
(in-module "Gst.RTSPServer") (in-module "Gst.RTSPServer")
(parent "GObject") (parent "GObject")
(c-name "GstRTSPServer") (c-name "GstRTSPServer")
(gtype-id "GST_TYPE_RTSP_SERVER") (gtype-id "GST_TYPE_RTSP_SERVER")
) )
;; From gst/rtsp-server/rtsp-media-mapping.h
(define-object MediaMapping
(in-module "Gst.RTSPServer")
(parent "GObject")
(c-name "GstRTSPMediaMapping")
(gtype-id "GST_TYPE_RTSP_MEDIA_MAPPING")
)
;; From gst/rtsp-server/rtsp-media-factory.h
(define-object MediaFactory
(in-module "Gst.RTSPServer")
(parent "GObject")
(c-name "GstRTSPMediaFactory")
(gtype-id "GST_TYPE_RTSP_MEDIA_FACTORY")
)
;; From gst/rtsp-server/rtsp-media.h
(define-object Media
(in-module "Gst.RTSPServer")
(parent "GObject")
(c-name "GstRTSPMedia")
(gtype-id "GST_TYPE_RTSP_MEDIA")
)
;; From gst/rtsp-server/rtsp-session-pool.h
(define-object SessionPool
(in-module "Gst")
(parent "GObject")
(c-name "GstRTSPSessionPool")
(gtype-id "GST_TYPE_RTSP_SESSION_POOL")
)
;; From gst/rtsp-server/rtsp-session.h
(define-object Session
(in-module "Gst")
(parent "GObject")
(c-name "GstRTSPSession")
(gtype-id "GST_TYPE_RTSP_SESSION")
)
;; From gst/rtsp-server/rtsp-client.h
(define-object Client
(in-module "Gst")
(parent "GObject")
(c-name "GstRTSPClient")
(gtype-id "GST_TYPE_RTSP_CLIENT")
)

View file

@ -1,11 +1,99 @@
(include "rtspserver-types.defs") (include "rtspserver-types.defs")
;; From gst/rtsp-server/rtsp-server.h
(define-function rtsp_server_new (define-function rtsp_server_new
(c-name "gst_rtsp_server_new") (c-name "gst_rtsp_server_new")
(is-constructor-of "GstRTSPServer") (is-constructor-of "GstRTSPServer")
(return-type "GstRTSPServer*") (return-type "GstRTSPServer*")
) )
(define-method set_address
(of-object "GstRTSPServer")
(c-name "gst_rtsp_server_set_address")
(parameters
'("const-gchar*" "address")
)
)
(define-method get_address
(of-object "GstRTSPServer")
(c-name "gst_rtsp_server_get_address")
(return-type "const-gchar*")
)
(define-method set_service
(of-object "GstRTSPServer")
(c-name "gst_rtsp_server_set_service")
(parameters
'("const-gchar*" "service")
)
)
(define-method get_service
(of-object "GstRTSPServer")
(c-name "gst_rtsp_server_get_service")
(return-type "const-gchar*")
)
(define-method set_backlog
(of-object "GstRTSPServer")
(c-name "gst_rtsp_server_set_backlog")
(parameters
'("gint" "backlog")
)
)
(define-method get_backlog
(of-object "GstRTSPServer")
(c-name "gst_rtsp_server_get_backlog")
(return-type "gint")
)
(define-method set_session_pool
(of-object "GstRTSPServer")
(c-name "gst_rtsp_server_set_session_pool")
(parameters
'("GstRTSPSessionPool*" "pool")
)
)
(define-method get_session_pool
(of-object "GstRTSPServer")
(c-name "gst_rtsp_server_get_session_pool")
(return-type "GstRTSPSessionPool*")
)
(define-method set_media_mapping
(of-object "GstRTSPServer")
(c-name "gst_rtsp_server_set_media_mapping")
(parameters
'("GstRTSPMediaMapping*" "mapping")
)
)
(define-method get_media_mapping
(of-object "GstRTSPServer")
(c-name "gst_rtsp_server_get_media_mapping")
(return-type "GstRTSPMediaMapping*")
)
(define-function io_func
(c-name "gst_rtsp_server_io_func")
(return-type "gboolean")
(parameters
'("GIOChannel*" "channel")
'("GIOCondition" "condition")
'("GstRTSPServer*" "server")
)
)
(define-method get_io_channel
(of-object "GstRTSPServer")
(c-name "gst_rtsp_server_get_io_channel")
(return-type "GIOChannel*")
)
(define-method attach (define-method attach
(of-object "GstRTSPServer") (of-object "GstRTSPServer")
(c-name "gst_rtsp_server_attach") (c-name "gst_rtsp_server_attach")
@ -14,3 +102,298 @@
'("GMainContext*" "context") '("GMainContext*" "context")
) )
) )
(define-method create_watch
(of-object "GstRTSPServer")
(c-name "gst_rtsp_server_create_watch")
(return-type "GSource*")
)
;; From gst/rtsp-server/rtsp-media-mapping.h
(define-function rtsp_media_mapping_new
(c-name "gst_rtsp_media_mapping_new")
(is-constructor-of "GstRTSPMediaMapping")
(return-type "GstRTSPMediaMapping*")
)
;; TODO define const-GstRTSPUrl* on arg-types.py
(define-method find_factory
(of-object "GstRTSPMediaMapping")
(c-name "gst_rtsp_media_mapping_find_factory")
(return-type "GstRTSPMediaFactory*")
(parameters
'("const-GstRTSPUrl*" "url")
)
)
(define-method add_factory
(of-object "GstRTSPMediaMapping")
(c-name "gst_rtsp_media_mapping_add_factory")
(parameters
'("const-gchar*" "path")
'("GstRTSPMediaFactory*" "factory")
)
)
(define-method remove_factory
(of-object "GstRTSPMediaMapping")
(c-name "gst_rtsp_media_mapping_remove_factory")
(parameters
'("const-gchar*" "path")
)
)
;; From gst/rtsp-server/rtsp-media-factory.h
(define-function rtsp_media_factory_new
(c-name "gst_rtsp_media_factory_new")
(is-constructor-of "GstRTSMediaFactory")
(return-type "GstRTSPMediaFactory*")
)
(define-method set_launch
(of-object "GstRTSPMediaFactory")
(c-name "gst_rtsp_media_factory_set_launch")
(parameters
'("gchar*" "launch")
)
)
(define-method get_launch
(of-object "GstRTSPMediaFactory")
(c-name "gst_rtsp_media_factory_get_launch")
(return-type "gchar*")
)
(define-method set_shared
(of-object "GstRTSPMediaFactory")
(c-name "gst_rtsp_media_factory_set_shared")
(parameters
'("gboolean" "shared")
)
)
(define-method is_shared
(of-object "GstRTSPMediaFactory")
(c-name "gst_rtsp_media_factory_is_shared")
(return-type "gboolean")
)
(define-method set_eos_shutdown
(of-object "GstRTSPMediaFactory")
(c-name "gst_rtsp_media_factory_set_eos_shutdown")
(parameters
'("gboolean" "eos_shutdown")
)
)
(define-method is_eos_shutdown
(of-object "GstRTSPMediaFactory")
(c-name "gst_rtsp_media_factory_is_eos_shutdown")
(return-type "gboolean")
)
;; TODO define const-GstRTSPUrl* on arg-types.py
(define-method construct
(of-object "GstRTSPMediaFactory")
(c-name "gst_rtsp_media_factory_construct")
(return-type "GstRTSPMedia*")
(parameters
'("const-GstRTSPUrl*" "url")
)
)
(define-method collect_streams
(of-object "GstRTSPMediaFactory")
(c-name "gst_rtsp_media_factory_collect_streams")
(parameters
'("const-GstRTSPUrl*" "url")
'("GstRTSPMedia*" "media")
)
)
(define-virtual get_element
(of-object "GstRTSPMediaFactory")
(parameters
'("const-GstRTSPUrl*" "url")
)
(return-type "GstElement*")
)
(define-virtual construct
(of-object "GstRTSPMediaFactory")
(parameters
'("const-GstRTSPUrl*" "url")
)
(return-type "GstRTSPMedia*")
)
(define-virtual configure
(of-object "GstRTSPMediaFactory")
(parameters
'("GstRTSPMedia*" "media")
)
(return-type "none")
)
(define-virtual create_pipeline
(of-object "GstRTSPMediaFactory")
(parameters
'("GstRTSPMedia*" "media")
)
(return-type "GstElement*")
)
;; From gst/rtsp-server/rtsp-session-pool.h
(define-function gst_rtsp_session_pool_new
(c-name "gst_rtsp_session_pool_new")
(is-constructor-of "GstRTSPSessionPool")
(return-type "GstRTSPSessionPool*")
)
(define-method set_max_sessions
(of-object "GstRTSPSessionPool")
(c-name "gst_rtsp_session_pool_set_max_sessions")
(return-type "none")
(parameters
'("guint" "max")
)
)
(define-method get_max_sessions
(of-object "GstRTSPSessionPool")
(c-name "gst_rtsp_session_pool_get_max_sessions")
(return-type "guint")
)
(define-method get_n_sessions
(of-object "GstRTSPSessionPool")
(c-name "gst_rtsp_session_pool_get_n_sessions")
(return-type "guint")
)
(define-method create
(of-object "GstRTSPSessionPool")
(c-name "gst_rtsp_session_pool_create")
(return-type "GstRTSPSession*")
)
(define-method find
(of-object "GstRTSPSessionPool")
(c-name "gst_rtsp_session_pool_find")
(return-type "GstRTSPSession*")
(parameters
'("const-gchar*" "sessionid")
)
)
(define-method remove
(of-object "GstRTSPSessionPool")
(c-name "gst_rtsp_session_pool_remove")
(return-type "gboolean")
(parameters
'("GstRTSPSession*" "sess")
)
)
(define-method filter
(of-object "GstRTSPSessionPool")
(c-name "gst_rtsp_session_pool_filter")
(return-type "GList*")
(parameters
'("GstRTSPSessionFilterFunc" "func")
'("gpointer" "user_data")
)
)
(define-method cleanup
(of-object "GstRTSPSessionPool")
(c-name "gst_rtsp_session_pool_cleanup")
(return-type "guint")
)
(define-method create_watch
(of-object "GstRTSPSessionPool")
(c-name "gst_rtsp_session_pool_create_watch")
(return-type "GSource*")
)
;; From gst/rtsp-server/rtsp-client.h
(define-function gst_rtsp_client_new
(c-name "gst_rtsp_client_new")
(is-constructor-of "GstRTSPClient")
(return-type "GstRTSPClient*")
)
(define-method set_session_pool
(of-object "GstRTSPClient")
(c-name "gst_rtsp_client_set_session_pool")
(return-type "none")
(parameters
'("GstRTSPSessionPool*" "pool")
)
)
(define-method get_session_pool
(of-object "GstRTSPClient")
(c-name "gst_rtsp_client_get_session_pool")
(return-type "GstRTSPSessionPool*")
)
(define-method set_media_mapping
(of-object "GstRTSPClient")
(c-name "gst_rtsp_client_set_media_mapping")
(return-type "none")
(parameters
'("GstRTSPMediaMapping*" "mapping")
)
)
(define-method get_media_mapping
(of-object "GstRTSPClient")
(c-name "gst_rtsp_client_get_media_mapping")
(return-type "GstRTSPMediaMapping*")
)
(define-method accept
(of-object "GstRTSPClient")
(c-name "gst_rtsp_client_accept")
(return-type "gboolean")
(parameters
'("GIOChannel*" "channel")
)
)
;; From bindings/python/rtsp-params.h
(define-function gst_rtsp_params_set
(c-name "gst_rtsp_params_set")
(return-type "GstRTSPResult")
(parameters
'("GstRTSPClient*" "client")
'("GstRTSPUrl*" "uri")
'("GstRTSPSession*" "session")
'("GstRTSPMessage*" "request")
'("GstRTSPMessage*" "response")
)
)
(define-function gst_rtsp_params_get
(c-name "gst_rtsp_params_get")
(return-type "GstRTSPResult")
(parameters
'("GstRTSPClient*" "client")
'("GstRTSPUrl*" "uri")
'("GstRTSPSession*" "session")
'("GstRTSPMessage*" "request")
'("GstRTSPMessage*" "response")
)
)

View file

@ -5,6 +5,11 @@ headers
#define NO_IMPORT_PYGOBJECT #define NO_IMPORT_PYGOBJECT
#include <pygobject.h> #include <pygobject.h>
#include <gst/gst.h>
#include <gst/rtsp-server/rtsp-server.h>
#include <glib.h>
#ifdef HAVE_CONFIG_H #ifdef HAVE_CONFIG_H
# include <config.h> # include <config.h>
#endif #endif
@ -24,7 +29,6 @@ typedef struct {
%% %%
import gobject.GObject as PyGObject_Type import gobject.GObject as PyGObject_Type
import gobject.MainContext as PyGMainContext_Type import gobject.MainContext as PyGMainContext_Type
%% %%
override gst_rtsp_server_attach kwargs override gst_rtsp_server_attach kwargs
static PyObject * static PyObject *
@ -50,3 +54,14 @@ _wrap_gst_rtsp_server_attach (PyGObject *self,
return PyLong_FromLong (res); return PyLong_FromLong (res);
} }
%%
override gst_rtsp_server_create_watch kwargs
static PyObject *
_wrap_gst_rtsp_server_create_watch(PyGObject *self, PyObject *args, PyObject *keywords)
{
GSource *ret;
pyg_begin_allow_threads;
ret = gst_rtsp_server_create_watch(GST_RTSP_SERVER(self->obj));
pyg_end_allow_threads;
return pygobject_new((GObject *)ret);
}

130
bindings/python/test.py Normal file
View file

@ -0,0 +1,130 @@
import unittest
import rtspserver
def pubdir(obj):
return [d for d in dir(obj) if not d.startswith('_')]
#print 'Module listing:', pubdir(rtspserver)
from rtspserver import Server, SessionPool, Session, MediaMapping, MediaFactory
#print 'Server listing: ', pubdir(Server)
#print 'MediaMapping listing: ', pubdir(MediaMapping)
#print 'MediaFactory listing: ', pubdir(MediaFactory)
#print 'SessionPool listing: ', pubdir(SessionPool)
#print 'Session listing: ', pubdir(Session)
class ServerTestCase(unittest.TestCase):
def setUp(self):
self.server = Server()
def tearDown(self):
del self.server
def test_address(self):
""" Server address set/get """
addr = '1.2.3.4'
self.server.set_address(addr)
self.assertEquals(addr, self.server.get_address())
def test_service(self):
""" Server service set/get """
service = '12345'
self.server.set_service(service)
self.assertEquals(service, self.server.get_service())
def test_backlog(self):
""" Server backlog set/get """
backlog = 1234
self.server.set_backlog(backlog)
self.assertEquals(backlog, self.server.get_backlog())
def test_session_pool(self):
""" Server session pool set/get """
pool = SessionPool()
self.server.set_session_pool(pool)
self.assertEquals(pool, self.server.get_session_pool())
def test_media_mapping(self):
""" Server media mapping set/get """
mmap = MediaMapping()
self.server.set_media_mapping(mmap)
self.assertEquals(mmap, self.server.get_media_mapping())
class MediaMappingTestCase(unittest.TestCase):
def setUp(self):
self.mmap = MediaMapping()
def tearDown(self):
del self.mmap
def test_factory(self):
""" MediaMapping factory add/remove """
self.factory = MediaFactory()
self.mmap.add_factory("/test", self.factory)
self.mmap.remove_factory("/test")
class MediaFactoryTestCase(unittest.TestCase):
def setUp(self):
self.factory = MediaFactory()
def tearDown(self):
del self.factory
def test_launch(self):
""" MediaFactory launch set/get """
launch = "videotestsrc ! xvimagesink"
self.factory.set_launch(launch)
self.assertEquals(launch, self.factory.get_launch())
def test_shared(self):
""" MediaFactory shared set/is """
self.factory.set_shared(True)
self.assert_(self.factory.is_shared())
self.factory.set_shared(False)
self.assert_(not self.factory.is_shared())
def test_eos_shutdown(self):
""" MediaFactory eos_shutdown set/is """
self.factory.set_eos_shutdown(True)
self.assert_(self.factory.is_eos_shutdown())
self.factory.set_eos_shutdown(False)
self.assert_(not self.factory.is_eos_shutdown())
def alltests():
tests = []
for p in dir(ServerTestCase):
try:
if 'test_' in p:
tests.append(ServerTestCase(p))
except:
pass
for p in dir(MediaMappingTestCase):
try:
if 'test_' in p:
tests.append(MediaMappingTestCase(p))
except:
pass
for p in dir(MediaFactoryTestCase):
try:
if 'test_' in p:
tests.append(MediaFactoryTestCase(p))
except:
pass
return unittest.TestSuite(tests)
unittest.TextTestRunner(verbosity=2).run(alltests())

View file

@ -52,6 +52,7 @@ AS_AUTOTOOLS_ALTERNATE
dnl Add parameters for aclocal dnl Add parameters for aclocal
AC_SUBST(ACLOCAL_AMFLAGS, "-I m4 -I common/m4") AC_SUBST(ACLOCAL_AMFLAGS, "-I m4 -I common/m4")
AC_CONFIG_MACRO_DIR([m4])
dnl set up gettext dnl set up gettext
dnl the version check needs to stay here because autopoint greps for it dnl the version check needs to stay here because autopoint greps for it
@ -67,6 +68,8 @@ AG_GST_ARG_GCOV
AG_GST_ARG_WITH_PACKAGE_NAME AG_GST_ARG_WITH_PACKAGE_NAME
AG_GST_ARG_WITH_PACKAGE_ORIGIN AG_GST_ARG_WITH_PACKAGE_ORIGIN
AG_GST_PKG_CONFIG_PATH
dnl *** checks for platform *** dnl *** checks for platform ***
dnl * hardware/architecture * dnl * hardware/architecture *
@ -77,6 +80,16 @@ dnl find a compiler
AC_PROG_CC AC_PROG_CC
AM_PROG_CC_C_O AM_PROG_CC_C_O
AC_PATH_PROG(VALGRIND_PATH, valgrind, no)
AM_CONDITIONAL(HAVE_VALGRIND, test ! "x$VALGRIND_PATH" = "xno")
dnl check for gobject-introspection
GOBJECT_INTROSPECTION_CHECK([0.6.3])
dnl check for documentation tools
AG_GST_DOCBOOK_CHECK
GTK_DOC_CHECK([1.3])
dnl check for python dnl check for python
AM_PATH_PYTHON AM_PATH_PYTHON
AC_MSG_CHECKING(for python >= 2.3) AC_MSG_CHECKING(for python >= 2.3)
@ -89,49 +102,33 @@ sys.exit(0)"
if $PYTHON -c "$prog" 1>&AC_FD_CC 2>&AC_FD_CC if $PYTHON -c "$prog" 1>&AC_FD_CC 2>&AC_FD_CC
then then
HAVE_PYTHON=yes
AC_MSG_RESULT(okay) AC_MSG_RESULT(okay)
else else
AC_MSG_ERROR(too old) HAVE_PYTHON=no
AC_MSG_RESULT(no python)
fi fi
AM_CHECK_PYTHON_HEADERS(,[AC_MSG_ERROR(could not find Python headers)])
AC_PATH_PROG(VALGRIND_PATH, valgrind, no) AM_CHECK_PYTHON_HEADERS([HAVE_PYTHON_HEADERS=yes],[HAVE_PYTHON_HEADERS=no])
AM_CONDITIONAL(HAVE_VALGRIND, test ! "x$VALGRIND_PATH" = "xno")
dnl check for gobject-introspection
GOBJECT_INTROSPECTION_CHECK([0.6.3])
dnl check for documentation tools
AG_GST_DOCBOOK_CHECK
GTK_DOC_CHECK([1.3])
AC_SUBST(PYGOBJECT_REQ, 2.11.2)
dnl check for pygobject (optional, used in the bindings) dnl check for pygobject (optional, used in the bindings)
PYGOBJECT_REQ=2.11.2
PKG_CHECK_MODULES(PYGOBJECT, pygobject-2.0 >= $PYGOBJECT_REQ, PKG_CHECK_MODULES(PYGOBJECT, pygobject-2.0 >= $PYGOBJECT_REQ,
[ [HAVE_PYGOBJECT="yes"], [HAVE_PYGOBJECT="no"])
HAVE_PYGOBJECT="yes"
],
[
HAVE_PYGOBJECT="no"
])
AC_SUBST(PYGOBJECT_CFLAGS) AC_SUBST(PYGOBJECT_CFLAGS)
dnl check for gst-python dnl check for gst-python
PKG_CHECK_MODULES(PYGST, gst-python-0.10, PKG_CHECK_MODULES(PYGST, gst-python-0.10,
[ [HAVE_PYGST="yes"], [HAVE_PYGST="no"])
HAVE_PYGST="yes"
],
[
HAVE_PYGST="no"
])
if test "x$HAVE_PYGST" = "xyes"; then if test "x$HAVE_PYGST" = "xyes"; then
PYGST_DEFSDIR=`pkg-config gst-python-0.10 --variable=defsdir` PYGST_DEFSDIR=`pkg-config gst-python-0.10 --variable=defsdir`
fi fi
AC_SUBST(PYGST_DEFSDIR, $PYGST_DEFSDIR) AC_SUBST(PYGST_DEFSDIR, $PYGST_DEFSDIR)
if test "x$HAVE_PYTHON_HEADERS" = "xyes" -a \ if test \
"x$HAVE_PYTHON" = "xyes" -a \
"x$HAVE_PYTHON_HEADERS" = "xyes" -a \
"x$HAVE_PYGOBJECT" = "xyes" -a \ "x$HAVE_PYGOBJECT" = "xyes" -a \
"x$HAVE_PYGST" = "xyes"; then "x$HAVE_PYGST" = "xyes"; then
HAVE_PYTHON_BINDINGS="yes" HAVE_PYTHON_BINDINGS="yes"
@ -286,10 +283,10 @@ Makefile
gst-rtsp.spec gst-rtsp.spec
common/Makefile common/Makefile
common/m4/Makefile common/m4/Makefile
m4/Makefile
gst/Makefile gst/Makefile
gst/rtsp-server/Makefile gst/rtsp-server/Makefile
examples/Makefile examples/Makefile
tests/Makefile
bindings/Makefile bindings/Makefile
bindings/python/Makefile bindings/python/Makefile
bindings/python/codegen/Makefile bindings/python/codegen/Makefile

1
docs/.gitignore vendored Normal file
View file

@ -0,0 +1 @@
version.entities

View file

@ -9,3 +9,12 @@ DIST_SUBDIRS = libs
EXTRA_DIST = \ EXTRA_DIST = \
version.entities.in version.entities.in
upload:
@if test "x$(SUBDIRS)" != x; then \
for a in $(SUBDIRS); do \
cd $$a; \
make upload; \
cd ..; \
done; \
fi

22
docs/libs/.gitignore vendored Normal file
View file

@ -0,0 +1,22 @@
*.stamp
html
tmpl
xml
Makefile
Makefile.in
*-decl.txt
*-decl-list.txt
*-presed-scan.c
*-undeclared.txt
*-undocumented.txt
*-unused.txt
*-overrides.txt
*.args
*.hierarchy
*.interfaces
*.prerequisites
*.signals
doc-registry.xml
*-unused.sgml
*.bak

View file

@ -8,7 +8,7 @@ DOC_MODULE=$(MODULE)
# for upload-doc.mak # for upload-doc.mak
DOC=$(MODULE) DOC=$(MODULE)
FORMATS=html ps pdf FORMATS=html
html: html-build.stamp html: html-build.stamp
include $(top_srcdir)/common/upload-doc.mak include $(top_srcdir)/common/upload-doc.mak

View file

@ -9,15 +9,17 @@
<bookinfo> <bookinfo>
<title>GStreamer RTSP Server Reference Manual</title> <title>GStreamer RTSP Server Reference Manual</title>
<releaseinfo> <releaseinfo>
for GStreamer RTSP Server &GST_MAJORMINOR; for GStreamer RTSP Server &GST_VERSION;
</releaseinfo> </releaseinfo>
</bookinfo> </bookinfo>
<chapter> <chapter>
<xi:include href="xml/rtsp-client.xml"/> <xi:include href="xml/rtsp-client.xml"/>
<xi:include href="xml/rtsp-media-factory.xml"/> <xi:include href="xml/rtsp-media-factory.xml"/>
<xi:include href="xml/rtsp-media-factory-uri.xml"/>
<xi:include href="xml/rtsp-media-mapping.xml"/> <xi:include href="xml/rtsp-media-mapping.xml"/>
<xi:include href="xml/rtsp-media.xml"/> <xi:include href="xml/rtsp-media.xml"/>
<xi:include href="xml/rtsp-auth.xml"/>
<xi:include href="xml/rtsp-params.xml"/> <xi:include href="xml/rtsp-params.xml"/>
<xi:include href="xml/rtsp-sdp.xml"/> <xi:include href="xml/rtsp-sdp.xml"/>
<xi:include href="xml/rtsp-server.xml"/> <xi:include href="xml/rtsp-server.xml"/>

View file

@ -45,6 +45,30 @@ GST_IS_RTSP_MEDIA_FACTORY_CLASS
GST_RTSP_MEDIA_FACTORY_GET_CLASS GST_RTSP_MEDIA_FACTORY_GET_CLASS
</SECTION> </SECTION>
<SECTION>
<FILE>rtsp-media-factory-uri</FILE>
<TITLE>GstRTSPMediaFactoryURI</TITLE>
GST_RTSP_MEDIA_FACTORY_GET_LOCK
GST_RTSP_MEDIA_FACTORY_LOCK
GST_RTSP_MEDIA_FACTORY_UNLOCK
GstRTSPMediaFactoryURI
GstRTSPMediaFactoryURIClass
gst_rtsp_media_factory_uri_new
gst_rtsp_media_factory_uri_set_uri
gst_rtsp_media_factory_uri_get_uri
<SUBSECTION Standard>
GST_IS_RTSP_MEDIA_FACTORY_URI
GST_IS_RTSP_MEDIA_FACTORY_URI_CLASS
GST_RTSP_MEDIA_FACTORY_URI
GST_RTSP_MEDIA_FACTORY_URI_CAST
GST_RTSP_MEDIA_FACTORY_URI_CLASS
GST_RTSP_MEDIA_FACTORY_URI_CLASS_CAST
GST_RTSP_MEDIA_FACTORY_URI_GET_CLASS
GST_TYPE_RTSP_MEDIA_FACTORY_URI
gst_rtsp_media_factory_uri_get_type
</SECTION>
<SECTION> <SECTION>
<FILE>rtsp-media</FILE> <FILE>rtsp-media</FILE>
<TITLE>GstRTSPMedia</TITLE> <TITLE>GstRTSPMedia</TITLE>
@ -53,6 +77,7 @@ GstRTSPMedia
GstRTSPMediaClass GstRTSPMediaClass
GstRTSPMediaTrans GstRTSPMediaTrans
GstRTSPSendFunc GstRTSPSendFunc
GstRTSPSendListFunc
GstRTSPKeepAliveFunc GstRTSPKeepAliveFunc
GstRTSPMediaStatus GstRTSPMediaStatus
gst_rtsp_media_new gst_rtsp_media_new
@ -70,6 +95,7 @@ gst_rtsp_media_unprepare
gst_rtsp_media_n_streams gst_rtsp_media_n_streams
gst_rtsp_media_get_stream gst_rtsp_media_get_stream
gst_rtsp_media_seek gst_rtsp_media_seek
gst_rtsp_media_get_range_string
gst_rtsp_media_stream_rtp gst_rtsp_media_stream_rtp
gst_rtsp_media_stream_rtcp gst_rtsp_media_stream_rtcp
gst_rtsp_media_set_state gst_rtsp_media_set_state
@ -103,6 +129,8 @@ gst_rtsp_server_set_session_pool
gst_rtsp_server_get_session_pool gst_rtsp_server_get_session_pool
gst_rtsp_server_set_media_mapping gst_rtsp_server_set_media_mapping
gst_rtsp_server_get_media_mapping gst_rtsp_server_get_media_mapping
gst_rtsp_server_get_auth
gst_rtsp_server_set_auth
gst_rtsp_server_io_func gst_rtsp_server_io_func
gst_rtsp_server_get_io_channel gst_rtsp_server_get_io_channel
gst_rtsp_server_create_watch gst_rtsp_server_create_watch
@ -186,16 +214,42 @@ GST_IS_RTSP_SESSION_CLASS
GST_RTSP_SESSION_GET_CLASS GST_RTSP_SESSION_GET_CLASS
</SECTION> </SECTION>
<SECTION>
<FILE>rtsp-auth</FILE>
<TITLE>GstRTSPAuth</TITLE>
GstRTSPAuth
GstRTSPAuthClass
gst_rtsp_auth_new
gst_rtsp_auth_set_basic
gst_rtsp_auth_setup_auth
gst_rtsp_auth_check_method
gst_rtsp_auth_make_basic
<SUBSECTION Standard>
GST_IS_RTSP_AUTH
GST_IS_RTSP_AUTH_CLASS
GST_RTSP_AUTH
GST_RTSP_AUTH_CAST
GST_RTSP_AUTH_CLASS
GST_RTSP_AUTH_CLASS_CAST
GST_RTSP_AUTH_GET_CLASS
GST_TYPE_RTSP_AUTH
gst_rtsp_auth_get_type
</SECTION>
<SECTION> <SECTION>
<FILE>rtsp-client</FILE> <FILE>rtsp-client</FILE>
<TITLE>GstRTSPClient</TITLE> <TITLE>GstRTSPClient</TITLE>
GstRTSPClient GstRTSPClient
GstRTSPClientClass GstRTSPClientClass
gst_rtsp_client_new gst_rtsp_client_new
gst_rtsp_client_set_server
gst_rtsp_client_get_server
gst_rtsp_client_set_session_pool gst_rtsp_client_set_session_pool
gst_rtsp_client_get_session_pool gst_rtsp_client_get_session_pool
gst_rtsp_client_set_media_mapping gst_rtsp_client_set_media_mapping
gst_rtsp_client_get_media_mapping gst_rtsp_client_get_media_mapping
gst_rtsp_client_set_auth
gst_rtsp_client_get_auth
gst_rtsp_client_accept gst_rtsp_client_accept
<SUBSECTION Standard> <SUBSECTION Standard>
GST_RTSP_CLIENT_CLASS GST_RTSP_CLIENT_CLASS

View file

@ -1,4 +1,5 @@
#include <gst/gst.h> #include <gst/gst.h>
gst_rtsp_auth_get_type
gst_rtsp_media_mapping_get_type gst_rtsp_media_mapping_get_type
gst_rtsp_media_factory_get_type gst_rtsp_media_factory_get_type
gst_rtsp_media_get_type gst_rtsp_media_get_type

View file

@ -1 +1,2 @@
<!ENTITY GST_MAJORMINOR "@GST_MAJORMINOR@"> <!ENTITY GST_MAJORMINOR "@GST_MAJORMINOR@">
<!ENTITY GST_VERSION "@VERSION@">

2
examples/.gitignore vendored
View file

@ -4,3 +4,5 @@ test-ogg
test-readme test-readme
test-sdp test-sdp
test-video test-video
test-uri
test-auth

View file

@ -1,4 +1,4 @@
noinst_PROGRAMS = test-video test-ogg test-mp4 test-readme test-launch test-sdp test-uri noinst_PROGRAMS = test-video test-ogg test-mp4 test-readme test-launch test-sdp test-uri test-auth
INCLUDES = -I$(top_srcdir) -I$(srcdir) INCLUDES = -I$(top_srcdir) -I$(srcdir)

115
examples/test-auth.c Normal file
View file

@ -0,0 +1,115 @@
/* GStreamer
* Copyright (C) 2008 Wim Taymans <wim.taymans at gmail.com>
*
* 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.
*/
#include <gst/gst.h>
#include <gst/rtsp-server/rtsp-server.h>
static gboolean
timeout (GstRTSPServer * server, gboolean ignored)
{
GstRTSPSessionPool *pool;
pool = gst_rtsp_server_get_session_pool (server);
gst_rtsp_session_pool_cleanup (pool);
g_object_unref (pool);
return TRUE;
}
int
main (int argc, char *argv[])
{
GMainLoop *loop;
GstRTSPServer *server;
GstRTSPMediaMapping *mapping;
GstRTSPMediaFactory *factory;
GstRTSPAuth *auth;
gchar *basic;
gst_init (&argc, &argv);
loop = g_main_loop_new (NULL, FALSE);
/* create a server instance */
server = gst_rtsp_server_new ();
/* get the mapping for this server, every server has a default mapper object
* that be used to map uri mount points to media factories */
mapping = gst_rtsp_server_get_media_mapping (server);
/* make a media factory for a test stream. The default media factory can use
* gst-launch syntax to create pipelines.
* any launch line works as long as it contains elements named pay%d. Each
* element with pay%d names will be a stream */
factory = gst_rtsp_media_factory_new ();
gst_rtsp_media_factory_set_launch (factory, "( "
"videotestsrc ! video/x-raw-yuv,width=352,height=288,framerate=15/1 ! "
"x264enc ! rtph264pay name=pay0 pt=96 "
"audiotestsrc ! audio/x-raw-int,rate=8000 ! "
"alawenc ! rtppcmapay name=pay1 pt=97 " ")");
/* make a new authentication manager */
auth = gst_rtsp_auth_new ();
basic = gst_rtsp_auth_make_basic ("user", "admin");
gst_rtsp_auth_set_basic (auth, basic);
g_free (basic);
gst_rtsp_media_factory_set_auth (factory, auth);
g_object_unref (auth);
/* attach the test factory to the /test url */
gst_rtsp_media_mapping_add_factory (mapping, "/test", factory);
/* make another factory */
factory = gst_rtsp_media_factory_new ();
gst_rtsp_media_factory_set_launch (factory, "( "
"videotestsrc ! video/x-raw-yuv,width=352,height=288,framerate=30/1 ! "
"x264enc ! rtph264pay name=pay0 pt=96 )");
/* make a new authentication manager */
auth = gst_rtsp_auth_new ();
basic = gst_rtsp_auth_make_basic ("user2", "admin2");
gst_rtsp_auth_set_basic (auth, basic);
g_free (basic);
gst_rtsp_media_factory_set_auth (factory, auth);
g_object_unref (auth);
/* attach the test factory to the /test url */
gst_rtsp_media_mapping_add_factory (mapping, "/test2", factory);
/* don't need the ref to the mapper anymore */
g_object_unref (mapping);
/* attach the server to the default maincontext */
if (gst_rtsp_server_attach (server, NULL) == 0)
goto failed;
g_timeout_add_seconds (2, (GSourceFunc) timeout, server);
/* start serving */
g_main_loop_run (loop);
return 0;
/* ERRORS */
failed:
{
g_print ("failed to attach the server\n");
return -1;
}
}

View file

@ -60,7 +60,13 @@ main (int argc, char *argv[])
/* make a URI media factory for a test stream. */ /* make a URI media factory for a test stream. */
factory = gst_rtsp_media_factory_uri_new (); factory = gst_rtsp_media_factory_uri_new ();
/* when using GStreamer as a client, one can use the gst payloader, which is
* more efficient when there is no payloader for the compressed format */
/* g_object_set (factory, "use-gstpay", TRUE, NULL); */
gst_rtsp_media_factory_uri_set_uri (factory, argv[1]); gst_rtsp_media_factory_uri_set_uri (factory, argv[1]);
/* if you want multiple clients to see the same video, set the shared property
* to TRUE */
/* gst_rtsp_media_factory_set_shared ( GST_RTSP_MEDIA_FACTORY (factory), TRUE); */
/* attach the test factory to the /test url */ /* attach the test factory to the /test url */
gst_rtsp_media_mapping_add_factory (mapping, "/test", gst_rtsp_media_mapping_add_factory (mapping, "/test",

View file

@ -21,7 +21,13 @@
#include <gst/rtsp-server/rtsp-server.h> #include <gst/rtsp-server/rtsp-server.h>
/* define this if you want the resource to only be available when using
* user/admin as the password */
#undef WITH_AUTH
/* this timeout is periodically run to clean up the expired sessions from the
* pool. This needs to be run explicitly currently but might be done
* automatically as part of the mainloop. */
static gboolean static gboolean
timeout (GstRTSPServer * server, gboolean ignored) timeout (GstRTSPServer * server, gboolean ignored)
{ {
@ -41,6 +47,10 @@ main (int argc, char *argv[])
GstRTSPServer *server; GstRTSPServer *server;
GstRTSPMediaMapping *mapping; GstRTSPMediaMapping *mapping;
GstRTSPMediaFactory *factory; GstRTSPMediaFactory *factory;
#ifdef WITH_AUTH
GstRTSPAuth *auth;
gchar *basic;
#endif
gst_init (&argc, &argv); gst_init (&argc, &argv);
@ -53,6 +63,17 @@ main (int argc, char *argv[])
* that be used to map uri mount points to media factories */ * that be used to map uri mount points to media factories */
mapping = gst_rtsp_server_get_media_mapping (server); mapping = gst_rtsp_server_get_media_mapping (server);
#ifdef WITH_AUTH
/* make a new authentication manager. it can be added to control access to all
* the factories on the server or on individual factories. */
auth = gst_rtsp_auth_new ();
basic = gst_rtsp_auth_make_basic ("user", "admin");
gst_rtsp_auth_set_basic (auth, basic);
g_free (basic);
/* configure in the server */
gst_rtsp_server_set_auth (server, auth);
#endif
/* make a media factory for a test stream. The default media factory can use /* make a media factory for a test stream. The default media factory can use
* gst-launch syntax to create pipelines. * gst-launch syntax to create pipelines.
* any launch line works as long as it contains elements named pay%d. Each * any launch line works as long as it contains elements named pay%d. Each
@ -74,9 +95,10 @@ main (int argc, char *argv[])
if (gst_rtsp_server_attach (server, NULL) == 0) if (gst_rtsp_server_attach (server, NULL) == 0)
goto failed; goto failed;
/* add a timeout for the session cleanup */
g_timeout_add_seconds (2, (GSourceFunc) timeout, server); g_timeout_add_seconds (2, (GSourceFunc) timeout, server);
/* start serving */ /* start serving, this never stops */
g_main_loop_run (loop); g_main_loop_run (loop);
return 0; return 0;

2
gst/rtsp-server/.gitignore vendored Normal file
View file

@ -0,0 +1,2 @@
GstRtspServer-0.10.gir
GstRtspServer-0.10.typelib

View file

@ -1,4 +1,5 @@
public_headers = \ public_headers = \
rtsp-auth.h \
rtsp-params.h \ rtsp-params.h \
rtsp-sdp.h \ rtsp-sdp.h \
rtsp-media.h \ rtsp-media.h \
@ -11,6 +12,8 @@ public_headers = \
rtsp-server.h rtsp-server.h
c_sources = \ c_sources = \
rtsp-funnel.c \
rtsp-auth.c \
rtsp-params.c \ rtsp-params.c \
rtsp-sdp.c \ rtsp-sdp.c \
rtsp-media.c \ rtsp-media.c \
@ -22,6 +25,8 @@ c_sources = \
rtsp-client.c \ rtsp-client.c \
rtsp-server.c rtsp-server.c
noinst_HEADERS = rtsp-funnel.h
lib_LTLIBRARIES = \ lib_LTLIBRARIES = \
libgstrtspserver-@GST_MAJORMINOR@.la libgstrtspserver-@GST_MAJORMINOR@.la
@ -60,6 +65,8 @@ GstRtspServer-@GST_MAJORMINOR@.gir: $(INTROSPECTION_SCANNER) libgstrtspserver-@G
-DIN_GOBJECT_INTROSPECTION=1 \ -DIN_GOBJECT_INTROSPECTION=1 \
--c-include='gst/gst.h' \ --c-include='gst/gst.h' \
--add-include-path=`$(PKG_CONFIG) --variable=girdir gstreamer-0.10` \ --add-include-path=`$(PKG_CONFIG) --variable=girdir gstreamer-0.10` \
--add-include-path=`$(PKG_CONFIG) --variable=girdir gstreamer-rtsp-0.10` \
--add-include-path=`$(PKG_CONFIG) --variable=girdir gstreamer-sdp-0.10` \
--library=libgstrtspserver-0.10.la \ --library=libgstrtspserver-0.10.la \
--include=Gst-0.10 \ --include=Gst-0.10 \
--include=GstRtsp-0.10 \ --include=GstRtsp-0.10 \
@ -81,7 +88,14 @@ typelibsdir = $(libdir)/girepository-1.0/
typelibs_DATA = $(BUILT_GIRSOURCES:.gir=.typelib) typelibs_DATA = $(BUILT_GIRSOURCES:.gir=.typelib)
%.typelib: %.gir $(INTROSPECTION_COMPILER) %.typelib: %.gir $(INTROSPECTION_COMPILER)
$(AM_V_GEN)$(INTROSPECTION_COMPILER) --includedir=$(srcdir) --includedir=$(builddir) $(INTROSPECTION_COMPILER_OPTS) $< -o $(@F) $(AM_V_GEN)PKG_CONFIG_PATH="$(GST_PKG_CONFIG_PATH)" \
$(INTROSPECTION_COMPILER) \
--includedir=$(srcdir) \
--includedir=$(builddir) \
--includedir=`$(PKG_CONFIG) --variable=girdir gstreamer-0.10` \
--includedir=`$(PKG_CONFIG) --variable=girdir gstreamer-rtsp-0.10` \
--includedir=`$(PKG_CONFIG) --variable=girdir gstreamer-sdp-0.10` \
$(INTROSPECTION_COMPILER_OPTS) $< -o $(@F)
CLEANFILES += $(BUILT_GIRSOURCES) $(typelibs_DATA) CLEANFILES += $(BUILT_GIRSOURCES) $(typelibs_DATA)
endif endif

272
gst/rtsp-server/rtsp-auth.c Normal file
View file

@ -0,0 +1,272 @@
/* GStreamer
* Copyright (C) 2010 Wim Taymans <wim.taymans at gmail.com>
*
* 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.
*/
#include <string.h>
#include "rtsp-auth.h"
enum
{
PROP_0,
PROP_LAST
};
GST_DEBUG_CATEGORY_STATIC (rtsp_auth_debug);
#define GST_CAT_DEFAULT rtsp_auth_debug
static void gst_rtsp_auth_get_property (GObject * object, guint propid,
GValue * value, GParamSpec * pspec);
static void gst_rtsp_auth_set_property (GObject * object, guint propid,
const GValue * value, GParamSpec * pspec);
static void gst_rtsp_auth_finalize (GObject * obj);
static gboolean default_setup_auth (GstRTSPAuth * auth, GstRTSPClient * client,
GQuark hint, GstRTSPClientState * state);
static gboolean default_check_method (GstRTSPAuth * auth,
GstRTSPClient * client, GQuark hint, GstRTSPClientState * state);
G_DEFINE_TYPE (GstRTSPAuth, gst_rtsp_auth, G_TYPE_OBJECT);
static void
gst_rtsp_auth_class_init (GstRTSPAuthClass * klass)
{
GObjectClass *gobject_class;
gobject_class = G_OBJECT_CLASS (klass);
gobject_class->get_property = gst_rtsp_auth_get_property;
gobject_class->set_property = gst_rtsp_auth_set_property;
gobject_class->finalize = gst_rtsp_auth_finalize;
klass->setup_auth = default_setup_auth;
klass->check_method = default_check_method;
GST_DEBUG_CATEGORY_INIT (rtsp_auth_debug, "rtspauth", 0, "GstRTSPAuth");
}
static void
gst_rtsp_auth_init (GstRTSPAuth * auth)
{
/* bitwise or of all methods that need authentication */
auth->methods = GST_RTSP_DESCRIBE |
GST_RTSP_ANNOUNCE |
GST_RTSP_GET_PARAMETER |
GST_RTSP_SET_PARAMETER |
GST_RTSP_PAUSE |
GST_RTSP_PLAY | GST_RTSP_RECORD | GST_RTSP_SETUP | GST_RTSP_TEARDOWN;
}
static void
gst_rtsp_auth_finalize (GObject * obj)
{
GstRTSPAuth *auth = GST_RTSP_AUTH (obj);
GST_INFO ("finalize auth %p", auth);
g_free (auth->basic);
G_OBJECT_CLASS (gst_rtsp_auth_parent_class)->finalize (obj);
}
static void
gst_rtsp_auth_get_property (GObject * object, guint propid,
GValue * value, GParamSpec * pspec)
{
GstRTSPAuth *auth = GST_RTSP_AUTH (object);
switch (propid) {
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, propid, pspec);
}
}
static void
gst_rtsp_auth_set_property (GObject * object, guint propid,
const GValue * value, GParamSpec * pspec)
{
GstRTSPAuth *auth = GST_RTSP_AUTH (object);
switch (propid) {
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, propid, pspec);
}
}
/**
* gst_rtsp_auth_new:
*
* Create a new #GstRTSPAuth instance.
*
* Returns: a new #GstRTSPAuth
*/
GstRTSPAuth *
gst_rtsp_auth_new (void)
{
GstRTSPAuth *result;
result = g_object_new (GST_TYPE_RTSP_AUTH, NULL);
return result;
}
/**
* gst_rtsp_auth_set_basic:
* @auth: a #GstRTSPAuth
* @basic: the basic token
*
* Set the basic token for the default authentication algorithm.
*/
void
gst_rtsp_auth_set_basic (GstRTSPAuth * auth, const gchar * basic)
{
g_free (auth->basic);
auth->basic = g_strdup (basic);
}
static gboolean
default_setup_auth (GstRTSPAuth * auth, GstRTSPClient * client,
GQuark hint, GstRTSPClientState * state)
{
if (state->response == NULL)
return FALSE;
/* we only have Basic for now */
gst_rtsp_message_add_header (state->response, GST_RTSP_HDR_WWW_AUTHENTICATE,
"Basic realm=\"GStreamer RTSP Server\"");
return TRUE;
}
/**
* gst_rtsp_auth_setup_auth:
* @auth: a #GstRTSPAuth
* @client: the client
* @uri: the requested uri
* @session: the session
* @request: the request
* @response: the response
*
* Add authentication tokens to @response.
*
* Returns: FALSE if something is wrong.
*/
gboolean
gst_rtsp_auth_setup_auth (GstRTSPAuth * auth, GstRTSPClient * client,
GQuark hint, GstRTSPClientState * state)
{
gboolean result = FALSE;
GstRTSPAuthClass *klass;
klass = GST_RTSP_AUTH_GET_CLASS (auth);
GST_DEBUG_OBJECT (auth, "setup auth");
if (klass->setup_auth)
result = klass->setup_auth (auth, client, hint, state);
return result;
}
static gboolean
default_check_method (GstRTSPAuth * auth, GstRTSPClient * client,
GQuark hint, GstRTSPClientState * state)
{
gboolean result = TRUE;
GstRTSPResult res;
if (state->method & auth->methods != 0) {
gchar *authorization;
result = FALSE;
res =
gst_rtsp_message_get_header (state->request, GST_RTSP_HDR_AUTHORIZATION,
&authorization, 0);
if (res < 0)
goto no_auth;
/* parse type */
if (g_ascii_strncasecmp (authorization, "basic ", 6) == 0) {
GST_DEBUG_OBJECT (auth, "check Basic auth");
if (auth->basic && strcmp (&authorization[6], auth->basic) == 0)
result = TRUE;
} else if (g_ascii_strncasecmp (authorization, "digest ", 7) == 0) {
GST_DEBUG_OBJECT (auth, "check Digest auth");
/* not implemented yet */
result = FALSE;
}
}
return result;
no_auth:
{
GST_DEBUG_OBJECT (auth, "no authorization header found");
return FALSE;
}
}
/**
* gst_rtsp_auth_check_method:
* @auth: a #GstRTSPAuth
* @client: the client
* @hint: a hint
* @state: client state
*
* Check if @client is allowed to perform the actions of @state.
*
* Returns: FALSE if the action is not allowed.
*/
gboolean
gst_rtsp_auth_check (GstRTSPAuth * auth, GstRTSPClient * client,
GQuark hint, GstRTSPClientState * state)
{
gboolean result = FALSE;
GstRTSPAuthClass *klass;
klass = GST_RTSP_AUTH_GET_CLASS (auth);
GST_DEBUG_OBJECT (auth, "check state");
if (klass->check_method)
result = klass->check_method (auth, client, hint, state);
return result;
}
/**
* gst_rtsp_auth_make_basic:
* @user: a userid
* @pass: a password
*
* Construct a Basic authorisation token from @user and @pass.
*
* Returns: the base64 encoding of the string @user:@pass. g_free()
* after usage.
*/
gchar *
gst_rtsp_auth_make_basic (const gchar * user, const gchar * pass)
{
gchar *user_pass;
gchar *result;
user_pass = g_strjoin (":", user, pass, NULL);
result = g_base64_encode ((guchar *) user_pass, strlen (user_pass));
g_free (user_pass);
return result;
}

View file

@ -0,0 +1,80 @@
/* GStreamer
* Copyright (C) 2010 Wim Taymans <wim.taymans at gmail.com>
*
* 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.
*/
#include <gst/gst.h>
#ifndef __GST_RTSP_AUTH_H__
#define __GST_RTSP_AUTH_H__
typedef struct _GstRTSPAuth GstRTSPAuth;
typedef struct _GstRTSPAuthClass GstRTSPAuthClass;
#include "rtsp-client.h"
#include "rtsp-media-mapping.h"
#include "rtsp-session-pool.h"
G_BEGIN_DECLS
#define GST_TYPE_RTSP_AUTH (gst_rtsp_auth_get_type ())
#define GST_IS_RTSP_AUTH(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GST_TYPE_RTSP_AUTH))
#define GST_IS_RTSP_AUTH_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), GST_TYPE_RTSP_AUTH))
#define GST_RTSP_AUTH_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), GST_TYPE_RTSP_AUTH, GstRTSPAuthClass))
#define GST_RTSP_AUTH(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GST_TYPE_RTSP_AUTH, GstRTSPAuth))
#define GST_RTSP_AUTH_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), GST_TYPE_RTSP_AUTH, GstRTSPAuthClass))
#define GST_RTSP_AUTH_CAST(obj) ((GstRTSPAuth*)(obj))
#define GST_RTSP_AUTH_CLASS_CAST(klass) ((GstRTSPAuthClass*)(klass))
/**
* GstRTSPAuth:
*
* The authentication structure.
*/
struct _GstRTSPAuth {
GObject parent;
/*< private >*/
gchar *basic;
GstRTSPMethod methods;
};
struct _GstRTSPAuthClass {
GObjectClass parent_class;
gboolean (*setup_auth) (GstRTSPAuth *auth, GstRTSPClient * client,
GQuark hint, GstRTSPClientState *state);
gboolean (*check_method) (GstRTSPAuth *auth, GstRTSPClient * client,
GQuark hint, GstRTSPClientState *state);
};
GType gst_rtsp_auth_get_type (void);
GstRTSPAuth * gst_rtsp_auth_new (void);
void gst_rtsp_auth_set_basic (GstRTSPAuth *auth, const gchar * basic);
gboolean gst_rtsp_auth_setup_auth (GstRTSPAuth *auth, GstRTSPClient * client,
GQuark hint, GstRTSPClientState *state);
gboolean gst_rtsp_auth_check_method (GstRTSPAuth *auth, GstRTSPClient * client,
GQuark hint, GstRTSPClientState *state);
/* helpers */
gchar * gst_rtsp_auth_make_basic (const gchar * user, const gchar * pass);
G_END_DECLS
#endif /* __GST_RTSP_AUTH_H__ */

File diff suppressed because it is too large Load diff

View file

@ -17,31 +17,23 @@
* Boston, MA 02111-1307, USA. * Boston, MA 02111-1307, USA.
*/ */
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <errno.h>
#include <string.h>
#include <sys/time.h>
#include <sys/types.h>
#include <netinet/in.h>
#include <netdb.h>
#include <sys/socket.h>
#include <sys/wait.h>
#include <fcntl.h>
#include <arpa/inet.h>
#include <gst/gst.h> #include <gst/gst.h>
#include <gst/rtsp/gstrtspconnection.h> #include <gst/rtsp/gstrtspconnection.h>
#ifndef __GST_RTSP_CLIENT_H__ #ifndef __GST_RTSP_CLIENT_H__
#define __GST_RTSP_CLIENT_H__ #define __GST_RTSP_CLIENT_H__
G_BEGIN_DECLS
typedef struct _GstRTSPClient GstRTSPClient;
typedef struct _GstRTSPClientClass GstRTSPClientClass;
typedef struct _GstRTSPClientState GstRTSPClientState;
#include "rtsp-server.h"
#include "rtsp-media.h" #include "rtsp-media.h"
#include "rtsp-media-mapping.h" #include "rtsp-media-mapping.h"
#include "rtsp-session-pool.h" #include "rtsp-session-pool.h"
#include "rtsp-auth.h"
G_BEGIN_DECLS
#define GST_TYPE_RTSP_CLIENT (gst_rtsp_client_get_type ()) #define GST_TYPE_RTSP_CLIENT (gst_rtsp_client_get_type ())
#define GST_IS_RTSP_CLIENT(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GST_TYPE_RTSP_CLIENT)) #define GST_IS_RTSP_CLIENT(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GST_TYPE_RTSP_CLIENT))
@ -52,8 +44,29 @@ G_BEGIN_DECLS
#define GST_RTSP_CLIENT_CAST(obj) ((GstRTSPClient*)(obj)) #define GST_RTSP_CLIENT_CAST(obj) ((GstRTSPClient*)(obj))
#define GST_RTSP_CLIENT_CLASS_CAST(klass) ((GstRTSPClientClass*)(klass)) #define GST_RTSP_CLIENT_CLASS_CAST(klass) ((GstRTSPClientClass*)(klass))
typedef struct _GstRTSPClient GstRTSPClient; /**
typedef struct _GstRTSPClientClass GstRTSPClientClass; * GstRTSPClientState:
* @request: the complete request
* @uri: the complete url parsed from @request
* @method: the parsed method of @uri
* @session: the session, can be NULL
* @sessmedia: the session media for the url can be NULL
* @factory: the media factory for the url, can be NULL.
* @media: the session media for the url can be NULL
* @response: the response
*
* Information passed around containing the client state of a request.
*/
struct _GstRTSPClientState{
GstRTSPMessage *request;
GstRTSPUrl *uri;
GstRTSPMethod method;
GstRTSPSession *session;
GstRTSPSessionMedia *sessmedia;
GstRTSPMediaFactory *factory;
GstRTSPMedia *media;
GstRTSPMessage *response;
};
/** /**
* GstRTSPClient: * GstRTSPClient:
@ -80,8 +93,10 @@ struct _GstRTSPClient {
gchar *server_ip; gchar *server_ip;
gboolean is_ipv6; gboolean is_ipv6;
GstRTSPServer *server;
GstRTSPSessionPool *session_pool; GstRTSPSessionPool *session_pool;
GstRTSPMediaMapping *media_mapping; GstRTSPMediaMapping *media_mapping;
GstRTSPAuth *auth;
GstRTSPUrl *uri; GstRTSPUrl *uri;
GstRTSPMedia *media; GstRTSPMedia *media;
@ -92,12 +107,18 @@ struct _GstRTSPClient {
struct _GstRTSPClientClass { struct _GstRTSPClientClass {
GObjectClass parent_class; GObjectClass parent_class;
/* signals */
void (*closed) (GstRTSPClient *client);
}; };
GType gst_rtsp_client_get_type (void); GType gst_rtsp_client_get_type (void);
GstRTSPClient * gst_rtsp_client_new (void); GstRTSPClient * gst_rtsp_client_new (void);
void gst_rtsp_client_set_server (GstRTSPClient * client, GstRTSPServer * server);
GstRTSPServer * gst_rtsp_client_get_server (GstRTSPClient * client);
void gst_rtsp_client_set_session_pool (GstRTSPClient *client, void gst_rtsp_client_set_session_pool (GstRTSPClient *client,
GstRTSPSessionPool *pool); GstRTSPSessionPool *pool);
GstRTSPSessionPool * gst_rtsp_client_get_session_pool (GstRTSPClient *client); GstRTSPSessionPool * gst_rtsp_client_get_session_pool (GstRTSPClient *client);
@ -106,6 +127,10 @@ void gst_rtsp_client_set_media_mapping (GstRTSPClient *client,
GstRTSPMediaMapping *mapping); GstRTSPMediaMapping *mapping);
GstRTSPMediaMapping * gst_rtsp_client_get_media_mapping (GstRTSPClient *client); GstRTSPMediaMapping * gst_rtsp_client_get_media_mapping (GstRTSPClient *client);
void gst_rtsp_client_set_auth (GstRTSPClient *client, GstRTSPAuth *auth);
GstRTSPAuth * gst_rtsp_client_get_auth (GstRTSPClient *client);
gboolean gst_rtsp_client_accept (GstRTSPClient *client, gboolean gst_rtsp_client_accept (GstRTSPClient *client,
GIOChannel *channel); GIOChannel *channel);

View file

@ -0,0 +1,407 @@
/*
* Farsight2 - Farsight Funnel element
*
* Copyright 2007 Collabora Ltd.
* @author: Olivier Crete <olivier.crete@collabora.co.uk>
* Copyright 2007 Nokia Corp.
*
* rtsp-funnel.c: Simple Funnel element
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 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
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
/**
* SECTION:element-rtspfunnel
* @short_description: N-to-1 simple funnel
*
* Takes packets from various input sinks into one output source
*/
#ifdef HAVE_CONFIG_H
# include "config.h"
#endif
#include "rtsp-funnel.h"
GST_DEBUG_CATEGORY_STATIC (rtsp_funnel_debug);
#define GST_CAT_DEFAULT rtsp_funnel_debug
static const GstElementDetails rtsp_funnel_details =
GST_ELEMENT_DETAILS ("Farsight Funnel pipe fitting",
"Generic",
"N-to-1 pipe fitting",
"Olivier Crete <olivier.crete@collabora.co.uk>");
static GstStaticPadTemplate funnel_sink_template =
GST_STATIC_PAD_TEMPLATE ("sink%d",
GST_PAD_SINK,
GST_PAD_REQUEST,
GST_STATIC_CAPS_ANY);
static GstStaticPadTemplate funnel_src_template =
GST_STATIC_PAD_TEMPLATE ("src",
GST_PAD_SRC,
GST_PAD_ALWAYS,
GST_STATIC_CAPS_ANY);
static void
_do_init (GType type)
{
GST_DEBUG_CATEGORY_INIT (rtsp_funnel_debug, "rtspfunnel", 0,
"rtsp funnel element");
}
GST_BOILERPLATE_FULL (RTSPFunnel, rtsp_funnel, GstElement, GST_TYPE_ELEMENT,
_do_init);
static GstStateChangeReturn rtsp_funnel_change_state (GstElement * element,
GstStateChange transition);
static GstPad *rtsp_funnel_request_new_pad (GstElement * element,
GstPadTemplate * templ, const gchar * name);
static void rtsp_funnel_release_pad (GstElement * element, GstPad * pad);
static GstFlowReturn rtsp_funnel_chain (GstPad * pad, GstBuffer * buffer);
static gboolean rtsp_funnel_event (GstPad * pad, GstEvent * event);
static gboolean rtsp_funnel_src_event (GstPad * pad, GstEvent * event);
static GstCaps *rtsp_funnel_getcaps (GstPad * pad);
typedef struct
{
GstSegment segment;
} RTSPFunnelPadPrivate;
static void
rtsp_funnel_base_init (gpointer g_class)
{
GstElementClass *gstelement_class = GST_ELEMENT_CLASS (g_class);
gst_element_class_set_details (gstelement_class, &rtsp_funnel_details);
gst_element_class_add_pad_template (gstelement_class,
gst_static_pad_template_get (&funnel_sink_template));
gst_element_class_add_pad_template (gstelement_class,
gst_static_pad_template_get (&funnel_src_template));
}
static void
rtsp_funnel_dispose (GObject * object)
{
GList *item;
restart:
for (item = GST_ELEMENT_PADS (object); item; item = g_list_next (item)) {
GstPad *pad = GST_PAD (item->data);
if (GST_PAD_IS_SINK (pad)) {
gst_element_release_request_pad (GST_ELEMENT (object), pad);
goto restart;
}
}
G_OBJECT_CLASS (parent_class)->dispose (object);
}
static void
rtsp_funnel_class_init (RTSPFunnelClass * klass)
{
GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
GstElementClass *gstelement_class = GST_ELEMENT_CLASS (klass);
gobject_class->dispose = GST_DEBUG_FUNCPTR (rtsp_funnel_dispose);
gstelement_class->request_new_pad =
GST_DEBUG_FUNCPTR (rtsp_funnel_request_new_pad);
gstelement_class->release_pad = GST_DEBUG_FUNCPTR (rtsp_funnel_release_pad);
gstelement_class->change_state = GST_DEBUG_FUNCPTR (rtsp_funnel_change_state);
}
static void
rtsp_funnel_init (RTSPFunnel * funnel, RTSPFunnelClass * g_class)
{
funnel->srcpad = gst_pad_new_from_static_template (&funnel_src_template,
"src");
gst_pad_set_event_function (funnel->srcpad, rtsp_funnel_src_event);
gst_pad_use_fixed_caps (funnel->srcpad);
gst_element_add_pad (GST_ELEMENT (funnel), funnel->srcpad);
}
static GstPad *
rtsp_funnel_request_new_pad (GstElement * element, GstPadTemplate * templ,
const gchar * name)
{
GstPad *sinkpad;
RTSPFunnelPadPrivate *priv = g_slice_alloc0 (sizeof (RTSPFunnelPadPrivate));
GST_DEBUG_OBJECT (element, "requesting pad");
sinkpad = gst_pad_new_from_template (templ, name);
gst_pad_set_chain_function (sinkpad, GST_DEBUG_FUNCPTR (rtsp_funnel_chain));
gst_pad_set_event_function (sinkpad, GST_DEBUG_FUNCPTR (rtsp_funnel_event));
gst_pad_set_getcaps_function (sinkpad,
GST_DEBUG_FUNCPTR (rtsp_funnel_getcaps));
gst_segment_init (&priv->segment, GST_FORMAT_UNDEFINED);
gst_pad_set_element_private (sinkpad, priv);
gst_pad_set_active (sinkpad, TRUE);
gst_element_add_pad (element, sinkpad);
return sinkpad;
}
static void
rtsp_funnel_release_pad (GstElement * element, GstPad * pad)
{
RTSPFunnel *funnel = RTSP_FUNNEL (element);
RTSPFunnelPadPrivate *priv = gst_pad_get_element_private (pad);
GST_DEBUG_OBJECT (funnel, "releasing pad");
gst_pad_set_active (pad, FALSE);
if (priv)
g_slice_free1 (sizeof (RTSPFunnelPadPrivate), priv);
gst_element_remove_pad (GST_ELEMENT_CAST (funnel), pad);
}
static GstCaps *
rtsp_funnel_getcaps (GstPad * pad)
{
RTSPFunnel *funnel = RTSP_FUNNEL (gst_pad_get_parent (pad));
GstCaps *caps;
caps = gst_pad_peer_get_caps (funnel->srcpad);
if (caps == NULL)
caps = gst_caps_copy (gst_pad_get_pad_template_caps (pad));
gst_object_unref (funnel);
return caps;
}
static GstFlowReturn
rtsp_funnel_chain (GstPad * pad, GstBuffer * buffer)
{
GstFlowReturn res;
RTSPFunnel *funnel = RTSP_FUNNEL (gst_pad_get_parent (pad));
RTSPFunnelPadPrivate *priv = gst_pad_get_element_private (pad);
GstEvent *event = NULL;
GstClockTime newts;
GstCaps *padcaps;
GST_DEBUG_OBJECT (funnel, "received buffer %p", buffer);
GST_OBJECT_LOCK (funnel);
if (priv->segment.format == GST_FORMAT_UNDEFINED) {
GST_WARNING_OBJECT (funnel, "Got buffer without segment,"
" setting segment [0,inf[");
gst_segment_set_newsegment_full (&priv->segment, FALSE, 1.0, 1.0,
GST_FORMAT_TIME, 0, -1, 0);
}
if (GST_CLOCK_TIME_IS_VALID (GST_BUFFER_TIMESTAMP (buffer)))
gst_segment_set_last_stop (&priv->segment, priv->segment.format,
GST_BUFFER_TIMESTAMP (buffer));
newts = gst_segment_to_running_time (&priv->segment,
priv->segment.format, GST_BUFFER_TIMESTAMP (buffer));
if (newts != GST_BUFFER_TIMESTAMP (buffer)) {
buffer = gst_buffer_make_metadata_writable (buffer);
GST_BUFFER_TIMESTAMP (buffer) = newts;
}
if (!funnel->has_segment) {
event = gst_event_new_new_segment_full (FALSE, 1.0, 1.0, GST_FORMAT_TIME,
0, -1, 0);
funnel->has_segment = TRUE;
}
GST_OBJECT_UNLOCK (funnel);
if (event) {
if (!gst_pad_push_event (funnel->srcpad, event)) {
GST_WARNING_OBJECT (funnel, "Could not push out newsegment event");
res = GST_FLOW_ERROR;
goto out;
}
}
GST_OBJECT_LOCK (pad);
padcaps = GST_PAD_CAPS (funnel->srcpad);
GST_OBJECT_UNLOCK (pad);
if (GST_BUFFER_CAPS (buffer) && GST_BUFFER_CAPS (buffer) != padcaps) {
if (!gst_pad_set_caps (funnel->srcpad, GST_BUFFER_CAPS (buffer))) {
res = GST_FLOW_NOT_NEGOTIATED;
goto out;
}
}
res = gst_pad_push (funnel->srcpad, buffer);
GST_LOG_OBJECT (funnel, "handled buffer %s", gst_flow_get_name (res));
out:
gst_object_unref (funnel);
return res;
}
static gboolean
rtsp_funnel_event (GstPad * pad, GstEvent * event)
{
RTSPFunnel *funnel = RTSP_FUNNEL (gst_pad_get_parent (pad));
RTSPFunnelPadPrivate *priv = gst_pad_get_element_private (pad);
gboolean forward = TRUE;
gboolean res = TRUE;
switch (GST_EVENT_TYPE (event)) {
case GST_EVENT_NEWSEGMENT:
{
gboolean update;
gdouble rate, arate;
GstFormat format;
gint64 start;
gint64 stop;
gint64 time;
gst_event_parse_new_segment_full (event, &update, &rate, &arate,
&format, &start, &stop, &time);
GST_OBJECT_LOCK (funnel);
gst_segment_set_newsegment_full (&priv->segment, update, rate, arate,
format, start, stop, time);
GST_OBJECT_UNLOCK (funnel);
forward = FALSE;
gst_event_unref (event);
}
break;
case GST_EVENT_FLUSH_STOP:
{
GST_OBJECT_LOCK (funnel);
gst_segment_init (&priv->segment, GST_FORMAT_UNDEFINED);
GST_OBJECT_UNLOCK (funnel);
}
break;
default:
break;
}
if (forward)
res = gst_pad_push_event (funnel->srcpad, event);
gst_object_unref (funnel);
return res;
}
static gboolean
rtsp_funnel_src_event (GstPad * pad, GstEvent * event)
{
GstElement *funnel;
GstIterator *iter;
GstPad *sinkpad;
gboolean result = FALSE;
gboolean done = FALSE;
funnel = gst_pad_get_parent_element (pad);
g_return_val_if_fail (funnel != NULL, FALSE);
iter = gst_element_iterate_sink_pads (funnel);
while (!done) {
switch (gst_iterator_next (iter, (gpointer) & sinkpad)) {
case GST_ITERATOR_OK:
gst_event_ref (event);
result |= gst_pad_push_event (sinkpad, event);
gst_object_unref (sinkpad);
break;
case GST_ITERATOR_RESYNC:
gst_iterator_resync (iter);
result = FALSE;
break;
case GST_ITERATOR_ERROR:
GST_WARNING_OBJECT (funnel, "Error iterating sinkpads");
case GST_ITERATOR_DONE:
done = TRUE;
break;
}
}
gst_iterator_free (iter);
gst_object_unref (funnel);
gst_event_unref (event);
return result;
}
static void
reset_pad (gpointer data, gpointer user_data)
{
GstPad *pad = data;
RTSPFunnelPadPrivate *priv = gst_pad_get_element_private (pad);
GST_OBJECT_LOCK (pad);
gst_segment_init (&priv->segment, GST_FORMAT_UNDEFINED);
GST_OBJECT_UNLOCK (pad);
gst_object_unref (pad);
}
static GstStateChangeReturn
rtsp_funnel_change_state (GstElement * element, GstStateChange transition)
{
RTSPFunnel *funnel = RTSP_FUNNEL (element);
GstStateChangeReturn ret;
switch (transition) {
case GST_STATE_CHANGE_READY_TO_PAUSED:
{
GstIterator *iter = gst_element_iterate_sink_pads (element);
GstIteratorResult res;
do {
res = gst_iterator_foreach (iter, reset_pad, NULL);
} while (res == GST_ITERATOR_RESYNC);
gst_iterator_free (iter);
if (res == GST_ITERATOR_ERROR)
return GST_STATE_CHANGE_FAILURE;
GST_OBJECT_LOCK (funnel);
funnel->has_segment = FALSE;
GST_OBJECT_UNLOCK (funnel);
}
break;
default:
break;
}
ret = GST_ELEMENT_CLASS (parent_class)->change_state (element, transition);
return ret;
}

View file

@ -0,0 +1,69 @@
/*
* Farsight2 - Farsight Funnel element
*
* Copyright 2007 Collabora Ltd.
* @author: Olivier Crete <olivier.crete@collabora.co.uk>
* Copyright 2007 Nokia Corp.
*
* rtsp-funnel.h: Simple Funnel element
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 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
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
#ifndef __RTSP_FUNNEL_H__
#define __RTSP_FUNNEL_H__
#include <gst/gst.h>
G_BEGIN_DECLS
#define RTSP_TYPE_FUNNEL \
(rtsp_funnel_get_type ())
#define RTSP_FUNNEL(obj) \
(G_TYPE_CHECK_INSTANCE_CAST((obj),RTSP_TYPE_FUNNEL,RTSPFunnel))
#define RTSP_FUNNEL_CLASS(klass) \
(G_TYPE_CHECK_CLASS_CAST((klass),RTSP_TYPE_FUNNEL,RTSPFunnelClass))
#define RTSP_IS_FUNNEL(obj) \
(G_TYPE_CHECK_INSTANCE_TYPE((obj),RTSP_TYPE_FUNNEL))
#define RTSP_IS_FUNNEL_CLASS(klass) \
(G_TYPE_CHECK_CLASS_TYPE((klass),RTSP_TYPE_FUNNEL))
typedef struct _RTSPFunnel RTSPFunnel;
typedef struct _RTSPFunnelClass RTSPFunnelClass;
/**
* RTSPFunnel:
*
* Opaque #RTSPFunnel data structure.
*/
struct _RTSPFunnel {
GstElement element;
/*< private >*/
GstPad *srcpad;
gboolean has_segment;
};
struct _RTSPFunnelClass {
GstElementClass parent_class;
};
GType rtsp_funnel_get_type (void);
G_END_DECLS
#endif /* __RTSP_FUNNEL_H__ */

View file

@ -17,14 +17,18 @@
* Boston, MA 02111-1307, USA. * Boston, MA 02111-1307, USA.
*/ */
#include <string.h>
#include "rtsp-media-factory-uri.h" #include "rtsp-media-factory-uri.h"
#define DEFAULT_URI NULL #define DEFAULT_URI NULL
#define DEFAULT_USE_GSTPAY FALSE
enum enum
{ {
PROP_0, PROP_0,
PROP_URI, PROP_URI,
PROP_USE_GSTPAY,
PROP_LAST PROP_LAST
}; };
@ -56,7 +60,7 @@ free_data (FactoryData * data)
static const gchar *factory_key = "GstRTSPMediaFactoryURI"; static const gchar *factory_key = "GstRTSPMediaFactoryURI";
GST_DEBUG_CATEGORY (rtsp_media_factory_uri_debug); GST_DEBUG_CATEGORY_STATIC (rtsp_media_factory_uri_debug);
#define GST_CAT_DEFAULT rtsp_media_factory_uri_debug #define GST_CAT_DEFAULT rtsp_media_factory_uri_debug
static void gst_rtsp_media_factory_uri_get_property (GObject * object, static void gst_rtsp_media_factory_uri_get_property (GObject * object,
@ -93,6 +97,16 @@ gst_rtsp_media_factory_uri_class_init (GstRTSPMediaFactoryURIClass * klass)
g_param_spec_string ("uri", "URI", g_param_spec_string ("uri", "URI",
"The URI of the resource to stream", DEFAULT_URI, "The URI of the resource to stream", DEFAULT_URI,
G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
/**
* GstRTSPMediaFactoryURI::use-gstpay
*
* Allow the usage of gstpay in order to avoid decoding of compressed formats
* without a payloader.
*/
g_object_class_install_property (gobject_class, PROP_USE_GSTPAY,
g_param_spec_boolean ("use-gstpay", "Use gstpay",
"Use the gstpay payloader to avoid decoding", DEFAULT_USE_GSTPAY,
G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
mediafactory_class->get_element = rtsp_media_factory_uri_get_element; mediafactory_class->get_element = rtsp_media_factory_uri_get_element;
@ -100,13 +114,68 @@ gst_rtsp_media_factory_uri_class_init (GstRTSPMediaFactoryURIClass * klass)
0, "GstRTSPMediaFactoryUri"); 0, "GstRTSPMediaFactoryUri");
} }
typedef struct
{
GList *demux;
GList *payload;
GList *decode;
} FilterData;
static gboolean
payloader_filter (GstPluginFeature * feature, FilterData * data)
{
gboolean res;
const gchar *klass;
GstElementFactory *fact;
GList **list = NULL;
/* we only care about element factories */
if (G_UNLIKELY (!GST_IS_ELEMENT_FACTORY (feature)))
return FALSE;
if (gst_plugin_feature_get_rank (feature) < GST_RANK_MARGINAL)
return FALSE;
fact = GST_ELEMENT_FACTORY_CAST (feature);
klass = gst_element_factory_get_klass (fact);
if (strstr (klass, "Decoder"))
list = &data->decode;
else if (strstr (klass, "Demux"))
list = &data->demux;
else if (strstr (klass, "Parser") && strstr (klass, "Codec"))
list = &data->demux;
else if (strstr (klass, "Payloader") && strstr (klass, "RTP"))
list = &data->payload;
if (list) {
GST_DEBUG ("adding %s", GST_PLUGIN_FEATURE_NAME (fact));
*list = g_list_prepend (*list, fact);
}
return FALSE;
}
static void static void
gst_rtsp_media_factory_uri_init (GstRTSPMediaFactoryURI * factory) gst_rtsp_media_factory_uri_init (GstRTSPMediaFactoryURI * factory)
{ {
FilterData data = { NULL, NULL, NULL };
factory->uri = g_strdup (DEFAULT_URI); factory->uri = g_strdup (DEFAULT_URI);
factory->factories = factory->use_gstpay = DEFAULT_USE_GSTPAY;
gst_element_factory_list_get_elements (GST_ELEMENT_FACTORY_TYPE_PAYLOADER,
GST_RANK_NONE); /* get the feature list using the filter */
gst_default_registry_feature_filter ((GstPluginFeatureFilter)
payloader_filter, FALSE, &data);
/* sort */
factory->demuxers =
g_list_sort (data.demux, gst_plugin_feature_rank_compare_func);
factory->payloaders =
g_list_sort (data.payload, gst_plugin_feature_rank_compare_func);
factory->decoders =
g_list_sort (data.decode, gst_plugin_feature_rank_compare_func);
factory->raw_vcaps = gst_static_caps_get (&raw_video_caps); factory->raw_vcaps = gst_static_caps_get (&raw_video_caps);
factory->raw_acaps = gst_static_caps_get (&raw_audio_caps); factory->raw_acaps = gst_static_caps_get (&raw_audio_caps);
} }
@ -117,7 +186,9 @@ gst_rtsp_media_factory_uri_finalize (GObject * obj)
GstRTSPMediaFactoryURI *factory = GST_RTSP_MEDIA_FACTORY_URI (obj); GstRTSPMediaFactoryURI *factory = GST_RTSP_MEDIA_FACTORY_URI (obj);
g_free (factory->uri); g_free (factory->uri);
gst_plugin_feature_list_free (factory->factories); gst_plugin_feature_list_free (factory->demuxers);
gst_plugin_feature_list_free (factory->payloaders);
gst_plugin_feature_list_free (factory->decoders);
gst_caps_unref (factory->raw_vcaps); gst_caps_unref (factory->raw_vcaps);
gst_caps_unref (factory->raw_acaps); gst_caps_unref (factory->raw_acaps);
@ -134,6 +205,9 @@ gst_rtsp_media_factory_uri_get_property (GObject * object, guint propid,
case PROP_URI: case PROP_URI:
g_value_take_string (value, gst_rtsp_media_factory_uri_get_uri (factory)); g_value_take_string (value, gst_rtsp_media_factory_uri_get_uri (factory));
break; break;
case PROP_USE_GSTPAY:
g_value_set_boolean (value, factory->use_gstpay);
break;
default: default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, propid, pspec); G_OBJECT_WARN_INVALID_PROPERTY_ID (object, propid, pspec);
} }
@ -149,6 +223,9 @@ gst_rtsp_media_factory_uri_set_property (GObject * object, guint propid,
case PROP_URI: case PROP_URI:
gst_rtsp_media_factory_uri_set_uri (factory, g_value_get_string (value)); gst_rtsp_media_factory_uri_set_uri (factory, g_value_get_string (value));
break; break;
case PROP_USE_GSTPAY:
factory->use_gstpay = g_value_get_boolean (value);
break;
default: default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, propid, pspec); G_OBJECT_WARN_INVALID_PROPERTY_ID (object, propid, pspec);
} }
@ -219,26 +296,43 @@ find_payloader (GstRTSPMediaFactoryURI * urifact, GstCaps * caps)
GList *list, *tmp; GList *list, *tmp;
GstElementFactory *factory = NULL; GstElementFactory *factory = NULL;
/* find payloader that can link */ /* first find a demuxer that can link */
list = gst_element_factory_list_filter (urifact->factories, caps, list = gst_element_factory_list_filter (urifact->demuxers, caps,
GST_PAD_SINK, FALSE); GST_PAD_SINK, FALSE);
for (tmp = list; tmp; tmp = g_list_next (tmp)) { if (list != NULL) {
GstElementFactory *f = GST_ELEMENT_FACTORY_CAST (tmp->data); /* we have a demuxer, try that one first */
const gchar *name;
name = gst_plugin_feature_get_name (GST_PLUGIN_FEATURE (f));
if (strcmp (name, "gdppay") == 0)
continue;
factory = f;
break;
}
if (factory)
g_object_ref (factory);
gst_plugin_feature_list_free (list); gst_plugin_feature_list_free (list);
return NULL;
}
/* no demuxer try a depayloader */
list = gst_element_factory_list_filter (urifact->payloaders, caps,
GST_PAD_SINK, FALSE);
if (list == NULL) {
if (urifact->use_gstpay) {
/* no depayloader or parser/demuxer, use gstpay when allowed */
factory = gst_element_factory_find ("rtpgstpay");
} else {
/* no depayloader, try a decoder, we'll get to a payloader for a decoded
* video or audio format, worst case. */
list = gst_element_factory_list_filter (urifact->decoders, caps,
GST_PAD_SINK, FALSE);
if (list != NULL) {
/* we have a decoder, try that one first */
gst_plugin_feature_list_free (list);
return NULL;
}
}
}
if (list != NULL) {
factory = GST_ELEMENT_FACTORY_CAST (list->data);
g_object_ref (factory);
gst_plugin_feature_list_free (list);
}
return factory; return factory;
} }
@ -259,8 +353,9 @@ autoplug_continue_cb (GstElement * uribin, GstPad * pad, GstCaps * caps,
if (!(factory = find_payloader (data->factory, caps))) if (!(factory = find_payloader (data->factory, caps)))
goto no_factory; goto no_factory;
/* we found a payloader, stop autoplugging */ /* we found a payloader, stop autoplugging so we can plug the
GST_DEBUG ("found payloader factory %s", * payloader. */
GST_DEBUG ("found factory %s",
gst_plugin_feature_get_name (GST_PLUGIN_FEATURE (factory))); gst_plugin_feature_get_name (GST_PLUGIN_FEATURE (factory)));
gst_object_unref (factory); gst_object_unref (factory);
@ -349,6 +444,10 @@ pad_added_cb (GstElement * uribin, GstPad * pad, GstElement * element)
g_object_set (payloader, "pt", data->pt, NULL); g_object_set (payloader, "pt", data->pt, NULL);
data->pt++; data->pt++;
if (g_object_class_find_property (G_OBJECT_GET_CLASS (payloader),
"buffer-list"))
g_object_set (payloader, "buffer-list", TRUE, NULL);
/* add the payloader to the pipeline */ /* add the payloader to the pipeline */
gst_bin_add (GST_BIN_CAST (element), payloader); gst_bin_add (GST_BIN_CAST (element), payloader);
gst_element_set_state (payloader, GST_STATE_PLAYING); gst_element_set_state (payloader, GST_STATE_PLAYING);

View file

@ -49,9 +49,13 @@ struct _GstRTSPMediaFactoryURI {
GstRTSPMediaFactory parent; GstRTSPMediaFactory parent;
gchar *uri; gchar *uri;
gboolean use_gstpay;
GstCaps *raw_vcaps; GstCaps *raw_vcaps;
GstCaps *raw_acaps; GstCaps *raw_acaps;
GList *factories; GList *demuxers;
GList *payloaders;
GList *decoders;
}; };
/** /**

View file

@ -22,6 +22,7 @@
#define DEFAULT_LAUNCH NULL #define DEFAULT_LAUNCH NULL
#define DEFAULT_SHARED FALSE #define DEFAULT_SHARED FALSE
#define DEFAULT_EOS_SHUTDOWN FALSE #define DEFAULT_EOS_SHUTDOWN FALSE
#define DEFAULT_BUFFER_SIZE 0x80000
enum enum
{ {
@ -29,10 +30,11 @@ enum
PROP_LAUNCH, PROP_LAUNCH,
PROP_SHARED, PROP_SHARED,
PROP_EOS_SHUTDOWN, PROP_EOS_SHUTDOWN,
PROP_BUFFER_SIZE,
PROP_LAST PROP_LAST
}; };
GST_DEBUG_CATEGORY (rtsp_media_debug); GST_DEBUG_CATEGORY_STATIC (rtsp_media_debug);
#define GST_CAT_DEFAULT rtsp_media_debug #define GST_CAT_DEFAULT rtsp_media_debug
static void gst_rtsp_media_factory_get_property (GObject * object, guint propid, static void gst_rtsp_media_factory_get_property (GObject * object, guint propid,
@ -96,13 +98,19 @@ gst_rtsp_media_factory_class_init (GstRTSPMediaFactoryClass * klass)
"Send EOS down the pipeline before shutting down", "Send EOS down the pipeline before shutting down",
DEFAULT_EOS_SHUTDOWN, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); DEFAULT_EOS_SHUTDOWN, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
g_object_class_install_property (gobject_class, PROP_BUFFER_SIZE,
g_param_spec_uint ("buffer-size", "Buffer Size",
"The kernel UDP buffer size to use", 0, G_MAXUINT,
DEFAULT_BUFFER_SIZE, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
klass->gen_key = default_gen_key; klass->gen_key = default_gen_key;
klass->get_element = default_get_element; klass->get_element = default_get_element;
klass->construct = default_construct; klass->construct = default_construct;
klass->configure = default_configure; klass->configure = default_configure;
klass->create_pipeline = default_create_pipeline; klass->create_pipeline = default_create_pipeline;
GST_DEBUG_CATEGORY_INIT (rtsp_media_debug, "rtspmedia", 0, "GstRTSPMedia"); GST_DEBUG_CATEGORY_INIT (rtsp_media_debug, "rtspmediafactory", 0,
"GstRTSPMediaFactory");
} }
static void static void
@ -111,6 +119,7 @@ gst_rtsp_media_factory_init (GstRTSPMediaFactory * factory)
factory->launch = g_strdup (DEFAULT_LAUNCH); factory->launch = g_strdup (DEFAULT_LAUNCH);
factory->shared = DEFAULT_SHARED; factory->shared = DEFAULT_SHARED;
factory->eos_shutdown = DEFAULT_EOS_SHUTDOWN; factory->eos_shutdown = DEFAULT_EOS_SHUTDOWN;
factory->buffer_size = DEFAULT_BUFFER_SIZE;
factory->lock = g_mutex_new (); factory->lock = g_mutex_new ();
factory->medias_lock = g_mutex_new (); factory->medias_lock = g_mutex_new ();
@ -127,6 +136,8 @@ gst_rtsp_media_factory_finalize (GObject * obj)
g_mutex_free (factory->medias_lock); g_mutex_free (factory->medias_lock);
g_free (factory->launch); g_free (factory->launch);
g_mutex_free (factory->lock); g_mutex_free (factory->lock);
if (factory->auth)
g_object_unref (factory->auth);
G_OBJECT_CLASS (gst_rtsp_media_factory_parent_class)->finalize (obj); G_OBJECT_CLASS (gst_rtsp_media_factory_parent_class)->finalize (obj);
} }
@ -148,6 +159,10 @@ gst_rtsp_media_factory_get_property (GObject * object, guint propid,
g_value_set_boolean (value, g_value_set_boolean (value,
gst_rtsp_media_factory_is_eos_shutdown (factory)); gst_rtsp_media_factory_is_eos_shutdown (factory));
break; break;
case PROP_BUFFER_SIZE:
g_value_set_uint (value,
gst_rtsp_media_factory_get_buffer_size (factory));
break;
default: default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, propid, pspec); G_OBJECT_WARN_INVALID_PROPERTY_ID (object, propid, pspec);
} }
@ -170,6 +185,10 @@ gst_rtsp_media_factory_set_property (GObject * object, guint propid,
gst_rtsp_media_factory_set_eos_shutdown (factory, gst_rtsp_media_factory_set_eos_shutdown (factory,
g_value_get_boolean (value)); g_value_get_boolean (value));
break; break;
case PROP_BUFFER_SIZE:
gst_rtsp_media_factory_set_buffer_size (factory,
g_value_get_uint (value));
break;
default: default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, propid, pspec); G_OBJECT_WARN_INVALID_PROPERTY_ID (object, propid, pspec);
} }
@ -326,6 +345,94 @@ gst_rtsp_media_factory_is_eos_shutdown (GstRTSPMediaFactory * factory)
return result; return result;
} }
/**
* gst_rtsp_media_factory_set_buffer_size:
* @factory: a #GstRTSPMedia
* @size: the new value
*
* Set the kernel UDP buffer size.
*/
void
gst_rtsp_media_factory_set_buffer_size (GstRTSPMediaFactory * factory,
guint size)
{
g_return_if_fail (GST_IS_RTSP_MEDIA_FACTORY (factory));
GST_RTSP_MEDIA_FACTORY_LOCK (factory);
factory->buffer_size = size;
GST_RTSP_MEDIA_FACTORY_UNLOCK (factory);
}
/**
* gst_rtsp_media_factory_get_buffer_size:
* @factory: a #GstRTSPMedia
*
* Get the kernel UDP buffer size.
*
* Returns: the kernel UDP buffer size.
*/
guint
gst_rtsp_media_factory_get_buffer_size (GstRTSPMediaFactory * factory)
{
guint result;
g_return_val_if_fail (GST_IS_RTSP_MEDIA_FACTORY (factory), 0);
GST_RTSP_MEDIA_FACTORY_LOCK (factory);
result = factory->buffer_size;
GST_RTSP_MEDIA_FACTORY_UNLOCK (factory);
return result;
}
/**
* gst_rtsp_media_factory_set_auth:
* @factory: a #GstRTSPMediaFactory
* @auth: a #GstRTSPAuth
*
* configure @auth to be used as the authentication manager of @factory.
*/
void
gst_rtsp_media_factory_set_auth (GstRTSPMediaFactory * factory,
GstRTSPAuth * auth)
{
GstRTSPAuth *old;
g_return_if_fail (GST_IS_RTSP_MEDIA_FACTORY (factory));
old = factory->auth;
if (old != auth) {
if (auth)
g_object_ref (auth);
factory->auth = auth;
if (old)
g_object_unref (old);
}
}
/**
* gst_rtsp_media_factory_get_auth:
* @factory: a #GstRTSPMediaFactory
*
* Get the #GstRTSPAuth used as the authentication manager of @factory.
*
* Returns: the #GstRTSPAuth of @factory. g_object_unref() after
* usage.
*/
GstRTSPAuth *
gst_rtsp_media_factory_get_auth (GstRTSPMediaFactory * factory)
{
GstRTSPAuth *result;
g_return_val_if_fail (GST_IS_RTSP_MEDIA_FACTORY (factory), NULL);
if ((result = factory->auth))
g_object_ref (result);
return result;
}
static gboolean static gboolean
compare_media (gpointer key, GstRTSPMedia * media1, GstRTSPMedia * media2) compare_media (gpointer key, GstRTSPMedia * media1, GstRTSPMedia * media2)
{ {
@ -608,13 +715,22 @@ static void
default_configure (GstRTSPMediaFactory * factory, GstRTSPMedia * media) default_configure (GstRTSPMediaFactory * factory, GstRTSPMedia * media)
{ {
gboolean shared, eos_shutdown; gboolean shared, eos_shutdown;
guint size;
GstRTSPAuth *auth;
/* configure the sharedness */ /* configure the sharedness */
GST_RTSP_MEDIA_FACTORY_LOCK (factory); GST_RTSP_MEDIA_FACTORY_LOCK (factory);
shared = factory->shared; shared = factory->shared;
eos_shutdown = factory->eos_shutdown; eos_shutdown = factory->eos_shutdown;
size = factory->buffer_size;
GST_RTSP_MEDIA_FACTORY_UNLOCK (factory); GST_RTSP_MEDIA_FACTORY_UNLOCK (factory);
gst_rtsp_media_set_shared (media, shared); gst_rtsp_media_set_shared (media, shared);
gst_rtsp_media_set_eos_shutdown (media, eos_shutdown); gst_rtsp_media_set_eos_shutdown (media, eos_shutdown);
gst_rtsp_media_set_buffer_size (media, size);
if ((auth = gst_rtsp_media_factory_get_auth (factory))) {
gst_rtsp_media_set_auth (media, auth);
g_object_unref (auth);
}
} }

View file

@ -21,6 +21,7 @@
#include <gst/rtsp/gstrtspurl.h> #include <gst/rtsp/gstrtspurl.h>
#include "rtsp-media.h" #include "rtsp-media.h"
#include "rtsp-auth.h"
#ifndef __GST_RTSP_MEDIA_FACTORY_H__ #ifndef __GST_RTSP_MEDIA_FACTORY_H__
#define __GST_RTSP_MEDIA_FACTORY_H__ #define __GST_RTSP_MEDIA_FACTORY_H__
@ -62,6 +63,8 @@ struct _GstRTSPMediaFactory {
gchar *launch; gchar *launch;
gboolean shared; gboolean shared;
gboolean eos_shutdown; gboolean eos_shutdown;
GstRTSPAuth *auth;
guint buffer_size;
GMutex *medias_lock; GMutex *medias_lock;
GHashTable *medias; GHashTable *medias;
@ -116,6 +119,13 @@ void gst_rtsp_media_factory_set_eos_shutdown (GstRTSPMediaFac
gboolean eos_shutdown); gboolean eos_shutdown);
gboolean gst_rtsp_media_factory_is_eos_shutdown (GstRTSPMediaFactory *factory); gboolean gst_rtsp_media_factory_is_eos_shutdown (GstRTSPMediaFactory *factory);
void gst_rtsp_media_factory_set_auth (GstRTSPMediaFactory *factory, GstRTSPAuth *auth);
GstRTSPAuth * gst_rtsp_media_factory_get_auth (GstRTSPMediaFactory *factory);
void gst_rtsp_media_factory_set_buffer_size (GstRTSPMediaFactory * factory, guint size);
guint gst_rtsp_media_factory_get_buffer_size (GstRTSPMediaFactory * factory);
/* creating the media from the factory and a url */ /* creating the media from the factory and a url */
GstRTSPMedia * gst_rtsp_media_factory_construct (GstRTSPMediaFactory *factory, GstRTSPMedia * gst_rtsp_media_factory_construct (GstRTSPMediaFactory *factory,
const GstRTSPUrl *url); const GstRTSPUrl *url);

View file

@ -21,7 +21,7 @@
G_DEFINE_TYPE (GstRTSPMediaMapping, gst_rtsp_media_mapping, G_TYPE_OBJECT); G_DEFINE_TYPE (GstRTSPMediaMapping, gst_rtsp_media_mapping, G_TYPE_OBJECT);
GST_DEBUG_CATEGORY_EXTERN (rtsp_media_debug); GST_DEBUG_CATEGORY_STATIC (rtsp_media_debug);
#define GST_CAT_DEFAULT rtsp_media_debug #define GST_CAT_DEFAULT rtsp_media_debug
static void gst_rtsp_media_mapping_finalize (GObject * obj); static void gst_rtsp_media_mapping_finalize (GObject * obj);
@ -39,11 +39,16 @@ gst_rtsp_media_mapping_class_init (GstRTSPMediaMappingClass * klass)
gobject_class->finalize = gst_rtsp_media_mapping_finalize; gobject_class->finalize = gst_rtsp_media_mapping_finalize;
klass->find_media = find_media; klass->find_media = find_media;
GST_DEBUG_CATEGORY_INIT (rtsp_media_debug, "rtspmediamapping", 0,
"GstRTSPMediaMapping");
} }
static void static void
gst_rtsp_media_mapping_init (GstRTSPMediaMapping * mapping) gst_rtsp_media_mapping_init (GstRTSPMediaMapping * mapping)
{ {
GST_DEBUG_OBJECT (mapping, "created");
mapping->mappings = g_hash_table_new_full (g_str_hash, g_str_equal, mapping->mappings = g_hash_table_new_full (g_str_hash, g_str_equal,
g_free, g_object_unref); g_free, g_object_unref);
} }
@ -53,6 +58,8 @@ gst_rtsp_media_mapping_finalize (GObject * obj)
{ {
GstRTSPMediaMapping *mapping = GST_RTSP_MEDIA_MAPPING (obj); GstRTSPMediaMapping *mapping = GST_RTSP_MEDIA_MAPPING (obj);
GST_DEBUG_OBJECT (mapping, "finalized");
g_hash_table_unref (mapping->mappings); g_hash_table_unref (mapping->mappings);
G_OBJECT_CLASS (gst_rtsp_media_mapping_parent_class)->finalize (obj); G_OBJECT_CLASS (gst_rtsp_media_mapping_parent_class)->finalize (obj);

View file

@ -23,6 +23,7 @@
#include <gst/app/gstappsrc.h> #include <gst/app/gstappsrc.h>
#include <gst/app/gstappsink.h> #include <gst/app/gstappsink.h>
#include "rtsp-funnel.h"
#include "rtsp-media.h" #include "rtsp-media.h"
#define DEFAULT_SHARED FALSE #define DEFAULT_SHARED FALSE
@ -30,6 +31,7 @@
#define DEFAULT_PROTOCOLS GST_RTSP_LOWER_TRANS_UDP | GST_RTSP_LOWER_TRANS_TCP #define DEFAULT_PROTOCOLS GST_RTSP_LOWER_TRANS_UDP | GST_RTSP_LOWER_TRANS_TCP
//#define DEFAULT_PROTOCOLS GST_RTSP_LOWER_TRANS_UDP_MCAST //#define DEFAULT_PROTOCOLS GST_RTSP_LOWER_TRANS_UDP_MCAST
#define DEFAULT_EOS_SHUTDOWN FALSE #define DEFAULT_EOS_SHUTDOWN FALSE
#define DEFAULT_BUFFER_SIZE 0x80000
/* define to dump received RTCP packets */ /* define to dump received RTCP packets */
#undef DUMP_STATS #undef DUMP_STATS
@ -41,16 +43,19 @@ enum
PROP_REUSABLE, PROP_REUSABLE,
PROP_PROTOCOLS, PROP_PROTOCOLS,
PROP_EOS_SHUTDOWN, PROP_EOS_SHUTDOWN,
PROP_BUFFER_SIZE,
PROP_LAST PROP_LAST
}; };
enum enum
{ {
SIGNAL_PREPARED,
SIGNAL_UNPREPARED, SIGNAL_UNPREPARED,
SIGNAL_NEW_STATE,
SIGNAL_LAST SIGNAL_LAST
}; };
GST_DEBUG_CATEGORY_EXTERN (rtsp_media_debug); GST_DEBUG_CATEGORY_STATIC (rtsp_media_debug);
#define GST_CAT_DEFAULT rtsp_media_debug #define GST_CAT_DEFAULT rtsp_media_debug
static GQuark ssrc_stream_map_key; static GQuark ssrc_stream_map_key;
@ -103,14 +108,31 @@ gst_rtsp_media_class_init (GstRTSPMediaClass * klass)
"Send an EOS event to the pipeline before unpreparing", "Send an EOS event to the pipeline before unpreparing",
DEFAULT_EOS_SHUTDOWN, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); DEFAULT_EOS_SHUTDOWN, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
g_object_class_install_property (gobject_class, PROP_BUFFER_SIZE,
g_param_spec_uint ("buffer-size", "Buffer Size",
"The kernel UDP buffer size to use", 0, G_MAXUINT,
DEFAULT_BUFFER_SIZE, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
gst_rtsp_media_signals[SIGNAL_PREPARED] =
g_signal_new ("prepared", G_TYPE_FROM_CLASS (klass), G_SIGNAL_RUN_LAST,
G_STRUCT_OFFSET (GstRTSPMediaClass, prepared), NULL, NULL,
g_cclosure_marshal_VOID__VOID, G_TYPE_NONE, 0, G_TYPE_NONE);
gst_rtsp_media_signals[SIGNAL_UNPREPARED] = gst_rtsp_media_signals[SIGNAL_UNPREPARED] =
g_signal_new ("unprepared", G_TYPE_FROM_CLASS (klass), G_SIGNAL_RUN_LAST, g_signal_new ("unprepared", G_TYPE_FROM_CLASS (klass), G_SIGNAL_RUN_LAST,
G_STRUCT_OFFSET (GstRTSPMediaClass, unprepared), NULL, NULL, G_STRUCT_OFFSET (GstRTSPMediaClass, unprepared), NULL, NULL,
g_cclosure_marshal_VOID__VOID, G_TYPE_NONE, 0, G_TYPE_NONE); g_cclosure_marshal_VOID__VOID, G_TYPE_NONE, 0, G_TYPE_NONE);
gst_rtsp_media_signals[SIGNAL_NEW_STATE] =
g_signal_new ("new-state", G_TYPE_FROM_CLASS (klass), G_SIGNAL_RUN_LAST,
G_STRUCT_OFFSET (GstRTSPMediaClass, new_state), NULL, NULL,
g_cclosure_marshal_VOID__INT, G_TYPE_NONE, 0, G_TYPE_INT);
klass->context = g_main_context_new (); klass->context = g_main_context_new ();
klass->loop = g_main_loop_new (klass->context, TRUE); klass->loop = g_main_loop_new (klass->context, TRUE);
GST_DEBUG_CATEGORY_INIT (rtsp_media_debug, "rtspmedia", 0, "GstRTSPMedia");
klass->thread = g_thread_create ((GThreadFunc) do_loop, klass, TRUE, &error); klass->thread = g_thread_create ((GThreadFunc) do_loop, klass, TRUE, &error);
if (error != NULL) { if (error != NULL) {
g_critical ("could not start bus thread: %s", error->message); g_critical ("could not start bus thread: %s", error->message);
@ -119,6 +141,9 @@ gst_rtsp_media_class_init (GstRTSPMediaClass * klass)
klass->unprepare = default_unprepare; klass->unprepare = default_unprepare;
ssrc_stream_map_key = g_quark_from_static_string ("GstRTSPServer.stream"); ssrc_stream_map_key = g_quark_from_static_string ("GstRTSPServer.stream");
gst_element_register (NULL, "rtspfunnel", GST_RANK_NONE, RTSP_TYPE_FUNNEL);
} }
static void static void
@ -132,45 +157,7 @@ gst_rtsp_media_init (GstRTSPMedia * media)
media->reusable = DEFAULT_REUSABLE; media->reusable = DEFAULT_REUSABLE;
media->protocols = DEFAULT_PROTOCOLS; media->protocols = DEFAULT_PROTOCOLS;
media->eos_shutdown = DEFAULT_EOS_SHUTDOWN; media->eos_shutdown = DEFAULT_EOS_SHUTDOWN;
} media->buffer_size = DEFAULT_BUFFER_SIZE;
/* FIXME. this should be done in multiudpsink */
typedef struct
{
gint count;
gchar *dest;
gint min, max;
} RTSPDestination;
static gint
dest_compare (RTSPDestination * a, RTSPDestination * b)
{
if ((a->min == b->min) && (a->max == b->max)
&& (strcmp (a->dest, b->dest) == 0))
return 0;
return 1;
}
static RTSPDestination *
create_destination (const gchar * dest, gint min, gint max)
{
RTSPDestination *res;
res = g_slice_new (RTSPDestination);
res->count = 1;
res->dest = g_strdup (dest);
res->min = min;
res->max = max;
return res;
}
static void
free_destination (RTSPDestination * dest)
{
g_free (dest->dest);
g_slice_free (RTSPDestination, dest);
} }
void void
@ -208,9 +195,6 @@ gst_rtsp_media_stream_free (GstRTSPMediaStream * stream)
g_list_free (stream->transports); g_list_free (stream->transports);
g_list_foreach (stream->destinations, (GFunc) free_destination, NULL);
g_list_free (stream->destinations);
g_free (stream); g_free (stream);
} }
@ -271,6 +255,9 @@ gst_rtsp_media_get_property (GObject * object, guint propid,
case PROP_EOS_SHUTDOWN: case PROP_EOS_SHUTDOWN:
g_value_set_boolean (value, gst_rtsp_media_is_eos_shutdown (media)); g_value_set_boolean (value, gst_rtsp_media_is_eos_shutdown (media));
break; break;
case PROP_BUFFER_SIZE:
g_value_set_uint (value, gst_rtsp_media_get_buffer_size (media));
break;
default: default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, propid, pspec); G_OBJECT_WARN_INVALID_PROPERTY_ID (object, propid, pspec);
} }
@ -295,6 +282,9 @@ gst_rtsp_media_set_property (GObject * object, guint propid,
case PROP_EOS_SHUTDOWN: case PROP_EOS_SHUTDOWN:
gst_rtsp_media_set_eos_shutdown (media, g_value_get_boolean (value)); gst_rtsp_media_set_eos_shutdown (media, g_value_get_boolean (value));
break; break;
case PROP_BUFFER_SIZE:
gst_rtsp_media_set_buffer_size (media, g_value_get_uint (value));
break;
default: default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, propid, pspec); G_OBJECT_WARN_INVALID_PROPERTY_ID (object, propid, pspec);
} }
@ -341,7 +331,7 @@ collect_media_stats (GstRTSPMedia * media)
GST_INFO ("stats: position %" GST_TIME_FORMAT ", duration %" GST_INFO ("stats: position %" GST_TIME_FORMAT ", duration %"
GST_TIME_FORMAT, GST_TIME_ARGS (position), GST_TIME_ARGS (duration)); GST_TIME_FORMAT, GST_TIME_ARGS (position), GST_TIME_ARGS (duration));
if (position == -1 || media->active > 0) { if (position == -1) {
media->range.min.type = GST_RTSP_TIME_NOW; media->range.min.type = GST_RTSP_TIME_NOW;
media->range.min.seconds = -1; media->range.min.seconds = -1;
} else { } else {
@ -507,6 +497,85 @@ gst_rtsp_media_is_eos_shutdown (GstRTSPMedia * media)
return media->eos_shutdown; return media->eos_shutdown;
} }
/**
* gst_rtsp_media_set_buffer_size:
* @media: a #GstRTSPMedia
* @size: the new value
*
* Set the kernel UDP buffer size.
*/
void
gst_rtsp_media_set_buffer_size (GstRTSPMedia * media, guint size)
{
g_return_if_fail (GST_IS_RTSP_MEDIA (media));
media->buffer_size = size;
}
/**
* gst_rtsp_media_get_buffer_size:
* @media: a #GstRTSPMedia
*
* Get the kernel UDP buffer size.
*
* Returns: the kernel UDP buffer size.
*/
guint
gst_rtsp_media_get_buffer_size (GstRTSPMedia * media)
{
g_return_val_if_fail (GST_IS_RTSP_MEDIA (media), FALSE);
return media->buffer_size;
}
/**
* gst_rtsp_media_set_auth:
* @media: a #GstRTSPMedia
* @auth: a #GstRTSPAuth
*
* configure @auth to be used as the authentication manager of @media.
*/
void
gst_rtsp_media_set_auth (GstRTSPMedia * media, GstRTSPAuth * auth)
{
GstRTSPAuth *old;
g_return_if_fail (GST_IS_RTSP_MEDIA (media));
old = media->auth;
if (old != auth) {
if (auth)
g_object_ref (auth);
media->auth = auth;
if (old)
g_object_unref (old);
}
}
/**
* gst_rtsp_media_get_auth:
* @media: a #GstRTSPMedia
*
* Get the #GstRTSPAuth used as the authentication manager of @media.
*
* Returns: the #GstRTSPAuth of @media. g_object_unref() after
* usage.
*/
GstRTSPAuth *
gst_rtsp_media_get_auth (GstRTSPMedia * media)
{
GstRTSPAuth *result;
g_return_val_if_fail (GST_IS_RTSP_MEDIA (media), NULL);
if ((result = media->auth))
g_object_ref (result);
return result;
}
/** /**
* gst_rtsp_media_n_streams: * gst_rtsp_media_n_streams:
* @media: a #GstRTSPMedia * @media: a #GstRTSPMedia
@ -548,6 +617,34 @@ gst_rtsp_media_get_stream (GstRTSPMedia * media, guint idx)
return res; return res;
} }
/**
* gst_rtsp_media_get_range_string:
* @media: a #GstRTSPMedia
* @play: for the PLAY request
*
* Get the current range as a string.
*
* Returns: The range as a string, g_free() after usage.
*/
gchar *
gst_rtsp_media_get_range_string (GstRTSPMedia * media, gboolean play)
{
gchar *result;
GstRTSPTimeRange range;
/* make copy */
range = media->range;
if (!play && media->active > 0) {
range.min.type = GST_RTSP_TIME_NOW;
range.min.seconds = -1;
}
result = gst_rtsp_range_to_string (&range);
return result;
}
/** /**
* gst_rtsp_media_seek: * gst_rtsp_media_seek:
* @media: a #GstRTSPMedia * @media: a #GstRTSPMedia
@ -804,10 +901,16 @@ again:
"send-duplicates")) { "send-duplicates")) {
g_object_set (G_OBJECT (udpsink0), "send-duplicates", FALSE, NULL); g_object_set (G_OBJECT (udpsink0), "send-duplicates", FALSE, NULL);
g_object_set (G_OBJECT (udpsink1), "send-duplicates", FALSE, NULL); g_object_set (G_OBJECT (udpsink1), "send-duplicates", FALSE, NULL);
stream->filter_duplicates = FALSE;
} else { } else {
GST_WARNING ("multiudpsink version found without send-duplicates property"); g_warning
stream->filter_duplicates = TRUE; ("old multiudpsink version found without send-duplicates property");
}
if (g_object_class_find_property (G_OBJECT_GET_CLASS (udpsink0),
"buffer-size")) {
g_object_set (G_OBJECT (udpsink0), "buffer-size", media->buffer_size, NULL);
} else {
GST_WARNING ("multiudpsink version found without buffer-size property");
} }
g_object_get (G_OBJECT (udpsrc1), "sock", &sockfd, NULL); g_object_get (G_OBJECT (udpsrc1), "sock", &sockfd, NULL);
@ -1068,10 +1171,42 @@ handle_new_buffer (GstAppSink * sink, gpointer user_data)
return GST_FLOW_OK; return GST_FLOW_OK;
} }
static GstFlowReturn
handle_new_buffer_list (GstAppSink * sink, gpointer user_data)
{
GList *walk;
GstBufferList *blist;
GstRTSPMediaStream *stream;
blist = gst_app_sink_pull_buffer_list (sink);
if (!blist)
return GST_FLOW_OK;
stream = (GstRTSPMediaStream *) user_data;
for (walk = stream->transports; walk; walk = g_list_next (walk)) {
GstRTSPMediaTrans *tr = (GstRTSPMediaTrans *) walk->data;
if (GST_ELEMENT_CAST (sink) == stream->appsink[0]) {
if (tr->send_rtp_list)
tr->send_rtp_list (blist, tr->transport->interleaved.min,
tr->user_data);
} else {
if (tr->send_rtcp_list)
tr->send_rtcp_list (blist, tr->transport->interleaved.max,
tr->user_data);
}
}
gst_buffer_list_unref (blist);
return GST_FLOW_OK;
}
static GstAppSinkCallbacks sink_cb = { static GstAppSinkCallbacks sink_cb = {
NULL, /* not interested in EOS */ NULL, /* not interested in EOS */
NULL, /* not interested in preroll buffers */ NULL, /* not interested in preroll buffers */
handle_new_buffer handle_new_buffer,
handle_new_buffer_list
}; };
/* prepare the pipeline objects to handle @stream in @media */ /* prepare the pipeline objects to handle @stream in @media */
@ -1190,8 +1325,7 @@ setup_stream (GstRTSPMediaStream * stream, guint idx, GstRTSPMedia * media)
gst_object_unref (teepad); gst_object_unref (teepad);
/* make selector for the RTP receivers */ /* make selector for the RTP receivers */
stream->selector[0] = gst_element_factory_make ("input-selector", NULL); stream->selector[0] = gst_element_factory_make ("rtspfunnel", NULL);
g_object_set (stream->selector[0], "select-all", TRUE, NULL);
gst_bin_add (GST_BIN_CAST (media->pipeline), stream->selector[0]); gst_bin_add (GST_BIN_CAST (media->pipeline), stream->selector[0]);
pad = gst_element_get_static_pad (stream->selector[0], "src"); pad = gst_element_get_static_pad (stream->selector[0], "src");
@ -1211,8 +1345,7 @@ setup_stream (GstRTSPMediaStream * stream, guint idx, GstRTSPMedia * media)
gst_object_unref (selpad); gst_object_unref (selpad);
/* make selector for the RTCP receivers */ /* make selector for the RTCP receivers */
stream->selector[1] = gst_element_factory_make ("input-selector", NULL); stream->selector[1] = gst_element_factory_make ("rtspfunnel", NULL);
g_object_set (stream->selector[1], "select-all", TRUE, NULL);
gst_bin_add (GST_BIN_CAST (media->pipeline), stream->selector[1]); gst_bin_add (GST_BIN_CAST (media->pipeline), stream->selector[1]);
pad = gst_element_get_static_pad (stream->selector[1], "src"); pad = gst_element_get_static_pad (stream->selector[1], "src");
@ -1594,6 +1727,8 @@ gst_rtsp_media_prepare (GstRTSPMedia * media)
if (status == GST_RTSP_MEDIA_STATUS_ERROR) if (status == GST_RTSP_MEDIA_STATUS_ERROR)
goto state_failed; goto state_failed;
g_signal_emit (media, gst_rtsp_media_signals[SIGNAL_PREPARED], 0, NULL);
GST_INFO ("object %p is prerolled", media); GST_INFO ("object %p is prerolled", media);
return TRUE; return TRUE;
@ -1686,83 +1821,18 @@ static void
add_udp_destination (GstRTSPMedia * media, GstRTSPMediaStream * stream, add_udp_destination (GstRTSPMedia * media, GstRTSPMediaStream * stream,
gchar * dest, gint min, gint max) gchar * dest, gint min, gint max)
{ {
gboolean do_add = TRUE;
RTSPDestination *ndest;
if (stream->filter_duplicates) {
RTSPDestination fdest;
GList *find;
fdest.dest = dest;
fdest.min = min;
fdest.max = max;
/* first see if we already added this destination */
find =
g_list_find_custom (stream->destinations, &fdest,
(GCompareFunc) dest_compare);
if (find) {
ndest = (RTSPDestination *) find->data;
GST_INFO ("already streaming to %s:%d-%d with %d clients", dest, min, max,
ndest->count);
ndest->count++;
do_add = FALSE;
}
}
if (do_add) {
GST_INFO ("adding %s:%d-%d", dest, min, max); GST_INFO ("adding %s:%d-%d", dest, min, max);
g_signal_emit_by_name (stream->udpsink[0], "add", dest, min, NULL); g_signal_emit_by_name (stream->udpsink[0], "add", dest, min, NULL);
g_signal_emit_by_name (stream->udpsink[1], "add", dest, max, NULL); g_signal_emit_by_name (stream->udpsink[1], "add", dest, max, NULL);
if (stream->filter_duplicates) {
ndest = create_destination (dest, min, max);
stream->destinations = g_list_prepend (stream->destinations, ndest);
}
}
} }
static void static void
remove_udp_destination (GstRTSPMedia * media, GstRTSPMediaStream * stream, remove_udp_destination (GstRTSPMedia * media, GstRTSPMediaStream * stream,
gchar * dest, gint min, gint max) gchar * dest, gint min, gint max)
{ {
gboolean do_remove = TRUE;
RTSPDestination *ndest = NULL;
GList *find = NULL;
if (stream->filter_duplicates) {
RTSPDestination fdest;
fdest.dest = dest;
fdest.min = min;
fdest.max = max;
/* first see if we already added this destination */
find =
g_list_find_custom (stream->destinations, &fdest,
(GCompareFunc) dest_compare);
if (!find)
return;
ndest = (RTSPDestination *) find->data;
if (--ndest->count > 0) {
do_remove = FALSE;
GST_INFO ("still streaming to %s:%d-%d with %d clients", dest, min, max,
ndest->count);
}
}
if (do_remove) {
GST_INFO ("removing %s:%d-%d", dest, min, max); GST_INFO ("removing %s:%d-%d", dest, min, max);
g_signal_emit_by_name (stream->udpsink[0], "remove", dest, min, NULL); g_signal_emit_by_name (stream->udpsink[0], "remove", dest, min, NULL);
g_signal_emit_by_name (stream->udpsink[1], "remove", dest, max, NULL); g_signal_emit_by_name (stream->udpsink[1], "remove", dest, max, NULL);
if (stream->filter_duplicates) {
stream->destinations = g_list_delete_link (stream->destinations, find);
free_destination (ndest);
}
}
} }
/** /**
@ -1888,17 +1958,23 @@ gst_rtsp_media_set_state (GstRTSPMedia * media, GstState state,
else else
do_state = FALSE; do_state = FALSE;
GST_INFO ("active %d media %p", media->active, media); GST_INFO ("state %d active %d media %p do_state %d", state, media->active,
media, do_state);
if (do_state && media->target_state != state) { if (media->target_state != state) {
if (do_state) {
if (state == GST_STATE_NULL) { if (state == GST_STATE_NULL) {
gst_rtsp_media_unprepare (media); gst_rtsp_media_unprepare (media);
} else { } else {
GST_INFO ("state %s media %p", gst_element_state_get_name (state), media); GST_INFO ("state %s media %p", gst_element_state_get_name (state),
media);
media->target_state = state; media->target_state = state;
ret = gst_element_set_state (media->pipeline, state); ret = gst_element_set_state (media->pipeline, state);
} }
} }
g_signal_emit (media, gst_rtsp_media_signals[SIGNAL_NEW_STATE], 0, state,
NULL);
}
/* remember where we are */ /* remember where we are */
if (state == GST_STATE_PAUSED || old_active != media->active) if (state == GST_STATE_PAUSED || old_active != media->active)

View file

@ -42,6 +42,7 @@ typedef struct _GstRTSPMediaClass GstRTSPMediaClass;
typedef struct _GstRTSPMediaTrans GstRTSPMediaTrans; typedef struct _GstRTSPMediaTrans GstRTSPMediaTrans;
typedef gboolean (*GstRTSPSendFunc) (GstBuffer *buffer, guint8 channel, gpointer user_data); typedef gboolean (*GstRTSPSendFunc) (GstBuffer *buffer, guint8 channel, gpointer user_data);
typedef gboolean (*GstRTSPSendListFunc) (GstBufferList *blist, guint8 channel, gpointer user_data);
typedef void (*GstRTSPKeepAliveFunc) (gpointer user_data); typedef void (*GstRTSPKeepAliveFunc) (gpointer user_data);
/** /**
@ -49,6 +50,8 @@ typedef void (*GstRTSPKeepAliveFunc) (gpointer user_data);
* @idx: a stream index * @idx: a stream index
* @send_rtp: callback for sending RTP messages * @send_rtp: callback for sending RTP messages
* @send_rtcp: callback for sending RTCP messages * @send_rtcp: callback for sending RTCP messages
* @send_rtp_list: callback for sending RTP messages
* @send_rtcp_list: callback for sending RTCP messages
* @user_data: user data passed in the callbacks * @user_data: user data passed in the callbacks
* @notify: free function for the user_data. * @notify: free function for the user_data.
* @keep_alive: keep alive callback * @keep_alive: keep alive callback
@ -66,6 +69,8 @@ struct _GstRTSPMediaTrans {
GstRTSPSendFunc send_rtp; GstRTSPSendFunc send_rtp;
GstRTSPSendFunc send_rtcp; GstRTSPSendFunc send_rtcp;
GstRTSPSendListFunc send_rtp_list;
GstRTSPSendListFunc send_rtcp_list;
gpointer user_data; gpointer user_data;
GDestroyNotify notify; GDestroyNotify notify;
@ -80,16 +85,17 @@ struct _GstRTSPMediaTrans {
GObject *rtpsource; GObject *rtpsource;
}; };
#include "rtsp-auth.h"
/** /**
* GstRTSPMediaStream: * GstRTSPMediaStream:
* @srcpad: the srcpad of the stream * @srcpad: the srcpad of the stream
* @payloader: the payloader of the format * @payloader: the payloader of the format
* @prepared: if the stream is prepared for streaming * @prepared: if the stream is prepared for streaming
* @server_port: the server udp ports
* @recv_rtp_sink: sinkpad for RTP buffers * @recv_rtp_sink: sinkpad for RTP buffers
* @recv_rtcp_sink: sinkpad for RTCP buffers * @recv_rtcp_sink: sinkpad for RTCP buffers
* @recv_rtp_src: srcpad for RTP buffers * @send_rtp_src: srcpad for RTP buffers
* @recv_rtcp_src: srcpad for RTCP buffers * @send_rtcp_src: srcpad for RTCP buffers
* @udpsrc: the udp source elements for RTP/RTCP * @udpsrc: the udp source elements for RTP/RTCP
* @udpsink: the udp sink elements for RTP/RTCP * @udpsink: the udp sink elements for RTP/RTCP
* @appsrc: the app source elements for RTP/RTCP * @appsrc: the app source elements for RTP/RTCP
@ -136,11 +142,6 @@ struct _GstRTSPMediaStream {
/* transports we stream to */ /* transports we stream to */
GList *transports; GList *transports;
/* to filter out duplicate destinations in case multiudpsink is too old to do
* this for us */
gboolean filter_duplicates;
GList *destinations;
}; };
/** /**
@ -200,6 +201,8 @@ struct _GstRTSPMedia {
gboolean reused; gboolean reused;
gboolean is_ipv6; gboolean is_ipv6;
gboolean eos_shutdown; gboolean eos_shutdown;
guint buffer_size;
GstRTSPAuth *auth;
GstElement *element; GstElement *element;
GArray *streams; GArray *streams;
@ -250,7 +253,10 @@ struct _GstRTSPMediaClass {
gboolean (*unprepare) (GstRTSPMedia *media); gboolean (*unprepare) (GstRTSPMedia *media);
/* signals */ /* signals */
gboolean (*prepared) (GstRTSPMedia *media);
gboolean (*unprepared) (GstRTSPMedia *media); gboolean (*unprepared) (GstRTSPMedia *media);
gboolean (*new_state) (GstRTSPMedia *media, GstState state);
}; };
GType gst_rtsp_media_get_type (void); GType gst_rtsp_media_get_type (void);
@ -270,6 +276,12 @@ GstRTSPLowerTrans gst_rtsp_media_get_protocols (GstRTSPMedia *media);
void gst_rtsp_media_set_eos_shutdown (GstRTSPMedia *media, gboolean eos_shutdown); void gst_rtsp_media_set_eos_shutdown (GstRTSPMedia *media, gboolean eos_shutdown);
gboolean gst_rtsp_media_is_eos_shutdown (GstRTSPMedia *media); gboolean gst_rtsp_media_is_eos_shutdown (GstRTSPMedia *media);
void gst_rtsp_media_set_auth (GstRTSPMedia *media, GstRTSPAuth *auth);
GstRTSPAuth * gst_rtsp_media_get_auth (GstRTSPMedia *media);
void gst_rtsp_media_set_buffer_size (GstRTSPMedia *media, guint size);
guint gst_rtsp_media_get_buffer_size (GstRTSPMedia *media);
/* prepare the media for playback */ /* prepare the media for playback */
gboolean gst_rtsp_media_prepare (GstRTSPMedia *media); gboolean gst_rtsp_media_prepare (GstRTSPMedia *media);
gboolean gst_rtsp_media_is_prepared (GstRTSPMedia *media); gboolean gst_rtsp_media_is_prepared (GstRTSPMedia *media);
@ -280,6 +292,7 @@ guint gst_rtsp_media_n_streams (GstRTSPMedia *media);
GstRTSPMediaStream * gst_rtsp_media_get_stream (GstRTSPMedia *media, guint idx); GstRTSPMediaStream * gst_rtsp_media_get_stream (GstRTSPMedia *media, guint idx);
gboolean gst_rtsp_media_seek (GstRTSPMedia *media, GstRTSPTimeRange *range); gboolean gst_rtsp_media_seek (GstRTSPMedia *media, GstRTSPTimeRange *range);
gchar * gst_rtsp_media_get_range_string (GstRTSPMedia *media, gboolean play);
GstFlowReturn gst_rtsp_media_stream_rtp (GstRTSPMediaStream *stream, GstBuffer *buffer); GstFlowReturn gst_rtsp_media_stream_rtp (GstRTSPMediaStream *stream, GstBuffer *buffer);
GstFlowReturn gst_rtsp_media_stream_rtcp (GstRTSPMediaStream *stream, GstBuffer *buffer); GstFlowReturn gst_rtsp_media_stream_rtcp (GstRTSPMediaStream *stream, GstBuffer *buffer);

View file

@ -21,9 +21,7 @@
#include "rtsp-params.h" #include "rtsp-params.h"
GstRTSPResult GstRTSPResult
gst_rtsp_params_set (GstRTSPClient * client, GstRTSPUrl * uri, gst_rtsp_params_set (GstRTSPClient * client, GstRTSPClientState * state)
GstRTSPSession * session, GstRTSPMessage * request,
GstRTSPMessage * response)
{ {
GstRTSPStatusCode code; GstRTSPStatusCode code;
@ -31,16 +29,14 @@ gst_rtsp_params_set (GstRTSPClient * client, GstRTSPUrl * uri,
* with a list of the parameters */ * with a list of the parameters */
code = GST_RTSP_STS_PARAMETER_NOT_UNDERSTOOD; code = GST_RTSP_STS_PARAMETER_NOT_UNDERSTOOD;
gst_rtsp_message_init_response (response, code, gst_rtsp_message_init_response (state->response, code,
gst_rtsp_status_as_text (code), request); gst_rtsp_status_as_text (code), state->request);
return GST_RTSP_OK; return GST_RTSP_OK;
} }
GstRTSPResult GstRTSPResult
gst_rtsp_params_get (GstRTSPClient * client, GstRTSPUrl * uri, gst_rtsp_params_get (GstRTSPClient * client, GstRTSPClientState * state)
GstRTSPSession * session, GstRTSPMessage * request,
GstRTSPMessage * response)
{ {
GstRTSPStatusCode code; GstRTSPStatusCode code;
@ -48,8 +44,8 @@ gst_rtsp_params_get (GstRTSPClient * client, GstRTSPUrl * uri,
* with a list of the parameters */ * with a list of the parameters */
code = GST_RTSP_STS_PARAMETER_NOT_UNDERSTOOD; code = GST_RTSP_STS_PARAMETER_NOT_UNDERSTOOD;
gst_rtsp_message_init_response (response, code, gst_rtsp_message_init_response (state->response, code,
gst_rtsp_status_as_text (code), request); gst_rtsp_status_as_text (code), state->request);
return GST_RTSP_OK; return GST_RTSP_OK;
} }

View file

@ -30,13 +30,8 @@
G_BEGIN_DECLS G_BEGIN_DECLS
GstRTSPResult gst_rtsp_params_set (GstRTSPClient * client, GstRTSPUrl * uri, GstRTSPResult gst_rtsp_params_set (GstRTSPClient * client, GstRTSPClientState * state);
GstRTSPSession * session, GstRTSPMessage * request, GstRTSPResult gst_rtsp_params_get (GstRTSPClient * client, GstRTSPClientState * state);
GstRTSPMessage * response);
GstRTSPResult gst_rtsp_params_get (GstRTSPClient * client, GstRTSPUrl * uri,
GstRTSPSession * session, GstRTSPMessage * request,
GstRTSPMessage * response);
G_END_DECLS G_END_DECLS

View file

@ -43,7 +43,7 @@ gst_rtsp_sdp_from_media (GstSDPMessage * sdp, GstSDPInfo * info,
n_streams = gst_rtsp_media_n_streams (media); n_streams = gst_rtsp_media_n_streams (media);
rangestr = gst_rtsp_range_to_string (&media->range); rangestr = gst_rtsp_media_get_range_string (media, FALSE);
gst_sdp_message_add_attribute (sdp, "range", rangestr); gst_sdp_message_add_attribute (sdp, "range", rangestr);
g_free (rangestr); g_free (rangestr);

View file

@ -17,6 +17,19 @@
* Boston, MA 02111-1307, USA. * Boston, MA 02111-1307, USA.
*/ */
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <errno.h>
#include <string.h>
#include <sys/time.h>
#include <sys/types.h>
#include <netinet/in.h>
#include <netdb.h>
#include <sys/socket.h>
#include <sys/wait.h>
#include <fcntl.h>
#include <arpa/inet.h>
#include <sys/ioctl.h> #include <sys/ioctl.h>
#include "rtsp-server.h" #include "rtsp-server.h"
@ -55,8 +68,9 @@ static void gst_rtsp_server_set_property (GObject * object, guint propid,
const GValue * value, GParamSpec * pspec); const GValue * value, GParamSpec * pspec);
static void gst_rtsp_server_finalize (GObject * object); static void gst_rtsp_server_finalize (GObject * object);
static GstRTSPClient *default_accept_client (GstRTSPServer * server, static GstRTSPClient *default_create_client (GstRTSPServer * server);
GIOChannel * channel); static gboolean default_accept_client (GstRTSPServer * server,
GstRTSPClient * client, GIOChannel * channel);
static void static void
gst_rtsp_server_class_init (GstRTSPServerClass * klass) gst_rtsp_server_class_init (GstRTSPServerClass * klass)
@ -127,6 +141,7 @@ gst_rtsp_server_class_init (GstRTSPServerClass * klass)
GST_TYPE_RTSP_MEDIA_MAPPING, GST_TYPE_RTSP_MEDIA_MAPPING,
G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
klass->create_client = default_create_client;
klass->accept_client = default_accept_client; klass->accept_client = default_accept_client;
GST_DEBUG_CATEGORY_INIT (rtsp_server_debug, "rtspserver", 0, "GstRTSPServer"); GST_DEBUG_CATEGORY_INIT (rtsp_server_debug, "rtspserver", 0, "GstRTSPServer");
@ -135,6 +150,7 @@ gst_rtsp_server_class_init (GstRTSPServerClass * klass)
static void static void
gst_rtsp_server_init (GstRTSPServer * server) gst_rtsp_server_init (GstRTSPServer * server)
{ {
server->lock = g_mutex_new ();
server->address = g_strdup (DEFAULT_ADDRESS); server->address = g_strdup (DEFAULT_ADDRESS);
server->service = g_strdup (DEFAULT_SERVICE); server->service = g_strdup (DEFAULT_SERVICE);
server->backlog = DEFAULT_BACKLOG; server->backlog = DEFAULT_BACKLOG;
@ -147,11 +163,20 @@ gst_rtsp_server_finalize (GObject * object)
{ {
GstRTSPServer *server = GST_RTSP_SERVER (object); GstRTSPServer *server = GST_RTSP_SERVER (object);
GST_DEBUG_OBJECT (server, "finalize server");
g_free (server->address); g_free (server->address);
g_free (server->service); g_free (server->service);
g_object_unref (server->session_pool); g_object_unref (server->session_pool);
g_object_unref (server->media_mapping); g_object_unref (server->media_mapping);
if (server->auth)
g_object_unref (server->auth);
g_mutex_free (server->lock);
G_OBJECT_CLASS (gst_rtsp_server_parent_class)->finalize (object);
} }
/** /**
@ -184,8 +209,10 @@ gst_rtsp_server_set_address (GstRTSPServer * server, const gchar * address)
g_return_if_fail (GST_IS_RTSP_SERVER (server)); g_return_if_fail (GST_IS_RTSP_SERVER (server));
g_return_if_fail (address != NULL); g_return_if_fail (address != NULL);
GST_RTSP_SERVER_LOCK (server);
g_free (server->address); g_free (server->address);
server->address = g_strdup (address); server->address = g_strdup (address);
GST_RTSP_SERVER_UNLOCK (server);
} }
/** /**
@ -199,9 +226,14 @@ gst_rtsp_server_set_address (GstRTSPServer * server, const gchar * address)
gchar * gchar *
gst_rtsp_server_get_address (GstRTSPServer * server) gst_rtsp_server_get_address (GstRTSPServer * server)
{ {
gchar *result;
g_return_val_if_fail (GST_IS_RTSP_SERVER (server), NULL); g_return_val_if_fail (GST_IS_RTSP_SERVER (server), NULL);
return g_strdup (server->address); GST_RTSP_SERVER_LOCK (server);
result = g_strdup (server->address);
GST_RTSP_SERVER_UNLOCK (server);
return result;
} }
/** /**
@ -221,8 +253,10 @@ gst_rtsp_server_set_service (GstRTSPServer * server, const gchar * service)
g_return_if_fail (GST_IS_RTSP_SERVER (server)); g_return_if_fail (GST_IS_RTSP_SERVER (server));
g_return_if_fail (service != NULL); g_return_if_fail (service != NULL);
GST_RTSP_SERVER_LOCK (server);
g_free (server->service); g_free (server->service);
server->service = g_strdup (service); server->service = g_strdup (service);
GST_RTSP_SERVER_UNLOCK (server);
} }
/** /**
@ -236,9 +270,15 @@ gst_rtsp_server_set_service (GstRTSPServer * server, const gchar * service)
gchar * gchar *
gst_rtsp_server_get_service (GstRTSPServer * server) gst_rtsp_server_get_service (GstRTSPServer * server)
{ {
gchar *result;
g_return_val_if_fail (GST_IS_RTSP_SERVER (server), NULL); g_return_val_if_fail (GST_IS_RTSP_SERVER (server), NULL);
return g_strdup (server->service); GST_RTSP_SERVER_LOCK (server);
result = g_strdup (server->service);
GST_RTSP_SERVER_UNLOCK (server);
return result;
} }
/** /**
@ -256,7 +296,9 @@ gst_rtsp_server_set_backlog (GstRTSPServer * server, gint backlog)
{ {
g_return_if_fail (GST_IS_RTSP_SERVER (server)); g_return_if_fail (GST_IS_RTSP_SERVER (server));
GST_RTSP_SERVER_LOCK (server);
server->backlog = backlog; server->backlog = backlog;
GST_RTSP_SERVER_UNLOCK (server);
} }
/** /**
@ -270,9 +312,15 @@ gst_rtsp_server_set_backlog (GstRTSPServer * server, gint backlog)
gint gint
gst_rtsp_server_get_backlog (GstRTSPServer * server) gst_rtsp_server_get_backlog (GstRTSPServer * server)
{ {
gint result;
g_return_val_if_fail (GST_IS_RTSP_SERVER (server), -1); g_return_val_if_fail (GST_IS_RTSP_SERVER (server), -1);
return server->backlog; GST_RTSP_SERVER_LOCK (server);
result = server->backlog;
GST_RTSP_SERVER_UNLOCK (server);
return result;
} }
/** /**
@ -290,15 +338,16 @@ gst_rtsp_server_set_session_pool (GstRTSPServer * server,
g_return_if_fail (GST_IS_RTSP_SERVER (server)); g_return_if_fail (GST_IS_RTSP_SERVER (server));
old = server->session_pool;
if (old != pool) {
if (pool) if (pool)
g_object_ref (pool); g_object_ref (pool);
GST_RTSP_SERVER_LOCK (server);
old = server->session_pool;
server->session_pool = pool; server->session_pool = pool;
GST_RTSP_SERVER_UNLOCK (server);
if (old) if (old)
g_object_unref (old); g_object_unref (old);
}
} }
/** /**
@ -317,8 +366,10 @@ gst_rtsp_server_get_session_pool (GstRTSPServer * server)
g_return_val_if_fail (GST_IS_RTSP_SERVER (server), NULL); g_return_val_if_fail (GST_IS_RTSP_SERVER (server), NULL);
GST_RTSP_SERVER_LOCK (server);
if ((result = server->session_pool)) if ((result = server->session_pool))
g_object_ref (result); g_object_ref (result);
GST_RTSP_SERVER_UNLOCK (server);
return result; return result;
} }
@ -338,15 +389,16 @@ gst_rtsp_server_set_media_mapping (GstRTSPServer * server,
g_return_if_fail (GST_IS_RTSP_SERVER (server)); g_return_if_fail (GST_IS_RTSP_SERVER (server));
old = server->media_mapping;
if (old != mapping) {
if (mapping) if (mapping)
g_object_ref (mapping); g_object_ref (mapping);
GST_RTSP_SERVER_LOCK (server);
old = server->media_mapping;
server->media_mapping = mapping; server->media_mapping = mapping;
GST_RTSP_SERVER_UNLOCK (server);
if (old) if (old)
g_object_unref (old); g_object_unref (old);
}
} }
@ -366,8 +418,61 @@ gst_rtsp_server_get_media_mapping (GstRTSPServer * server)
g_return_val_if_fail (GST_IS_RTSP_SERVER (server), NULL); g_return_val_if_fail (GST_IS_RTSP_SERVER (server), NULL);
GST_RTSP_SERVER_LOCK (server);
if ((result = server->media_mapping)) if ((result = server->media_mapping))
g_object_ref (result); g_object_ref (result);
GST_RTSP_SERVER_UNLOCK (server);
return result;
}
/**
* gst_rtsp_server_set_auth:
* @server: a #GstRTSPServer
* @auth: a #GstRTSPAuth
*
* configure @auth to be used as the authentication manager of @server.
*/
void
gst_rtsp_server_set_auth (GstRTSPServer * server, GstRTSPAuth * auth)
{
GstRTSPAuth *old;
g_return_if_fail (GST_IS_RTSP_SERVER (server));
if (auth)
g_object_ref (auth);
GST_RTSP_SERVER_LOCK (server);
old = server->auth;
server->auth = auth;
GST_RTSP_SERVER_UNLOCK (server);
if (old)
g_object_unref (old);
}
/**
* gst_rtsp_server_get_auth:
* @server: a #GstRTSPServer
*
* Get the #GstRTSPAuth used as the authentication manager of @server.
*
* Returns: the #GstRTSPAuth of @server. g_object_unref() after
* usage.
*/
GstRTSPAuth *
gst_rtsp_server_get_auth (GstRTSPServer * server)
{
GstRTSPAuth *result;
g_return_val_if_fail (GST_IS_RTSP_SERVER (server), NULL);
GST_RTSP_SERVER_LOCK (server);
if ((result = server->auth))
g_object_ref (result);
GST_RTSP_SERVER_UNLOCK (server);
return result; return result;
} }
@ -426,17 +531,28 @@ gst_rtsp_server_set_property (GObject * object, guint propid,
} }
} }
/* Prepare a server socket for @server and make it listen on the configured port */ /**
static gboolean * gst_rtsp_server_get_io_channel:
gst_rtsp_server_sink_init_send (GstRTSPServer * server) * @server: a #GstRTSPServer
*
* Create a #GIOChannel for @server. The io channel will listen on the
* configured service.
*
* Returns: the GIOChannel for @server or NULL when an error occured.
*/
GIOChannel *
gst_rtsp_server_get_io_channel (GstRTSPServer * server)
{ {
int ret, sockfd; GIOChannel *channel;
int ret, sockfd = -1;
struct addrinfo hints; struct addrinfo hints;
struct addrinfo *result, *rp; struct addrinfo *result, *rp;
#ifdef USE_SOLINGER #ifdef USE_SOLINGER
struct linger linger; struct linger linger;
#endif #endif
g_return_val_if_fail (GST_IS_RTSP_SERVER (server), NULL);
memset (&hints, 0, sizeof (struct addrinfo)); memset (&hints, 0, sizeof (struct addrinfo));
hints.ai_family = AF_UNSPEC; /* Allow IPv4 or IPv6 */ hints.ai_family = AF_UNSPEC; /* Allow IPv4 or IPv6 */
hints.ai_socktype = SOCK_STREAM; /* stream socket */ hints.ai_socktype = SOCK_STREAM; /* stream socket */
@ -449,6 +565,7 @@ gst_rtsp_server_sink_init_send (GstRTSPServer * server)
GST_DEBUG_OBJECT (server, "getting address info of %s/%s", server->address, GST_DEBUG_OBJECT (server, "getting address info of %s/%s", server->address,
server->service); server->service);
GST_RTSP_SERVER_LOCK (server);
/* resolve the server IP address */ /* resolve the server IP address */
if ((ret = if ((ret =
getaddrinfo (server->address, server->service, &hints, &result)) != 0) getaddrinfo (server->address, server->service, &hints, &result)) != 0)
@ -464,6 +581,15 @@ gst_rtsp_server_sink_init_send (GstRTSPServer * server)
continue; continue;
} }
/* make address reusable */
ret = 1;
if (setsockopt (sockfd, SOL_SOCKET, SO_REUSEADDR,
(void *) &ret, sizeof (ret)) < 0) {
/* warn but try to bind anyway */
GST_WARNING_OBJECT (server, "failed to reuse socker (%s)",
g_strerror (errno));
}
if (bind (sockfd, rp->ai_addr, rp->ai_addrlen) == 0) { if (bind (sockfd, rp->ai_addr, rp->ai_addrlen) == 0) {
GST_DEBUG_OBJECT (server, "bind on %s", rp->ai_canonname); GST_DEBUG_OBJECT (server, "bind on %s", rp->ai_canonname);
break; break;
@ -472,26 +598,18 @@ gst_rtsp_server_sink_init_send (GstRTSPServer * server)
GST_DEBUG_OBJECT (server, "failed to bind socket (%s), try next", GST_DEBUG_OBJECT (server, "failed to bind socket (%s), try next",
g_strerror (errno)); g_strerror (errno));
close (sockfd); close (sockfd);
sockfd = -1;
} }
freeaddrinfo (result); freeaddrinfo (result);
if (rp == NULL) if (sockfd == -1)
goto no_socket; goto no_socket;
server->server_sock.fd = sockfd; GST_DEBUG_OBJECT (server, "opened sending server socket with fd %d", sockfd);
GST_DEBUG_OBJECT (server, "opened sending server socket with fd %d",
server->server_sock.fd);
/* make address reusable */
ret = 1;
if (setsockopt (server->server_sock.fd, SOL_SOCKET, SO_REUSEADDR,
(void *) &ret, sizeof (ret)) < 0)
goto reuse_failed;
/* keep connection alive; avoids SIGPIPE during write */ /* keep connection alive; avoids SIGPIPE during write */
ret = 1; ret = 1;
if (setsockopt (server->server_sock.fd, SOL_SOCKET, SO_KEEPALIVE, if (setsockopt (sockfd, SOL_SOCKET, SO_KEEPALIVE,
(void *) &ret, sizeof (ret)) < 0) (void *) &ret, sizeof (ret)) < 0)
goto keepalive_failed; goto keepalive_failed;
@ -501,43 +619,42 @@ gst_rtsp_server_sink_init_send (GstRTSPServer * server)
* client. */ * client. */
linger.l_onoff = 1; linger.l_onoff = 1;
linger.l_linger = 5; linger.l_linger = 5;
if (setsockopt (server->server_sock.fd, SOL_SOCKET, SO_LINGER, if (setsockopt (sockfd, SOL_SOCKET, SO_LINGER,
(void *) &linger, sizeof (linger)) < 0) (void *) &linger, sizeof (linger)) < 0)
goto linger_failed; goto linger_failed;
#endif #endif
/* set the server socket to nonblocking */ /* set the server socket to nonblocking */
fcntl (server->server_sock.fd, F_SETFL, O_NONBLOCK); fcntl (sockfd, F_SETFL, O_NONBLOCK);
GST_DEBUG_OBJECT (server, "listening on server socket %d with queue of %d", GST_DEBUG_OBJECT (server, "listening on server socket %d with queue of %d",
server->server_sock.fd, server->backlog); sockfd, server->backlog);
if (listen (server->server_sock.fd, server->backlog) == -1) if (listen (sockfd, server->backlog) == -1)
goto listen_failed; goto listen_failed;
GST_DEBUG_OBJECT (server, GST_DEBUG_OBJECT (server,
"listened on server socket %d, returning from connection setup", "listened on server socket %d, returning from connection setup", sockfd);
server->server_sock.fd);
/* create IO channel for the socket */
channel = g_io_channel_unix_new (sockfd);
g_io_channel_set_close_on_unref (channel, TRUE);
GST_INFO_OBJECT (server, "listening on service %s", server->service); GST_INFO_OBJECT (server, "listening on service %s", server->service);
GST_RTSP_SERVER_UNLOCK (server);
return TRUE; return channel;
/* ERRORS */ /* ERRORS */
no_address: no_address:
{ {
GST_ERROR_OBJECT (server, "failed to resolve address: %s", GST_ERROR_OBJECT (server, "failed to resolve address: %s",
gai_strerror (ret)); gai_strerror (ret));
return FALSE; goto close_error;
} }
no_socket: no_socket:
{ {
GST_ERROR_OBJECT (server, "failed to create socket: %s", GST_ERROR_OBJECT (server, "failed to create socket: %s",
g_strerror (errno)); g_strerror (errno));
return FALSE;
}
reuse_failed:
{
GST_ERROR_OBJECT (server, "failed to reuse socket: %s", g_strerror (errno));
goto close_error; goto close_error;
} }
keepalive_failed: keepalive_failed:
@ -562,18 +679,44 @@ listen_failed:
} }
close_error: close_error:
{ {
if (server->server_sock.fd >= 0) { if (sockfd >= 0) {
close (server->server_sock.fd); close (sockfd);
server->server_sock.fd = -1;
} }
return FALSE; GST_RTSP_SERVER_UNLOCK (server);
return NULL;
} }
} }
/* default method for creating a new client object in the server to accept and static void
* handle a client connection on this server */ unmanage_client (GstRTSPClient * client, GstRTSPServer * server)
{
GST_DEBUG_OBJECT (server, "unmanage client %p", client);
gst_rtsp_client_set_server (client, NULL);
GST_RTSP_SERVER_LOCK (server);
server->clients = g_list_remove (server->clients, client);
GST_RTSP_SERVER_UNLOCK (server);
g_object_unref (client);
}
/* add the client to the active list of clients, takes ownership of
* the client */
static void
manage_client (GstRTSPServer * server, GstRTSPClient * client)
{
GST_DEBUG_OBJECT (server, "manage client %p", client);
gst_rtsp_client_set_server (client, server);
GST_RTSP_SERVER_LOCK (server);
g_signal_connect (client, "closed", (GCallback) unmanage_client, server);
server->clients = g_list_prepend (server->clients, client);
GST_RTSP_SERVER_UNLOCK (server);
}
static GstRTSPClient * static GstRTSPClient *
default_accept_client (GstRTSPServer * server, GIOChannel * channel) default_create_client (GstRTSPServer * server)
{ {
GstRTSPClient *client; GstRTSPClient *client;
@ -581,26 +724,38 @@ default_accept_client (GstRTSPServer * server, GIOChannel * channel)
client = gst_rtsp_client_new (); client = gst_rtsp_client_new ();
/* set the session pool that this client should use */ /* set the session pool that this client should use */
GST_RTSP_SERVER_LOCK (server);
gst_rtsp_client_set_session_pool (client, server->session_pool); gst_rtsp_client_set_session_pool (client, server->session_pool);
/* set the media mapping that this client should use */ /* set the media mapping that this client should use */
gst_rtsp_client_set_media_mapping (client, server->media_mapping); gst_rtsp_client_set_media_mapping (client, server->media_mapping);
/* set authentication manager */
gst_rtsp_client_set_auth (client, server->auth);
GST_RTSP_SERVER_UNLOCK (server);
return client;
}
/* default method for creating a new client object in the server to accept and
* handle a client connection on this server */
static gboolean
default_accept_client (GstRTSPServer * server, GstRTSPClient * client,
GIOChannel * channel)
{
/* accept connections for that client, this function returns after accepting /* accept connections for that client, this function returns after accepting
* the connection and will run the remainder of the communication with the * the connection and will run the remainder of the communication with the
* client asyncronously. */ * client asyncronously. */
if (!gst_rtsp_client_accept (client, channel)) if (!gst_rtsp_client_accept (client, channel))
goto accept_failed; goto accept_failed;
return client; return TRUE;
/* ERRORS */ /* ERRORS */
accept_failed: accept_failed:
{ {
GST_ERROR_OBJECT (server, GST_ERROR_OBJECT (server,
"Could not accept client on server socket %d: %s (%d)", "Could not accept client on server : %s (%d)", g_strerror (errno),
server->server_sock.fd, g_strerror (errno), errno); errno);
gst_object_unref (client); return FALSE;
return NULL;
} }
} }
@ -618,21 +773,26 @@ gboolean
gst_rtsp_server_io_func (GIOChannel * channel, GIOCondition condition, gst_rtsp_server_io_func (GIOChannel * channel, GIOCondition condition,
GstRTSPServer * server) GstRTSPServer * server)
{ {
gboolean result;
GstRTSPClient *client = NULL; GstRTSPClient *client = NULL;
GstRTSPServerClass *klass; GstRTSPServerClass *klass;
if (condition & G_IO_IN) { if (condition & G_IO_IN) {
klass = GST_RTSP_SERVER_GET_CLASS (server); klass = GST_RTSP_SERVER_GET_CLASS (server);
/* a new client connected, create a client object to handle the client. */ if (klass->create_client)
if (klass->accept_client) client = klass->create_client (server);
client = klass->accept_client (server, channel);
if (client == NULL) if (client == NULL)
goto client_failed; goto client_failed;
/* can unref the client now, when the request is finished, it will be /* a new client connected, create a client object to handle the client. */
* unreffed async. */ if (klass->accept_client)
gst_object_unref (client); result = klass->accept_client (server, client, channel);
if (!result)
goto accept_failed;
/* manage the client connection */
manage_client (server, client);
} else { } else {
GST_WARNING_OBJECT (server, "received unknown event %08x", condition); GST_WARNING_OBJECT (server, "received unknown event %08x", condition);
} }
@ -644,35 +804,19 @@ client_failed:
GST_ERROR_OBJECT (server, "failed to create a client"); GST_ERROR_OBJECT (server, "failed to create a client");
return FALSE; return FALSE;
} }
accept_failed:
{
GST_ERROR_OBJECT (server, "failed to accept client");
gst_object_unref (client);
return FALSE;
}
} }
/** static void
* gst_rtsp_server_get_io_channel: watch_destroyed (GstRTSPServer * server)
* @server: a #GstRTSPServer
*
* Create a #GIOChannel for @server.
*
* Returns: the GIOChannel for @server or NULL when an error occured.
*/
GIOChannel *
gst_rtsp_server_get_io_channel (GstRTSPServer * server)
{ {
g_return_val_if_fail (GST_IS_RTSP_SERVER (server), NULL); GST_DEBUG_OBJECT (server, "source destroyed");
g_object_unref (server);
if (server->io_channel == NULL) {
if (!gst_rtsp_server_sink_init_send (server))
goto init_failed;
/* create IO channel for the socket */
server->io_channel = g_io_channel_unix_new (server->server_sock.fd);
}
return server->io_channel;
init_failed:
{
GST_ERROR_OBJECT (server, "failed to initialize server");
return NULL;
}
} }
/** /**
@ -687,24 +831,26 @@ init_failed:
GSource * GSource *
gst_rtsp_server_create_watch (GstRTSPServer * server) gst_rtsp_server_create_watch (GstRTSPServer * server)
{ {
g_return_val_if_fail (GST_IS_RTSP_SERVER (server), NULL);
if (server->io_watch == NULL) {
GIOChannel *channel; GIOChannel *channel;
GSource *source;
g_return_val_if_fail (GST_IS_RTSP_SERVER (server), NULL);
channel = gst_rtsp_server_get_io_channel (server); channel = gst_rtsp_server_get_io_channel (server);
if (channel == NULL) if (channel == NULL)
goto no_channel; goto no_channel;
/* create a watch for reads (new connections) and possible errors */ /* create a watch for reads (new connections) and possible errors */
server->io_watch = g_io_create_watch (channel, G_IO_IN | source = g_io_create_watch (channel, G_IO_IN |
G_IO_ERR | G_IO_HUP | G_IO_NVAL); G_IO_ERR | G_IO_HUP | G_IO_NVAL);
g_io_channel_unref (channel);
/* configure the callback */ /* configure the callback */
g_source_set_callback (server->io_watch, g_source_set_callback (source,
(GSourceFunc) gst_rtsp_server_io_func, server, NULL); (GSourceFunc) gst_rtsp_server_io_func, g_object_ref (server),
} (GDestroyNotify) watch_destroyed);
return server->io_watch;
return source;
no_channel: no_channel:
{ {
@ -719,7 +865,8 @@ no_channel:
* @context: a #GMainContext * @context: a #GMainContext
* *
* Attaches @server to @context. When the mainloop for @context is run, the * Attaches @server to @context. When the mainloop for @context is run, the
* server will be dispatched. * server will be dispatched. When @context is NULL, the default context will be
* used).
* *
* This function should be called when the server properties and urls are fully * This function should be called when the server properties and urls are fully
* configured and the server is ready to start. * configured and the server is ready to start.
@ -739,6 +886,7 @@ gst_rtsp_server_attach (GstRTSPServer * server, GMainContext * context)
goto no_source; goto no_source;
res = g_source_attach (source, context); res = g_source_attach (source, context);
g_source_unref (source);
return res; return res;

View file

@ -17,31 +17,21 @@
* Boston, MA 02111-1307, USA. * Boston, MA 02111-1307, USA.
*/ */
#include <stdio.h> #ifndef __GST_RTSP_SERVER_H__
#include <stdlib.h> #define __GST_RTSP_SERVER_H__
#include <unistd.h>
#include <errno.h>
#include <string.h>
#include <sys/time.h>
#include <sys/types.h>
#include <netinet/in.h>
#include <netdb.h>
#include <sys/socket.h>
#include <sys/wait.h>
#include <fcntl.h>
#include <arpa/inet.h>
#include <gst/gst.h> #include <gst/gst.h>
G_BEGIN_DECLS
typedef struct _GstRTSPServer GstRTSPServer;
typedef struct _GstRTSPServerClass GstRTSPServerClass;
#include "rtsp-session-pool.h" #include "rtsp-session-pool.h"
#include "rtsp-media-mapping.h" #include "rtsp-media-mapping.h"
#include "rtsp-media-factory-uri.h" #include "rtsp-media-factory-uri.h"
#include "rtsp-client.h" #include "rtsp-client.h"
#include "rtsp-auth.h"
#ifndef __GST_RTSP_SERVER_H__
#define __GST_RTSP_SERVER_H__
G_BEGIN_DECLS
#define GST_TYPE_RTSP_SERVER (gst_rtsp_server_get_type ()) #define GST_TYPE_RTSP_SERVER (gst_rtsp_server_get_type ())
#define GST_IS_RTSP_SERVER(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GST_TYPE_RTSP_SERVER)) #define GST_IS_RTSP_SERVER(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GST_TYPE_RTSP_SERVER))
@ -52,43 +42,53 @@ G_BEGIN_DECLS
#define GST_RTSP_SERVER_CAST(obj) ((GstRTSPServer*)(obj)) #define GST_RTSP_SERVER_CAST(obj) ((GstRTSPServer*)(obj))
#define GST_RTSP_SERVER_CLASS_CAST(klass) ((GstRTSPServerClass*)(klass)) #define GST_RTSP_SERVER_CLASS_CAST(klass) ((GstRTSPServerClass*)(klass))
typedef struct _GstRTSPServer GstRTSPServer; #define GST_RTSP_SERVER_GET_LOCK(server) (GST_RTSP_SERVER_CAST(server)->lock)
typedef struct _GstRTSPServerClass GstRTSPServerClass; #define GST_RTSP_SERVER_LOCK(server) (g_mutex_lock(GST_RTSP_SERVER_GET_LOCK(server)))
#define GST_RTSP_SERVER_UNLOCK(server) (g_mutex_unlock(GST_RTSP_SERVER_GET_LOCK(server)))
/**
* GstRTSPServer:
*
* This object listens on a port, creates and manages the clients connected to
* it.
*/
struct _GstRTSPServer { struct _GstRTSPServer {
GObject parent; GObject parent;
GMutex *lock;
/* server information */ /* server information */
gchar *address; gchar *address;
gchar *service; gchar *service;
gint backlog; gint backlog;
struct sockaddr_in server_sin;
/* socket and channels */
GstPollFD server_sock;
GIOChannel *io_channel;
GSource *io_watch;
/* sessions on this server */ /* sessions on this server */
GstRTSPSessionPool *session_pool; GstRTSPSessionPool *session_pool;
/* media mapper for this server */ /* media mapper for this server */
GstRTSPMediaMapping *media_mapping; GstRTSPMediaMapping *media_mapping;
/* authentication manager */
GstRTSPAuth *auth;
/* the clients that are connected */
GList *clients;
}; };
/** /**
* GstRTSPServerClass: * GstRTSPServerClass:
* *
* @accept_client: Create, configure, accept and return a new GstRTSPClient * @create_client: Create, configure a new GstRTSPClient
* object that handles the new connection on @channel. * object that handles the new connection on @channel.
* @accept_client: accept a new GstRTSPClient
* *
* The RTSP server class structure * The RTSP server class structure
*/ */
struct _GstRTSPServerClass { struct _GstRTSPServerClass {
GObjectClass parent_class; GObjectClass parent_class;
GstRTSPClient * (*accept_client) (GstRTSPServer *server, GIOChannel *channel); GstRTSPClient * (*create_client) (GstRTSPServer *server);
gboolean (*accept_client) (GstRTSPServer *server, GstRTSPClient *client, GIOChannel *channel);
}; };
GType gst_rtsp_server_get_type (void); GType gst_rtsp_server_get_type (void);
@ -110,6 +110,9 @@ GstRTSPSessionPool * gst_rtsp_server_get_session_pool (GstRTSPServer *serve
void gst_rtsp_server_set_media_mapping (GstRTSPServer *server, GstRTSPMediaMapping *mapping); void gst_rtsp_server_set_media_mapping (GstRTSPServer *server, GstRTSPMediaMapping *mapping);
GstRTSPMediaMapping * gst_rtsp_server_get_media_mapping (GstRTSPServer *server); GstRTSPMediaMapping * gst_rtsp_server_get_media_mapping (GstRTSPServer *server);
void gst_rtsp_server_set_auth (GstRTSPServer *server, GstRTSPAuth *auth);
GstRTSPAuth * gst_rtsp_server_get_auth (GstRTSPServer *server);
gboolean gst_rtsp_server_io_func (GIOChannel *channel, GIOCondition condition, gboolean gst_rtsp_server_io_func (GIOChannel *channel, GIOCondition condition,
GstRTSPServer *server); GstRTSPServer *server);

View file

@ -30,7 +30,15 @@ enum
PROP_LAST PROP_LAST
}; };
GST_DEBUG_CATEGORY (rtsp_session_debug); static const gchar session_id_charset[] =
{ 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o',
'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z', 'A', 'B', 'C', 'D',
'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S',
'T', 'U', 'V', 'W', 'X', 'Y', 'Z', '0', '1', '2', '3', '4', '5', '6', '7',
'8', '9', '$', '-', '_', '.', '+'
};
GST_DEBUG_CATEGORY_STATIC (rtsp_session_debug);
#define GST_CAT_DEFAULT rtsp_session_debug #define GST_CAT_DEFAULT rtsp_session_debug
static void gst_rtsp_session_pool_get_property (GObject * object, guint propid, static void gst_rtsp_session_pool_get_property (GObject * object, guint propid,
@ -62,8 +70,8 @@ gst_rtsp_session_pool_class_init (GstRTSPSessionPoolClass * klass)
klass->create_session_id = create_session_id; klass->create_session_id = create_session_id;
GST_DEBUG_CATEGORY_INIT (rtsp_session_debug, "rtspsession", 0, GST_DEBUG_CATEGORY_INIT (rtsp_session_debug, "rtspsessionpool", 0,
"GstRTSPSession"); "GstRTSPSessionPool");
} }
static void static void
@ -235,7 +243,9 @@ create_session_id (GstRTSPSessionPool * pool)
gint i; gint i;
for (i = 0; i < 16; i++) { for (i = 0; i < 16; i++) {
id[i] = g_random_int_range ('a', 'z'); id[i] =
session_id_charset[g_random_int_range (0,
G_N_ELEMENTS (session_id_charset))];
} }
return g_strndup (id, 16); return g_strndup (id, 16);

View file

@ -22,10 +22,14 @@
#ifndef __GST_RTSP_SESSION_POOL_H__ #ifndef __GST_RTSP_SESSION_POOL_H__
#define __GST_RTSP_SESSION_POOL_H__ #define __GST_RTSP_SESSION_POOL_H__
#include "rtsp-session.h"
G_BEGIN_DECLS G_BEGIN_DECLS
typedef struct _GstRTSPSessionPool GstRTSPSessionPool;
typedef struct _GstRTSPSessionPoolClass GstRTSPSessionPoolClass;
#include "rtsp-session.h"
#define GST_TYPE_RTSP_SESSION_POOL (gst_rtsp_session_pool_get_type ()) #define GST_TYPE_RTSP_SESSION_POOL (gst_rtsp_session_pool_get_type ())
#define GST_IS_RTSP_SESSION_POOL(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GST_TYPE_RTSP_SESSION_POOL)) #define GST_IS_RTSP_SESSION_POOL(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GST_TYPE_RTSP_SESSION_POOL))
#define GST_IS_RTSP_SESSION_POOL_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), GST_TYPE_RTSP_SESSION_POOL)) #define GST_IS_RTSP_SESSION_POOL_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), GST_TYPE_RTSP_SESSION_POOL))
@ -35,9 +39,6 @@ G_BEGIN_DECLS
#define GST_RTSP_SESSION_POOL_CAST(obj) ((GstRTSPSessionPool*)(obj)) #define GST_RTSP_SESSION_POOL_CAST(obj) ((GstRTSPSessionPool*)(obj))
#define GST_RTSP_SESSION_POOL_CLASS_CAST(klass) ((GstRTSPSessionPoolClass*)(klass)) #define GST_RTSP_SESSION_POOL_CLASS_CAST(klass) ((GstRTSPSessionPoolClass*)(klass))
typedef struct _GstRTSPSessionPool GstRTSPSessionPool;
typedef struct _GstRTSPSessionPoolClass GstRTSPSessionPoolClass;
/** /**
* GstRTSPSessionPool: * GstRTSPSessionPool:
* @max_sessions: the maximum number of sessions. * @max_sessions: the maximum number of sessions.

View file

@ -32,7 +32,7 @@ enum
PROP_LAST PROP_LAST
}; };
GST_DEBUG_CATEGORY_EXTERN (rtsp_session_debug); GST_DEBUG_CATEGORY_STATIC (rtsp_session_debug);
#define GST_CAT_DEFAULT rtsp_session_debug #define GST_CAT_DEFAULT rtsp_session_debug
static void gst_rtsp_session_get_property (GObject * object, guint propid, static void gst_rtsp_session_get_property (GObject * object, guint propid,
@ -63,6 +63,9 @@ gst_rtsp_session_class_init (GstRTSPSessionClass * klass)
g_param_spec_uint ("timeout", "timeout", g_param_spec_uint ("timeout", "timeout",
"the timeout of the session (0 = never)", 0, G_MAXUINT, "the timeout of the session (0 = never)", 0, G_MAXUINT,
DEFAULT_TIMEOUT, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); DEFAULT_TIMEOUT, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
GST_DEBUG_CATEGORY_INIT (rtsp_session_debug, "rtspsession", 0,
"GstRTSPSession");
} }
static void static void
@ -79,7 +82,8 @@ gst_rtsp_session_free_stream (GstRTSPSessionStream * stream)
GST_INFO ("free session stream %p", stream); GST_INFO ("free session stream %p", stream);
/* remove callbacks now */ /* remove callbacks now */
gst_rtsp_session_stream_set_callbacks (stream, NULL, NULL, NULL, NULL); gst_rtsp_session_stream_set_callbacks (stream, NULL, NULL, NULL, NULL, NULL,
NULL);
gst_rtsp_session_stream_set_keepalive (stream, NULL, NULL, NULL); gst_rtsp_session_stream_set_keepalive (stream, NULL, NULL, NULL);
gst_rtsp_media_trans_cleanup (&stream->trans); gst_rtsp_media_trans_cleanup (&stream->trans);
@ -549,6 +553,8 @@ gst_rtsp_session_stream_set_transport (GstRTSPSessionStream * stream,
* @stream: a #GstRTSPSessionStream * @stream: a #GstRTSPSessionStream
* @send_rtp: a callback called when RTP should be sent * @send_rtp: a callback called when RTP should be sent
* @send_rtcp: a callback called when RTCP should be sent * @send_rtcp: a callback called when RTCP should be sent
* @send_rtp_list: a callback called when RTP should be sent
* @send_rtcp_list: a callback called when RTCP should be sent
* @user_data: user data passed to callbacks * @user_data: user data passed to callbacks
* @notify: called with the user_data when no longer needed. * @notify: called with the user_data when no longer needed.
* *
@ -557,11 +563,14 @@ gst_rtsp_session_stream_set_transport (GstRTSPSessionStream * stream,
*/ */
void void
gst_rtsp_session_stream_set_callbacks (GstRTSPSessionStream * stream, gst_rtsp_session_stream_set_callbacks (GstRTSPSessionStream * stream,
GstRTSPSendFunc send_rtp, GstRTSPSendFunc send_rtcp, gpointer user_data, GstRTSPSendFunc send_rtp, GstRTSPSendFunc send_rtcp,
GDestroyNotify notify) GstRTSPSendListFunc send_rtp_list, GstRTSPSendListFunc send_rtcp_list,
gpointer user_data, GDestroyNotify notify)
{ {
stream->trans.send_rtp = send_rtp; stream->trans.send_rtp = send_rtp;
stream->trans.send_rtcp = send_rtcp; stream->trans.send_rtcp = send_rtcp;
stream->trans.send_rtp_list = send_rtp_list;
stream->trans.send_rtcp_list = send_rtcp_list;
if (stream->trans.notify) if (stream->trans.notify)
stream->trans.notify (stream->trans.user_data); stream->trans.notify (stream->trans.user_data);
stream->trans.user_data = user_data; stream->trans.user_data = user_data;

View file

@ -21,8 +21,6 @@
#include <gst/rtsp/gstrtsptransport.h> #include <gst/rtsp/gstrtsptransport.h>
#include "rtsp-media.h"
#ifndef __GST_RTSP_SESSION_H__ #ifndef __GST_RTSP_SESSION_H__
#define __GST_RTSP_SESSION_H__ #define __GST_RTSP_SESSION_H__
@ -43,6 +41,8 @@ typedef struct _GstRTSPSessionClass GstRTSPSessionClass;
typedef struct _GstRTSPSessionStream GstRTSPSessionStream; typedef struct _GstRTSPSessionStream GstRTSPSessionStream;
typedef struct _GstRTSPSessionMedia GstRTSPSessionMedia; typedef struct _GstRTSPSessionMedia GstRTSPSessionMedia;
#include "rtsp-media.h"
/** /**
* GstRTSPSessionStream: * GstRTSPSessionStream:
* @trans: the media transport * @trans: the media transport
@ -154,6 +154,8 @@ GstRTSPTransport * gst_rtsp_session_stream_set_transport (GstRTSPSessionStre
void gst_rtsp_session_stream_set_callbacks (GstRTSPSessionStream *stream, void gst_rtsp_session_stream_set_callbacks (GstRTSPSessionStream *stream,
GstRTSPSendFunc send_rtp, GstRTSPSendFunc send_rtp,
GstRTSPSendFunc send_rtcp, GstRTSPSendFunc send_rtcp,
GstRTSPSendListFunc send_rtp_list,
GstRTSPSendListFunc send_rtcp_list,
gpointer user_data, gpointer user_data,
GDestroyNotify notify); GDestroyNotify notify);
void gst_rtsp_session_stream_set_keepalive (GstRTSPSessionStream *stream, void gst_rtsp_session_stream_set_keepalive (GstRTSPSessionStream *stream,

View file

@ -1,18 +0,0 @@
EXTRA_DIST = \
codeset.m4
gettext.m4
glibc21.m4 \
iconv.m4 \
intdiv0.m4 \
inttypes-pri.m4 \
nttypes.m4 \
inttypes_h.m4 \
isc-posix.m4 \
lcmessage.m4 \
lib-ld.m4 \
lib-link.m4 \
lib-prefix.m4 \
progtest.m4 \
stdint_h.m4 \
uintmax_t.m4 \
ulonglong.m4

View file

@ -1,23 +0,0 @@
# codeset.m4 serial AM1 (gettext-0.10.40)
dnl Copyright (C) 2000-2002 Free Software Foundation, Inc.
dnl This file is free software, distributed under the terms of the GNU
dnl General Public License. As a special exception to the GNU General
dnl Public License, this file may be distributed as part of a program
dnl that contains a configuration script generated by Autoconf, under
dnl the same distribution terms as the rest of that program.
dnl From Bruno Haible.
AC_DEFUN([AM_LANGINFO_CODESET],
[
AC_CACHE_CHECK([for nl_langinfo and CODESET], am_cv_langinfo_codeset,
[AC_TRY_LINK([#include <langinfo.h>],
[char* cs = nl_langinfo(CODESET);],
am_cv_langinfo_codeset=yes,
am_cv_langinfo_codeset=no)
])
if test $am_cv_langinfo_codeset = yes; then
AC_DEFINE(HAVE_LANGINFO_CODESET, 1,
[Define if you have <langinfo.h> and nl_langinfo(CODESET).])
fi
])

1
tests/.gitignore vendored Normal file
View file

@ -0,0 +1 @@
test-cleanup

9
tests/Makefile.am Normal file
View file

@ -0,0 +1,9 @@
noinst_PROGRAMS = test-cleanup
INCLUDES = -I$(top_srcdir) -I$(srcdir)
AM_CFLAGS = $(GST_PLUGINS_BASE_CFLAGS) $(GST_CFLAGS)
AM_LDFLAGS = \
$(GST_LIBS) \
$(top_builddir)/gst/rtsp-server/libgstrtspserver-@GST_MAJORMINOR@.la

68
tests/test-cleanup.c Normal file
View file

@ -0,0 +1,68 @@
/* GStreamer
* Copyright (C) 2008 Wim Taymans <wim.taymans at gmail.com>
*
* 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.
*/
#include <gst/gst.h>
#include <gst/rtsp-server/rtsp-server.h>
static gboolean
timeout (GMainLoop * loop, gboolean ignored)
{
g_main_loop_quit (loop);
return FALSE;
}
int
main (int argc, char *argv[])
{
GMainLoop *loop;
GstRTSPServer *server;
guint id;
gst_init (&argc, &argv);
loop = g_main_loop_new (NULL, FALSE);
/* create a server instance */
server = gst_rtsp_server_new ();
/* attach the server to the default maincontext */
if ((id = gst_rtsp_server_attach (server, NULL)) == 0)
goto failed;
g_timeout_add_seconds (2, (GSourceFunc) timeout, loop);
/* start serving */
g_main_loop_run (loop);
/* cleanup */
g_source_remove (id);
g_object_unref (server);
g_main_loop_unref (loop);
return 0;
/* ERRORS */
failed:
{
g_print ("failed to attach the server\n");
return -1;
}
}