mirror of
https://gitlab.freedesktop.org/gstreamer/gstreamer.git
synced 2024-11-24 10:41:04 +00:00
Merge branch 'master' into 0.11
Conflicts: common configure.ac
This commit is contained in:
commit
6959ebd8e8
52 changed files with 3117 additions and 586 deletions
4
.gitignore
vendored
4
.gitignore
vendored
|
@ -10,6 +10,7 @@
|
|||
*~
|
||||
.deps
|
||||
.libs
|
||||
ABOUT-NLS
|
||||
INSTALL
|
||||
Makefile
|
||||
Makefile.in
|
||||
|
@ -21,6 +22,7 @@ config.guess
|
|||
config.h
|
||||
config.h.in
|
||||
config.log
|
||||
config.rpath
|
||||
config.status
|
||||
config.sub
|
||||
configure
|
||||
|
@ -34,3 +36,5 @@ bindings/python/rtspserver.c
|
|||
tags
|
||||
gst-rtsp.spec
|
||||
stamp-h.in
|
||||
|
||||
/m4/*m4
|
||||
|
|
44
Makefile.am
44
Makefile.am
|
@ -3,11 +3,11 @@ DISTCHECK_CONFIGURE_FLAGS=--enable-gtk-doc
|
|||
SUBDIRS = \
|
||||
gst \
|
||||
bindings \
|
||||
m4 \
|
||||
common \
|
||||
pkgconfig \
|
||||
docs \
|
||||
examples
|
||||
examples \
|
||||
tests
|
||||
|
||||
DIST_SUBDIRS = $(SUBDIRS)
|
||||
|
||||
|
@ -16,13 +16,15 @@ EXTRA_DIST = \
|
|||
AUTHORS COPYING NEWS README RELEASE REQUIREMENTS \
|
||||
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
|
||||
|
||||
include $(top_srcdir)/common/release.mak
|
||||
include $(top_srcdir)/common/po.mak
|
||||
|
||||
include $(top_srcdir)/common/coverage/lcov.mak
|
||||
|
||||
check-valgrind:
|
||||
cd tests/check && make check-valgrind
|
||||
|
||||
|
@ -37,7 +39,41 @@ endif
|
|||
# cruft: plugins that have been merged or moved or renamed
|
||||
CRUFT_FILES = \
|
||||
$(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
|
||||
|
||||
|
|
|
@ -83,7 +83,7 @@ tool_run "$libtoolize" "--copy --force"
|
|||
tool_run "$aclocal" "-I m4 -I common/m4 $ACLOCAL_FLAGS"
|
||||
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
|
||||
|
||||
tool_run "$autoconf"
|
||||
|
|
|
@ -37,6 +37,7 @@ rtspserver.c: $(DEFS) $(OVERRIDES) arg-types.py
|
|||
($(PYTHON) $(srcdir)/codegen/codegen.py \
|
||||
--load-types $(srcdir)/arg-types.py \
|
||||
--register $(srcdir)/rtspserver-types.defs \
|
||||
--register $(PYGST_DEFSDIR)/gst-types.defs \
|
||||
--override $(srcdir)/$*.override \
|
||||
--extendpath $(top_builddir)/gst/ \
|
||||
--extendpath $(srcdir)/ \
|
||||
|
|
|
@ -145,6 +145,54 @@ class GstIteratorArg(ArgType):
|
|||
info.varlist.add('GstIterator', '*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):
|
||||
|
||||
def get_c_type(self):
|
||||
|
@ -165,6 +213,31 @@ class GstMiniObjectParam(Parameter):
|
|||
|
||||
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):
|
||||
|
||||
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('const-GstCaps*', GstCapsArg())
|
||||
matcher.register('GstIterator*', GstIteratorArg())
|
||||
matcher.register('const-GstRTSPUrl*', GstRTSPUrlArg())
|
||||
matcher.register('GstRTSPUrl*', GstRTSPUrlArg())
|
||||
|
||||
arg = PointerArg('gpointer', 'G_TYPE_POINTER')
|
||||
matcher.register('GstClockID', arg)
|
||||
|
|
|
@ -1,6 +1,63 @@
|
|||
;; From gst/rtsp-server/rtsp-server.h
|
||||
|
||||
(define-object Server
|
||||
(in-module "Gst.RTSPServer")
|
||||
(parent "GObject")
|
||||
(c-name "GstRTSPServer")
|
||||
(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")
|
||||
)
|
||||
|
||||
|
|
|
@ -1,11 +1,99 @@
|
|||
(include "rtspserver-types.defs")
|
||||
|
||||
;; From gst/rtsp-server/rtsp-server.h
|
||||
|
||||
(define-function rtsp_server_new
|
||||
(c-name "gst_rtsp_server_new")
|
||||
(is-constructor-of "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
|
||||
(of-object "GstRTSPServer")
|
||||
(c-name "gst_rtsp_server_attach")
|
||||
|
@ -14,3 +102,298 @@
|
|||
'("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")
|
||||
)
|
||||
)
|
||||
|
|
|
@ -5,6 +5,11 @@ headers
|
|||
#define NO_IMPORT_PYGOBJECT
|
||||
#include <pygobject.h>
|
||||
|
||||
#include <gst/gst.h>
|
||||
#include <gst/rtsp-server/rtsp-server.h>
|
||||
|
||||
#include <glib.h>
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
# include <config.h>
|
||||
#endif
|
||||
|
@ -24,7 +29,6 @@ typedef struct {
|
|||
%%
|
||||
import gobject.GObject as PyGObject_Type
|
||||
import gobject.MainContext as PyGMainContext_Type
|
||||
|
||||
%%
|
||||
override gst_rtsp_server_attach kwargs
|
||||
static PyObject *
|
||||
|
@ -50,3 +54,14 @@ _wrap_gst_rtsp_server_attach (PyGObject *self,
|
|||
|
||||
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
130
bindings/python/test.py
Normal 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())
|
51
configure.ac
51
configure.ac
|
@ -52,6 +52,7 @@ AS_AUTOTOOLS_ALTERNATE
|
|||
|
||||
dnl Add parameters for aclocal
|
||||
AC_SUBST(ACLOCAL_AMFLAGS, "-I m4 -I common/m4")
|
||||
AC_CONFIG_MACRO_DIR([m4])
|
||||
|
||||
dnl set up gettext
|
||||
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_ORIGIN
|
||||
|
||||
AG_GST_PKG_CONFIG_PATH
|
||||
|
||||
dnl *** checks for platform ***
|
||||
|
||||
dnl * hardware/architecture *
|
||||
|
@ -77,6 +80,16 @@ dnl find a compiler
|
|||
AC_PROG_CC
|
||||
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
|
||||
AM_PATH_PYTHON
|
||||
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
|
||||
then
|
||||
HAVE_PYTHON=yes
|
||||
AC_MSG_RESULT(okay)
|
||||
else
|
||||
AC_MSG_ERROR(too old)
|
||||
HAVE_PYTHON=no
|
||||
AC_MSG_RESULT(no python)
|
||||
fi
|
||||
AM_CHECK_PYTHON_HEADERS(,[AC_MSG_ERROR(could not find Python headers)])
|
||||
|
||||
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])
|
||||
|
||||
AC_SUBST(PYGOBJECT_REQ, 2.11.2)
|
||||
AM_CHECK_PYTHON_HEADERS([HAVE_PYTHON_HEADERS=yes],[HAVE_PYTHON_HEADERS=no])
|
||||
|
||||
dnl check for pygobject (optional, used in the bindings)
|
||||
PYGOBJECT_REQ=2.11.2
|
||||
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)
|
||||
|
||||
dnl check for gst-python
|
||||
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
|
||||
PYGST_DEFSDIR=`pkg-config gst-python-0.10 --variable=defsdir`
|
||||
fi
|
||||
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_PYGST" = "xyes"; then
|
||||
HAVE_PYTHON_BINDINGS="yes"
|
||||
|
@ -286,10 +283,10 @@ Makefile
|
|||
gst-rtsp.spec
|
||||
common/Makefile
|
||||
common/m4/Makefile
|
||||
m4/Makefile
|
||||
gst/Makefile
|
||||
gst/rtsp-server/Makefile
|
||||
examples/Makefile
|
||||
tests/Makefile
|
||||
bindings/Makefile
|
||||
bindings/python/Makefile
|
||||
bindings/python/codegen/Makefile
|
||||
|
|
1
docs/.gitignore
vendored
Normal file
1
docs/.gitignore
vendored
Normal file
|
@ -0,0 +1 @@
|
|||
version.entities
|
|
@ -9,3 +9,12 @@ DIST_SUBDIRS = libs
|
|||
|
||||
EXTRA_DIST = \
|
||||
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
22
docs/libs/.gitignore
vendored
Normal 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
|
|
@ -8,7 +8,7 @@ DOC_MODULE=$(MODULE)
|
|||
|
||||
# for upload-doc.mak
|
||||
DOC=$(MODULE)
|
||||
FORMATS=html ps pdf
|
||||
FORMATS=html
|
||||
html: html-build.stamp
|
||||
include $(top_srcdir)/common/upload-doc.mak
|
||||
|
||||
|
|
|
@ -9,15 +9,17 @@
|
|||
<bookinfo>
|
||||
<title>GStreamer RTSP Server Reference Manual</title>
|
||||
<releaseinfo>
|
||||
for GStreamer RTSP Server &GST_MAJORMINOR;
|
||||
for GStreamer RTSP Server &GST_VERSION;
|
||||
</releaseinfo>
|
||||
</bookinfo>
|
||||
|
||||
<chapter>
|
||||
<xi:include href="xml/rtsp-client.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.xml"/>
|
||||
<xi:include href="xml/rtsp-auth.xml"/>
|
||||
<xi:include href="xml/rtsp-params.xml"/>
|
||||
<xi:include href="xml/rtsp-sdp.xml"/>
|
||||
<xi:include href="xml/rtsp-server.xml"/>
|
||||
|
|
|
@ -45,6 +45,30 @@ GST_IS_RTSP_MEDIA_FACTORY_CLASS
|
|||
GST_RTSP_MEDIA_FACTORY_GET_CLASS
|
||||
</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>
|
||||
<FILE>rtsp-media</FILE>
|
||||
<TITLE>GstRTSPMedia</TITLE>
|
||||
|
@ -53,6 +77,7 @@ GstRTSPMedia
|
|||
GstRTSPMediaClass
|
||||
GstRTSPMediaTrans
|
||||
GstRTSPSendFunc
|
||||
GstRTSPSendListFunc
|
||||
GstRTSPKeepAliveFunc
|
||||
GstRTSPMediaStatus
|
||||
gst_rtsp_media_new
|
||||
|
@ -70,6 +95,7 @@ gst_rtsp_media_unprepare
|
|||
gst_rtsp_media_n_streams
|
||||
gst_rtsp_media_get_stream
|
||||
gst_rtsp_media_seek
|
||||
gst_rtsp_media_get_range_string
|
||||
gst_rtsp_media_stream_rtp
|
||||
gst_rtsp_media_stream_rtcp
|
||||
gst_rtsp_media_set_state
|
||||
|
@ -103,6 +129,8 @@ gst_rtsp_server_set_session_pool
|
|||
gst_rtsp_server_get_session_pool
|
||||
gst_rtsp_server_set_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_get_io_channel
|
||||
gst_rtsp_server_create_watch
|
||||
|
@ -186,16 +214,42 @@ GST_IS_RTSP_SESSION_CLASS
|
|||
GST_RTSP_SESSION_GET_CLASS
|
||||
</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>
|
||||
<FILE>rtsp-client</FILE>
|
||||
<TITLE>GstRTSPClient</TITLE>
|
||||
GstRTSPClient
|
||||
GstRTSPClientClass
|
||||
gst_rtsp_client_new
|
||||
gst_rtsp_client_set_server
|
||||
gst_rtsp_client_get_server
|
||||
gst_rtsp_client_set_session_pool
|
||||
gst_rtsp_client_get_session_pool
|
||||
gst_rtsp_client_set_media_mapping
|
||||
gst_rtsp_client_get_media_mapping
|
||||
gst_rtsp_client_set_auth
|
||||
gst_rtsp_client_get_auth
|
||||
gst_rtsp_client_accept
|
||||
<SUBSECTION Standard>
|
||||
GST_RTSP_CLIENT_CLASS
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
#include <gst/gst.h>
|
||||
gst_rtsp_auth_get_type
|
||||
gst_rtsp_media_mapping_get_type
|
||||
gst_rtsp_media_factory_get_type
|
||||
gst_rtsp_media_get_type
|
||||
|
|
|
@ -1 +1,2 @@
|
|||
<!ENTITY GST_MAJORMINOR "@GST_MAJORMINOR@">
|
||||
<!ENTITY GST_VERSION "@VERSION@">
|
||||
|
|
2
examples/.gitignore
vendored
2
examples/.gitignore
vendored
|
@ -4,3 +4,5 @@ test-ogg
|
|||
test-readme
|
||||
test-sdp
|
||||
test-video
|
||||
test-uri
|
||||
test-auth
|
||||
|
|
|
@ -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)
|
||||
|
||||
|
|
115
examples/test-auth.c
Normal file
115
examples/test-auth.c
Normal 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;
|
||||
}
|
||||
}
|
|
@ -60,7 +60,13 @@ main (int argc, char *argv[])
|
|||
|
||||
/* make a URI media factory for a test stream. */
|
||||
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]);
|
||||
/* 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 */
|
||||
gst_rtsp_media_mapping_add_factory (mapping, "/test",
|
||||
|
|
|
@ -21,7 +21,13 @@
|
|||
|
||||
#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
|
||||
timeout (GstRTSPServer * server, gboolean ignored)
|
||||
{
|
||||
|
@ -41,6 +47,10 @@ main (int argc, char *argv[])
|
|||
GstRTSPServer *server;
|
||||
GstRTSPMediaMapping *mapping;
|
||||
GstRTSPMediaFactory *factory;
|
||||
#ifdef WITH_AUTH
|
||||
GstRTSPAuth *auth;
|
||||
gchar *basic;
|
||||
#endif
|
||||
|
||||
gst_init (&argc, &argv);
|
||||
|
||||
|
@ -53,6 +63,17 @@ main (int argc, char *argv[])
|
|||
* that be used to map uri mount points to media factories */
|
||||
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
|
||||
* gst-launch syntax to create pipelines.
|
||||
* 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)
|
||||
goto failed;
|
||||
|
||||
/* add a timeout for the session cleanup */
|
||||
g_timeout_add_seconds (2, (GSourceFunc) timeout, server);
|
||||
|
||||
/* start serving */
|
||||
/* start serving, this never stops */
|
||||
g_main_loop_run (loop);
|
||||
|
||||
return 0;
|
||||
|
|
2
gst/rtsp-server/.gitignore
vendored
Normal file
2
gst/rtsp-server/.gitignore
vendored
Normal file
|
@ -0,0 +1,2 @@
|
|||
GstRtspServer-0.10.gir
|
||||
GstRtspServer-0.10.typelib
|
|
@ -1,4 +1,5 @@
|
|||
public_headers = \
|
||||
rtsp-auth.h \
|
||||
rtsp-params.h \
|
||||
rtsp-sdp.h \
|
||||
rtsp-media.h \
|
||||
|
@ -11,6 +12,8 @@ public_headers = \
|
|||
rtsp-server.h
|
||||
|
||||
c_sources = \
|
||||
rtsp-funnel.c \
|
||||
rtsp-auth.c \
|
||||
rtsp-params.c \
|
||||
rtsp-sdp.c \
|
||||
rtsp-media.c \
|
||||
|
@ -22,6 +25,8 @@ c_sources = \
|
|||
rtsp-client.c \
|
||||
rtsp-server.c
|
||||
|
||||
noinst_HEADERS = rtsp-funnel.h
|
||||
|
||||
lib_LTLIBRARIES = \
|
||||
libgstrtspserver-@GST_MAJORMINOR@.la
|
||||
|
||||
|
@ -60,6 +65,8 @@ GstRtspServer-@GST_MAJORMINOR@.gir: $(INTROSPECTION_SCANNER) libgstrtspserver-@G
|
|||
-DIN_GOBJECT_INTROSPECTION=1 \
|
||||
--c-include='gst/gst.h' \
|
||||
--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 \
|
||||
--include=Gst-0.10 \
|
||||
--include=GstRtsp-0.10 \
|
||||
|
@ -81,7 +88,14 @@ typelibsdir = $(libdir)/girepository-1.0/
|
|||
typelibs_DATA = $(BUILT_GIRSOURCES:.gir=.typelib)
|
||||
|
||||
%.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)
|
||||
endif
|
||||
|
|
272
gst/rtsp-server/rtsp-auth.c
Normal file
272
gst/rtsp-server/rtsp-auth.c
Normal 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;
|
||||
}
|
80
gst/rtsp-server/rtsp-auth.h
Normal file
80
gst/rtsp-server/rtsp-auth.h
Normal 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
|
@ -17,31 +17,23 @@
|
|||
* 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/rtsp/gstrtspconnection.h>
|
||||
|
||||
#ifndef __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-mapping.h"
|
||||
#include "rtsp-session-pool.h"
|
||||
|
||||
G_BEGIN_DECLS
|
||||
#include "rtsp-auth.h"
|
||||
|
||||
#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))
|
||||
|
@ -52,8 +44,29 @@ G_BEGIN_DECLS
|
|||
#define GST_RTSP_CLIENT_CAST(obj) ((GstRTSPClient*)(obj))
|
||||
#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:
|
||||
|
@ -80,8 +93,10 @@ struct _GstRTSPClient {
|
|||
gchar *server_ip;
|
||||
gboolean is_ipv6;
|
||||
|
||||
GstRTSPServer *server;
|
||||
GstRTSPSessionPool *session_pool;
|
||||
GstRTSPMediaMapping *media_mapping;
|
||||
GstRTSPAuth *auth;
|
||||
|
||||
GstRTSPUrl *uri;
|
||||
GstRTSPMedia *media;
|
||||
|
@ -92,12 +107,18 @@ struct _GstRTSPClient {
|
|||
|
||||
struct _GstRTSPClientClass {
|
||||
GObjectClass parent_class;
|
||||
|
||||
/* signals */
|
||||
void (*closed) (GstRTSPClient *client);
|
||||
};
|
||||
|
||||
GType gst_rtsp_client_get_type (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,
|
||||
GstRTSPSessionPool *pool);
|
||||
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 * 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,
|
||||
GIOChannel *channel);
|
||||
|
||||
|
|
407
gst/rtsp-server/rtsp-funnel.c
Normal file
407
gst/rtsp-server/rtsp-funnel.c
Normal 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;
|
||||
}
|
69
gst/rtsp-server/rtsp-funnel.h
Normal file
69
gst/rtsp-server/rtsp-funnel.h
Normal 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__ */
|
|
@ -17,14 +17,18 @@
|
|||
* Boston, MA 02111-1307, USA.
|
||||
*/
|
||||
|
||||
#include <string.h>
|
||||
|
||||
#include "rtsp-media-factory-uri.h"
|
||||
|
||||
#define DEFAULT_URI NULL
|
||||
#define DEFAULT_USE_GSTPAY FALSE
|
||||
|
||||
enum
|
||||
{
|
||||
PROP_0,
|
||||
PROP_URI,
|
||||
PROP_USE_GSTPAY,
|
||||
PROP_LAST
|
||||
};
|
||||
|
||||
|
@ -56,7 +60,7 @@ free_data (FactoryData * data)
|
|||
|
||||
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
|
||||
|
||||
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",
|
||||
"The URI of the resource to stream", DEFAULT_URI,
|
||||
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;
|
||||
|
||||
|
@ -100,13 +114,68 @@ gst_rtsp_media_factory_uri_class_init (GstRTSPMediaFactoryURIClass * klass)
|
|||
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
|
||||
gst_rtsp_media_factory_uri_init (GstRTSPMediaFactoryURI * factory)
|
||||
{
|
||||
FilterData data = { NULL, NULL, NULL };
|
||||
|
||||
factory->uri = g_strdup (DEFAULT_URI);
|
||||
factory->factories =
|
||||
gst_element_factory_list_get_elements (GST_ELEMENT_FACTORY_TYPE_PAYLOADER,
|
||||
GST_RANK_NONE);
|
||||
factory->use_gstpay = DEFAULT_USE_GSTPAY;
|
||||
|
||||
/* 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_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);
|
||||
|
||||
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_acaps);
|
||||
|
||||
|
@ -134,6 +205,9 @@ gst_rtsp_media_factory_uri_get_property (GObject * object, guint propid,
|
|||
case PROP_URI:
|
||||
g_value_take_string (value, gst_rtsp_media_factory_uri_get_uri (factory));
|
||||
break;
|
||||
case PROP_USE_GSTPAY:
|
||||
g_value_set_boolean (value, factory->use_gstpay);
|
||||
break;
|
||||
default:
|
||||
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:
|
||||
gst_rtsp_media_factory_uri_set_uri (factory, g_value_get_string (value));
|
||||
break;
|
||||
case PROP_USE_GSTPAY:
|
||||
factory->use_gstpay = g_value_get_boolean (value);
|
||||
break;
|
||||
default:
|
||||
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, propid, pspec);
|
||||
}
|
||||
|
@ -219,26 +296,43 @@ find_payloader (GstRTSPMediaFactoryURI * urifact, GstCaps * caps)
|
|||
GList *list, *tmp;
|
||||
GstElementFactory *factory = NULL;
|
||||
|
||||
/* find payloader that can link */
|
||||
list = gst_element_factory_list_filter (urifact->factories, caps,
|
||||
/* first find a demuxer that can link */
|
||||
list = gst_element_factory_list_filter (urifact->demuxers, caps,
|
||||
GST_PAD_SINK, FALSE);
|
||||
|
||||
for (tmp = list; tmp; tmp = g_list_next (tmp)) {
|
||||
GstElementFactory *f = GST_ELEMENT_FACTORY_CAST (tmp->data);
|
||||
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);
|
||||
|
||||
if (list != NULL) {
|
||||
/* we have a demuxer, try that one first */
|
||||
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;
|
||||
}
|
||||
|
||||
|
@ -259,8 +353,9 @@ autoplug_continue_cb (GstElement * uribin, GstPad * pad, GstCaps * caps,
|
|||
if (!(factory = find_payloader (data->factory, caps)))
|
||||
goto no_factory;
|
||||
|
||||
/* we found a payloader, stop autoplugging */
|
||||
GST_DEBUG ("found payloader factory %s",
|
||||
/* we found a payloader, stop autoplugging so we can plug the
|
||||
* payloader. */
|
||||
GST_DEBUG ("found factory %s",
|
||||
gst_plugin_feature_get_name (GST_PLUGIN_FEATURE (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);
|
||||
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 */
|
||||
gst_bin_add (GST_BIN_CAST (element), payloader);
|
||||
gst_element_set_state (payloader, GST_STATE_PLAYING);
|
||||
|
|
|
@ -49,9 +49,13 @@ struct _GstRTSPMediaFactoryURI {
|
|||
GstRTSPMediaFactory parent;
|
||||
|
||||
gchar *uri;
|
||||
gboolean use_gstpay;
|
||||
|
||||
GstCaps *raw_vcaps;
|
||||
GstCaps *raw_acaps;
|
||||
GList *factories;
|
||||
GList *demuxers;
|
||||
GList *payloaders;
|
||||
GList *decoders;
|
||||
};
|
||||
|
||||
/**
|
||||
|
|
|
@ -22,6 +22,7 @@
|
|||
#define DEFAULT_LAUNCH NULL
|
||||
#define DEFAULT_SHARED FALSE
|
||||
#define DEFAULT_EOS_SHUTDOWN FALSE
|
||||
#define DEFAULT_BUFFER_SIZE 0x80000
|
||||
|
||||
enum
|
||||
{
|
||||
|
@ -29,10 +30,11 @@ enum
|
|||
PROP_LAUNCH,
|
||||
PROP_SHARED,
|
||||
PROP_EOS_SHUTDOWN,
|
||||
PROP_BUFFER_SIZE,
|
||||
PROP_LAST
|
||||
};
|
||||
|
||||
GST_DEBUG_CATEGORY (rtsp_media_debug);
|
||||
GST_DEBUG_CATEGORY_STATIC (rtsp_media_debug);
|
||||
#define GST_CAT_DEFAULT rtsp_media_debug
|
||||
|
||||
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",
|
||||
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->get_element = default_get_element;
|
||||
klass->construct = default_construct;
|
||||
klass->configure = default_configure;
|
||||
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
|
||||
|
@ -111,6 +119,7 @@ gst_rtsp_media_factory_init (GstRTSPMediaFactory * factory)
|
|||
factory->launch = g_strdup (DEFAULT_LAUNCH);
|
||||
factory->shared = DEFAULT_SHARED;
|
||||
factory->eos_shutdown = DEFAULT_EOS_SHUTDOWN;
|
||||
factory->buffer_size = DEFAULT_BUFFER_SIZE;
|
||||
|
||||
factory->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_free (factory->launch);
|
||||
g_mutex_free (factory->lock);
|
||||
if (factory->auth)
|
||||
g_object_unref (factory->auth);
|
||||
|
||||
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,
|
||||
gst_rtsp_media_factory_is_eos_shutdown (factory));
|
||||
break;
|
||||
case PROP_BUFFER_SIZE:
|
||||
g_value_set_uint (value,
|
||||
gst_rtsp_media_factory_get_buffer_size (factory));
|
||||
break;
|
||||
default:
|
||||
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,
|
||||
g_value_get_boolean (value));
|
||||
break;
|
||||
case PROP_BUFFER_SIZE:
|
||||
gst_rtsp_media_factory_set_buffer_size (factory,
|
||||
g_value_get_uint (value));
|
||||
break;
|
||||
default:
|
||||
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, propid, pspec);
|
||||
}
|
||||
|
@ -326,6 +345,94 @@ gst_rtsp_media_factory_is_eos_shutdown (GstRTSPMediaFactory * factory)
|
|||
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
|
||||
compare_media (gpointer key, GstRTSPMedia * media1, GstRTSPMedia * media2)
|
||||
{
|
||||
|
@ -608,13 +715,22 @@ static void
|
|||
default_configure (GstRTSPMediaFactory * factory, GstRTSPMedia * media)
|
||||
{
|
||||
gboolean shared, eos_shutdown;
|
||||
guint size;
|
||||
GstRTSPAuth *auth;
|
||||
|
||||
/* configure the sharedness */
|
||||
GST_RTSP_MEDIA_FACTORY_LOCK (factory);
|
||||
shared = factory->shared;
|
||||
eos_shutdown = factory->eos_shutdown;
|
||||
size = factory->buffer_size;
|
||||
GST_RTSP_MEDIA_FACTORY_UNLOCK (factory);
|
||||
|
||||
gst_rtsp_media_set_shared (media, shared);
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -21,6 +21,7 @@
|
|||
#include <gst/rtsp/gstrtspurl.h>
|
||||
|
||||
#include "rtsp-media.h"
|
||||
#include "rtsp-auth.h"
|
||||
|
||||
#ifndef __GST_RTSP_MEDIA_FACTORY_H__
|
||||
#define __GST_RTSP_MEDIA_FACTORY_H__
|
||||
|
@ -62,6 +63,8 @@ struct _GstRTSPMediaFactory {
|
|||
gchar *launch;
|
||||
gboolean shared;
|
||||
gboolean eos_shutdown;
|
||||
GstRTSPAuth *auth;
|
||||
guint buffer_size;
|
||||
|
||||
GMutex *medias_lock;
|
||||
GHashTable *medias;
|
||||
|
@ -116,6 +119,13 @@ void gst_rtsp_media_factory_set_eos_shutdown (GstRTSPMediaFac
|
|||
gboolean eos_shutdown);
|
||||
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 */
|
||||
GstRTSPMedia * gst_rtsp_media_factory_construct (GstRTSPMediaFactory *factory,
|
||||
const GstRTSPUrl *url);
|
||||
|
|
|
@ -21,7 +21,7 @@
|
|||
|
||||
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
|
||||
|
||||
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;
|
||||
|
||||
klass->find_media = find_media;
|
||||
|
||||
GST_DEBUG_CATEGORY_INIT (rtsp_media_debug, "rtspmediamapping", 0,
|
||||
"GstRTSPMediaMapping");
|
||||
}
|
||||
|
||||
static void
|
||||
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,
|
||||
g_free, g_object_unref);
|
||||
}
|
||||
|
@ -53,6 +58,8 @@ gst_rtsp_media_mapping_finalize (GObject * obj)
|
|||
{
|
||||
GstRTSPMediaMapping *mapping = GST_RTSP_MEDIA_MAPPING (obj);
|
||||
|
||||
GST_DEBUG_OBJECT (mapping, "finalized");
|
||||
|
||||
g_hash_table_unref (mapping->mappings);
|
||||
|
||||
G_OBJECT_CLASS (gst_rtsp_media_mapping_parent_class)->finalize (obj);
|
||||
|
|
|
@ -23,6 +23,7 @@
|
|||
#include <gst/app/gstappsrc.h>
|
||||
#include <gst/app/gstappsink.h>
|
||||
|
||||
#include "rtsp-funnel.h"
|
||||
#include "rtsp-media.h"
|
||||
|
||||
#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_MCAST
|
||||
#define DEFAULT_EOS_SHUTDOWN FALSE
|
||||
#define DEFAULT_BUFFER_SIZE 0x80000
|
||||
|
||||
/* define to dump received RTCP packets */
|
||||
#undef DUMP_STATS
|
||||
|
@ -41,16 +43,19 @@ enum
|
|||
PROP_REUSABLE,
|
||||
PROP_PROTOCOLS,
|
||||
PROP_EOS_SHUTDOWN,
|
||||
PROP_BUFFER_SIZE,
|
||||
PROP_LAST
|
||||
};
|
||||
|
||||
enum
|
||||
{
|
||||
SIGNAL_PREPARED,
|
||||
SIGNAL_UNPREPARED,
|
||||
SIGNAL_NEW_STATE,
|
||||
SIGNAL_LAST
|
||||
};
|
||||
|
||||
GST_DEBUG_CATEGORY_EXTERN (rtsp_media_debug);
|
||||
GST_DEBUG_CATEGORY_STATIC (rtsp_media_debug);
|
||||
#define GST_CAT_DEFAULT rtsp_media_debug
|
||||
|
||||
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",
|
||||
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] =
|
||||
g_signal_new ("unprepared", G_TYPE_FROM_CLASS (klass), G_SIGNAL_RUN_LAST,
|
||||
G_STRUCT_OFFSET (GstRTSPMediaClass, unprepared), NULL, NULL,
|
||||
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->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);
|
||||
if (error != NULL) {
|
||||
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;
|
||||
|
||||
ssrc_stream_map_key = g_quark_from_static_string ("GstRTSPServer.stream");
|
||||
|
||||
gst_element_register (NULL, "rtspfunnel", GST_RANK_NONE, RTSP_TYPE_FUNNEL);
|
||||
|
||||
}
|
||||
|
||||
static void
|
||||
|
@ -132,45 +157,7 @@ gst_rtsp_media_init (GstRTSPMedia * media)
|
|||
media->reusable = DEFAULT_REUSABLE;
|
||||
media->protocols = DEFAULT_PROTOCOLS;
|
||||
media->eos_shutdown = DEFAULT_EOS_SHUTDOWN;
|
||||
}
|
||||
|
||||
/* 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);
|
||||
media->buffer_size = DEFAULT_BUFFER_SIZE;
|
||||
}
|
||||
|
||||
void
|
||||
|
@ -208,9 +195,6 @@ gst_rtsp_media_stream_free (GstRTSPMediaStream * stream)
|
|||
|
||||
g_list_free (stream->transports);
|
||||
|
||||
g_list_foreach (stream->destinations, (GFunc) free_destination, NULL);
|
||||
g_list_free (stream->destinations);
|
||||
|
||||
g_free (stream);
|
||||
}
|
||||
|
||||
|
@ -271,6 +255,9 @@ gst_rtsp_media_get_property (GObject * object, guint propid,
|
|||
case PROP_EOS_SHUTDOWN:
|
||||
g_value_set_boolean (value, gst_rtsp_media_is_eos_shutdown (media));
|
||||
break;
|
||||
case PROP_BUFFER_SIZE:
|
||||
g_value_set_uint (value, gst_rtsp_media_get_buffer_size (media));
|
||||
break;
|
||||
default:
|
||||
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:
|
||||
gst_rtsp_media_set_eos_shutdown (media, g_value_get_boolean (value));
|
||||
break;
|
||||
case PROP_BUFFER_SIZE:
|
||||
gst_rtsp_media_set_buffer_size (media, g_value_get_uint (value));
|
||||
break;
|
||||
default:
|
||||
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_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.seconds = -1;
|
||||
} else {
|
||||
|
@ -507,6 +497,85 @@ gst_rtsp_media_is_eos_shutdown (GstRTSPMedia * media)
|
|||
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:
|
||||
* @media: a #GstRTSPMedia
|
||||
|
@ -548,6 +617,34 @@ gst_rtsp_media_get_stream (GstRTSPMedia * media, guint idx)
|
|||
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:
|
||||
* @media: a #GstRTSPMedia
|
||||
|
@ -804,10 +901,16 @@ again:
|
|||
"send-duplicates")) {
|
||||
g_object_set (G_OBJECT (udpsink0), "send-duplicates", FALSE, NULL);
|
||||
g_object_set (G_OBJECT (udpsink1), "send-duplicates", FALSE, NULL);
|
||||
stream->filter_duplicates = FALSE;
|
||||
} else {
|
||||
GST_WARNING ("multiudpsink version found without send-duplicates property");
|
||||
stream->filter_duplicates = TRUE;
|
||||
g_warning
|
||||
("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);
|
||||
|
@ -1068,10 +1171,42 @@ handle_new_buffer (GstAppSink * sink, gpointer user_data)
|
|||
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 = {
|
||||
NULL, /* not interested in EOS */
|
||||
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 */
|
||||
|
@ -1190,8 +1325,7 @@ setup_stream (GstRTSPMediaStream * stream, guint idx, GstRTSPMedia * media)
|
|||
gst_object_unref (teepad);
|
||||
|
||||
/* make selector for the RTP receivers */
|
||||
stream->selector[0] = gst_element_factory_make ("input-selector", NULL);
|
||||
g_object_set (stream->selector[0], "select-all", TRUE, NULL);
|
||||
stream->selector[0] = gst_element_factory_make ("rtspfunnel", NULL);
|
||||
gst_bin_add (GST_BIN_CAST (media->pipeline), stream->selector[0]);
|
||||
|
||||
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);
|
||||
|
||||
/* make selector for the RTCP receivers */
|
||||
stream->selector[1] = gst_element_factory_make ("input-selector", NULL);
|
||||
g_object_set (stream->selector[1], "select-all", TRUE, NULL);
|
||||
stream->selector[1] = gst_element_factory_make ("rtspfunnel", NULL);
|
||||
gst_bin_add (GST_BIN_CAST (media->pipeline), stream->selector[1]);
|
||||
|
||||
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)
|
||||
goto state_failed;
|
||||
|
||||
g_signal_emit (media, gst_rtsp_media_signals[SIGNAL_PREPARED], 0, NULL);
|
||||
|
||||
GST_INFO ("object %p is prerolled", media);
|
||||
|
||||
return TRUE;
|
||||
|
@ -1686,83 +1821,18 @@ static void
|
|||
add_udp_destination (GstRTSPMedia * media, GstRTSPMediaStream * stream,
|
||||
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);
|
||||
g_signal_emit_by_name (stream->udpsink[0], "add", dest, min, 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
|
||||
remove_udp_destination (GstRTSPMedia * media, GstRTSPMediaStream * stream,
|
||||
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);
|
||||
g_signal_emit_by_name (stream->udpsink[0], "remove", dest, min, 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
|
||||
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) {
|
||||
gst_rtsp_media_unprepare (media);
|
||||
} 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;
|
||||
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 */
|
||||
if (state == GST_STATE_PAUSED || old_active != media->active)
|
||||
|
|
|
@ -42,6 +42,7 @@ typedef struct _GstRTSPMediaClass GstRTSPMediaClass;
|
|||
typedef struct _GstRTSPMediaTrans GstRTSPMediaTrans;
|
||||
|
||||
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);
|
||||
|
||||
/**
|
||||
|
@ -49,6 +50,8 @@ typedef void (*GstRTSPKeepAliveFunc) (gpointer user_data);
|
|||
* @idx: a stream index
|
||||
* @send_rtp: callback for sending RTP 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
|
||||
* @notify: free function for the user_data.
|
||||
* @keep_alive: keep alive callback
|
||||
|
@ -66,6 +69,8 @@ struct _GstRTSPMediaTrans {
|
|||
|
||||
GstRTSPSendFunc send_rtp;
|
||||
GstRTSPSendFunc send_rtcp;
|
||||
GstRTSPSendListFunc send_rtp_list;
|
||||
GstRTSPSendListFunc send_rtcp_list;
|
||||
gpointer user_data;
|
||||
GDestroyNotify notify;
|
||||
|
||||
|
@ -80,16 +85,17 @@ struct _GstRTSPMediaTrans {
|
|||
GObject *rtpsource;
|
||||
};
|
||||
|
||||
#include "rtsp-auth.h"
|
||||
|
||||
/**
|
||||
* GstRTSPMediaStream:
|
||||
* @srcpad: the srcpad of the stream
|
||||
* @payloader: the payloader of the format
|
||||
* @prepared: if the stream is prepared for streaming
|
||||
* @server_port: the server udp ports
|
||||
* @recv_rtp_sink: sinkpad for RTP buffers
|
||||
* @recv_rtcp_sink: sinkpad for RTCP buffers
|
||||
* @recv_rtp_src: srcpad for RTP buffers
|
||||
* @recv_rtcp_src: srcpad for RTCP buffers
|
||||
* @send_rtp_src: srcpad for RTP buffers
|
||||
* @send_rtcp_src: srcpad for RTCP buffers
|
||||
* @udpsrc: the udp source elements for RTP/RTCP
|
||||
* @udpsink: the udp sink elements for RTP/RTCP
|
||||
* @appsrc: the app source elements for RTP/RTCP
|
||||
|
@ -136,11 +142,6 @@ struct _GstRTSPMediaStream {
|
|||
|
||||
/* transports we stream to */
|
||||
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 is_ipv6;
|
||||
gboolean eos_shutdown;
|
||||
guint buffer_size;
|
||||
GstRTSPAuth *auth;
|
||||
|
||||
GstElement *element;
|
||||
GArray *streams;
|
||||
|
@ -250,7 +253,10 @@ struct _GstRTSPMediaClass {
|
|||
gboolean (*unprepare) (GstRTSPMedia *media);
|
||||
|
||||
/* signals */
|
||||
gboolean (*prepared) (GstRTSPMedia *media);
|
||||
gboolean (*unprepared) (GstRTSPMedia *media);
|
||||
|
||||
gboolean (*new_state) (GstRTSPMedia *media, GstState state);
|
||||
};
|
||||
|
||||
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);
|
||||
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 */
|
||||
gboolean gst_rtsp_media_prepare (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);
|
||||
|
||||
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_rtcp (GstRTSPMediaStream *stream, GstBuffer *buffer);
|
||||
|
|
|
@ -21,9 +21,7 @@
|
|||
#include "rtsp-params.h"
|
||||
|
||||
GstRTSPResult
|
||||
gst_rtsp_params_set (GstRTSPClient * client, GstRTSPUrl * uri,
|
||||
GstRTSPSession * session, GstRTSPMessage * request,
|
||||
GstRTSPMessage * response)
|
||||
gst_rtsp_params_set (GstRTSPClient * client, GstRTSPClientState * state)
|
||||
{
|
||||
GstRTSPStatusCode code;
|
||||
|
||||
|
@ -31,16 +29,14 @@ gst_rtsp_params_set (GstRTSPClient * client, GstRTSPUrl * uri,
|
|||
* with a list of the parameters */
|
||||
code = GST_RTSP_STS_PARAMETER_NOT_UNDERSTOOD;
|
||||
|
||||
gst_rtsp_message_init_response (response, code,
|
||||
gst_rtsp_status_as_text (code), request);
|
||||
gst_rtsp_message_init_response (state->response, code,
|
||||
gst_rtsp_status_as_text (code), state->request);
|
||||
|
||||
return GST_RTSP_OK;
|
||||
}
|
||||
|
||||
GstRTSPResult
|
||||
gst_rtsp_params_get (GstRTSPClient * client, GstRTSPUrl * uri,
|
||||
GstRTSPSession * session, GstRTSPMessage * request,
|
||||
GstRTSPMessage * response)
|
||||
gst_rtsp_params_get (GstRTSPClient * client, GstRTSPClientState * state)
|
||||
{
|
||||
GstRTSPStatusCode code;
|
||||
|
||||
|
@ -48,8 +44,8 @@ gst_rtsp_params_get (GstRTSPClient * client, GstRTSPUrl * uri,
|
|||
* with a list of the parameters */
|
||||
code = GST_RTSP_STS_PARAMETER_NOT_UNDERSTOOD;
|
||||
|
||||
gst_rtsp_message_init_response (response, code,
|
||||
gst_rtsp_status_as_text (code), request);
|
||||
gst_rtsp_message_init_response (state->response, code,
|
||||
gst_rtsp_status_as_text (code), state->request);
|
||||
|
||||
return GST_RTSP_OK;
|
||||
}
|
||||
|
|
|
@ -30,13 +30,8 @@
|
|||
|
||||
G_BEGIN_DECLS
|
||||
|
||||
GstRTSPResult gst_rtsp_params_set (GstRTSPClient * client, GstRTSPUrl * uri,
|
||||
GstRTSPSession * session, GstRTSPMessage * request,
|
||||
GstRTSPMessage * response);
|
||||
|
||||
GstRTSPResult gst_rtsp_params_get (GstRTSPClient * client, GstRTSPUrl * uri,
|
||||
GstRTSPSession * session, GstRTSPMessage * request,
|
||||
GstRTSPMessage * response);
|
||||
GstRTSPResult gst_rtsp_params_set (GstRTSPClient * client, GstRTSPClientState * state);
|
||||
GstRTSPResult gst_rtsp_params_get (GstRTSPClient * client, GstRTSPClientState * state);
|
||||
|
||||
G_END_DECLS
|
||||
|
||||
|
|
|
@ -43,7 +43,7 @@ gst_rtsp_sdp_from_media (GstSDPMessage * sdp, GstSDPInfo * info,
|
|||
|
||||
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);
|
||||
g_free (rangestr);
|
||||
|
||||
|
|
|
@ -17,6 +17,19 @@
|
|||
* 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 "rtsp-server.h"
|
||||
|
@ -55,8 +68,9 @@ static void gst_rtsp_server_set_property (GObject * object, guint propid,
|
|||
const GValue * value, GParamSpec * pspec);
|
||||
static void gst_rtsp_server_finalize (GObject * object);
|
||||
|
||||
static GstRTSPClient *default_accept_client (GstRTSPServer * server,
|
||||
GIOChannel * channel);
|
||||
static GstRTSPClient *default_create_client (GstRTSPServer * server);
|
||||
static gboolean default_accept_client (GstRTSPServer * server,
|
||||
GstRTSPClient * client, GIOChannel * channel);
|
||||
|
||||
static void
|
||||
gst_rtsp_server_class_init (GstRTSPServerClass * klass)
|
||||
|
@ -127,6 +141,7 @@ gst_rtsp_server_class_init (GstRTSPServerClass * klass)
|
|||
GST_TYPE_RTSP_MEDIA_MAPPING,
|
||||
G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
|
||||
|
||||
klass->create_client = default_create_client;
|
||||
klass->accept_client = default_accept_client;
|
||||
|
||||
GST_DEBUG_CATEGORY_INIT (rtsp_server_debug, "rtspserver", 0, "GstRTSPServer");
|
||||
|
@ -135,6 +150,7 @@ gst_rtsp_server_class_init (GstRTSPServerClass * klass)
|
|||
static void
|
||||
gst_rtsp_server_init (GstRTSPServer * server)
|
||||
{
|
||||
server->lock = g_mutex_new ();
|
||||
server->address = g_strdup (DEFAULT_ADDRESS);
|
||||
server->service = g_strdup (DEFAULT_SERVICE);
|
||||
server->backlog = DEFAULT_BACKLOG;
|
||||
|
@ -147,11 +163,20 @@ gst_rtsp_server_finalize (GObject * object)
|
|||
{
|
||||
GstRTSPServer *server = GST_RTSP_SERVER (object);
|
||||
|
||||
GST_DEBUG_OBJECT (server, "finalize server");
|
||||
|
||||
g_free (server->address);
|
||||
g_free (server->service);
|
||||
|
||||
g_object_unref (server->session_pool);
|
||||
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 (address != NULL);
|
||||
|
||||
GST_RTSP_SERVER_LOCK (server);
|
||||
g_free (server->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 *
|
||||
gst_rtsp_server_get_address (GstRTSPServer * server)
|
||||
{
|
||||
gchar *result;
|
||||
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 (service != NULL);
|
||||
|
||||
GST_RTSP_SERVER_LOCK (server);
|
||||
g_free (server->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 *
|
||||
gst_rtsp_server_get_service (GstRTSPServer * server)
|
||||
{
|
||||
gchar *result;
|
||||
|
||||
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));
|
||||
|
||||
GST_RTSP_SERVER_LOCK (server);
|
||||
server->backlog = backlog;
|
||||
GST_RTSP_SERVER_UNLOCK (server);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -270,9 +312,15 @@ gst_rtsp_server_set_backlog (GstRTSPServer * server, gint backlog)
|
|||
gint
|
||||
gst_rtsp_server_get_backlog (GstRTSPServer * server)
|
||||
{
|
||||
gint result;
|
||||
|
||||
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));
|
||||
|
||||
old = server->session_pool;
|
||||
|
||||
if (old != pool) {
|
||||
if (pool)
|
||||
g_object_ref (pool);
|
||||
|
||||
GST_RTSP_SERVER_LOCK (server);
|
||||
old = server->session_pool;
|
||||
server->session_pool = pool;
|
||||
GST_RTSP_SERVER_UNLOCK (server);
|
||||
|
||||
if (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);
|
||||
|
||||
GST_RTSP_SERVER_LOCK (server);
|
||||
if ((result = server->session_pool))
|
||||
g_object_ref (result);
|
||||
GST_RTSP_SERVER_UNLOCK (server);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
@ -338,15 +389,16 @@ gst_rtsp_server_set_media_mapping (GstRTSPServer * server,
|
|||
|
||||
g_return_if_fail (GST_IS_RTSP_SERVER (server));
|
||||
|
||||
old = server->media_mapping;
|
||||
|
||||
if (old != mapping) {
|
||||
if (mapping)
|
||||
g_object_ref (mapping);
|
||||
|
||||
GST_RTSP_SERVER_LOCK (server);
|
||||
old = server->media_mapping;
|
||||
server->media_mapping = mapping;
|
||||
GST_RTSP_SERVER_UNLOCK (server);
|
||||
|
||||
if (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);
|
||||
|
||||
GST_RTSP_SERVER_LOCK (server);
|
||||
if ((result = server->media_mapping))
|
||||
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;
|
||||
}
|
||||
|
@ -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_sink_init_send (GstRTSPServer * server)
|
||||
/**
|
||||
* gst_rtsp_server_get_io_channel:
|
||||
* @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 *result, *rp;
|
||||
#ifdef USE_SOLINGER
|
||||
struct linger linger;
|
||||
#endif
|
||||
|
||||
g_return_val_if_fail (GST_IS_RTSP_SERVER (server), NULL);
|
||||
|
||||
memset (&hints, 0, sizeof (struct addrinfo));
|
||||
hints.ai_family = AF_UNSPEC; /* Allow IPv4 or IPv6 */
|
||||
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,
|
||||
server->service);
|
||||
|
||||
GST_RTSP_SERVER_LOCK (server);
|
||||
/* resolve the server IP address */
|
||||
if ((ret =
|
||||
getaddrinfo (server->address, server->service, &hints, &result)) != 0)
|
||||
|
@ -464,6 +581,15 @@ gst_rtsp_server_sink_init_send (GstRTSPServer * server)
|
|||
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) {
|
||||
GST_DEBUG_OBJECT (server, "bind on %s", rp->ai_canonname);
|
||||
break;
|
||||
|
@ -472,26 +598,18 @@ gst_rtsp_server_sink_init_send (GstRTSPServer * server)
|
|||
GST_DEBUG_OBJECT (server, "failed to bind socket (%s), try next",
|
||||
g_strerror (errno));
|
||||
close (sockfd);
|
||||
sockfd = -1;
|
||||
}
|
||||
freeaddrinfo (result);
|
||||
|
||||
if (rp == NULL)
|
||||
if (sockfd == -1)
|
||||
goto no_socket;
|
||||
|
||||
server->server_sock.fd = 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;
|
||||
GST_DEBUG_OBJECT (server, "opened sending server socket with fd %d", sockfd);
|
||||
|
||||
/* keep connection alive; avoids SIGPIPE during write */
|
||||
ret = 1;
|
||||
if (setsockopt (server->server_sock.fd, SOL_SOCKET, SO_KEEPALIVE,
|
||||
if (setsockopt (sockfd, SOL_SOCKET, SO_KEEPALIVE,
|
||||
(void *) &ret, sizeof (ret)) < 0)
|
||||
goto keepalive_failed;
|
||||
|
||||
|
@ -501,43 +619,42 @@ gst_rtsp_server_sink_init_send (GstRTSPServer * server)
|
|||
* client. */
|
||||
linger.l_onoff = 1;
|
||||
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)
|
||||
goto linger_failed;
|
||||
#endif
|
||||
|
||||
/* 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",
|
||||
server->server_sock.fd, server->backlog);
|
||||
if (listen (server->server_sock.fd, server->backlog) == -1)
|
||||
sockfd, server->backlog);
|
||||
if (listen (sockfd, server->backlog) == -1)
|
||||
goto listen_failed;
|
||||
|
||||
GST_DEBUG_OBJECT (server,
|
||||
"listened on server socket %d, returning from connection setup",
|
||||
server->server_sock.fd);
|
||||
"listened on server socket %d, returning from connection setup", sockfd);
|
||||
|
||||
/* 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_RTSP_SERVER_UNLOCK (server);
|
||||
|
||||
return TRUE;
|
||||
return channel;
|
||||
|
||||
/* ERRORS */
|
||||
no_address:
|
||||
{
|
||||
GST_ERROR_OBJECT (server, "failed to resolve address: %s",
|
||||
gai_strerror (ret));
|
||||
return FALSE;
|
||||
goto close_error;
|
||||
}
|
||||
no_socket:
|
||||
{
|
||||
GST_ERROR_OBJECT (server, "failed to create socket: %s",
|
||||
g_strerror (errno));
|
||||
return FALSE;
|
||||
}
|
||||
reuse_failed:
|
||||
{
|
||||
GST_ERROR_OBJECT (server, "failed to reuse socket: %s", g_strerror (errno));
|
||||
goto close_error;
|
||||
}
|
||||
keepalive_failed:
|
||||
|
@ -562,18 +679,44 @@ listen_failed:
|
|||
}
|
||||
close_error:
|
||||
{
|
||||
if (server->server_sock.fd >= 0) {
|
||||
close (server->server_sock.fd);
|
||||
server->server_sock.fd = -1;
|
||||
if (sockfd >= 0) {
|
||||
close (sockfd);
|
||||
}
|
||||
return FALSE;
|
||||
GST_RTSP_SERVER_UNLOCK (server);
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
/* default method for creating a new client object in the server to accept and
|
||||
* handle a client connection on this server */
|
||||
static void
|
||||
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 *
|
||||
default_accept_client (GstRTSPServer * server, GIOChannel * channel)
|
||||
default_create_client (GstRTSPServer * server)
|
||||
{
|
||||
GstRTSPClient *client;
|
||||
|
||||
|
@ -581,26 +724,38 @@ default_accept_client (GstRTSPServer * server, GIOChannel * channel)
|
|||
client = gst_rtsp_client_new ();
|
||||
|
||||
/* set the session pool that this client should use */
|
||||
GST_RTSP_SERVER_LOCK (server);
|
||||
gst_rtsp_client_set_session_pool (client, server->session_pool);
|
||||
/* set the media mapping that this client should use */
|
||||
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
|
||||
* the connection and will run the remainder of the communication with the
|
||||
* client asyncronously. */
|
||||
if (!gst_rtsp_client_accept (client, channel))
|
||||
goto accept_failed;
|
||||
|
||||
return client;
|
||||
return TRUE;
|
||||
|
||||
/* ERRORS */
|
||||
accept_failed:
|
||||
{
|
||||
GST_ERROR_OBJECT (server,
|
||||
"Could not accept client on server socket %d: %s (%d)",
|
||||
server->server_sock.fd, g_strerror (errno), errno);
|
||||
gst_object_unref (client);
|
||||
return NULL;
|
||||
"Could not accept client on server : %s (%d)", g_strerror (errno),
|
||||
errno);
|
||||
return FALSE;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -618,21 +773,26 @@ gboolean
|
|||
gst_rtsp_server_io_func (GIOChannel * channel, GIOCondition condition,
|
||||
GstRTSPServer * server)
|
||||
{
|
||||
gboolean result;
|
||||
GstRTSPClient *client = NULL;
|
||||
GstRTSPServerClass *klass;
|
||||
|
||||
if (condition & G_IO_IN) {
|
||||
klass = GST_RTSP_SERVER_GET_CLASS (server);
|
||||
|
||||
/* a new client connected, create a client object to handle the client. */
|
||||
if (klass->accept_client)
|
||||
client = klass->accept_client (server, channel);
|
||||
if (klass->create_client)
|
||||
client = klass->create_client (server);
|
||||
if (client == NULL)
|
||||
goto client_failed;
|
||||
|
||||
/* can unref the client now, when the request is finished, it will be
|
||||
* unreffed async. */
|
||||
gst_object_unref (client);
|
||||
/* a new client connected, create a client object to handle the client. */
|
||||
if (klass->accept_client)
|
||||
result = klass->accept_client (server, client, channel);
|
||||
if (!result)
|
||||
goto accept_failed;
|
||||
|
||||
/* manage the client connection */
|
||||
manage_client (server, client);
|
||||
} else {
|
||||
GST_WARNING_OBJECT (server, "received unknown event %08x", condition);
|
||||
}
|
||||
|
@ -644,35 +804,19 @@ client_failed:
|
|||
GST_ERROR_OBJECT (server, "failed to create a client");
|
||||
return FALSE;
|
||||
}
|
||||
accept_failed:
|
||||
{
|
||||
GST_ERROR_OBJECT (server, "failed to accept client");
|
||||
gst_object_unref (client);
|
||||
return FALSE;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* gst_rtsp_server_get_io_channel:
|
||||
* @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)
|
||||
static void
|
||||
watch_destroyed (GstRTSPServer * server)
|
||||
{
|
||||
g_return_val_if_fail (GST_IS_RTSP_SERVER (server), NULL);
|
||||
|
||||
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;
|
||||
}
|
||||
GST_DEBUG_OBJECT (server, "source destroyed");
|
||||
g_object_unref (server);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -687,24 +831,26 @@ init_failed:
|
|||
GSource *
|
||||
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;
|
||||
GSource *source;
|
||||
|
||||
g_return_val_if_fail (GST_IS_RTSP_SERVER (server), NULL);
|
||||
|
||||
channel = gst_rtsp_server_get_io_channel (server);
|
||||
if (channel == NULL)
|
||||
goto no_channel;
|
||||
|
||||
/* 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_channel_unref (channel);
|
||||
|
||||
/* configure the callback */
|
||||
g_source_set_callback (server->io_watch,
|
||||
(GSourceFunc) gst_rtsp_server_io_func, server, NULL);
|
||||
}
|
||||
return server->io_watch;
|
||||
g_source_set_callback (source,
|
||||
(GSourceFunc) gst_rtsp_server_io_func, g_object_ref (server),
|
||||
(GDestroyNotify) watch_destroyed);
|
||||
|
||||
return source;
|
||||
|
||||
no_channel:
|
||||
{
|
||||
|
@ -719,7 +865,8 @@ no_channel:
|
|||
* @context: a #GMainContext
|
||||
*
|
||||
* 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
|
||||
* configured and the server is ready to start.
|
||||
|
@ -739,6 +886,7 @@ gst_rtsp_server_attach (GstRTSPServer * server, GMainContext * context)
|
|||
goto no_source;
|
||||
|
||||
res = g_source_attach (source, context);
|
||||
g_source_unref (source);
|
||||
|
||||
return res;
|
||||
|
||||
|
|
|
@ -17,31 +17,21 @@
|
|||
* 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>
|
||||
#ifndef __GST_RTSP_SERVER_H__
|
||||
#define __GST_RTSP_SERVER_H__
|
||||
|
||||
#include <gst/gst.h>
|
||||
|
||||
G_BEGIN_DECLS
|
||||
|
||||
typedef struct _GstRTSPServer GstRTSPServer;
|
||||
typedef struct _GstRTSPServerClass GstRTSPServerClass;
|
||||
|
||||
#include "rtsp-session-pool.h"
|
||||
#include "rtsp-media-mapping.h"
|
||||
#include "rtsp-media-factory-uri.h"
|
||||
#include "rtsp-client.h"
|
||||
|
||||
#ifndef __GST_RTSP_SERVER_H__
|
||||
#define __GST_RTSP_SERVER_H__
|
||||
|
||||
G_BEGIN_DECLS
|
||||
#include "rtsp-auth.h"
|
||||
|
||||
#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))
|
||||
|
@ -52,43 +42,53 @@ G_BEGIN_DECLS
|
|||
#define GST_RTSP_SERVER_CAST(obj) ((GstRTSPServer*)(obj))
|
||||
#define GST_RTSP_SERVER_CLASS_CAST(klass) ((GstRTSPServerClass*)(klass))
|
||||
|
||||
typedef struct _GstRTSPServer GstRTSPServer;
|
||||
typedef struct _GstRTSPServerClass GstRTSPServerClass;
|
||||
#define GST_RTSP_SERVER_GET_LOCK(server) (GST_RTSP_SERVER_CAST(server)->lock)
|
||||
#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 {
|
||||
GObject parent;
|
||||
|
||||
GMutex *lock;
|
||||
|
||||
/* server information */
|
||||
gchar *address;
|
||||
gchar *service;
|
||||
gint backlog;
|
||||
|
||||
struct sockaddr_in server_sin;
|
||||
|
||||
/* socket and channels */
|
||||
GstPollFD server_sock;
|
||||
GIOChannel *io_channel;
|
||||
GSource *io_watch;
|
||||
|
||||
/* sessions on this server */
|
||||
GstRTSPSessionPool *session_pool;
|
||||
|
||||
/* media mapper for this server */
|
||||
GstRTSPMediaMapping *media_mapping;
|
||||
|
||||
/* authentication manager */
|
||||
GstRTSPAuth *auth;
|
||||
|
||||
/* the clients that are connected */
|
||||
GList *clients;
|
||||
};
|
||||
|
||||
/**
|
||||
* 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.
|
||||
* @accept_client: accept a new GstRTSPClient
|
||||
*
|
||||
* The RTSP server class structure
|
||||
*/
|
||||
struct _GstRTSPServerClass {
|
||||
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);
|
||||
|
@ -110,6 +110,9 @@ GstRTSPSessionPool * gst_rtsp_server_get_session_pool (GstRTSPServer *serve
|
|||
void gst_rtsp_server_set_media_mapping (GstRTSPServer *server, GstRTSPMediaMapping *mapping);
|
||||
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,
|
||||
GstRTSPServer *server);
|
||||
|
||||
|
|
|
@ -30,7 +30,15 @@ enum
|
|||
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
|
||||
|
||||
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;
|
||||
|
||||
GST_DEBUG_CATEGORY_INIT (rtsp_session_debug, "rtspsession", 0,
|
||||
"GstRTSPSession");
|
||||
GST_DEBUG_CATEGORY_INIT (rtsp_session_debug, "rtspsessionpool", 0,
|
||||
"GstRTSPSessionPool");
|
||||
}
|
||||
|
||||
static void
|
||||
|
@ -235,7 +243,9 @@ create_session_id (GstRTSPSessionPool * pool)
|
|||
gint 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);
|
||||
|
|
|
@ -22,10 +22,14 @@
|
|||
#ifndef __GST_RTSP_SESSION_POOL_H__
|
||||
#define __GST_RTSP_SESSION_POOL_H__
|
||||
|
||||
#include "rtsp-session.h"
|
||||
|
||||
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_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))
|
||||
|
@ -35,9 +39,6 @@ G_BEGIN_DECLS
|
|||
#define GST_RTSP_SESSION_POOL_CAST(obj) ((GstRTSPSessionPool*)(obj))
|
||||
#define GST_RTSP_SESSION_POOL_CLASS_CAST(klass) ((GstRTSPSessionPoolClass*)(klass))
|
||||
|
||||
typedef struct _GstRTSPSessionPool GstRTSPSessionPool;
|
||||
typedef struct _GstRTSPSessionPoolClass GstRTSPSessionPoolClass;
|
||||
|
||||
/**
|
||||
* GstRTSPSessionPool:
|
||||
* @max_sessions: the maximum number of sessions.
|
||||
|
|
|
@ -32,7 +32,7 @@ enum
|
|||
PROP_LAST
|
||||
};
|
||||
|
||||
GST_DEBUG_CATEGORY_EXTERN (rtsp_session_debug);
|
||||
GST_DEBUG_CATEGORY_STATIC (rtsp_session_debug);
|
||||
#define GST_CAT_DEFAULT rtsp_session_debug
|
||||
|
||||
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",
|
||||
"the timeout of the session (0 = never)", 0, G_MAXUINT,
|
||||
DEFAULT_TIMEOUT, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
|
||||
|
||||
GST_DEBUG_CATEGORY_INIT (rtsp_session_debug, "rtspsession", 0,
|
||||
"GstRTSPSession");
|
||||
}
|
||||
|
||||
static void
|
||||
|
@ -79,7 +82,8 @@ gst_rtsp_session_free_stream (GstRTSPSessionStream * stream)
|
|||
GST_INFO ("free session stream %p", stream);
|
||||
|
||||
/* 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_media_trans_cleanup (&stream->trans);
|
||||
|
@ -549,6 +553,8 @@ gst_rtsp_session_stream_set_transport (GstRTSPSessionStream * stream,
|
|||
* @stream: a #GstRTSPSessionStream
|
||||
* @send_rtp: a callback called when RTP 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
|
||||
* @notify: called with the user_data when no longer needed.
|
||||
*
|
||||
|
@ -557,11 +563,14 @@ gst_rtsp_session_stream_set_transport (GstRTSPSessionStream * stream,
|
|||
*/
|
||||
void
|
||||
gst_rtsp_session_stream_set_callbacks (GstRTSPSessionStream * stream,
|
||||
GstRTSPSendFunc send_rtp, GstRTSPSendFunc send_rtcp, gpointer user_data,
|
||||
GDestroyNotify notify)
|
||||
GstRTSPSendFunc send_rtp, GstRTSPSendFunc send_rtcp,
|
||||
GstRTSPSendListFunc send_rtp_list, GstRTSPSendListFunc send_rtcp_list,
|
||||
gpointer user_data, GDestroyNotify notify)
|
||||
{
|
||||
stream->trans.send_rtp = send_rtp;
|
||||
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)
|
||||
stream->trans.notify (stream->trans.user_data);
|
||||
stream->trans.user_data = user_data;
|
||||
|
|
|
@ -21,8 +21,6 @@
|
|||
|
||||
#include <gst/rtsp/gstrtsptransport.h>
|
||||
|
||||
#include "rtsp-media.h"
|
||||
|
||||
#ifndef __GST_RTSP_SESSION_H__
|
||||
#define __GST_RTSP_SESSION_H__
|
||||
|
||||
|
@ -43,6 +41,8 @@ typedef struct _GstRTSPSessionClass GstRTSPSessionClass;
|
|||
typedef struct _GstRTSPSessionStream GstRTSPSessionStream;
|
||||
typedef struct _GstRTSPSessionMedia GstRTSPSessionMedia;
|
||||
|
||||
#include "rtsp-media.h"
|
||||
|
||||
/**
|
||||
* GstRTSPSessionStream:
|
||||
* @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,
|
||||
GstRTSPSendFunc send_rtp,
|
||||
GstRTSPSendFunc send_rtcp,
|
||||
GstRTSPSendListFunc send_rtp_list,
|
||||
GstRTSPSendListFunc send_rtcp_list,
|
||||
gpointer user_data,
|
||||
GDestroyNotify notify);
|
||||
void gst_rtsp_session_stream_set_keepalive (GstRTSPSessionStream *stream,
|
||||
|
|
|
@ -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
|
|
@ -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
1
tests/.gitignore
vendored
Normal file
|
@ -0,0 +1 @@
|
|||
test-cleanup
|
9
tests/Makefile.am
Normal file
9
tests/Makefile.am
Normal 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
68
tests/test-cleanup.c
Normal 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;
|
||||
}
|
||||
}
|
Loading…
Reference in a new issue