mirror of
https://gitlab.freedesktop.org/gstreamer/gstreamer.git
synced 2024-11-28 04:31:06 +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
|
.deps
|
||||||
.libs
|
.libs
|
||||||
|
ABOUT-NLS
|
||||||
INSTALL
|
INSTALL
|
||||||
Makefile
|
Makefile
|
||||||
Makefile.in
|
Makefile.in
|
||||||
|
@ -21,6 +22,7 @@ config.guess
|
||||||
config.h
|
config.h
|
||||||
config.h.in
|
config.h.in
|
||||||
config.log
|
config.log
|
||||||
|
config.rpath
|
||||||
config.status
|
config.status
|
||||||
config.sub
|
config.sub
|
||||||
configure
|
configure
|
||||||
|
@ -34,3 +36,5 @@ bindings/python/rtspserver.c
|
||||||
tags
|
tags
|
||||||
gst-rtsp.spec
|
gst-rtsp.spec
|
||||||
stamp-h.in
|
stamp-h.in
|
||||||
|
|
||||||
|
/m4/*m4
|
||||||
|
|
44
Makefile.am
44
Makefile.am
|
@ -3,11 +3,11 @@ DISTCHECK_CONFIGURE_FLAGS=--enable-gtk-doc
|
||||||
SUBDIRS = \
|
SUBDIRS = \
|
||||||
gst \
|
gst \
|
||||||
bindings \
|
bindings \
|
||||||
m4 \
|
|
||||||
common \
|
common \
|
||||||
pkgconfig \
|
pkgconfig \
|
||||||
docs \
|
docs \
|
||||||
examples
|
examples \
|
||||||
|
tests
|
||||||
|
|
||||||
DIST_SUBDIRS = $(SUBDIRS)
|
DIST_SUBDIRS = $(SUBDIRS)
|
||||||
|
|
||||||
|
@ -16,13 +16,15 @@ EXTRA_DIST = \
|
||||||
AUTHORS COPYING NEWS README RELEASE REQUIREMENTS \
|
AUTHORS COPYING NEWS README RELEASE REQUIREMENTS \
|
||||||
gst-rtsp.spec docs/design/gst-rtp-server-design
|
gst-rtsp.spec docs/design/gst-rtp-server-design
|
||||||
|
|
||||||
ACLOCAL_AMFLAGS = -I common/m4 -I m4
|
ACLOCAL_AMFLAGS = -I m4 -I common/m4
|
||||||
|
|
||||||
DISTCLEANFILES = _stdint.h gst-rtsp.spec
|
DISTCLEANFILES = _stdint.h gst-rtsp.spec
|
||||||
|
|
||||||
include $(top_srcdir)/common/release.mak
|
include $(top_srcdir)/common/release.mak
|
||||||
include $(top_srcdir)/common/po.mak
|
include $(top_srcdir)/common/po.mak
|
||||||
|
|
||||||
|
include $(top_srcdir)/common/coverage/lcov.mak
|
||||||
|
|
||||||
check-valgrind:
|
check-valgrind:
|
||||||
cd tests/check && make check-valgrind
|
cd tests/check && make check-valgrind
|
||||||
|
|
||||||
|
@ -37,7 +39,41 @@ endif
|
||||||
# cruft: plugins that have been merged or moved or renamed
|
# cruft: plugins that have been merged or moved or renamed
|
||||||
CRUFT_FILES = \
|
CRUFT_FILES = \
|
||||||
$(top_builddir)/common/shave \
|
$(top_builddir)/common/shave \
|
||||||
$(top_builddir)/common/shave-libtool
|
$(top_builddir)/common/shave-libtool \
|
||||||
|
$(top_builddir)/common/m4/codeset.m4 \
|
||||||
|
$(top_builddir)/common/m4/gettext.m4 \
|
||||||
|
$(top_builddir)/common/m4/glibc2.m4 \
|
||||||
|
$(top_builddir)/common/m4/glibc21.m4 \
|
||||||
|
$(top_builddir)/common/m4/iconv.m4 \
|
||||||
|
$(top_builddir)/common/m4/intdiv0.m4 \
|
||||||
|
$(top_builddir)/common/m4/intl.m4 \
|
||||||
|
$(top_builddir)/common/m4/intldir.m4 \
|
||||||
|
$(top_builddir)/common/m4/intlmacosx.m4 \
|
||||||
|
$(top_builddir)/common/m4/intmax.m4 \
|
||||||
|
$(top_builddir)/common/m4/inttypes-pri.m4 \
|
||||||
|
$(top_builddir)/common/m4/inttypes_h.m4 \
|
||||||
|
$(top_builddir)/common/m4/lcmessage.m4 \
|
||||||
|
$(top_builddir)/common/m4/lib-ld.m4 \
|
||||||
|
$(top_builddir)/common/m4/lib-link.m4 \
|
||||||
|
$(top_builddir)/common/m4/lib-prefix.m4 \
|
||||||
|
$(top_builddir)/common/m4/libtool.m4 \
|
||||||
|
$(top_builddir)/common/m4/lock.m4 \
|
||||||
|
$(top_builddir)/common/m4/longlong.m4 \
|
||||||
|
$(top_builddir)/common/m4/ltoptions.m4 \
|
||||||
|
$(top_builddir)/common/m4/ltsugar.m4 \
|
||||||
|
$(top_builddir)/common/m4/ltversion.m4 \
|
||||||
|
$(top_builddir)/common/m4/lt~obsolete.m4 \
|
||||||
|
$(top_builddir)/common/m4/nls.m4 \
|
||||||
|
$(top_builddir)/common/m4/po.m4 \
|
||||||
|
$(top_builddir)/common/m4/printf-posix.m4 \
|
||||||
|
$(top_builddir)/common/m4/progtest.m4 \
|
||||||
|
$(top_builddir)/common/m4/size_max.m4 \
|
||||||
|
$(top_builddir)/common/m4/stdint_h.m4 \
|
||||||
|
$(top_builddir)/common/m4/uintmax_t.m4 \
|
||||||
|
$(top_builddir)/common/m4/visibility.m4 \
|
||||||
|
$(top_builddir)/common/m4/wchar_t.m4 \
|
||||||
|
$(top_builddir)/common/m4/wint_t.m4 \
|
||||||
|
$(top_builddir)/common/m4/xsize.m4
|
||||||
|
|
||||||
include $(top_srcdir)/common/cruft.mak
|
include $(top_srcdir)/common/cruft.mak
|
||||||
|
|
||||||
|
|
|
@ -83,7 +83,7 @@ tool_run "$libtoolize" "--copy --force"
|
||||||
tool_run "$aclocal" "-I m4 -I common/m4 $ACLOCAL_FLAGS"
|
tool_run "$aclocal" "-I m4 -I common/m4 $ACLOCAL_FLAGS"
|
||||||
tool_run "$autoheader"
|
tool_run "$autoheader"
|
||||||
|
|
||||||
# touch the stamp-h.in build stamp so we don't re-run autoheader in maintainer mode -- wingo
|
# touch the stamp-h.in build stamp so we don't re-run autoheader in maintainer mode
|
||||||
echo timestamp > stamp-h.in 2> /dev/null
|
echo timestamp > stamp-h.in 2> /dev/null
|
||||||
|
|
||||||
tool_run "$autoconf"
|
tool_run "$autoconf"
|
||||||
|
|
|
@ -37,6 +37,7 @@ rtspserver.c: $(DEFS) $(OVERRIDES) arg-types.py
|
||||||
($(PYTHON) $(srcdir)/codegen/codegen.py \
|
($(PYTHON) $(srcdir)/codegen/codegen.py \
|
||||||
--load-types $(srcdir)/arg-types.py \
|
--load-types $(srcdir)/arg-types.py \
|
||||||
--register $(srcdir)/rtspserver-types.defs \
|
--register $(srcdir)/rtspserver-types.defs \
|
||||||
|
--register $(PYGST_DEFSDIR)/gst-types.defs \
|
||||||
--override $(srcdir)/$*.override \
|
--override $(srcdir)/$*.override \
|
||||||
--extendpath $(top_builddir)/gst/ \
|
--extendpath $(top_builddir)/gst/ \
|
||||||
--extendpath $(srcdir)/ \
|
--extendpath $(srcdir)/ \
|
||||||
|
|
|
@ -145,6 +145,54 @@ class GstIteratorArg(ArgType):
|
||||||
info.varlist.add('GstIterator', '*ret')
|
info.varlist.add('GstIterator', '*ret')
|
||||||
info.codeafter.append(' return pygst_iterator_new(ret);')
|
info.codeafter.append(' return pygst_iterator_new(ret);')
|
||||||
|
|
||||||
|
class GstRTSPUrlArg(ArgType):
|
||||||
|
"""GstRTSPUrl node generator"""
|
||||||
|
|
||||||
|
before = (' parse_result = gst_rtsp_url_parse (py_%(name)s, &%(name)s);\n'
|
||||||
|
' if (parse_result != GST_RTSP_OK) {\n'
|
||||||
|
' PyErr_SetString(PyExc_TypeError, "invalid url");\n'
|
||||||
|
' return NULL;\n'
|
||||||
|
' }')
|
||||||
|
beforenull = (' if (py_%(name)s == NULL)\n'
|
||||||
|
' %(name)s = NULL;\n'
|
||||||
|
' else\n'
|
||||||
|
' ' + before)
|
||||||
|
after = (' if (%(name)s)\n'
|
||||||
|
' gst_rtsp_url_free (%(name)s);\n')
|
||||||
|
|
||||||
|
def write_param(self, ptype, pname, pdflt, pnull, keeprefcount, info):
|
||||||
|
if ptype in ('const-GstRTSPUrl*', 'GstRTSPUrl*'):
|
||||||
|
self.write_normal_param(pname, pdflt, pnull, info)
|
||||||
|
else:
|
||||||
|
raise RuntimeError, "write_param not implemented for %s" % ptype
|
||||||
|
|
||||||
|
def write_normal_param(self, pname, pdflt, pnull, info):
|
||||||
|
info.varlist.add('GstRTSPResult', 'parse_result')
|
||||||
|
if pdflt:
|
||||||
|
assert pdflt == 'NULL'
|
||||||
|
info.varlist.add('const char', '*py_' + pname + ' = NULL')
|
||||||
|
else:
|
||||||
|
info.varlist.add('const char', '*py_' + pname)
|
||||||
|
info.varlist.add('GstRTSPUrl', '*'+pname)
|
||||||
|
info.add_parselist('s', ['&py_'+pname], [pname])
|
||||||
|
info.arglist.append(pname)
|
||||||
|
if pnull:
|
||||||
|
info.codebefore.append (self.beforenull % { 'name' : pname })
|
||||||
|
else:
|
||||||
|
info.codebefore.append (self.before % { 'name' : pname })
|
||||||
|
info.codeafter.append (self.after % { 'name' : pname })
|
||||||
|
|
||||||
|
def write_return(self, ptype, ownsreturn, info):
|
||||||
|
if ptype == 'GstRTSPUrl*':
|
||||||
|
info.varlist.add('GstRTSPUrl', '*ret')
|
||||||
|
copyval = 'FALSE'
|
||||||
|
elif ptype == 'const-GstRTSPUrl*':
|
||||||
|
info.varlist.add('const GstRTSPUrl', '*ret')
|
||||||
|
copyval = 'TRUE'
|
||||||
|
else:
|
||||||
|
raise RuntimeError, "write_return not implemented for %s" % ptype
|
||||||
|
info.codeafter.append(' return pyg_boxed_new (GST_TYPE_RTSP_URL, ret, '+copyval+', TRUE);')
|
||||||
|
|
||||||
class GstMiniObjectParam(Parameter):
|
class GstMiniObjectParam(Parameter):
|
||||||
|
|
||||||
def get_c_type(self):
|
def get_c_type(self):
|
||||||
|
@ -165,6 +213,31 @@ class GstMiniObjectParam(Parameter):
|
||||||
|
|
||||||
matcher.register_reverse('GstMiniObject*', GstMiniObjectParam)
|
matcher.register_reverse('GstMiniObject*', GstMiniObjectParam)
|
||||||
|
|
||||||
|
class GstRTSPUrlParam(Parameter):
|
||||||
|
|
||||||
|
def get_c_type(self):
|
||||||
|
c_type = self.props.get('c_type', None)
|
||||||
|
if c_type and c_type.startswith('const'):
|
||||||
|
return 'const GstRTSPUrl *'
|
||||||
|
return 'GstRTSPUrl *'
|
||||||
|
|
||||||
|
def convert_c2py(self):
|
||||||
|
self.wrapper.add_declaration("char *%s_str = NULL;" % self.name)
|
||||||
|
self.wrapper.add_declaration("PyObject *py_%s = NULL;" % self.name)
|
||||||
|
self.wrapper.write_code(code=("if (%(name)s) {\n"
|
||||||
|
" %(name)s_str = gst_rtsp_url_get_request_uri ((GstRTSPUrl*) %(name)s);\n"
|
||||||
|
" py_%(name)s = PyString_FromString (%(name)s_str);\n"
|
||||||
|
" g_free (%(name)s_str);\n"
|
||||||
|
"} else {\n"
|
||||||
|
" Py_INCREF(Py_None);\n"
|
||||||
|
" py_%(name)s = Py_None;\n"
|
||||||
|
"}" % {'name': self.name}),
|
||||||
|
cleanup=("Py_DECREF(py_%s);" % self.name))
|
||||||
|
self.wrapper.add_pyargv_item("py_%s" % self.name)
|
||||||
|
|
||||||
|
matcher.register_reverse('const-GstRTSPUrl*', GstRTSPUrlParam)
|
||||||
|
matcher.register_reverse('GstRTSPUrl*', GstRTSPUrlParam)
|
||||||
|
|
||||||
class GstMiniObjectReturn(ReturnType):
|
class GstMiniObjectReturn(ReturnType):
|
||||||
|
|
||||||
def get_c_type(self):
|
def get_c_type(self):
|
||||||
|
@ -343,6 +416,8 @@ matcher.register('GstCaps', GstCapsArg()) #FIXME: does this work?
|
||||||
matcher.register('GstCaps*', GstCapsArg()) #FIXME: does this work?
|
matcher.register('GstCaps*', GstCapsArg()) #FIXME: does this work?
|
||||||
matcher.register('const-GstCaps*', GstCapsArg())
|
matcher.register('const-GstCaps*', GstCapsArg())
|
||||||
matcher.register('GstIterator*', GstIteratorArg())
|
matcher.register('GstIterator*', GstIteratorArg())
|
||||||
|
matcher.register('const-GstRTSPUrl*', GstRTSPUrlArg())
|
||||||
|
matcher.register('GstRTSPUrl*', GstRTSPUrlArg())
|
||||||
|
|
||||||
arg = PointerArg('gpointer', 'G_TYPE_POINTER')
|
arg = PointerArg('gpointer', 'G_TYPE_POINTER')
|
||||||
matcher.register('GstClockID', arg)
|
matcher.register('GstClockID', arg)
|
||||||
|
|
|
@ -1,6 +1,63 @@
|
||||||
|
;; From gst/rtsp-server/rtsp-server.h
|
||||||
|
|
||||||
(define-object Server
|
(define-object Server
|
||||||
(in-module "Gst.RTSPServer")
|
(in-module "Gst.RTSPServer")
|
||||||
(parent "GObject")
|
(parent "GObject")
|
||||||
(c-name "GstRTSPServer")
|
(c-name "GstRTSPServer")
|
||||||
(gtype-id "GST_TYPE_RTSP_SERVER")
|
(gtype-id "GST_TYPE_RTSP_SERVER")
|
||||||
)
|
)
|
||||||
|
|
||||||
|
;; From gst/rtsp-server/rtsp-media-mapping.h
|
||||||
|
|
||||||
|
(define-object MediaMapping
|
||||||
|
(in-module "Gst.RTSPServer")
|
||||||
|
(parent "GObject")
|
||||||
|
(c-name "GstRTSPMediaMapping")
|
||||||
|
(gtype-id "GST_TYPE_RTSP_MEDIA_MAPPING")
|
||||||
|
)
|
||||||
|
|
||||||
|
;; From gst/rtsp-server/rtsp-media-factory.h
|
||||||
|
|
||||||
|
(define-object MediaFactory
|
||||||
|
(in-module "Gst.RTSPServer")
|
||||||
|
(parent "GObject")
|
||||||
|
(c-name "GstRTSPMediaFactory")
|
||||||
|
(gtype-id "GST_TYPE_RTSP_MEDIA_FACTORY")
|
||||||
|
)
|
||||||
|
|
||||||
|
;; From gst/rtsp-server/rtsp-media.h
|
||||||
|
|
||||||
|
(define-object Media
|
||||||
|
(in-module "Gst.RTSPServer")
|
||||||
|
(parent "GObject")
|
||||||
|
(c-name "GstRTSPMedia")
|
||||||
|
(gtype-id "GST_TYPE_RTSP_MEDIA")
|
||||||
|
)
|
||||||
|
|
||||||
|
;; From gst/rtsp-server/rtsp-session-pool.h
|
||||||
|
|
||||||
|
(define-object SessionPool
|
||||||
|
(in-module "Gst")
|
||||||
|
(parent "GObject")
|
||||||
|
(c-name "GstRTSPSessionPool")
|
||||||
|
(gtype-id "GST_TYPE_RTSP_SESSION_POOL")
|
||||||
|
)
|
||||||
|
|
||||||
|
;; From gst/rtsp-server/rtsp-session.h
|
||||||
|
|
||||||
|
(define-object Session
|
||||||
|
(in-module "Gst")
|
||||||
|
(parent "GObject")
|
||||||
|
(c-name "GstRTSPSession")
|
||||||
|
(gtype-id "GST_TYPE_RTSP_SESSION")
|
||||||
|
)
|
||||||
|
|
||||||
|
;; From gst/rtsp-server/rtsp-client.h
|
||||||
|
|
||||||
|
(define-object Client
|
||||||
|
(in-module "Gst")
|
||||||
|
(parent "GObject")
|
||||||
|
(c-name "GstRTSPClient")
|
||||||
|
(gtype-id "GST_TYPE_RTSP_CLIENT")
|
||||||
|
)
|
||||||
|
|
||||||
|
|
|
@ -1,11 +1,99 @@
|
||||||
(include "rtspserver-types.defs")
|
(include "rtspserver-types.defs")
|
||||||
|
|
||||||
|
;; From gst/rtsp-server/rtsp-server.h
|
||||||
|
|
||||||
(define-function rtsp_server_new
|
(define-function rtsp_server_new
|
||||||
(c-name "gst_rtsp_server_new")
|
(c-name "gst_rtsp_server_new")
|
||||||
(is-constructor-of "GstRTSPServer")
|
(is-constructor-of "GstRTSPServer")
|
||||||
(return-type "GstRTSPServer*")
|
(return-type "GstRTSPServer*")
|
||||||
)
|
)
|
||||||
|
|
||||||
|
(define-method set_address
|
||||||
|
(of-object "GstRTSPServer")
|
||||||
|
(c-name "gst_rtsp_server_set_address")
|
||||||
|
(parameters
|
||||||
|
'("const-gchar*" "address")
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
|
(define-method get_address
|
||||||
|
(of-object "GstRTSPServer")
|
||||||
|
(c-name "gst_rtsp_server_get_address")
|
||||||
|
(return-type "const-gchar*")
|
||||||
|
)
|
||||||
|
|
||||||
|
(define-method set_service
|
||||||
|
(of-object "GstRTSPServer")
|
||||||
|
(c-name "gst_rtsp_server_set_service")
|
||||||
|
(parameters
|
||||||
|
'("const-gchar*" "service")
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
|
(define-method get_service
|
||||||
|
(of-object "GstRTSPServer")
|
||||||
|
(c-name "gst_rtsp_server_get_service")
|
||||||
|
(return-type "const-gchar*")
|
||||||
|
)
|
||||||
|
|
||||||
|
(define-method set_backlog
|
||||||
|
(of-object "GstRTSPServer")
|
||||||
|
(c-name "gst_rtsp_server_set_backlog")
|
||||||
|
(parameters
|
||||||
|
'("gint" "backlog")
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
|
(define-method get_backlog
|
||||||
|
(of-object "GstRTSPServer")
|
||||||
|
(c-name "gst_rtsp_server_get_backlog")
|
||||||
|
(return-type "gint")
|
||||||
|
)
|
||||||
|
|
||||||
|
(define-method set_session_pool
|
||||||
|
(of-object "GstRTSPServer")
|
||||||
|
(c-name "gst_rtsp_server_set_session_pool")
|
||||||
|
(parameters
|
||||||
|
'("GstRTSPSessionPool*" "pool")
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
|
(define-method get_session_pool
|
||||||
|
(of-object "GstRTSPServer")
|
||||||
|
(c-name "gst_rtsp_server_get_session_pool")
|
||||||
|
(return-type "GstRTSPSessionPool*")
|
||||||
|
)
|
||||||
|
|
||||||
|
(define-method set_media_mapping
|
||||||
|
(of-object "GstRTSPServer")
|
||||||
|
(c-name "gst_rtsp_server_set_media_mapping")
|
||||||
|
(parameters
|
||||||
|
'("GstRTSPMediaMapping*" "mapping")
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
|
(define-method get_media_mapping
|
||||||
|
(of-object "GstRTSPServer")
|
||||||
|
(c-name "gst_rtsp_server_get_media_mapping")
|
||||||
|
(return-type "GstRTSPMediaMapping*")
|
||||||
|
)
|
||||||
|
|
||||||
|
(define-function io_func
|
||||||
|
(c-name "gst_rtsp_server_io_func")
|
||||||
|
(return-type "gboolean")
|
||||||
|
(parameters
|
||||||
|
'("GIOChannel*" "channel")
|
||||||
|
'("GIOCondition" "condition")
|
||||||
|
'("GstRTSPServer*" "server")
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
|
(define-method get_io_channel
|
||||||
|
(of-object "GstRTSPServer")
|
||||||
|
(c-name "gst_rtsp_server_get_io_channel")
|
||||||
|
(return-type "GIOChannel*")
|
||||||
|
)
|
||||||
|
|
||||||
(define-method attach
|
(define-method attach
|
||||||
(of-object "GstRTSPServer")
|
(of-object "GstRTSPServer")
|
||||||
(c-name "gst_rtsp_server_attach")
|
(c-name "gst_rtsp_server_attach")
|
||||||
|
@ -14,3 +102,298 @@
|
||||||
'("GMainContext*" "context")
|
'("GMainContext*" "context")
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
|
|
||||||
|
(define-method create_watch
|
||||||
|
(of-object "GstRTSPServer")
|
||||||
|
(c-name "gst_rtsp_server_create_watch")
|
||||||
|
(return-type "GSource*")
|
||||||
|
)
|
||||||
|
|
||||||
|
;; From gst/rtsp-server/rtsp-media-mapping.h
|
||||||
|
|
||||||
|
(define-function rtsp_media_mapping_new
|
||||||
|
(c-name "gst_rtsp_media_mapping_new")
|
||||||
|
(is-constructor-of "GstRTSPMediaMapping")
|
||||||
|
(return-type "GstRTSPMediaMapping*")
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
;; TODO define const-GstRTSPUrl* on arg-types.py
|
||||||
|
(define-method find_factory
|
||||||
|
(of-object "GstRTSPMediaMapping")
|
||||||
|
(c-name "gst_rtsp_media_mapping_find_factory")
|
||||||
|
(return-type "GstRTSPMediaFactory*")
|
||||||
|
(parameters
|
||||||
|
'("const-GstRTSPUrl*" "url")
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
|
(define-method add_factory
|
||||||
|
(of-object "GstRTSPMediaMapping")
|
||||||
|
(c-name "gst_rtsp_media_mapping_add_factory")
|
||||||
|
(parameters
|
||||||
|
'("const-gchar*" "path")
|
||||||
|
'("GstRTSPMediaFactory*" "factory")
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
|
(define-method remove_factory
|
||||||
|
(of-object "GstRTSPMediaMapping")
|
||||||
|
(c-name "gst_rtsp_media_mapping_remove_factory")
|
||||||
|
(parameters
|
||||||
|
'("const-gchar*" "path")
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
|
;; From gst/rtsp-server/rtsp-media-factory.h
|
||||||
|
|
||||||
|
(define-function rtsp_media_factory_new
|
||||||
|
(c-name "gst_rtsp_media_factory_new")
|
||||||
|
(is-constructor-of "GstRTSMediaFactory")
|
||||||
|
(return-type "GstRTSPMediaFactory*")
|
||||||
|
)
|
||||||
|
|
||||||
|
(define-method set_launch
|
||||||
|
(of-object "GstRTSPMediaFactory")
|
||||||
|
(c-name "gst_rtsp_media_factory_set_launch")
|
||||||
|
(parameters
|
||||||
|
'("gchar*" "launch")
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
|
(define-method get_launch
|
||||||
|
(of-object "GstRTSPMediaFactory")
|
||||||
|
(c-name "gst_rtsp_media_factory_get_launch")
|
||||||
|
(return-type "gchar*")
|
||||||
|
)
|
||||||
|
|
||||||
|
(define-method set_shared
|
||||||
|
(of-object "GstRTSPMediaFactory")
|
||||||
|
(c-name "gst_rtsp_media_factory_set_shared")
|
||||||
|
(parameters
|
||||||
|
'("gboolean" "shared")
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
|
(define-method is_shared
|
||||||
|
(of-object "GstRTSPMediaFactory")
|
||||||
|
(c-name "gst_rtsp_media_factory_is_shared")
|
||||||
|
(return-type "gboolean")
|
||||||
|
)
|
||||||
|
|
||||||
|
(define-method set_eos_shutdown
|
||||||
|
(of-object "GstRTSPMediaFactory")
|
||||||
|
(c-name "gst_rtsp_media_factory_set_eos_shutdown")
|
||||||
|
(parameters
|
||||||
|
'("gboolean" "eos_shutdown")
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
|
(define-method is_eos_shutdown
|
||||||
|
(of-object "GstRTSPMediaFactory")
|
||||||
|
(c-name "gst_rtsp_media_factory_is_eos_shutdown")
|
||||||
|
(return-type "gboolean")
|
||||||
|
)
|
||||||
|
|
||||||
|
;; TODO define const-GstRTSPUrl* on arg-types.py
|
||||||
|
(define-method construct
|
||||||
|
(of-object "GstRTSPMediaFactory")
|
||||||
|
(c-name "gst_rtsp_media_factory_construct")
|
||||||
|
(return-type "GstRTSPMedia*")
|
||||||
|
(parameters
|
||||||
|
'("const-GstRTSPUrl*" "url")
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
|
(define-method collect_streams
|
||||||
|
(of-object "GstRTSPMediaFactory")
|
||||||
|
(c-name "gst_rtsp_media_factory_collect_streams")
|
||||||
|
(parameters
|
||||||
|
'("const-GstRTSPUrl*" "url")
|
||||||
|
'("GstRTSPMedia*" "media")
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
|
(define-virtual get_element
|
||||||
|
(of-object "GstRTSPMediaFactory")
|
||||||
|
(parameters
|
||||||
|
'("const-GstRTSPUrl*" "url")
|
||||||
|
)
|
||||||
|
(return-type "GstElement*")
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
(define-virtual construct
|
||||||
|
(of-object "GstRTSPMediaFactory")
|
||||||
|
(parameters
|
||||||
|
'("const-GstRTSPUrl*" "url")
|
||||||
|
)
|
||||||
|
(return-type "GstRTSPMedia*")
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
(define-virtual configure
|
||||||
|
(of-object "GstRTSPMediaFactory")
|
||||||
|
(parameters
|
||||||
|
'("GstRTSPMedia*" "media")
|
||||||
|
)
|
||||||
|
(return-type "none")
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
(define-virtual create_pipeline
|
||||||
|
(of-object "GstRTSPMediaFactory")
|
||||||
|
(parameters
|
||||||
|
'("GstRTSPMedia*" "media")
|
||||||
|
)
|
||||||
|
(return-type "GstElement*")
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
;; From gst/rtsp-server/rtsp-session-pool.h
|
||||||
|
|
||||||
|
(define-function gst_rtsp_session_pool_new
|
||||||
|
(c-name "gst_rtsp_session_pool_new")
|
||||||
|
(is-constructor-of "GstRTSPSessionPool")
|
||||||
|
(return-type "GstRTSPSessionPool*")
|
||||||
|
)
|
||||||
|
|
||||||
|
(define-method set_max_sessions
|
||||||
|
(of-object "GstRTSPSessionPool")
|
||||||
|
(c-name "gst_rtsp_session_pool_set_max_sessions")
|
||||||
|
(return-type "none")
|
||||||
|
(parameters
|
||||||
|
'("guint" "max")
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
|
(define-method get_max_sessions
|
||||||
|
(of-object "GstRTSPSessionPool")
|
||||||
|
(c-name "gst_rtsp_session_pool_get_max_sessions")
|
||||||
|
(return-type "guint")
|
||||||
|
)
|
||||||
|
|
||||||
|
(define-method get_n_sessions
|
||||||
|
(of-object "GstRTSPSessionPool")
|
||||||
|
(c-name "gst_rtsp_session_pool_get_n_sessions")
|
||||||
|
(return-type "guint")
|
||||||
|
)
|
||||||
|
|
||||||
|
(define-method create
|
||||||
|
(of-object "GstRTSPSessionPool")
|
||||||
|
(c-name "gst_rtsp_session_pool_create")
|
||||||
|
(return-type "GstRTSPSession*")
|
||||||
|
)
|
||||||
|
|
||||||
|
(define-method find
|
||||||
|
(of-object "GstRTSPSessionPool")
|
||||||
|
(c-name "gst_rtsp_session_pool_find")
|
||||||
|
(return-type "GstRTSPSession*")
|
||||||
|
(parameters
|
||||||
|
'("const-gchar*" "sessionid")
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
|
(define-method remove
|
||||||
|
(of-object "GstRTSPSessionPool")
|
||||||
|
(c-name "gst_rtsp_session_pool_remove")
|
||||||
|
(return-type "gboolean")
|
||||||
|
(parameters
|
||||||
|
'("GstRTSPSession*" "sess")
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
|
(define-method filter
|
||||||
|
(of-object "GstRTSPSessionPool")
|
||||||
|
(c-name "gst_rtsp_session_pool_filter")
|
||||||
|
(return-type "GList*")
|
||||||
|
(parameters
|
||||||
|
'("GstRTSPSessionFilterFunc" "func")
|
||||||
|
'("gpointer" "user_data")
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
|
(define-method cleanup
|
||||||
|
(of-object "GstRTSPSessionPool")
|
||||||
|
(c-name "gst_rtsp_session_pool_cleanup")
|
||||||
|
(return-type "guint")
|
||||||
|
)
|
||||||
|
|
||||||
|
(define-method create_watch
|
||||||
|
(of-object "GstRTSPSessionPool")
|
||||||
|
(c-name "gst_rtsp_session_pool_create_watch")
|
||||||
|
(return-type "GSource*")
|
||||||
|
)
|
||||||
|
|
||||||
|
;; From gst/rtsp-server/rtsp-client.h
|
||||||
|
|
||||||
|
(define-function gst_rtsp_client_new
|
||||||
|
(c-name "gst_rtsp_client_new")
|
||||||
|
(is-constructor-of "GstRTSPClient")
|
||||||
|
(return-type "GstRTSPClient*")
|
||||||
|
)
|
||||||
|
|
||||||
|
(define-method set_session_pool
|
||||||
|
(of-object "GstRTSPClient")
|
||||||
|
(c-name "gst_rtsp_client_set_session_pool")
|
||||||
|
(return-type "none")
|
||||||
|
(parameters
|
||||||
|
'("GstRTSPSessionPool*" "pool")
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
|
(define-method get_session_pool
|
||||||
|
(of-object "GstRTSPClient")
|
||||||
|
(c-name "gst_rtsp_client_get_session_pool")
|
||||||
|
(return-type "GstRTSPSessionPool*")
|
||||||
|
)
|
||||||
|
|
||||||
|
(define-method set_media_mapping
|
||||||
|
(of-object "GstRTSPClient")
|
||||||
|
(c-name "gst_rtsp_client_set_media_mapping")
|
||||||
|
(return-type "none")
|
||||||
|
(parameters
|
||||||
|
'("GstRTSPMediaMapping*" "mapping")
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
|
(define-method get_media_mapping
|
||||||
|
(of-object "GstRTSPClient")
|
||||||
|
(c-name "gst_rtsp_client_get_media_mapping")
|
||||||
|
(return-type "GstRTSPMediaMapping*")
|
||||||
|
)
|
||||||
|
|
||||||
|
(define-method accept
|
||||||
|
(of-object "GstRTSPClient")
|
||||||
|
(c-name "gst_rtsp_client_accept")
|
||||||
|
(return-type "gboolean")
|
||||||
|
(parameters
|
||||||
|
'("GIOChannel*" "channel")
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
|
;; From bindings/python/rtsp-params.h
|
||||||
|
|
||||||
|
(define-function gst_rtsp_params_set
|
||||||
|
(c-name "gst_rtsp_params_set")
|
||||||
|
(return-type "GstRTSPResult")
|
||||||
|
(parameters
|
||||||
|
'("GstRTSPClient*" "client")
|
||||||
|
'("GstRTSPUrl*" "uri")
|
||||||
|
'("GstRTSPSession*" "session")
|
||||||
|
'("GstRTSPMessage*" "request")
|
||||||
|
'("GstRTSPMessage*" "response")
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
|
(define-function gst_rtsp_params_get
|
||||||
|
(c-name "gst_rtsp_params_get")
|
||||||
|
(return-type "GstRTSPResult")
|
||||||
|
(parameters
|
||||||
|
'("GstRTSPClient*" "client")
|
||||||
|
'("GstRTSPUrl*" "uri")
|
||||||
|
'("GstRTSPSession*" "session")
|
||||||
|
'("GstRTSPMessage*" "request")
|
||||||
|
'("GstRTSPMessage*" "response")
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
|
@ -5,6 +5,11 @@ headers
|
||||||
#define NO_IMPORT_PYGOBJECT
|
#define NO_IMPORT_PYGOBJECT
|
||||||
#include <pygobject.h>
|
#include <pygobject.h>
|
||||||
|
|
||||||
|
#include <gst/gst.h>
|
||||||
|
#include <gst/rtsp-server/rtsp-server.h>
|
||||||
|
|
||||||
|
#include <glib.h>
|
||||||
|
|
||||||
#ifdef HAVE_CONFIG_H
|
#ifdef HAVE_CONFIG_H
|
||||||
# include <config.h>
|
# include <config.h>
|
||||||
#endif
|
#endif
|
||||||
|
@ -24,7 +29,6 @@ typedef struct {
|
||||||
%%
|
%%
|
||||||
import gobject.GObject as PyGObject_Type
|
import gobject.GObject as PyGObject_Type
|
||||||
import gobject.MainContext as PyGMainContext_Type
|
import gobject.MainContext as PyGMainContext_Type
|
||||||
|
|
||||||
%%
|
%%
|
||||||
override gst_rtsp_server_attach kwargs
|
override gst_rtsp_server_attach kwargs
|
||||||
static PyObject *
|
static PyObject *
|
||||||
|
@ -50,3 +54,14 @@ _wrap_gst_rtsp_server_attach (PyGObject *self,
|
||||||
|
|
||||||
return PyLong_FromLong (res);
|
return PyLong_FromLong (res);
|
||||||
}
|
}
|
||||||
|
%%
|
||||||
|
override gst_rtsp_server_create_watch kwargs
|
||||||
|
static PyObject *
|
||||||
|
_wrap_gst_rtsp_server_create_watch(PyGObject *self, PyObject *args, PyObject *keywords)
|
||||||
|
{
|
||||||
|
GSource *ret;
|
||||||
|
pyg_begin_allow_threads;
|
||||||
|
ret = gst_rtsp_server_create_watch(GST_RTSP_SERVER(self->obj));
|
||||||
|
pyg_end_allow_threads;
|
||||||
|
return pygobject_new((GObject *)ret);
|
||||||
|
}
|
||||||
|
|
130
bindings/python/test.py
Normal file
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
|
dnl Add parameters for aclocal
|
||||||
AC_SUBST(ACLOCAL_AMFLAGS, "-I m4 -I common/m4")
|
AC_SUBST(ACLOCAL_AMFLAGS, "-I m4 -I common/m4")
|
||||||
|
AC_CONFIG_MACRO_DIR([m4])
|
||||||
|
|
||||||
dnl set up gettext
|
dnl set up gettext
|
||||||
dnl the version check needs to stay here because autopoint greps for it
|
dnl the version check needs to stay here because autopoint greps for it
|
||||||
|
@ -67,6 +68,8 @@ AG_GST_ARG_GCOV
|
||||||
AG_GST_ARG_WITH_PACKAGE_NAME
|
AG_GST_ARG_WITH_PACKAGE_NAME
|
||||||
AG_GST_ARG_WITH_PACKAGE_ORIGIN
|
AG_GST_ARG_WITH_PACKAGE_ORIGIN
|
||||||
|
|
||||||
|
AG_GST_PKG_CONFIG_PATH
|
||||||
|
|
||||||
dnl *** checks for platform ***
|
dnl *** checks for platform ***
|
||||||
|
|
||||||
dnl * hardware/architecture *
|
dnl * hardware/architecture *
|
||||||
|
@ -77,6 +80,16 @@ dnl find a compiler
|
||||||
AC_PROG_CC
|
AC_PROG_CC
|
||||||
AM_PROG_CC_C_O
|
AM_PROG_CC_C_O
|
||||||
|
|
||||||
|
AC_PATH_PROG(VALGRIND_PATH, valgrind, no)
|
||||||
|
AM_CONDITIONAL(HAVE_VALGRIND, test ! "x$VALGRIND_PATH" = "xno")
|
||||||
|
|
||||||
|
dnl check for gobject-introspection
|
||||||
|
GOBJECT_INTROSPECTION_CHECK([0.6.3])
|
||||||
|
|
||||||
|
dnl check for documentation tools
|
||||||
|
AG_GST_DOCBOOK_CHECK
|
||||||
|
GTK_DOC_CHECK([1.3])
|
||||||
|
|
||||||
dnl check for python
|
dnl check for python
|
||||||
AM_PATH_PYTHON
|
AM_PATH_PYTHON
|
||||||
AC_MSG_CHECKING(for python >= 2.3)
|
AC_MSG_CHECKING(for python >= 2.3)
|
||||||
|
@ -89,49 +102,33 @@ sys.exit(0)"
|
||||||
|
|
||||||
if $PYTHON -c "$prog" 1>&AC_FD_CC 2>&AC_FD_CC
|
if $PYTHON -c "$prog" 1>&AC_FD_CC 2>&AC_FD_CC
|
||||||
then
|
then
|
||||||
|
HAVE_PYTHON=yes
|
||||||
AC_MSG_RESULT(okay)
|
AC_MSG_RESULT(okay)
|
||||||
else
|
else
|
||||||
AC_MSG_ERROR(too old)
|
HAVE_PYTHON=no
|
||||||
|
AC_MSG_RESULT(no python)
|
||||||
fi
|
fi
|
||||||
AM_CHECK_PYTHON_HEADERS(,[AC_MSG_ERROR(could not find Python headers)])
|
|
||||||
|
|
||||||
AC_PATH_PROG(VALGRIND_PATH, valgrind, no)
|
AM_CHECK_PYTHON_HEADERS([HAVE_PYTHON_HEADERS=yes],[HAVE_PYTHON_HEADERS=no])
|
||||||
AM_CONDITIONAL(HAVE_VALGRIND, test ! "x$VALGRIND_PATH" = "xno")
|
|
||||||
|
|
||||||
dnl check for gobject-introspection
|
|
||||||
GOBJECT_INTROSPECTION_CHECK([0.6.3])
|
|
||||||
|
|
||||||
dnl check for documentation tools
|
|
||||||
AG_GST_DOCBOOK_CHECK
|
|
||||||
GTK_DOC_CHECK([1.3])
|
|
||||||
|
|
||||||
AC_SUBST(PYGOBJECT_REQ, 2.11.2)
|
|
||||||
|
|
||||||
dnl check for pygobject (optional, used in the bindings)
|
dnl check for pygobject (optional, used in the bindings)
|
||||||
|
PYGOBJECT_REQ=2.11.2
|
||||||
PKG_CHECK_MODULES(PYGOBJECT, pygobject-2.0 >= $PYGOBJECT_REQ,
|
PKG_CHECK_MODULES(PYGOBJECT, pygobject-2.0 >= $PYGOBJECT_REQ,
|
||||||
[
|
[HAVE_PYGOBJECT="yes"], [HAVE_PYGOBJECT="no"])
|
||||||
HAVE_PYGOBJECT="yes"
|
|
||||||
],
|
|
||||||
[
|
|
||||||
HAVE_PYGOBJECT="no"
|
|
||||||
])
|
|
||||||
AC_SUBST(PYGOBJECT_CFLAGS)
|
AC_SUBST(PYGOBJECT_CFLAGS)
|
||||||
|
|
||||||
dnl check for gst-python
|
dnl check for gst-python
|
||||||
PKG_CHECK_MODULES(PYGST, gst-python-0.10,
|
PKG_CHECK_MODULES(PYGST, gst-python-0.10,
|
||||||
[
|
[HAVE_PYGST="yes"], [HAVE_PYGST="no"])
|
||||||
HAVE_PYGST="yes"
|
|
||||||
],
|
|
||||||
[
|
|
||||||
HAVE_PYGST="no"
|
|
||||||
])
|
|
||||||
|
|
||||||
if test "x$HAVE_PYGST" = "xyes"; then
|
if test "x$HAVE_PYGST" = "xyes"; then
|
||||||
PYGST_DEFSDIR=`pkg-config gst-python-0.10 --variable=defsdir`
|
PYGST_DEFSDIR=`pkg-config gst-python-0.10 --variable=defsdir`
|
||||||
fi
|
fi
|
||||||
AC_SUBST(PYGST_DEFSDIR, $PYGST_DEFSDIR)
|
AC_SUBST(PYGST_DEFSDIR, $PYGST_DEFSDIR)
|
||||||
|
|
||||||
if test "x$HAVE_PYTHON_HEADERS" = "xyes" -a \
|
if test \
|
||||||
|
"x$HAVE_PYTHON" = "xyes" -a \
|
||||||
|
"x$HAVE_PYTHON_HEADERS" = "xyes" -a \
|
||||||
"x$HAVE_PYGOBJECT" = "xyes" -a \
|
"x$HAVE_PYGOBJECT" = "xyes" -a \
|
||||||
"x$HAVE_PYGST" = "xyes"; then
|
"x$HAVE_PYGST" = "xyes"; then
|
||||||
HAVE_PYTHON_BINDINGS="yes"
|
HAVE_PYTHON_BINDINGS="yes"
|
||||||
|
@ -286,10 +283,10 @@ Makefile
|
||||||
gst-rtsp.spec
|
gst-rtsp.spec
|
||||||
common/Makefile
|
common/Makefile
|
||||||
common/m4/Makefile
|
common/m4/Makefile
|
||||||
m4/Makefile
|
|
||||||
gst/Makefile
|
gst/Makefile
|
||||||
gst/rtsp-server/Makefile
|
gst/rtsp-server/Makefile
|
||||||
examples/Makefile
|
examples/Makefile
|
||||||
|
tests/Makefile
|
||||||
bindings/Makefile
|
bindings/Makefile
|
||||||
bindings/python/Makefile
|
bindings/python/Makefile
|
||||||
bindings/python/codegen/Makefile
|
bindings/python/codegen/Makefile
|
||||||
|
|
1
docs/.gitignore
vendored
Normal file
1
docs/.gitignore
vendored
Normal file
|
@ -0,0 +1 @@
|
||||||
|
version.entities
|
|
@ -9,3 +9,12 @@ DIST_SUBDIRS = libs
|
||||||
|
|
||||||
EXTRA_DIST = \
|
EXTRA_DIST = \
|
||||||
version.entities.in
|
version.entities.in
|
||||||
|
|
||||||
|
upload:
|
||||||
|
@if test "x$(SUBDIRS)" != x; then \
|
||||||
|
for a in $(SUBDIRS); do \
|
||||||
|
cd $$a; \
|
||||||
|
make upload; \
|
||||||
|
cd ..; \
|
||||||
|
done; \
|
||||||
|
fi
|
||||||
|
|
22
docs/libs/.gitignore
vendored
Normal file
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
|
# for upload-doc.mak
|
||||||
DOC=$(MODULE)
|
DOC=$(MODULE)
|
||||||
FORMATS=html ps pdf
|
FORMATS=html
|
||||||
html: html-build.stamp
|
html: html-build.stamp
|
||||||
include $(top_srcdir)/common/upload-doc.mak
|
include $(top_srcdir)/common/upload-doc.mak
|
||||||
|
|
||||||
|
|
|
@ -9,15 +9,17 @@
|
||||||
<bookinfo>
|
<bookinfo>
|
||||||
<title>GStreamer RTSP Server Reference Manual</title>
|
<title>GStreamer RTSP Server Reference Manual</title>
|
||||||
<releaseinfo>
|
<releaseinfo>
|
||||||
for GStreamer RTSP Server &GST_MAJORMINOR;
|
for GStreamer RTSP Server &GST_VERSION;
|
||||||
</releaseinfo>
|
</releaseinfo>
|
||||||
</bookinfo>
|
</bookinfo>
|
||||||
|
|
||||||
<chapter>
|
<chapter>
|
||||||
<xi:include href="xml/rtsp-client.xml"/>
|
<xi:include href="xml/rtsp-client.xml"/>
|
||||||
<xi:include href="xml/rtsp-media-factory.xml"/>
|
<xi:include href="xml/rtsp-media-factory.xml"/>
|
||||||
|
<xi:include href="xml/rtsp-media-factory-uri.xml"/>
|
||||||
<xi:include href="xml/rtsp-media-mapping.xml"/>
|
<xi:include href="xml/rtsp-media-mapping.xml"/>
|
||||||
<xi:include href="xml/rtsp-media.xml"/>
|
<xi:include href="xml/rtsp-media.xml"/>
|
||||||
|
<xi:include href="xml/rtsp-auth.xml"/>
|
||||||
<xi:include href="xml/rtsp-params.xml"/>
|
<xi:include href="xml/rtsp-params.xml"/>
|
||||||
<xi:include href="xml/rtsp-sdp.xml"/>
|
<xi:include href="xml/rtsp-sdp.xml"/>
|
||||||
<xi:include href="xml/rtsp-server.xml"/>
|
<xi:include href="xml/rtsp-server.xml"/>
|
||||||
|
|
|
@ -45,6 +45,30 @@ GST_IS_RTSP_MEDIA_FACTORY_CLASS
|
||||||
GST_RTSP_MEDIA_FACTORY_GET_CLASS
|
GST_RTSP_MEDIA_FACTORY_GET_CLASS
|
||||||
</SECTION>
|
</SECTION>
|
||||||
|
|
||||||
|
<SECTION>
|
||||||
|
<FILE>rtsp-media-factory-uri</FILE>
|
||||||
|
<TITLE>GstRTSPMediaFactoryURI</TITLE>
|
||||||
|
GST_RTSP_MEDIA_FACTORY_GET_LOCK
|
||||||
|
GST_RTSP_MEDIA_FACTORY_LOCK
|
||||||
|
GST_RTSP_MEDIA_FACTORY_UNLOCK
|
||||||
|
GstRTSPMediaFactoryURI
|
||||||
|
GstRTSPMediaFactoryURIClass
|
||||||
|
gst_rtsp_media_factory_uri_new
|
||||||
|
gst_rtsp_media_factory_uri_set_uri
|
||||||
|
gst_rtsp_media_factory_uri_get_uri
|
||||||
|
<SUBSECTION Standard>
|
||||||
|
GST_IS_RTSP_MEDIA_FACTORY_URI
|
||||||
|
GST_IS_RTSP_MEDIA_FACTORY_URI_CLASS
|
||||||
|
GST_RTSP_MEDIA_FACTORY_URI
|
||||||
|
GST_RTSP_MEDIA_FACTORY_URI_CAST
|
||||||
|
GST_RTSP_MEDIA_FACTORY_URI_CLASS
|
||||||
|
GST_RTSP_MEDIA_FACTORY_URI_CLASS_CAST
|
||||||
|
GST_RTSP_MEDIA_FACTORY_URI_GET_CLASS
|
||||||
|
GST_TYPE_RTSP_MEDIA_FACTORY_URI
|
||||||
|
gst_rtsp_media_factory_uri_get_type
|
||||||
|
</SECTION>
|
||||||
|
|
||||||
|
|
||||||
<SECTION>
|
<SECTION>
|
||||||
<FILE>rtsp-media</FILE>
|
<FILE>rtsp-media</FILE>
|
||||||
<TITLE>GstRTSPMedia</TITLE>
|
<TITLE>GstRTSPMedia</TITLE>
|
||||||
|
@ -53,6 +77,7 @@ GstRTSPMedia
|
||||||
GstRTSPMediaClass
|
GstRTSPMediaClass
|
||||||
GstRTSPMediaTrans
|
GstRTSPMediaTrans
|
||||||
GstRTSPSendFunc
|
GstRTSPSendFunc
|
||||||
|
GstRTSPSendListFunc
|
||||||
GstRTSPKeepAliveFunc
|
GstRTSPKeepAliveFunc
|
||||||
GstRTSPMediaStatus
|
GstRTSPMediaStatus
|
||||||
gst_rtsp_media_new
|
gst_rtsp_media_new
|
||||||
|
@ -70,6 +95,7 @@ gst_rtsp_media_unprepare
|
||||||
gst_rtsp_media_n_streams
|
gst_rtsp_media_n_streams
|
||||||
gst_rtsp_media_get_stream
|
gst_rtsp_media_get_stream
|
||||||
gst_rtsp_media_seek
|
gst_rtsp_media_seek
|
||||||
|
gst_rtsp_media_get_range_string
|
||||||
gst_rtsp_media_stream_rtp
|
gst_rtsp_media_stream_rtp
|
||||||
gst_rtsp_media_stream_rtcp
|
gst_rtsp_media_stream_rtcp
|
||||||
gst_rtsp_media_set_state
|
gst_rtsp_media_set_state
|
||||||
|
@ -103,6 +129,8 @@ gst_rtsp_server_set_session_pool
|
||||||
gst_rtsp_server_get_session_pool
|
gst_rtsp_server_get_session_pool
|
||||||
gst_rtsp_server_set_media_mapping
|
gst_rtsp_server_set_media_mapping
|
||||||
gst_rtsp_server_get_media_mapping
|
gst_rtsp_server_get_media_mapping
|
||||||
|
gst_rtsp_server_get_auth
|
||||||
|
gst_rtsp_server_set_auth
|
||||||
gst_rtsp_server_io_func
|
gst_rtsp_server_io_func
|
||||||
gst_rtsp_server_get_io_channel
|
gst_rtsp_server_get_io_channel
|
||||||
gst_rtsp_server_create_watch
|
gst_rtsp_server_create_watch
|
||||||
|
@ -186,16 +214,42 @@ GST_IS_RTSP_SESSION_CLASS
|
||||||
GST_RTSP_SESSION_GET_CLASS
|
GST_RTSP_SESSION_GET_CLASS
|
||||||
</SECTION>
|
</SECTION>
|
||||||
|
|
||||||
|
<SECTION>
|
||||||
|
<FILE>rtsp-auth</FILE>
|
||||||
|
<TITLE>GstRTSPAuth</TITLE>
|
||||||
|
GstRTSPAuth
|
||||||
|
GstRTSPAuthClass
|
||||||
|
gst_rtsp_auth_new
|
||||||
|
gst_rtsp_auth_set_basic
|
||||||
|
gst_rtsp_auth_setup_auth
|
||||||
|
gst_rtsp_auth_check_method
|
||||||
|
gst_rtsp_auth_make_basic
|
||||||
|
<SUBSECTION Standard>
|
||||||
|
GST_IS_RTSP_AUTH
|
||||||
|
GST_IS_RTSP_AUTH_CLASS
|
||||||
|
GST_RTSP_AUTH
|
||||||
|
GST_RTSP_AUTH_CAST
|
||||||
|
GST_RTSP_AUTH_CLASS
|
||||||
|
GST_RTSP_AUTH_CLASS_CAST
|
||||||
|
GST_RTSP_AUTH_GET_CLASS
|
||||||
|
GST_TYPE_RTSP_AUTH
|
||||||
|
gst_rtsp_auth_get_type
|
||||||
|
</SECTION>
|
||||||
|
|
||||||
<SECTION>
|
<SECTION>
|
||||||
<FILE>rtsp-client</FILE>
|
<FILE>rtsp-client</FILE>
|
||||||
<TITLE>GstRTSPClient</TITLE>
|
<TITLE>GstRTSPClient</TITLE>
|
||||||
GstRTSPClient
|
GstRTSPClient
|
||||||
GstRTSPClientClass
|
GstRTSPClientClass
|
||||||
gst_rtsp_client_new
|
gst_rtsp_client_new
|
||||||
|
gst_rtsp_client_set_server
|
||||||
|
gst_rtsp_client_get_server
|
||||||
gst_rtsp_client_set_session_pool
|
gst_rtsp_client_set_session_pool
|
||||||
gst_rtsp_client_get_session_pool
|
gst_rtsp_client_get_session_pool
|
||||||
gst_rtsp_client_set_media_mapping
|
gst_rtsp_client_set_media_mapping
|
||||||
gst_rtsp_client_get_media_mapping
|
gst_rtsp_client_get_media_mapping
|
||||||
|
gst_rtsp_client_set_auth
|
||||||
|
gst_rtsp_client_get_auth
|
||||||
gst_rtsp_client_accept
|
gst_rtsp_client_accept
|
||||||
<SUBSECTION Standard>
|
<SUBSECTION Standard>
|
||||||
GST_RTSP_CLIENT_CLASS
|
GST_RTSP_CLIENT_CLASS
|
||||||
|
|
|
@ -1,4 +1,5 @@
|
||||||
#include <gst/gst.h>
|
#include <gst/gst.h>
|
||||||
|
gst_rtsp_auth_get_type
|
||||||
gst_rtsp_media_mapping_get_type
|
gst_rtsp_media_mapping_get_type
|
||||||
gst_rtsp_media_factory_get_type
|
gst_rtsp_media_factory_get_type
|
||||||
gst_rtsp_media_get_type
|
gst_rtsp_media_get_type
|
||||||
|
|
|
@ -1 +1,2 @@
|
||||||
<!ENTITY GST_MAJORMINOR "@GST_MAJORMINOR@">
|
<!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-readme
|
||||||
test-sdp
|
test-sdp
|
||||||
test-video
|
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)
|
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. */
|
/* make a URI media factory for a test stream. */
|
||||||
factory = gst_rtsp_media_factory_uri_new ();
|
factory = gst_rtsp_media_factory_uri_new ();
|
||||||
|
/* when using GStreamer as a client, one can use the gst payloader, which is
|
||||||
|
* more efficient when there is no payloader for the compressed format */
|
||||||
|
/* g_object_set (factory, "use-gstpay", TRUE, NULL); */
|
||||||
gst_rtsp_media_factory_uri_set_uri (factory, argv[1]);
|
gst_rtsp_media_factory_uri_set_uri (factory, argv[1]);
|
||||||
|
/* if you want multiple clients to see the same video, set the shared property
|
||||||
|
* to TRUE */
|
||||||
|
/* gst_rtsp_media_factory_set_shared ( GST_RTSP_MEDIA_FACTORY (factory), TRUE); */
|
||||||
|
|
||||||
/* attach the test factory to the /test url */
|
/* attach the test factory to the /test url */
|
||||||
gst_rtsp_media_mapping_add_factory (mapping, "/test",
|
gst_rtsp_media_mapping_add_factory (mapping, "/test",
|
||||||
|
|
|
@ -21,7 +21,13 @@
|
||||||
|
|
||||||
#include <gst/rtsp-server/rtsp-server.h>
|
#include <gst/rtsp-server/rtsp-server.h>
|
||||||
|
|
||||||
|
/* define this if you want the resource to only be available when using
|
||||||
|
* user/admin as the password */
|
||||||
|
#undef WITH_AUTH
|
||||||
|
|
||||||
|
/* this timeout is periodically run to clean up the expired sessions from the
|
||||||
|
* pool. This needs to be run explicitly currently but might be done
|
||||||
|
* automatically as part of the mainloop. */
|
||||||
static gboolean
|
static gboolean
|
||||||
timeout (GstRTSPServer * server, gboolean ignored)
|
timeout (GstRTSPServer * server, gboolean ignored)
|
||||||
{
|
{
|
||||||
|
@ -41,6 +47,10 @@ main (int argc, char *argv[])
|
||||||
GstRTSPServer *server;
|
GstRTSPServer *server;
|
||||||
GstRTSPMediaMapping *mapping;
|
GstRTSPMediaMapping *mapping;
|
||||||
GstRTSPMediaFactory *factory;
|
GstRTSPMediaFactory *factory;
|
||||||
|
#ifdef WITH_AUTH
|
||||||
|
GstRTSPAuth *auth;
|
||||||
|
gchar *basic;
|
||||||
|
#endif
|
||||||
|
|
||||||
gst_init (&argc, &argv);
|
gst_init (&argc, &argv);
|
||||||
|
|
||||||
|
@ -53,6 +63,17 @@ main (int argc, char *argv[])
|
||||||
* that be used to map uri mount points to media factories */
|
* that be used to map uri mount points to media factories */
|
||||||
mapping = gst_rtsp_server_get_media_mapping (server);
|
mapping = gst_rtsp_server_get_media_mapping (server);
|
||||||
|
|
||||||
|
#ifdef WITH_AUTH
|
||||||
|
/* make a new authentication manager. it can be added to control access to all
|
||||||
|
* the factories on the server or on individual factories. */
|
||||||
|
auth = gst_rtsp_auth_new ();
|
||||||
|
basic = gst_rtsp_auth_make_basic ("user", "admin");
|
||||||
|
gst_rtsp_auth_set_basic (auth, basic);
|
||||||
|
g_free (basic);
|
||||||
|
/* configure in the server */
|
||||||
|
gst_rtsp_server_set_auth (server, auth);
|
||||||
|
#endif
|
||||||
|
|
||||||
/* make a media factory for a test stream. The default media factory can use
|
/* make a media factory for a test stream. The default media factory can use
|
||||||
* gst-launch syntax to create pipelines.
|
* gst-launch syntax to create pipelines.
|
||||||
* any launch line works as long as it contains elements named pay%d. Each
|
* any launch line works as long as it contains elements named pay%d. Each
|
||||||
|
@ -74,9 +95,10 @@ main (int argc, char *argv[])
|
||||||
if (gst_rtsp_server_attach (server, NULL) == 0)
|
if (gst_rtsp_server_attach (server, NULL) == 0)
|
||||||
goto failed;
|
goto failed;
|
||||||
|
|
||||||
|
/* add a timeout for the session cleanup */
|
||||||
g_timeout_add_seconds (2, (GSourceFunc) timeout, server);
|
g_timeout_add_seconds (2, (GSourceFunc) timeout, server);
|
||||||
|
|
||||||
/* start serving */
|
/* start serving, this never stops */
|
||||||
g_main_loop_run (loop);
|
g_main_loop_run (loop);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
|
|
2
gst/rtsp-server/.gitignore
vendored
Normal file
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 = \
|
public_headers = \
|
||||||
|
rtsp-auth.h \
|
||||||
rtsp-params.h \
|
rtsp-params.h \
|
||||||
rtsp-sdp.h \
|
rtsp-sdp.h \
|
||||||
rtsp-media.h \
|
rtsp-media.h \
|
||||||
|
@ -11,6 +12,8 @@ public_headers = \
|
||||||
rtsp-server.h
|
rtsp-server.h
|
||||||
|
|
||||||
c_sources = \
|
c_sources = \
|
||||||
|
rtsp-funnel.c \
|
||||||
|
rtsp-auth.c \
|
||||||
rtsp-params.c \
|
rtsp-params.c \
|
||||||
rtsp-sdp.c \
|
rtsp-sdp.c \
|
||||||
rtsp-media.c \
|
rtsp-media.c \
|
||||||
|
@ -22,6 +25,8 @@ c_sources = \
|
||||||
rtsp-client.c \
|
rtsp-client.c \
|
||||||
rtsp-server.c
|
rtsp-server.c
|
||||||
|
|
||||||
|
noinst_HEADERS = rtsp-funnel.h
|
||||||
|
|
||||||
lib_LTLIBRARIES = \
|
lib_LTLIBRARIES = \
|
||||||
libgstrtspserver-@GST_MAJORMINOR@.la
|
libgstrtspserver-@GST_MAJORMINOR@.la
|
||||||
|
|
||||||
|
@ -60,6 +65,8 @@ GstRtspServer-@GST_MAJORMINOR@.gir: $(INTROSPECTION_SCANNER) libgstrtspserver-@G
|
||||||
-DIN_GOBJECT_INTROSPECTION=1 \
|
-DIN_GOBJECT_INTROSPECTION=1 \
|
||||||
--c-include='gst/gst.h' \
|
--c-include='gst/gst.h' \
|
||||||
--add-include-path=`$(PKG_CONFIG) --variable=girdir gstreamer-0.10` \
|
--add-include-path=`$(PKG_CONFIG) --variable=girdir gstreamer-0.10` \
|
||||||
|
--add-include-path=`$(PKG_CONFIG) --variable=girdir gstreamer-rtsp-0.10` \
|
||||||
|
--add-include-path=`$(PKG_CONFIG) --variable=girdir gstreamer-sdp-0.10` \
|
||||||
--library=libgstrtspserver-0.10.la \
|
--library=libgstrtspserver-0.10.la \
|
||||||
--include=Gst-0.10 \
|
--include=Gst-0.10 \
|
||||||
--include=GstRtsp-0.10 \
|
--include=GstRtsp-0.10 \
|
||||||
|
@ -81,7 +88,14 @@ typelibsdir = $(libdir)/girepository-1.0/
|
||||||
typelibs_DATA = $(BUILT_GIRSOURCES:.gir=.typelib)
|
typelibs_DATA = $(BUILT_GIRSOURCES:.gir=.typelib)
|
||||||
|
|
||||||
%.typelib: %.gir $(INTROSPECTION_COMPILER)
|
%.typelib: %.gir $(INTROSPECTION_COMPILER)
|
||||||
$(AM_V_GEN)$(INTROSPECTION_COMPILER) --includedir=$(srcdir) --includedir=$(builddir) $(INTROSPECTION_COMPILER_OPTS) $< -o $(@F)
|
$(AM_V_GEN)PKG_CONFIG_PATH="$(GST_PKG_CONFIG_PATH)" \
|
||||||
|
$(INTROSPECTION_COMPILER) \
|
||||||
|
--includedir=$(srcdir) \
|
||||||
|
--includedir=$(builddir) \
|
||||||
|
--includedir=`$(PKG_CONFIG) --variable=girdir gstreamer-0.10` \
|
||||||
|
--includedir=`$(PKG_CONFIG) --variable=girdir gstreamer-rtsp-0.10` \
|
||||||
|
--includedir=`$(PKG_CONFIG) --variable=girdir gstreamer-sdp-0.10` \
|
||||||
|
$(INTROSPECTION_COMPILER_OPTS) $< -o $(@F)
|
||||||
|
|
||||||
CLEANFILES += $(BUILT_GIRSOURCES) $(typelibs_DATA)
|
CLEANFILES += $(BUILT_GIRSOURCES) $(typelibs_DATA)
|
||||||
endif
|
endif
|
||||||
|
|
272
gst/rtsp-server/rtsp-auth.c
Normal file
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.
|
* Boston, MA 02111-1307, USA.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include <stdio.h>
|
|
||||||
#include <stdlib.h>
|
|
||||||
#include <unistd.h>
|
|
||||||
#include <errno.h>
|
|
||||||
#include <string.h>
|
|
||||||
#include <sys/time.h>
|
|
||||||
#include <sys/types.h>
|
|
||||||
#include <netinet/in.h>
|
|
||||||
#include <netdb.h>
|
|
||||||
#include <sys/socket.h>
|
|
||||||
#include <sys/wait.h>
|
|
||||||
#include <fcntl.h>
|
|
||||||
#include <arpa/inet.h>
|
|
||||||
|
|
||||||
#include <gst/gst.h>
|
#include <gst/gst.h>
|
||||||
#include <gst/rtsp/gstrtspconnection.h>
|
#include <gst/rtsp/gstrtspconnection.h>
|
||||||
|
|
||||||
#ifndef __GST_RTSP_CLIENT_H__
|
#ifndef __GST_RTSP_CLIENT_H__
|
||||||
#define __GST_RTSP_CLIENT_H__
|
#define __GST_RTSP_CLIENT_H__
|
||||||
|
|
||||||
|
G_BEGIN_DECLS
|
||||||
|
|
||||||
|
typedef struct _GstRTSPClient GstRTSPClient;
|
||||||
|
typedef struct _GstRTSPClientClass GstRTSPClientClass;
|
||||||
|
typedef struct _GstRTSPClientState GstRTSPClientState;
|
||||||
|
|
||||||
|
#include "rtsp-server.h"
|
||||||
#include "rtsp-media.h"
|
#include "rtsp-media.h"
|
||||||
#include "rtsp-media-mapping.h"
|
#include "rtsp-media-mapping.h"
|
||||||
#include "rtsp-session-pool.h"
|
#include "rtsp-session-pool.h"
|
||||||
|
#include "rtsp-auth.h"
|
||||||
G_BEGIN_DECLS
|
|
||||||
|
|
||||||
#define GST_TYPE_RTSP_CLIENT (gst_rtsp_client_get_type ())
|
#define GST_TYPE_RTSP_CLIENT (gst_rtsp_client_get_type ())
|
||||||
#define GST_IS_RTSP_CLIENT(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GST_TYPE_RTSP_CLIENT))
|
#define GST_IS_RTSP_CLIENT(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GST_TYPE_RTSP_CLIENT))
|
||||||
|
@ -52,8 +44,29 @@ G_BEGIN_DECLS
|
||||||
#define GST_RTSP_CLIENT_CAST(obj) ((GstRTSPClient*)(obj))
|
#define GST_RTSP_CLIENT_CAST(obj) ((GstRTSPClient*)(obj))
|
||||||
#define GST_RTSP_CLIENT_CLASS_CAST(klass) ((GstRTSPClientClass*)(klass))
|
#define GST_RTSP_CLIENT_CLASS_CAST(klass) ((GstRTSPClientClass*)(klass))
|
||||||
|
|
||||||
typedef struct _GstRTSPClient GstRTSPClient;
|
/**
|
||||||
typedef struct _GstRTSPClientClass GstRTSPClientClass;
|
* GstRTSPClientState:
|
||||||
|
* @request: the complete request
|
||||||
|
* @uri: the complete url parsed from @request
|
||||||
|
* @method: the parsed method of @uri
|
||||||
|
* @session: the session, can be NULL
|
||||||
|
* @sessmedia: the session media for the url can be NULL
|
||||||
|
* @factory: the media factory for the url, can be NULL.
|
||||||
|
* @media: the session media for the url can be NULL
|
||||||
|
* @response: the response
|
||||||
|
*
|
||||||
|
* Information passed around containing the client state of a request.
|
||||||
|
*/
|
||||||
|
struct _GstRTSPClientState{
|
||||||
|
GstRTSPMessage *request;
|
||||||
|
GstRTSPUrl *uri;
|
||||||
|
GstRTSPMethod method;
|
||||||
|
GstRTSPSession *session;
|
||||||
|
GstRTSPSessionMedia *sessmedia;
|
||||||
|
GstRTSPMediaFactory *factory;
|
||||||
|
GstRTSPMedia *media;
|
||||||
|
GstRTSPMessage *response;
|
||||||
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* GstRTSPClient:
|
* GstRTSPClient:
|
||||||
|
@ -80,8 +93,10 @@ struct _GstRTSPClient {
|
||||||
gchar *server_ip;
|
gchar *server_ip;
|
||||||
gboolean is_ipv6;
|
gboolean is_ipv6;
|
||||||
|
|
||||||
|
GstRTSPServer *server;
|
||||||
GstRTSPSessionPool *session_pool;
|
GstRTSPSessionPool *session_pool;
|
||||||
GstRTSPMediaMapping *media_mapping;
|
GstRTSPMediaMapping *media_mapping;
|
||||||
|
GstRTSPAuth *auth;
|
||||||
|
|
||||||
GstRTSPUrl *uri;
|
GstRTSPUrl *uri;
|
||||||
GstRTSPMedia *media;
|
GstRTSPMedia *media;
|
||||||
|
@ -92,12 +107,18 @@ struct _GstRTSPClient {
|
||||||
|
|
||||||
struct _GstRTSPClientClass {
|
struct _GstRTSPClientClass {
|
||||||
GObjectClass parent_class;
|
GObjectClass parent_class;
|
||||||
|
|
||||||
|
/* signals */
|
||||||
|
void (*closed) (GstRTSPClient *client);
|
||||||
};
|
};
|
||||||
|
|
||||||
GType gst_rtsp_client_get_type (void);
|
GType gst_rtsp_client_get_type (void);
|
||||||
|
|
||||||
GstRTSPClient * gst_rtsp_client_new (void);
|
GstRTSPClient * gst_rtsp_client_new (void);
|
||||||
|
|
||||||
|
void gst_rtsp_client_set_server (GstRTSPClient * client, GstRTSPServer * server);
|
||||||
|
GstRTSPServer * gst_rtsp_client_get_server (GstRTSPClient * client);
|
||||||
|
|
||||||
void gst_rtsp_client_set_session_pool (GstRTSPClient *client,
|
void gst_rtsp_client_set_session_pool (GstRTSPClient *client,
|
||||||
GstRTSPSessionPool *pool);
|
GstRTSPSessionPool *pool);
|
||||||
GstRTSPSessionPool * gst_rtsp_client_get_session_pool (GstRTSPClient *client);
|
GstRTSPSessionPool * gst_rtsp_client_get_session_pool (GstRTSPClient *client);
|
||||||
|
@ -106,6 +127,10 @@ void gst_rtsp_client_set_media_mapping (GstRTSPClient *client,
|
||||||
GstRTSPMediaMapping *mapping);
|
GstRTSPMediaMapping *mapping);
|
||||||
GstRTSPMediaMapping * gst_rtsp_client_get_media_mapping (GstRTSPClient *client);
|
GstRTSPMediaMapping * gst_rtsp_client_get_media_mapping (GstRTSPClient *client);
|
||||||
|
|
||||||
|
void gst_rtsp_client_set_auth (GstRTSPClient *client, GstRTSPAuth *auth);
|
||||||
|
GstRTSPAuth * gst_rtsp_client_get_auth (GstRTSPClient *client);
|
||||||
|
|
||||||
|
|
||||||
gboolean gst_rtsp_client_accept (GstRTSPClient *client,
|
gboolean gst_rtsp_client_accept (GstRTSPClient *client,
|
||||||
GIOChannel *channel);
|
GIOChannel *channel);
|
||||||
|
|
||||||
|
|
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.
|
* Boston, MA 02111-1307, USA.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
#include "rtsp-media-factory-uri.h"
|
#include "rtsp-media-factory-uri.h"
|
||||||
|
|
||||||
#define DEFAULT_URI NULL
|
#define DEFAULT_URI NULL
|
||||||
|
#define DEFAULT_USE_GSTPAY FALSE
|
||||||
|
|
||||||
enum
|
enum
|
||||||
{
|
{
|
||||||
PROP_0,
|
PROP_0,
|
||||||
PROP_URI,
|
PROP_URI,
|
||||||
|
PROP_USE_GSTPAY,
|
||||||
PROP_LAST
|
PROP_LAST
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -56,7 +60,7 @@ free_data (FactoryData * data)
|
||||||
|
|
||||||
static const gchar *factory_key = "GstRTSPMediaFactoryURI";
|
static const gchar *factory_key = "GstRTSPMediaFactoryURI";
|
||||||
|
|
||||||
GST_DEBUG_CATEGORY (rtsp_media_factory_uri_debug);
|
GST_DEBUG_CATEGORY_STATIC (rtsp_media_factory_uri_debug);
|
||||||
#define GST_CAT_DEFAULT rtsp_media_factory_uri_debug
|
#define GST_CAT_DEFAULT rtsp_media_factory_uri_debug
|
||||||
|
|
||||||
static void gst_rtsp_media_factory_uri_get_property (GObject * object,
|
static void gst_rtsp_media_factory_uri_get_property (GObject * object,
|
||||||
|
@ -93,6 +97,16 @@ gst_rtsp_media_factory_uri_class_init (GstRTSPMediaFactoryURIClass * klass)
|
||||||
g_param_spec_string ("uri", "URI",
|
g_param_spec_string ("uri", "URI",
|
||||||
"The URI of the resource to stream", DEFAULT_URI,
|
"The URI of the resource to stream", DEFAULT_URI,
|
||||||
G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
|
G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
|
||||||
|
/**
|
||||||
|
* GstRTSPMediaFactoryURI::use-gstpay
|
||||||
|
*
|
||||||
|
* Allow the usage of gstpay in order to avoid decoding of compressed formats
|
||||||
|
* without a payloader.
|
||||||
|
*/
|
||||||
|
g_object_class_install_property (gobject_class, PROP_USE_GSTPAY,
|
||||||
|
g_param_spec_boolean ("use-gstpay", "Use gstpay",
|
||||||
|
"Use the gstpay payloader to avoid decoding", DEFAULT_USE_GSTPAY,
|
||||||
|
G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
|
||||||
|
|
||||||
mediafactory_class->get_element = rtsp_media_factory_uri_get_element;
|
mediafactory_class->get_element = rtsp_media_factory_uri_get_element;
|
||||||
|
|
||||||
|
@ -100,13 +114,68 @@ gst_rtsp_media_factory_uri_class_init (GstRTSPMediaFactoryURIClass * klass)
|
||||||
0, "GstRTSPMediaFactoryUri");
|
0, "GstRTSPMediaFactoryUri");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
typedef struct
|
||||||
|
{
|
||||||
|
GList *demux;
|
||||||
|
GList *payload;
|
||||||
|
GList *decode;
|
||||||
|
} FilterData;
|
||||||
|
|
||||||
|
static gboolean
|
||||||
|
payloader_filter (GstPluginFeature * feature, FilterData * data)
|
||||||
|
{
|
||||||
|
gboolean res;
|
||||||
|
const gchar *klass;
|
||||||
|
GstElementFactory *fact;
|
||||||
|
GList **list = NULL;
|
||||||
|
|
||||||
|
/* we only care about element factories */
|
||||||
|
if (G_UNLIKELY (!GST_IS_ELEMENT_FACTORY (feature)))
|
||||||
|
return FALSE;
|
||||||
|
|
||||||
|
if (gst_plugin_feature_get_rank (feature) < GST_RANK_MARGINAL)
|
||||||
|
return FALSE;
|
||||||
|
|
||||||
|
fact = GST_ELEMENT_FACTORY_CAST (feature);
|
||||||
|
|
||||||
|
klass = gst_element_factory_get_klass (fact);
|
||||||
|
|
||||||
|
if (strstr (klass, "Decoder"))
|
||||||
|
list = &data->decode;
|
||||||
|
else if (strstr (klass, "Demux"))
|
||||||
|
list = &data->demux;
|
||||||
|
else if (strstr (klass, "Parser") && strstr (klass, "Codec"))
|
||||||
|
list = &data->demux;
|
||||||
|
else if (strstr (klass, "Payloader") && strstr (klass, "RTP"))
|
||||||
|
list = &data->payload;
|
||||||
|
|
||||||
|
if (list) {
|
||||||
|
GST_DEBUG ("adding %s", GST_PLUGIN_FEATURE_NAME (fact));
|
||||||
|
*list = g_list_prepend (*list, fact);
|
||||||
|
}
|
||||||
|
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
gst_rtsp_media_factory_uri_init (GstRTSPMediaFactoryURI * factory)
|
gst_rtsp_media_factory_uri_init (GstRTSPMediaFactoryURI * factory)
|
||||||
{
|
{
|
||||||
|
FilterData data = { NULL, NULL, NULL };
|
||||||
|
|
||||||
factory->uri = g_strdup (DEFAULT_URI);
|
factory->uri = g_strdup (DEFAULT_URI);
|
||||||
factory->factories =
|
factory->use_gstpay = DEFAULT_USE_GSTPAY;
|
||||||
gst_element_factory_list_get_elements (GST_ELEMENT_FACTORY_TYPE_PAYLOADER,
|
|
||||||
GST_RANK_NONE);
|
/* get the feature list using the filter */
|
||||||
|
gst_default_registry_feature_filter ((GstPluginFeatureFilter)
|
||||||
|
payloader_filter, FALSE, &data);
|
||||||
|
/* sort */
|
||||||
|
factory->demuxers =
|
||||||
|
g_list_sort (data.demux, gst_plugin_feature_rank_compare_func);
|
||||||
|
factory->payloaders =
|
||||||
|
g_list_sort (data.payload, gst_plugin_feature_rank_compare_func);
|
||||||
|
factory->decoders =
|
||||||
|
g_list_sort (data.decode, gst_plugin_feature_rank_compare_func);
|
||||||
|
|
||||||
factory->raw_vcaps = gst_static_caps_get (&raw_video_caps);
|
factory->raw_vcaps = gst_static_caps_get (&raw_video_caps);
|
||||||
factory->raw_acaps = gst_static_caps_get (&raw_audio_caps);
|
factory->raw_acaps = gst_static_caps_get (&raw_audio_caps);
|
||||||
}
|
}
|
||||||
|
@ -117,7 +186,9 @@ gst_rtsp_media_factory_uri_finalize (GObject * obj)
|
||||||
GstRTSPMediaFactoryURI *factory = GST_RTSP_MEDIA_FACTORY_URI (obj);
|
GstRTSPMediaFactoryURI *factory = GST_RTSP_MEDIA_FACTORY_URI (obj);
|
||||||
|
|
||||||
g_free (factory->uri);
|
g_free (factory->uri);
|
||||||
gst_plugin_feature_list_free (factory->factories);
|
gst_plugin_feature_list_free (factory->demuxers);
|
||||||
|
gst_plugin_feature_list_free (factory->payloaders);
|
||||||
|
gst_plugin_feature_list_free (factory->decoders);
|
||||||
gst_caps_unref (factory->raw_vcaps);
|
gst_caps_unref (factory->raw_vcaps);
|
||||||
gst_caps_unref (factory->raw_acaps);
|
gst_caps_unref (factory->raw_acaps);
|
||||||
|
|
||||||
|
@ -134,6 +205,9 @@ gst_rtsp_media_factory_uri_get_property (GObject * object, guint propid,
|
||||||
case PROP_URI:
|
case PROP_URI:
|
||||||
g_value_take_string (value, gst_rtsp_media_factory_uri_get_uri (factory));
|
g_value_take_string (value, gst_rtsp_media_factory_uri_get_uri (factory));
|
||||||
break;
|
break;
|
||||||
|
case PROP_USE_GSTPAY:
|
||||||
|
g_value_set_boolean (value, factory->use_gstpay);
|
||||||
|
break;
|
||||||
default:
|
default:
|
||||||
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, propid, pspec);
|
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, propid, pspec);
|
||||||
}
|
}
|
||||||
|
@ -149,6 +223,9 @@ gst_rtsp_media_factory_uri_set_property (GObject * object, guint propid,
|
||||||
case PROP_URI:
|
case PROP_URI:
|
||||||
gst_rtsp_media_factory_uri_set_uri (factory, g_value_get_string (value));
|
gst_rtsp_media_factory_uri_set_uri (factory, g_value_get_string (value));
|
||||||
break;
|
break;
|
||||||
|
case PROP_USE_GSTPAY:
|
||||||
|
factory->use_gstpay = g_value_get_boolean (value);
|
||||||
|
break;
|
||||||
default:
|
default:
|
||||||
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, propid, pspec);
|
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, propid, pspec);
|
||||||
}
|
}
|
||||||
|
@ -219,26 +296,43 @@ find_payloader (GstRTSPMediaFactoryURI * urifact, GstCaps * caps)
|
||||||
GList *list, *tmp;
|
GList *list, *tmp;
|
||||||
GstElementFactory *factory = NULL;
|
GstElementFactory *factory = NULL;
|
||||||
|
|
||||||
/* find payloader that can link */
|
/* first find a demuxer that can link */
|
||||||
list = gst_element_factory_list_filter (urifact->factories, caps,
|
list = gst_element_factory_list_filter (urifact->demuxers, caps,
|
||||||
GST_PAD_SINK, FALSE);
|
GST_PAD_SINK, FALSE);
|
||||||
|
|
||||||
for (tmp = list; tmp; tmp = g_list_next (tmp)) {
|
if (list != NULL) {
|
||||||
GstElementFactory *f = GST_ELEMENT_FACTORY_CAST (tmp->data);
|
/* we have a demuxer, try that one first */
|
||||||
const gchar *name;
|
|
||||||
|
|
||||||
name = gst_plugin_feature_get_name (GST_PLUGIN_FEATURE (f));
|
|
||||||
if (strcmp (name, "gdppay") == 0)
|
|
||||||
continue;
|
|
||||||
|
|
||||||
factory = f;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
if (factory)
|
|
||||||
g_object_ref (factory);
|
|
||||||
|
|
||||||
gst_plugin_feature_list_free (list);
|
gst_plugin_feature_list_free (list);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* no demuxer try a depayloader */
|
||||||
|
list = gst_element_factory_list_filter (urifact->payloaders, caps,
|
||||||
|
GST_PAD_SINK, FALSE);
|
||||||
|
|
||||||
|
if (list == NULL) {
|
||||||
|
if (urifact->use_gstpay) {
|
||||||
|
/* no depayloader or parser/demuxer, use gstpay when allowed */
|
||||||
|
factory = gst_element_factory_find ("rtpgstpay");
|
||||||
|
} else {
|
||||||
|
/* no depayloader, try a decoder, we'll get to a payloader for a decoded
|
||||||
|
* video or audio format, worst case. */
|
||||||
|
list = gst_element_factory_list_filter (urifact->decoders, caps,
|
||||||
|
GST_PAD_SINK, FALSE);
|
||||||
|
|
||||||
|
if (list != NULL) {
|
||||||
|
/* we have a decoder, try that one first */
|
||||||
|
gst_plugin_feature_list_free (list);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (list != NULL) {
|
||||||
|
factory = GST_ELEMENT_FACTORY_CAST (list->data);
|
||||||
|
g_object_ref (factory);
|
||||||
|
gst_plugin_feature_list_free (list);
|
||||||
|
}
|
||||||
return factory;
|
return factory;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -259,8 +353,9 @@ autoplug_continue_cb (GstElement * uribin, GstPad * pad, GstCaps * caps,
|
||||||
if (!(factory = find_payloader (data->factory, caps)))
|
if (!(factory = find_payloader (data->factory, caps)))
|
||||||
goto no_factory;
|
goto no_factory;
|
||||||
|
|
||||||
/* we found a payloader, stop autoplugging */
|
/* we found a payloader, stop autoplugging so we can plug the
|
||||||
GST_DEBUG ("found payloader factory %s",
|
* payloader. */
|
||||||
|
GST_DEBUG ("found factory %s",
|
||||||
gst_plugin_feature_get_name (GST_PLUGIN_FEATURE (factory)));
|
gst_plugin_feature_get_name (GST_PLUGIN_FEATURE (factory)));
|
||||||
gst_object_unref (factory);
|
gst_object_unref (factory);
|
||||||
|
|
||||||
|
@ -349,6 +444,10 @@ pad_added_cb (GstElement * uribin, GstPad * pad, GstElement * element)
|
||||||
g_object_set (payloader, "pt", data->pt, NULL);
|
g_object_set (payloader, "pt", data->pt, NULL);
|
||||||
data->pt++;
|
data->pt++;
|
||||||
|
|
||||||
|
if (g_object_class_find_property (G_OBJECT_GET_CLASS (payloader),
|
||||||
|
"buffer-list"))
|
||||||
|
g_object_set (payloader, "buffer-list", TRUE, NULL);
|
||||||
|
|
||||||
/* add the payloader to the pipeline */
|
/* add the payloader to the pipeline */
|
||||||
gst_bin_add (GST_BIN_CAST (element), payloader);
|
gst_bin_add (GST_BIN_CAST (element), payloader);
|
||||||
gst_element_set_state (payloader, GST_STATE_PLAYING);
|
gst_element_set_state (payloader, GST_STATE_PLAYING);
|
||||||
|
|
|
@ -49,9 +49,13 @@ struct _GstRTSPMediaFactoryURI {
|
||||||
GstRTSPMediaFactory parent;
|
GstRTSPMediaFactory parent;
|
||||||
|
|
||||||
gchar *uri;
|
gchar *uri;
|
||||||
|
gboolean use_gstpay;
|
||||||
|
|
||||||
GstCaps *raw_vcaps;
|
GstCaps *raw_vcaps;
|
||||||
GstCaps *raw_acaps;
|
GstCaps *raw_acaps;
|
||||||
GList *factories;
|
GList *demuxers;
|
||||||
|
GList *payloaders;
|
||||||
|
GList *decoders;
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -22,6 +22,7 @@
|
||||||
#define DEFAULT_LAUNCH NULL
|
#define DEFAULT_LAUNCH NULL
|
||||||
#define DEFAULT_SHARED FALSE
|
#define DEFAULT_SHARED FALSE
|
||||||
#define DEFAULT_EOS_SHUTDOWN FALSE
|
#define DEFAULT_EOS_SHUTDOWN FALSE
|
||||||
|
#define DEFAULT_BUFFER_SIZE 0x80000
|
||||||
|
|
||||||
enum
|
enum
|
||||||
{
|
{
|
||||||
|
@ -29,10 +30,11 @@ enum
|
||||||
PROP_LAUNCH,
|
PROP_LAUNCH,
|
||||||
PROP_SHARED,
|
PROP_SHARED,
|
||||||
PROP_EOS_SHUTDOWN,
|
PROP_EOS_SHUTDOWN,
|
||||||
|
PROP_BUFFER_SIZE,
|
||||||
PROP_LAST
|
PROP_LAST
|
||||||
};
|
};
|
||||||
|
|
||||||
GST_DEBUG_CATEGORY (rtsp_media_debug);
|
GST_DEBUG_CATEGORY_STATIC (rtsp_media_debug);
|
||||||
#define GST_CAT_DEFAULT rtsp_media_debug
|
#define GST_CAT_DEFAULT rtsp_media_debug
|
||||||
|
|
||||||
static void gst_rtsp_media_factory_get_property (GObject * object, guint propid,
|
static void gst_rtsp_media_factory_get_property (GObject * object, guint propid,
|
||||||
|
@ -96,13 +98,19 @@ gst_rtsp_media_factory_class_init (GstRTSPMediaFactoryClass * klass)
|
||||||
"Send EOS down the pipeline before shutting down",
|
"Send EOS down the pipeline before shutting down",
|
||||||
DEFAULT_EOS_SHUTDOWN, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
|
DEFAULT_EOS_SHUTDOWN, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
|
||||||
|
|
||||||
|
g_object_class_install_property (gobject_class, PROP_BUFFER_SIZE,
|
||||||
|
g_param_spec_uint ("buffer-size", "Buffer Size",
|
||||||
|
"The kernel UDP buffer size to use", 0, G_MAXUINT,
|
||||||
|
DEFAULT_BUFFER_SIZE, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
|
||||||
|
|
||||||
klass->gen_key = default_gen_key;
|
klass->gen_key = default_gen_key;
|
||||||
klass->get_element = default_get_element;
|
klass->get_element = default_get_element;
|
||||||
klass->construct = default_construct;
|
klass->construct = default_construct;
|
||||||
klass->configure = default_configure;
|
klass->configure = default_configure;
|
||||||
klass->create_pipeline = default_create_pipeline;
|
klass->create_pipeline = default_create_pipeline;
|
||||||
|
|
||||||
GST_DEBUG_CATEGORY_INIT (rtsp_media_debug, "rtspmedia", 0, "GstRTSPMedia");
|
GST_DEBUG_CATEGORY_INIT (rtsp_media_debug, "rtspmediafactory", 0,
|
||||||
|
"GstRTSPMediaFactory");
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
|
@ -111,6 +119,7 @@ gst_rtsp_media_factory_init (GstRTSPMediaFactory * factory)
|
||||||
factory->launch = g_strdup (DEFAULT_LAUNCH);
|
factory->launch = g_strdup (DEFAULT_LAUNCH);
|
||||||
factory->shared = DEFAULT_SHARED;
|
factory->shared = DEFAULT_SHARED;
|
||||||
factory->eos_shutdown = DEFAULT_EOS_SHUTDOWN;
|
factory->eos_shutdown = DEFAULT_EOS_SHUTDOWN;
|
||||||
|
factory->buffer_size = DEFAULT_BUFFER_SIZE;
|
||||||
|
|
||||||
factory->lock = g_mutex_new ();
|
factory->lock = g_mutex_new ();
|
||||||
factory->medias_lock = g_mutex_new ();
|
factory->medias_lock = g_mutex_new ();
|
||||||
|
@ -127,6 +136,8 @@ gst_rtsp_media_factory_finalize (GObject * obj)
|
||||||
g_mutex_free (factory->medias_lock);
|
g_mutex_free (factory->medias_lock);
|
||||||
g_free (factory->launch);
|
g_free (factory->launch);
|
||||||
g_mutex_free (factory->lock);
|
g_mutex_free (factory->lock);
|
||||||
|
if (factory->auth)
|
||||||
|
g_object_unref (factory->auth);
|
||||||
|
|
||||||
G_OBJECT_CLASS (gst_rtsp_media_factory_parent_class)->finalize (obj);
|
G_OBJECT_CLASS (gst_rtsp_media_factory_parent_class)->finalize (obj);
|
||||||
}
|
}
|
||||||
|
@ -148,6 +159,10 @@ gst_rtsp_media_factory_get_property (GObject * object, guint propid,
|
||||||
g_value_set_boolean (value,
|
g_value_set_boolean (value,
|
||||||
gst_rtsp_media_factory_is_eos_shutdown (factory));
|
gst_rtsp_media_factory_is_eos_shutdown (factory));
|
||||||
break;
|
break;
|
||||||
|
case PROP_BUFFER_SIZE:
|
||||||
|
g_value_set_uint (value,
|
||||||
|
gst_rtsp_media_factory_get_buffer_size (factory));
|
||||||
|
break;
|
||||||
default:
|
default:
|
||||||
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, propid, pspec);
|
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, propid, pspec);
|
||||||
}
|
}
|
||||||
|
@ -170,6 +185,10 @@ gst_rtsp_media_factory_set_property (GObject * object, guint propid,
|
||||||
gst_rtsp_media_factory_set_eos_shutdown (factory,
|
gst_rtsp_media_factory_set_eos_shutdown (factory,
|
||||||
g_value_get_boolean (value));
|
g_value_get_boolean (value));
|
||||||
break;
|
break;
|
||||||
|
case PROP_BUFFER_SIZE:
|
||||||
|
gst_rtsp_media_factory_set_buffer_size (factory,
|
||||||
|
g_value_get_uint (value));
|
||||||
|
break;
|
||||||
default:
|
default:
|
||||||
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, propid, pspec);
|
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, propid, pspec);
|
||||||
}
|
}
|
||||||
|
@ -326,6 +345,94 @@ gst_rtsp_media_factory_is_eos_shutdown (GstRTSPMediaFactory * factory)
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* gst_rtsp_media_factory_set_buffer_size:
|
||||||
|
* @factory: a #GstRTSPMedia
|
||||||
|
* @size: the new value
|
||||||
|
*
|
||||||
|
* Set the kernel UDP buffer size.
|
||||||
|
*/
|
||||||
|
void
|
||||||
|
gst_rtsp_media_factory_set_buffer_size (GstRTSPMediaFactory * factory,
|
||||||
|
guint size)
|
||||||
|
{
|
||||||
|
g_return_if_fail (GST_IS_RTSP_MEDIA_FACTORY (factory));
|
||||||
|
|
||||||
|
GST_RTSP_MEDIA_FACTORY_LOCK (factory);
|
||||||
|
factory->buffer_size = size;
|
||||||
|
GST_RTSP_MEDIA_FACTORY_UNLOCK (factory);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* gst_rtsp_media_factory_get_buffer_size:
|
||||||
|
* @factory: a #GstRTSPMedia
|
||||||
|
*
|
||||||
|
* Get the kernel UDP buffer size.
|
||||||
|
*
|
||||||
|
* Returns: the kernel UDP buffer size.
|
||||||
|
*/
|
||||||
|
guint
|
||||||
|
gst_rtsp_media_factory_get_buffer_size (GstRTSPMediaFactory * factory)
|
||||||
|
{
|
||||||
|
guint result;
|
||||||
|
|
||||||
|
g_return_val_if_fail (GST_IS_RTSP_MEDIA_FACTORY (factory), 0);
|
||||||
|
|
||||||
|
GST_RTSP_MEDIA_FACTORY_LOCK (factory);
|
||||||
|
result = factory->buffer_size;
|
||||||
|
GST_RTSP_MEDIA_FACTORY_UNLOCK (factory);
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* gst_rtsp_media_factory_set_auth:
|
||||||
|
* @factory: a #GstRTSPMediaFactory
|
||||||
|
* @auth: a #GstRTSPAuth
|
||||||
|
*
|
||||||
|
* configure @auth to be used as the authentication manager of @factory.
|
||||||
|
*/
|
||||||
|
void
|
||||||
|
gst_rtsp_media_factory_set_auth (GstRTSPMediaFactory * factory,
|
||||||
|
GstRTSPAuth * auth)
|
||||||
|
{
|
||||||
|
GstRTSPAuth *old;
|
||||||
|
|
||||||
|
g_return_if_fail (GST_IS_RTSP_MEDIA_FACTORY (factory));
|
||||||
|
|
||||||
|
old = factory->auth;
|
||||||
|
|
||||||
|
if (old != auth) {
|
||||||
|
if (auth)
|
||||||
|
g_object_ref (auth);
|
||||||
|
factory->auth = auth;
|
||||||
|
if (old)
|
||||||
|
g_object_unref (old);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* gst_rtsp_media_factory_get_auth:
|
||||||
|
* @factory: a #GstRTSPMediaFactory
|
||||||
|
*
|
||||||
|
* Get the #GstRTSPAuth used as the authentication manager of @factory.
|
||||||
|
*
|
||||||
|
* Returns: the #GstRTSPAuth of @factory. g_object_unref() after
|
||||||
|
* usage.
|
||||||
|
*/
|
||||||
|
GstRTSPAuth *
|
||||||
|
gst_rtsp_media_factory_get_auth (GstRTSPMediaFactory * factory)
|
||||||
|
{
|
||||||
|
GstRTSPAuth *result;
|
||||||
|
|
||||||
|
g_return_val_if_fail (GST_IS_RTSP_MEDIA_FACTORY (factory), NULL);
|
||||||
|
|
||||||
|
if ((result = factory->auth))
|
||||||
|
g_object_ref (result);
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
static gboolean
|
static gboolean
|
||||||
compare_media (gpointer key, GstRTSPMedia * media1, GstRTSPMedia * media2)
|
compare_media (gpointer key, GstRTSPMedia * media1, GstRTSPMedia * media2)
|
||||||
{
|
{
|
||||||
|
@ -608,13 +715,22 @@ static void
|
||||||
default_configure (GstRTSPMediaFactory * factory, GstRTSPMedia * media)
|
default_configure (GstRTSPMediaFactory * factory, GstRTSPMedia * media)
|
||||||
{
|
{
|
||||||
gboolean shared, eos_shutdown;
|
gboolean shared, eos_shutdown;
|
||||||
|
guint size;
|
||||||
|
GstRTSPAuth *auth;
|
||||||
|
|
||||||
/* configure the sharedness */
|
/* configure the sharedness */
|
||||||
GST_RTSP_MEDIA_FACTORY_LOCK (factory);
|
GST_RTSP_MEDIA_FACTORY_LOCK (factory);
|
||||||
shared = factory->shared;
|
shared = factory->shared;
|
||||||
eos_shutdown = factory->eos_shutdown;
|
eos_shutdown = factory->eos_shutdown;
|
||||||
|
size = factory->buffer_size;
|
||||||
GST_RTSP_MEDIA_FACTORY_UNLOCK (factory);
|
GST_RTSP_MEDIA_FACTORY_UNLOCK (factory);
|
||||||
|
|
||||||
gst_rtsp_media_set_shared (media, shared);
|
gst_rtsp_media_set_shared (media, shared);
|
||||||
gst_rtsp_media_set_eos_shutdown (media, eos_shutdown);
|
gst_rtsp_media_set_eos_shutdown (media, eos_shutdown);
|
||||||
|
gst_rtsp_media_set_buffer_size (media, size);
|
||||||
|
|
||||||
|
if ((auth = gst_rtsp_media_factory_get_auth (factory))) {
|
||||||
|
gst_rtsp_media_set_auth (media, auth);
|
||||||
|
g_object_unref (auth);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -21,6 +21,7 @@
|
||||||
#include <gst/rtsp/gstrtspurl.h>
|
#include <gst/rtsp/gstrtspurl.h>
|
||||||
|
|
||||||
#include "rtsp-media.h"
|
#include "rtsp-media.h"
|
||||||
|
#include "rtsp-auth.h"
|
||||||
|
|
||||||
#ifndef __GST_RTSP_MEDIA_FACTORY_H__
|
#ifndef __GST_RTSP_MEDIA_FACTORY_H__
|
||||||
#define __GST_RTSP_MEDIA_FACTORY_H__
|
#define __GST_RTSP_MEDIA_FACTORY_H__
|
||||||
|
@ -62,6 +63,8 @@ struct _GstRTSPMediaFactory {
|
||||||
gchar *launch;
|
gchar *launch;
|
||||||
gboolean shared;
|
gboolean shared;
|
||||||
gboolean eos_shutdown;
|
gboolean eos_shutdown;
|
||||||
|
GstRTSPAuth *auth;
|
||||||
|
guint buffer_size;
|
||||||
|
|
||||||
GMutex *medias_lock;
|
GMutex *medias_lock;
|
||||||
GHashTable *medias;
|
GHashTable *medias;
|
||||||
|
@ -116,6 +119,13 @@ void gst_rtsp_media_factory_set_eos_shutdown (GstRTSPMediaFac
|
||||||
gboolean eos_shutdown);
|
gboolean eos_shutdown);
|
||||||
gboolean gst_rtsp_media_factory_is_eos_shutdown (GstRTSPMediaFactory *factory);
|
gboolean gst_rtsp_media_factory_is_eos_shutdown (GstRTSPMediaFactory *factory);
|
||||||
|
|
||||||
|
void gst_rtsp_media_factory_set_auth (GstRTSPMediaFactory *factory, GstRTSPAuth *auth);
|
||||||
|
GstRTSPAuth * gst_rtsp_media_factory_get_auth (GstRTSPMediaFactory *factory);
|
||||||
|
|
||||||
|
void gst_rtsp_media_factory_set_buffer_size (GstRTSPMediaFactory * factory, guint size);
|
||||||
|
guint gst_rtsp_media_factory_get_buffer_size (GstRTSPMediaFactory * factory);
|
||||||
|
|
||||||
|
|
||||||
/* creating the media from the factory and a url */
|
/* creating the media from the factory and a url */
|
||||||
GstRTSPMedia * gst_rtsp_media_factory_construct (GstRTSPMediaFactory *factory,
|
GstRTSPMedia * gst_rtsp_media_factory_construct (GstRTSPMediaFactory *factory,
|
||||||
const GstRTSPUrl *url);
|
const GstRTSPUrl *url);
|
||||||
|
|
|
@ -21,7 +21,7 @@
|
||||||
|
|
||||||
G_DEFINE_TYPE (GstRTSPMediaMapping, gst_rtsp_media_mapping, G_TYPE_OBJECT);
|
G_DEFINE_TYPE (GstRTSPMediaMapping, gst_rtsp_media_mapping, G_TYPE_OBJECT);
|
||||||
|
|
||||||
GST_DEBUG_CATEGORY_EXTERN (rtsp_media_debug);
|
GST_DEBUG_CATEGORY_STATIC (rtsp_media_debug);
|
||||||
#define GST_CAT_DEFAULT rtsp_media_debug
|
#define GST_CAT_DEFAULT rtsp_media_debug
|
||||||
|
|
||||||
static void gst_rtsp_media_mapping_finalize (GObject * obj);
|
static void gst_rtsp_media_mapping_finalize (GObject * obj);
|
||||||
|
@ -39,11 +39,16 @@ gst_rtsp_media_mapping_class_init (GstRTSPMediaMappingClass * klass)
|
||||||
gobject_class->finalize = gst_rtsp_media_mapping_finalize;
|
gobject_class->finalize = gst_rtsp_media_mapping_finalize;
|
||||||
|
|
||||||
klass->find_media = find_media;
|
klass->find_media = find_media;
|
||||||
|
|
||||||
|
GST_DEBUG_CATEGORY_INIT (rtsp_media_debug, "rtspmediamapping", 0,
|
||||||
|
"GstRTSPMediaMapping");
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
gst_rtsp_media_mapping_init (GstRTSPMediaMapping * mapping)
|
gst_rtsp_media_mapping_init (GstRTSPMediaMapping * mapping)
|
||||||
{
|
{
|
||||||
|
GST_DEBUG_OBJECT (mapping, "created");
|
||||||
|
|
||||||
mapping->mappings = g_hash_table_new_full (g_str_hash, g_str_equal,
|
mapping->mappings = g_hash_table_new_full (g_str_hash, g_str_equal,
|
||||||
g_free, g_object_unref);
|
g_free, g_object_unref);
|
||||||
}
|
}
|
||||||
|
@ -53,6 +58,8 @@ gst_rtsp_media_mapping_finalize (GObject * obj)
|
||||||
{
|
{
|
||||||
GstRTSPMediaMapping *mapping = GST_RTSP_MEDIA_MAPPING (obj);
|
GstRTSPMediaMapping *mapping = GST_RTSP_MEDIA_MAPPING (obj);
|
||||||
|
|
||||||
|
GST_DEBUG_OBJECT (mapping, "finalized");
|
||||||
|
|
||||||
g_hash_table_unref (mapping->mappings);
|
g_hash_table_unref (mapping->mappings);
|
||||||
|
|
||||||
G_OBJECT_CLASS (gst_rtsp_media_mapping_parent_class)->finalize (obj);
|
G_OBJECT_CLASS (gst_rtsp_media_mapping_parent_class)->finalize (obj);
|
||||||
|
|
|
@ -23,6 +23,7 @@
|
||||||
#include <gst/app/gstappsrc.h>
|
#include <gst/app/gstappsrc.h>
|
||||||
#include <gst/app/gstappsink.h>
|
#include <gst/app/gstappsink.h>
|
||||||
|
|
||||||
|
#include "rtsp-funnel.h"
|
||||||
#include "rtsp-media.h"
|
#include "rtsp-media.h"
|
||||||
|
|
||||||
#define DEFAULT_SHARED FALSE
|
#define DEFAULT_SHARED FALSE
|
||||||
|
@ -30,6 +31,7 @@
|
||||||
#define DEFAULT_PROTOCOLS GST_RTSP_LOWER_TRANS_UDP | GST_RTSP_LOWER_TRANS_TCP
|
#define DEFAULT_PROTOCOLS GST_RTSP_LOWER_TRANS_UDP | GST_RTSP_LOWER_TRANS_TCP
|
||||||
//#define DEFAULT_PROTOCOLS GST_RTSP_LOWER_TRANS_UDP_MCAST
|
//#define DEFAULT_PROTOCOLS GST_RTSP_LOWER_TRANS_UDP_MCAST
|
||||||
#define DEFAULT_EOS_SHUTDOWN FALSE
|
#define DEFAULT_EOS_SHUTDOWN FALSE
|
||||||
|
#define DEFAULT_BUFFER_SIZE 0x80000
|
||||||
|
|
||||||
/* define to dump received RTCP packets */
|
/* define to dump received RTCP packets */
|
||||||
#undef DUMP_STATS
|
#undef DUMP_STATS
|
||||||
|
@ -41,16 +43,19 @@ enum
|
||||||
PROP_REUSABLE,
|
PROP_REUSABLE,
|
||||||
PROP_PROTOCOLS,
|
PROP_PROTOCOLS,
|
||||||
PROP_EOS_SHUTDOWN,
|
PROP_EOS_SHUTDOWN,
|
||||||
|
PROP_BUFFER_SIZE,
|
||||||
PROP_LAST
|
PROP_LAST
|
||||||
};
|
};
|
||||||
|
|
||||||
enum
|
enum
|
||||||
{
|
{
|
||||||
|
SIGNAL_PREPARED,
|
||||||
SIGNAL_UNPREPARED,
|
SIGNAL_UNPREPARED,
|
||||||
|
SIGNAL_NEW_STATE,
|
||||||
SIGNAL_LAST
|
SIGNAL_LAST
|
||||||
};
|
};
|
||||||
|
|
||||||
GST_DEBUG_CATEGORY_EXTERN (rtsp_media_debug);
|
GST_DEBUG_CATEGORY_STATIC (rtsp_media_debug);
|
||||||
#define GST_CAT_DEFAULT rtsp_media_debug
|
#define GST_CAT_DEFAULT rtsp_media_debug
|
||||||
|
|
||||||
static GQuark ssrc_stream_map_key;
|
static GQuark ssrc_stream_map_key;
|
||||||
|
@ -103,14 +108,31 @@ gst_rtsp_media_class_init (GstRTSPMediaClass * klass)
|
||||||
"Send an EOS event to the pipeline before unpreparing",
|
"Send an EOS event to the pipeline before unpreparing",
|
||||||
DEFAULT_EOS_SHUTDOWN, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
|
DEFAULT_EOS_SHUTDOWN, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
|
||||||
|
|
||||||
|
g_object_class_install_property (gobject_class, PROP_BUFFER_SIZE,
|
||||||
|
g_param_spec_uint ("buffer-size", "Buffer Size",
|
||||||
|
"The kernel UDP buffer size to use", 0, G_MAXUINT,
|
||||||
|
DEFAULT_BUFFER_SIZE, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
|
||||||
|
|
||||||
|
gst_rtsp_media_signals[SIGNAL_PREPARED] =
|
||||||
|
g_signal_new ("prepared", G_TYPE_FROM_CLASS (klass), G_SIGNAL_RUN_LAST,
|
||||||
|
G_STRUCT_OFFSET (GstRTSPMediaClass, prepared), NULL, NULL,
|
||||||
|
g_cclosure_marshal_VOID__VOID, G_TYPE_NONE, 0, G_TYPE_NONE);
|
||||||
|
|
||||||
gst_rtsp_media_signals[SIGNAL_UNPREPARED] =
|
gst_rtsp_media_signals[SIGNAL_UNPREPARED] =
|
||||||
g_signal_new ("unprepared", G_TYPE_FROM_CLASS (klass), G_SIGNAL_RUN_LAST,
|
g_signal_new ("unprepared", G_TYPE_FROM_CLASS (klass), G_SIGNAL_RUN_LAST,
|
||||||
G_STRUCT_OFFSET (GstRTSPMediaClass, unprepared), NULL, NULL,
|
G_STRUCT_OFFSET (GstRTSPMediaClass, unprepared), NULL, NULL,
|
||||||
g_cclosure_marshal_VOID__VOID, G_TYPE_NONE, 0, G_TYPE_NONE);
|
g_cclosure_marshal_VOID__VOID, G_TYPE_NONE, 0, G_TYPE_NONE);
|
||||||
|
|
||||||
|
gst_rtsp_media_signals[SIGNAL_NEW_STATE] =
|
||||||
|
g_signal_new ("new-state", G_TYPE_FROM_CLASS (klass), G_SIGNAL_RUN_LAST,
|
||||||
|
G_STRUCT_OFFSET (GstRTSPMediaClass, new_state), NULL, NULL,
|
||||||
|
g_cclosure_marshal_VOID__INT, G_TYPE_NONE, 0, G_TYPE_INT);
|
||||||
|
|
||||||
klass->context = g_main_context_new ();
|
klass->context = g_main_context_new ();
|
||||||
klass->loop = g_main_loop_new (klass->context, TRUE);
|
klass->loop = g_main_loop_new (klass->context, TRUE);
|
||||||
|
|
||||||
|
GST_DEBUG_CATEGORY_INIT (rtsp_media_debug, "rtspmedia", 0, "GstRTSPMedia");
|
||||||
|
|
||||||
klass->thread = g_thread_create ((GThreadFunc) do_loop, klass, TRUE, &error);
|
klass->thread = g_thread_create ((GThreadFunc) do_loop, klass, TRUE, &error);
|
||||||
if (error != NULL) {
|
if (error != NULL) {
|
||||||
g_critical ("could not start bus thread: %s", error->message);
|
g_critical ("could not start bus thread: %s", error->message);
|
||||||
|
@ -119,6 +141,9 @@ gst_rtsp_media_class_init (GstRTSPMediaClass * klass)
|
||||||
klass->unprepare = default_unprepare;
|
klass->unprepare = default_unprepare;
|
||||||
|
|
||||||
ssrc_stream_map_key = g_quark_from_static_string ("GstRTSPServer.stream");
|
ssrc_stream_map_key = g_quark_from_static_string ("GstRTSPServer.stream");
|
||||||
|
|
||||||
|
gst_element_register (NULL, "rtspfunnel", GST_RANK_NONE, RTSP_TYPE_FUNNEL);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
|
@ -132,45 +157,7 @@ gst_rtsp_media_init (GstRTSPMedia * media)
|
||||||
media->reusable = DEFAULT_REUSABLE;
|
media->reusable = DEFAULT_REUSABLE;
|
||||||
media->protocols = DEFAULT_PROTOCOLS;
|
media->protocols = DEFAULT_PROTOCOLS;
|
||||||
media->eos_shutdown = DEFAULT_EOS_SHUTDOWN;
|
media->eos_shutdown = DEFAULT_EOS_SHUTDOWN;
|
||||||
}
|
media->buffer_size = DEFAULT_BUFFER_SIZE;
|
||||||
|
|
||||||
/* FIXME. this should be done in multiudpsink */
|
|
||||||
typedef struct
|
|
||||||
{
|
|
||||||
gint count;
|
|
||||||
gchar *dest;
|
|
||||||
gint min, max;
|
|
||||||
} RTSPDestination;
|
|
||||||
|
|
||||||
static gint
|
|
||||||
dest_compare (RTSPDestination * a, RTSPDestination * b)
|
|
||||||
{
|
|
||||||
if ((a->min == b->min) && (a->max == b->max)
|
|
||||||
&& (strcmp (a->dest, b->dest) == 0))
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
static RTSPDestination *
|
|
||||||
create_destination (const gchar * dest, gint min, gint max)
|
|
||||||
{
|
|
||||||
RTSPDestination *res;
|
|
||||||
|
|
||||||
res = g_slice_new (RTSPDestination);
|
|
||||||
res->count = 1;
|
|
||||||
res->dest = g_strdup (dest);
|
|
||||||
res->min = min;
|
|
||||||
res->max = max;
|
|
||||||
|
|
||||||
return res;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void
|
|
||||||
free_destination (RTSPDestination * dest)
|
|
||||||
{
|
|
||||||
g_free (dest->dest);
|
|
||||||
g_slice_free (RTSPDestination, dest);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
|
@ -208,9 +195,6 @@ gst_rtsp_media_stream_free (GstRTSPMediaStream * stream)
|
||||||
|
|
||||||
g_list_free (stream->transports);
|
g_list_free (stream->transports);
|
||||||
|
|
||||||
g_list_foreach (stream->destinations, (GFunc) free_destination, NULL);
|
|
||||||
g_list_free (stream->destinations);
|
|
||||||
|
|
||||||
g_free (stream);
|
g_free (stream);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -271,6 +255,9 @@ gst_rtsp_media_get_property (GObject * object, guint propid,
|
||||||
case PROP_EOS_SHUTDOWN:
|
case PROP_EOS_SHUTDOWN:
|
||||||
g_value_set_boolean (value, gst_rtsp_media_is_eos_shutdown (media));
|
g_value_set_boolean (value, gst_rtsp_media_is_eos_shutdown (media));
|
||||||
break;
|
break;
|
||||||
|
case PROP_BUFFER_SIZE:
|
||||||
|
g_value_set_uint (value, gst_rtsp_media_get_buffer_size (media));
|
||||||
|
break;
|
||||||
default:
|
default:
|
||||||
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, propid, pspec);
|
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, propid, pspec);
|
||||||
}
|
}
|
||||||
|
@ -295,6 +282,9 @@ gst_rtsp_media_set_property (GObject * object, guint propid,
|
||||||
case PROP_EOS_SHUTDOWN:
|
case PROP_EOS_SHUTDOWN:
|
||||||
gst_rtsp_media_set_eos_shutdown (media, g_value_get_boolean (value));
|
gst_rtsp_media_set_eos_shutdown (media, g_value_get_boolean (value));
|
||||||
break;
|
break;
|
||||||
|
case PROP_BUFFER_SIZE:
|
||||||
|
gst_rtsp_media_set_buffer_size (media, g_value_get_uint (value));
|
||||||
|
break;
|
||||||
default:
|
default:
|
||||||
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, propid, pspec);
|
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, propid, pspec);
|
||||||
}
|
}
|
||||||
|
@ -341,7 +331,7 @@ collect_media_stats (GstRTSPMedia * media)
|
||||||
GST_INFO ("stats: position %" GST_TIME_FORMAT ", duration %"
|
GST_INFO ("stats: position %" GST_TIME_FORMAT ", duration %"
|
||||||
GST_TIME_FORMAT, GST_TIME_ARGS (position), GST_TIME_ARGS (duration));
|
GST_TIME_FORMAT, GST_TIME_ARGS (position), GST_TIME_ARGS (duration));
|
||||||
|
|
||||||
if (position == -1 || media->active > 0) {
|
if (position == -1) {
|
||||||
media->range.min.type = GST_RTSP_TIME_NOW;
|
media->range.min.type = GST_RTSP_TIME_NOW;
|
||||||
media->range.min.seconds = -1;
|
media->range.min.seconds = -1;
|
||||||
} else {
|
} else {
|
||||||
|
@ -507,6 +497,85 @@ gst_rtsp_media_is_eos_shutdown (GstRTSPMedia * media)
|
||||||
return media->eos_shutdown;
|
return media->eos_shutdown;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* gst_rtsp_media_set_buffer_size:
|
||||||
|
* @media: a #GstRTSPMedia
|
||||||
|
* @size: the new value
|
||||||
|
*
|
||||||
|
* Set the kernel UDP buffer size.
|
||||||
|
*/
|
||||||
|
void
|
||||||
|
gst_rtsp_media_set_buffer_size (GstRTSPMedia * media, guint size)
|
||||||
|
{
|
||||||
|
g_return_if_fail (GST_IS_RTSP_MEDIA (media));
|
||||||
|
|
||||||
|
media->buffer_size = size;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* gst_rtsp_media_get_buffer_size:
|
||||||
|
* @media: a #GstRTSPMedia
|
||||||
|
*
|
||||||
|
* Get the kernel UDP buffer size.
|
||||||
|
*
|
||||||
|
* Returns: the kernel UDP buffer size.
|
||||||
|
*/
|
||||||
|
guint
|
||||||
|
gst_rtsp_media_get_buffer_size (GstRTSPMedia * media)
|
||||||
|
{
|
||||||
|
g_return_val_if_fail (GST_IS_RTSP_MEDIA (media), FALSE);
|
||||||
|
|
||||||
|
return media->buffer_size;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* gst_rtsp_media_set_auth:
|
||||||
|
* @media: a #GstRTSPMedia
|
||||||
|
* @auth: a #GstRTSPAuth
|
||||||
|
*
|
||||||
|
* configure @auth to be used as the authentication manager of @media.
|
||||||
|
*/
|
||||||
|
void
|
||||||
|
gst_rtsp_media_set_auth (GstRTSPMedia * media, GstRTSPAuth * auth)
|
||||||
|
{
|
||||||
|
GstRTSPAuth *old;
|
||||||
|
|
||||||
|
g_return_if_fail (GST_IS_RTSP_MEDIA (media));
|
||||||
|
|
||||||
|
old = media->auth;
|
||||||
|
|
||||||
|
if (old != auth) {
|
||||||
|
if (auth)
|
||||||
|
g_object_ref (auth);
|
||||||
|
media->auth = auth;
|
||||||
|
if (old)
|
||||||
|
g_object_unref (old);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* gst_rtsp_media_get_auth:
|
||||||
|
* @media: a #GstRTSPMedia
|
||||||
|
*
|
||||||
|
* Get the #GstRTSPAuth used as the authentication manager of @media.
|
||||||
|
*
|
||||||
|
* Returns: the #GstRTSPAuth of @media. g_object_unref() after
|
||||||
|
* usage.
|
||||||
|
*/
|
||||||
|
GstRTSPAuth *
|
||||||
|
gst_rtsp_media_get_auth (GstRTSPMedia * media)
|
||||||
|
{
|
||||||
|
GstRTSPAuth *result;
|
||||||
|
|
||||||
|
g_return_val_if_fail (GST_IS_RTSP_MEDIA (media), NULL);
|
||||||
|
|
||||||
|
if ((result = media->auth))
|
||||||
|
g_object_ref (result);
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* gst_rtsp_media_n_streams:
|
* gst_rtsp_media_n_streams:
|
||||||
* @media: a #GstRTSPMedia
|
* @media: a #GstRTSPMedia
|
||||||
|
@ -548,6 +617,34 @@ gst_rtsp_media_get_stream (GstRTSPMedia * media, guint idx)
|
||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* gst_rtsp_media_get_range_string:
|
||||||
|
* @media: a #GstRTSPMedia
|
||||||
|
* @play: for the PLAY request
|
||||||
|
*
|
||||||
|
* Get the current range as a string.
|
||||||
|
*
|
||||||
|
* Returns: The range as a string, g_free() after usage.
|
||||||
|
*/
|
||||||
|
gchar *
|
||||||
|
gst_rtsp_media_get_range_string (GstRTSPMedia * media, gboolean play)
|
||||||
|
{
|
||||||
|
gchar *result;
|
||||||
|
GstRTSPTimeRange range;
|
||||||
|
|
||||||
|
/* make copy */
|
||||||
|
range = media->range;
|
||||||
|
|
||||||
|
if (!play && media->active > 0) {
|
||||||
|
range.min.type = GST_RTSP_TIME_NOW;
|
||||||
|
range.min.seconds = -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
result = gst_rtsp_range_to_string (&range);
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* gst_rtsp_media_seek:
|
* gst_rtsp_media_seek:
|
||||||
* @media: a #GstRTSPMedia
|
* @media: a #GstRTSPMedia
|
||||||
|
@ -804,10 +901,16 @@ again:
|
||||||
"send-duplicates")) {
|
"send-duplicates")) {
|
||||||
g_object_set (G_OBJECT (udpsink0), "send-duplicates", FALSE, NULL);
|
g_object_set (G_OBJECT (udpsink0), "send-duplicates", FALSE, NULL);
|
||||||
g_object_set (G_OBJECT (udpsink1), "send-duplicates", FALSE, NULL);
|
g_object_set (G_OBJECT (udpsink1), "send-duplicates", FALSE, NULL);
|
||||||
stream->filter_duplicates = FALSE;
|
|
||||||
} else {
|
} else {
|
||||||
GST_WARNING ("multiudpsink version found without send-duplicates property");
|
g_warning
|
||||||
stream->filter_duplicates = TRUE;
|
("old multiudpsink version found without send-duplicates property");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (g_object_class_find_property (G_OBJECT_GET_CLASS (udpsink0),
|
||||||
|
"buffer-size")) {
|
||||||
|
g_object_set (G_OBJECT (udpsink0), "buffer-size", media->buffer_size, NULL);
|
||||||
|
} else {
|
||||||
|
GST_WARNING ("multiudpsink version found without buffer-size property");
|
||||||
}
|
}
|
||||||
|
|
||||||
g_object_get (G_OBJECT (udpsrc1), "sock", &sockfd, NULL);
|
g_object_get (G_OBJECT (udpsrc1), "sock", &sockfd, NULL);
|
||||||
|
@ -1068,10 +1171,42 @@ handle_new_buffer (GstAppSink * sink, gpointer user_data)
|
||||||
return GST_FLOW_OK;
|
return GST_FLOW_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static GstFlowReturn
|
||||||
|
handle_new_buffer_list (GstAppSink * sink, gpointer user_data)
|
||||||
|
{
|
||||||
|
GList *walk;
|
||||||
|
GstBufferList *blist;
|
||||||
|
GstRTSPMediaStream *stream;
|
||||||
|
|
||||||
|
blist = gst_app_sink_pull_buffer_list (sink);
|
||||||
|
if (!blist)
|
||||||
|
return GST_FLOW_OK;
|
||||||
|
|
||||||
|
stream = (GstRTSPMediaStream *) user_data;
|
||||||
|
|
||||||
|
for (walk = stream->transports; walk; walk = g_list_next (walk)) {
|
||||||
|
GstRTSPMediaTrans *tr = (GstRTSPMediaTrans *) walk->data;
|
||||||
|
|
||||||
|
if (GST_ELEMENT_CAST (sink) == stream->appsink[0]) {
|
||||||
|
if (tr->send_rtp_list)
|
||||||
|
tr->send_rtp_list (blist, tr->transport->interleaved.min,
|
||||||
|
tr->user_data);
|
||||||
|
} else {
|
||||||
|
if (tr->send_rtcp_list)
|
||||||
|
tr->send_rtcp_list (blist, tr->transport->interleaved.max,
|
||||||
|
tr->user_data);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
gst_buffer_list_unref (blist);
|
||||||
|
|
||||||
|
return GST_FLOW_OK;
|
||||||
|
}
|
||||||
|
|
||||||
static GstAppSinkCallbacks sink_cb = {
|
static GstAppSinkCallbacks sink_cb = {
|
||||||
NULL, /* not interested in EOS */
|
NULL, /* not interested in EOS */
|
||||||
NULL, /* not interested in preroll buffers */
|
NULL, /* not interested in preroll buffers */
|
||||||
handle_new_buffer
|
handle_new_buffer,
|
||||||
|
handle_new_buffer_list
|
||||||
};
|
};
|
||||||
|
|
||||||
/* prepare the pipeline objects to handle @stream in @media */
|
/* prepare the pipeline objects to handle @stream in @media */
|
||||||
|
@ -1190,8 +1325,7 @@ setup_stream (GstRTSPMediaStream * stream, guint idx, GstRTSPMedia * media)
|
||||||
gst_object_unref (teepad);
|
gst_object_unref (teepad);
|
||||||
|
|
||||||
/* make selector for the RTP receivers */
|
/* make selector for the RTP receivers */
|
||||||
stream->selector[0] = gst_element_factory_make ("input-selector", NULL);
|
stream->selector[0] = gst_element_factory_make ("rtspfunnel", NULL);
|
||||||
g_object_set (stream->selector[0], "select-all", TRUE, NULL);
|
|
||||||
gst_bin_add (GST_BIN_CAST (media->pipeline), stream->selector[0]);
|
gst_bin_add (GST_BIN_CAST (media->pipeline), stream->selector[0]);
|
||||||
|
|
||||||
pad = gst_element_get_static_pad (stream->selector[0], "src");
|
pad = gst_element_get_static_pad (stream->selector[0], "src");
|
||||||
|
@ -1211,8 +1345,7 @@ setup_stream (GstRTSPMediaStream * stream, guint idx, GstRTSPMedia * media)
|
||||||
gst_object_unref (selpad);
|
gst_object_unref (selpad);
|
||||||
|
|
||||||
/* make selector for the RTCP receivers */
|
/* make selector for the RTCP receivers */
|
||||||
stream->selector[1] = gst_element_factory_make ("input-selector", NULL);
|
stream->selector[1] = gst_element_factory_make ("rtspfunnel", NULL);
|
||||||
g_object_set (stream->selector[1], "select-all", TRUE, NULL);
|
|
||||||
gst_bin_add (GST_BIN_CAST (media->pipeline), stream->selector[1]);
|
gst_bin_add (GST_BIN_CAST (media->pipeline), stream->selector[1]);
|
||||||
|
|
||||||
pad = gst_element_get_static_pad (stream->selector[1], "src");
|
pad = gst_element_get_static_pad (stream->selector[1], "src");
|
||||||
|
@ -1594,6 +1727,8 @@ gst_rtsp_media_prepare (GstRTSPMedia * media)
|
||||||
if (status == GST_RTSP_MEDIA_STATUS_ERROR)
|
if (status == GST_RTSP_MEDIA_STATUS_ERROR)
|
||||||
goto state_failed;
|
goto state_failed;
|
||||||
|
|
||||||
|
g_signal_emit (media, gst_rtsp_media_signals[SIGNAL_PREPARED], 0, NULL);
|
||||||
|
|
||||||
GST_INFO ("object %p is prerolled", media);
|
GST_INFO ("object %p is prerolled", media);
|
||||||
|
|
||||||
return TRUE;
|
return TRUE;
|
||||||
|
@ -1686,83 +1821,18 @@ static void
|
||||||
add_udp_destination (GstRTSPMedia * media, GstRTSPMediaStream * stream,
|
add_udp_destination (GstRTSPMedia * media, GstRTSPMediaStream * stream,
|
||||||
gchar * dest, gint min, gint max)
|
gchar * dest, gint min, gint max)
|
||||||
{
|
{
|
||||||
gboolean do_add = TRUE;
|
|
||||||
RTSPDestination *ndest;
|
|
||||||
|
|
||||||
if (stream->filter_duplicates) {
|
|
||||||
RTSPDestination fdest;
|
|
||||||
GList *find;
|
|
||||||
|
|
||||||
fdest.dest = dest;
|
|
||||||
fdest.min = min;
|
|
||||||
fdest.max = max;
|
|
||||||
|
|
||||||
/* first see if we already added this destination */
|
|
||||||
find =
|
|
||||||
g_list_find_custom (stream->destinations, &fdest,
|
|
||||||
(GCompareFunc) dest_compare);
|
|
||||||
if (find) {
|
|
||||||
ndest = (RTSPDestination *) find->data;
|
|
||||||
|
|
||||||
GST_INFO ("already streaming to %s:%d-%d with %d clients", dest, min, max,
|
|
||||||
ndest->count);
|
|
||||||
ndest->count++;
|
|
||||||
do_add = FALSE;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (do_add) {
|
|
||||||
GST_INFO ("adding %s:%d-%d", dest, min, max);
|
GST_INFO ("adding %s:%d-%d", dest, min, max);
|
||||||
g_signal_emit_by_name (stream->udpsink[0], "add", dest, min, NULL);
|
g_signal_emit_by_name (stream->udpsink[0], "add", dest, min, NULL);
|
||||||
g_signal_emit_by_name (stream->udpsink[1], "add", dest, max, NULL);
|
g_signal_emit_by_name (stream->udpsink[1], "add", dest, max, NULL);
|
||||||
|
|
||||||
if (stream->filter_duplicates) {
|
|
||||||
ndest = create_destination (dest, min, max);
|
|
||||||
stream->destinations = g_list_prepend (stream->destinations, ndest);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
remove_udp_destination (GstRTSPMedia * media, GstRTSPMediaStream * stream,
|
remove_udp_destination (GstRTSPMedia * media, GstRTSPMediaStream * stream,
|
||||||
gchar * dest, gint min, gint max)
|
gchar * dest, gint min, gint max)
|
||||||
{
|
{
|
||||||
gboolean do_remove = TRUE;
|
|
||||||
RTSPDestination *ndest = NULL;
|
|
||||||
GList *find = NULL;
|
|
||||||
|
|
||||||
if (stream->filter_duplicates) {
|
|
||||||
RTSPDestination fdest;
|
|
||||||
|
|
||||||
fdest.dest = dest;
|
|
||||||
fdest.min = min;
|
|
||||||
fdest.max = max;
|
|
||||||
|
|
||||||
/* first see if we already added this destination */
|
|
||||||
find =
|
|
||||||
g_list_find_custom (stream->destinations, &fdest,
|
|
||||||
(GCompareFunc) dest_compare);
|
|
||||||
if (!find)
|
|
||||||
return;
|
|
||||||
|
|
||||||
ndest = (RTSPDestination *) find->data;
|
|
||||||
if (--ndest->count > 0) {
|
|
||||||
do_remove = FALSE;
|
|
||||||
GST_INFO ("still streaming to %s:%d-%d with %d clients", dest, min, max,
|
|
||||||
ndest->count);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (do_remove) {
|
|
||||||
GST_INFO ("removing %s:%d-%d", dest, min, max);
|
GST_INFO ("removing %s:%d-%d", dest, min, max);
|
||||||
g_signal_emit_by_name (stream->udpsink[0], "remove", dest, min, NULL);
|
g_signal_emit_by_name (stream->udpsink[0], "remove", dest, min, NULL);
|
||||||
g_signal_emit_by_name (stream->udpsink[1], "remove", dest, max, NULL);
|
g_signal_emit_by_name (stream->udpsink[1], "remove", dest, max, NULL);
|
||||||
|
|
||||||
if (stream->filter_duplicates) {
|
|
||||||
stream->destinations = g_list_delete_link (stream->destinations, find);
|
|
||||||
free_destination (ndest);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -1888,17 +1958,23 @@ gst_rtsp_media_set_state (GstRTSPMedia * media, GstState state,
|
||||||
else
|
else
|
||||||
do_state = FALSE;
|
do_state = FALSE;
|
||||||
|
|
||||||
GST_INFO ("active %d media %p", media->active, media);
|
GST_INFO ("state %d active %d media %p do_state %d", state, media->active,
|
||||||
|
media, do_state);
|
||||||
|
|
||||||
if (do_state && media->target_state != state) {
|
if (media->target_state != state) {
|
||||||
|
if (do_state) {
|
||||||
if (state == GST_STATE_NULL) {
|
if (state == GST_STATE_NULL) {
|
||||||
gst_rtsp_media_unprepare (media);
|
gst_rtsp_media_unprepare (media);
|
||||||
} else {
|
} else {
|
||||||
GST_INFO ("state %s media %p", gst_element_state_get_name (state), media);
|
GST_INFO ("state %s media %p", gst_element_state_get_name (state),
|
||||||
|
media);
|
||||||
media->target_state = state;
|
media->target_state = state;
|
||||||
ret = gst_element_set_state (media->pipeline, state);
|
ret = gst_element_set_state (media->pipeline, state);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
g_signal_emit (media, gst_rtsp_media_signals[SIGNAL_NEW_STATE], 0, state,
|
||||||
|
NULL);
|
||||||
|
}
|
||||||
|
|
||||||
/* remember where we are */
|
/* remember where we are */
|
||||||
if (state == GST_STATE_PAUSED || old_active != media->active)
|
if (state == GST_STATE_PAUSED || old_active != media->active)
|
||||||
|
|
|
@ -42,6 +42,7 @@ typedef struct _GstRTSPMediaClass GstRTSPMediaClass;
|
||||||
typedef struct _GstRTSPMediaTrans GstRTSPMediaTrans;
|
typedef struct _GstRTSPMediaTrans GstRTSPMediaTrans;
|
||||||
|
|
||||||
typedef gboolean (*GstRTSPSendFunc) (GstBuffer *buffer, guint8 channel, gpointer user_data);
|
typedef gboolean (*GstRTSPSendFunc) (GstBuffer *buffer, guint8 channel, gpointer user_data);
|
||||||
|
typedef gboolean (*GstRTSPSendListFunc) (GstBufferList *blist, guint8 channel, gpointer user_data);
|
||||||
typedef void (*GstRTSPKeepAliveFunc) (gpointer user_data);
|
typedef void (*GstRTSPKeepAliveFunc) (gpointer user_data);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -49,6 +50,8 @@ typedef void (*GstRTSPKeepAliveFunc) (gpointer user_data);
|
||||||
* @idx: a stream index
|
* @idx: a stream index
|
||||||
* @send_rtp: callback for sending RTP messages
|
* @send_rtp: callback for sending RTP messages
|
||||||
* @send_rtcp: callback for sending RTCP messages
|
* @send_rtcp: callback for sending RTCP messages
|
||||||
|
* @send_rtp_list: callback for sending RTP messages
|
||||||
|
* @send_rtcp_list: callback for sending RTCP messages
|
||||||
* @user_data: user data passed in the callbacks
|
* @user_data: user data passed in the callbacks
|
||||||
* @notify: free function for the user_data.
|
* @notify: free function for the user_data.
|
||||||
* @keep_alive: keep alive callback
|
* @keep_alive: keep alive callback
|
||||||
|
@ -66,6 +69,8 @@ struct _GstRTSPMediaTrans {
|
||||||
|
|
||||||
GstRTSPSendFunc send_rtp;
|
GstRTSPSendFunc send_rtp;
|
||||||
GstRTSPSendFunc send_rtcp;
|
GstRTSPSendFunc send_rtcp;
|
||||||
|
GstRTSPSendListFunc send_rtp_list;
|
||||||
|
GstRTSPSendListFunc send_rtcp_list;
|
||||||
gpointer user_data;
|
gpointer user_data;
|
||||||
GDestroyNotify notify;
|
GDestroyNotify notify;
|
||||||
|
|
||||||
|
@ -80,16 +85,17 @@ struct _GstRTSPMediaTrans {
|
||||||
GObject *rtpsource;
|
GObject *rtpsource;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
#include "rtsp-auth.h"
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* GstRTSPMediaStream:
|
* GstRTSPMediaStream:
|
||||||
* @srcpad: the srcpad of the stream
|
* @srcpad: the srcpad of the stream
|
||||||
* @payloader: the payloader of the format
|
* @payloader: the payloader of the format
|
||||||
* @prepared: if the stream is prepared for streaming
|
* @prepared: if the stream is prepared for streaming
|
||||||
* @server_port: the server udp ports
|
|
||||||
* @recv_rtp_sink: sinkpad for RTP buffers
|
* @recv_rtp_sink: sinkpad for RTP buffers
|
||||||
* @recv_rtcp_sink: sinkpad for RTCP buffers
|
* @recv_rtcp_sink: sinkpad for RTCP buffers
|
||||||
* @recv_rtp_src: srcpad for RTP buffers
|
* @send_rtp_src: srcpad for RTP buffers
|
||||||
* @recv_rtcp_src: srcpad for RTCP buffers
|
* @send_rtcp_src: srcpad for RTCP buffers
|
||||||
* @udpsrc: the udp source elements for RTP/RTCP
|
* @udpsrc: the udp source elements for RTP/RTCP
|
||||||
* @udpsink: the udp sink elements for RTP/RTCP
|
* @udpsink: the udp sink elements for RTP/RTCP
|
||||||
* @appsrc: the app source elements for RTP/RTCP
|
* @appsrc: the app source elements for RTP/RTCP
|
||||||
|
@ -136,11 +142,6 @@ struct _GstRTSPMediaStream {
|
||||||
|
|
||||||
/* transports we stream to */
|
/* transports we stream to */
|
||||||
GList *transports;
|
GList *transports;
|
||||||
|
|
||||||
/* to filter out duplicate destinations in case multiudpsink is too old to do
|
|
||||||
* this for us */
|
|
||||||
gboolean filter_duplicates;
|
|
||||||
GList *destinations;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -200,6 +201,8 @@ struct _GstRTSPMedia {
|
||||||
gboolean reused;
|
gboolean reused;
|
||||||
gboolean is_ipv6;
|
gboolean is_ipv6;
|
||||||
gboolean eos_shutdown;
|
gboolean eos_shutdown;
|
||||||
|
guint buffer_size;
|
||||||
|
GstRTSPAuth *auth;
|
||||||
|
|
||||||
GstElement *element;
|
GstElement *element;
|
||||||
GArray *streams;
|
GArray *streams;
|
||||||
|
@ -250,7 +253,10 @@ struct _GstRTSPMediaClass {
|
||||||
gboolean (*unprepare) (GstRTSPMedia *media);
|
gboolean (*unprepare) (GstRTSPMedia *media);
|
||||||
|
|
||||||
/* signals */
|
/* signals */
|
||||||
|
gboolean (*prepared) (GstRTSPMedia *media);
|
||||||
gboolean (*unprepared) (GstRTSPMedia *media);
|
gboolean (*unprepared) (GstRTSPMedia *media);
|
||||||
|
|
||||||
|
gboolean (*new_state) (GstRTSPMedia *media, GstState state);
|
||||||
};
|
};
|
||||||
|
|
||||||
GType gst_rtsp_media_get_type (void);
|
GType gst_rtsp_media_get_type (void);
|
||||||
|
@ -270,6 +276,12 @@ GstRTSPLowerTrans gst_rtsp_media_get_protocols (GstRTSPMedia *media);
|
||||||
void gst_rtsp_media_set_eos_shutdown (GstRTSPMedia *media, gboolean eos_shutdown);
|
void gst_rtsp_media_set_eos_shutdown (GstRTSPMedia *media, gboolean eos_shutdown);
|
||||||
gboolean gst_rtsp_media_is_eos_shutdown (GstRTSPMedia *media);
|
gboolean gst_rtsp_media_is_eos_shutdown (GstRTSPMedia *media);
|
||||||
|
|
||||||
|
void gst_rtsp_media_set_auth (GstRTSPMedia *media, GstRTSPAuth *auth);
|
||||||
|
GstRTSPAuth * gst_rtsp_media_get_auth (GstRTSPMedia *media);
|
||||||
|
|
||||||
|
void gst_rtsp_media_set_buffer_size (GstRTSPMedia *media, guint size);
|
||||||
|
guint gst_rtsp_media_get_buffer_size (GstRTSPMedia *media);
|
||||||
|
|
||||||
/* prepare the media for playback */
|
/* prepare the media for playback */
|
||||||
gboolean gst_rtsp_media_prepare (GstRTSPMedia *media);
|
gboolean gst_rtsp_media_prepare (GstRTSPMedia *media);
|
||||||
gboolean gst_rtsp_media_is_prepared (GstRTSPMedia *media);
|
gboolean gst_rtsp_media_is_prepared (GstRTSPMedia *media);
|
||||||
|
@ -280,6 +292,7 @@ guint gst_rtsp_media_n_streams (GstRTSPMedia *media);
|
||||||
GstRTSPMediaStream * gst_rtsp_media_get_stream (GstRTSPMedia *media, guint idx);
|
GstRTSPMediaStream * gst_rtsp_media_get_stream (GstRTSPMedia *media, guint idx);
|
||||||
|
|
||||||
gboolean gst_rtsp_media_seek (GstRTSPMedia *media, GstRTSPTimeRange *range);
|
gboolean gst_rtsp_media_seek (GstRTSPMedia *media, GstRTSPTimeRange *range);
|
||||||
|
gchar * gst_rtsp_media_get_range_string (GstRTSPMedia *media, gboolean play);
|
||||||
|
|
||||||
GstFlowReturn gst_rtsp_media_stream_rtp (GstRTSPMediaStream *stream, GstBuffer *buffer);
|
GstFlowReturn gst_rtsp_media_stream_rtp (GstRTSPMediaStream *stream, GstBuffer *buffer);
|
||||||
GstFlowReturn gst_rtsp_media_stream_rtcp (GstRTSPMediaStream *stream, GstBuffer *buffer);
|
GstFlowReturn gst_rtsp_media_stream_rtcp (GstRTSPMediaStream *stream, GstBuffer *buffer);
|
||||||
|
|
|
@ -21,9 +21,7 @@
|
||||||
#include "rtsp-params.h"
|
#include "rtsp-params.h"
|
||||||
|
|
||||||
GstRTSPResult
|
GstRTSPResult
|
||||||
gst_rtsp_params_set (GstRTSPClient * client, GstRTSPUrl * uri,
|
gst_rtsp_params_set (GstRTSPClient * client, GstRTSPClientState * state)
|
||||||
GstRTSPSession * session, GstRTSPMessage * request,
|
|
||||||
GstRTSPMessage * response)
|
|
||||||
{
|
{
|
||||||
GstRTSPStatusCode code;
|
GstRTSPStatusCode code;
|
||||||
|
|
||||||
|
@ -31,16 +29,14 @@ gst_rtsp_params_set (GstRTSPClient * client, GstRTSPUrl * uri,
|
||||||
* with a list of the parameters */
|
* with a list of the parameters */
|
||||||
code = GST_RTSP_STS_PARAMETER_NOT_UNDERSTOOD;
|
code = GST_RTSP_STS_PARAMETER_NOT_UNDERSTOOD;
|
||||||
|
|
||||||
gst_rtsp_message_init_response (response, code,
|
gst_rtsp_message_init_response (state->response, code,
|
||||||
gst_rtsp_status_as_text (code), request);
|
gst_rtsp_status_as_text (code), state->request);
|
||||||
|
|
||||||
return GST_RTSP_OK;
|
return GST_RTSP_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
GstRTSPResult
|
GstRTSPResult
|
||||||
gst_rtsp_params_get (GstRTSPClient * client, GstRTSPUrl * uri,
|
gst_rtsp_params_get (GstRTSPClient * client, GstRTSPClientState * state)
|
||||||
GstRTSPSession * session, GstRTSPMessage * request,
|
|
||||||
GstRTSPMessage * response)
|
|
||||||
{
|
{
|
||||||
GstRTSPStatusCode code;
|
GstRTSPStatusCode code;
|
||||||
|
|
||||||
|
@ -48,8 +44,8 @@ gst_rtsp_params_get (GstRTSPClient * client, GstRTSPUrl * uri,
|
||||||
* with a list of the parameters */
|
* with a list of the parameters */
|
||||||
code = GST_RTSP_STS_PARAMETER_NOT_UNDERSTOOD;
|
code = GST_RTSP_STS_PARAMETER_NOT_UNDERSTOOD;
|
||||||
|
|
||||||
gst_rtsp_message_init_response (response, code,
|
gst_rtsp_message_init_response (state->response, code,
|
||||||
gst_rtsp_status_as_text (code), request);
|
gst_rtsp_status_as_text (code), state->request);
|
||||||
|
|
||||||
return GST_RTSP_OK;
|
return GST_RTSP_OK;
|
||||||
}
|
}
|
||||||
|
|
|
@ -30,13 +30,8 @@
|
||||||
|
|
||||||
G_BEGIN_DECLS
|
G_BEGIN_DECLS
|
||||||
|
|
||||||
GstRTSPResult gst_rtsp_params_set (GstRTSPClient * client, GstRTSPUrl * uri,
|
GstRTSPResult gst_rtsp_params_set (GstRTSPClient * client, GstRTSPClientState * state);
|
||||||
GstRTSPSession * session, GstRTSPMessage * request,
|
GstRTSPResult gst_rtsp_params_get (GstRTSPClient * client, GstRTSPClientState * state);
|
||||||
GstRTSPMessage * response);
|
|
||||||
|
|
||||||
GstRTSPResult gst_rtsp_params_get (GstRTSPClient * client, GstRTSPUrl * uri,
|
|
||||||
GstRTSPSession * session, GstRTSPMessage * request,
|
|
||||||
GstRTSPMessage * response);
|
|
||||||
|
|
||||||
G_END_DECLS
|
G_END_DECLS
|
||||||
|
|
||||||
|
|
|
@ -43,7 +43,7 @@ gst_rtsp_sdp_from_media (GstSDPMessage * sdp, GstSDPInfo * info,
|
||||||
|
|
||||||
n_streams = gst_rtsp_media_n_streams (media);
|
n_streams = gst_rtsp_media_n_streams (media);
|
||||||
|
|
||||||
rangestr = gst_rtsp_range_to_string (&media->range);
|
rangestr = gst_rtsp_media_get_range_string (media, FALSE);
|
||||||
gst_sdp_message_add_attribute (sdp, "range", rangestr);
|
gst_sdp_message_add_attribute (sdp, "range", rangestr);
|
||||||
g_free (rangestr);
|
g_free (rangestr);
|
||||||
|
|
||||||
|
|
|
@ -17,6 +17,19 @@
|
||||||
* Boston, MA 02111-1307, USA.
|
* Boston, MA 02111-1307, USA.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
#include <errno.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <sys/time.h>
|
||||||
|
#include <sys/types.h>
|
||||||
|
#include <netinet/in.h>
|
||||||
|
#include <netdb.h>
|
||||||
|
#include <sys/socket.h>
|
||||||
|
#include <sys/wait.h>
|
||||||
|
#include <fcntl.h>
|
||||||
|
#include <arpa/inet.h>
|
||||||
#include <sys/ioctl.h>
|
#include <sys/ioctl.h>
|
||||||
|
|
||||||
#include "rtsp-server.h"
|
#include "rtsp-server.h"
|
||||||
|
@ -55,8 +68,9 @@ static void gst_rtsp_server_set_property (GObject * object, guint propid,
|
||||||
const GValue * value, GParamSpec * pspec);
|
const GValue * value, GParamSpec * pspec);
|
||||||
static void gst_rtsp_server_finalize (GObject * object);
|
static void gst_rtsp_server_finalize (GObject * object);
|
||||||
|
|
||||||
static GstRTSPClient *default_accept_client (GstRTSPServer * server,
|
static GstRTSPClient *default_create_client (GstRTSPServer * server);
|
||||||
GIOChannel * channel);
|
static gboolean default_accept_client (GstRTSPServer * server,
|
||||||
|
GstRTSPClient * client, GIOChannel * channel);
|
||||||
|
|
||||||
static void
|
static void
|
||||||
gst_rtsp_server_class_init (GstRTSPServerClass * klass)
|
gst_rtsp_server_class_init (GstRTSPServerClass * klass)
|
||||||
|
@ -127,6 +141,7 @@ gst_rtsp_server_class_init (GstRTSPServerClass * klass)
|
||||||
GST_TYPE_RTSP_MEDIA_MAPPING,
|
GST_TYPE_RTSP_MEDIA_MAPPING,
|
||||||
G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
|
G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
|
||||||
|
|
||||||
|
klass->create_client = default_create_client;
|
||||||
klass->accept_client = default_accept_client;
|
klass->accept_client = default_accept_client;
|
||||||
|
|
||||||
GST_DEBUG_CATEGORY_INIT (rtsp_server_debug, "rtspserver", 0, "GstRTSPServer");
|
GST_DEBUG_CATEGORY_INIT (rtsp_server_debug, "rtspserver", 0, "GstRTSPServer");
|
||||||
|
@ -135,6 +150,7 @@ gst_rtsp_server_class_init (GstRTSPServerClass * klass)
|
||||||
static void
|
static void
|
||||||
gst_rtsp_server_init (GstRTSPServer * server)
|
gst_rtsp_server_init (GstRTSPServer * server)
|
||||||
{
|
{
|
||||||
|
server->lock = g_mutex_new ();
|
||||||
server->address = g_strdup (DEFAULT_ADDRESS);
|
server->address = g_strdup (DEFAULT_ADDRESS);
|
||||||
server->service = g_strdup (DEFAULT_SERVICE);
|
server->service = g_strdup (DEFAULT_SERVICE);
|
||||||
server->backlog = DEFAULT_BACKLOG;
|
server->backlog = DEFAULT_BACKLOG;
|
||||||
|
@ -147,11 +163,20 @@ gst_rtsp_server_finalize (GObject * object)
|
||||||
{
|
{
|
||||||
GstRTSPServer *server = GST_RTSP_SERVER (object);
|
GstRTSPServer *server = GST_RTSP_SERVER (object);
|
||||||
|
|
||||||
|
GST_DEBUG_OBJECT (server, "finalize server");
|
||||||
|
|
||||||
g_free (server->address);
|
g_free (server->address);
|
||||||
g_free (server->service);
|
g_free (server->service);
|
||||||
|
|
||||||
g_object_unref (server->session_pool);
|
g_object_unref (server->session_pool);
|
||||||
g_object_unref (server->media_mapping);
|
g_object_unref (server->media_mapping);
|
||||||
|
|
||||||
|
if (server->auth)
|
||||||
|
g_object_unref (server->auth);
|
||||||
|
|
||||||
|
g_mutex_free (server->lock);
|
||||||
|
|
||||||
|
G_OBJECT_CLASS (gst_rtsp_server_parent_class)->finalize (object);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -184,8 +209,10 @@ gst_rtsp_server_set_address (GstRTSPServer * server, const gchar * address)
|
||||||
g_return_if_fail (GST_IS_RTSP_SERVER (server));
|
g_return_if_fail (GST_IS_RTSP_SERVER (server));
|
||||||
g_return_if_fail (address != NULL);
|
g_return_if_fail (address != NULL);
|
||||||
|
|
||||||
|
GST_RTSP_SERVER_LOCK (server);
|
||||||
g_free (server->address);
|
g_free (server->address);
|
||||||
server->address = g_strdup (address);
|
server->address = g_strdup (address);
|
||||||
|
GST_RTSP_SERVER_UNLOCK (server);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -199,9 +226,14 @@ gst_rtsp_server_set_address (GstRTSPServer * server, const gchar * address)
|
||||||
gchar *
|
gchar *
|
||||||
gst_rtsp_server_get_address (GstRTSPServer * server)
|
gst_rtsp_server_get_address (GstRTSPServer * server)
|
||||||
{
|
{
|
||||||
|
gchar *result;
|
||||||
g_return_val_if_fail (GST_IS_RTSP_SERVER (server), NULL);
|
g_return_val_if_fail (GST_IS_RTSP_SERVER (server), NULL);
|
||||||
|
|
||||||
return g_strdup (server->address);
|
GST_RTSP_SERVER_LOCK (server);
|
||||||
|
result = g_strdup (server->address);
|
||||||
|
GST_RTSP_SERVER_UNLOCK (server);
|
||||||
|
|
||||||
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -221,8 +253,10 @@ gst_rtsp_server_set_service (GstRTSPServer * server, const gchar * service)
|
||||||
g_return_if_fail (GST_IS_RTSP_SERVER (server));
|
g_return_if_fail (GST_IS_RTSP_SERVER (server));
|
||||||
g_return_if_fail (service != NULL);
|
g_return_if_fail (service != NULL);
|
||||||
|
|
||||||
|
GST_RTSP_SERVER_LOCK (server);
|
||||||
g_free (server->service);
|
g_free (server->service);
|
||||||
server->service = g_strdup (service);
|
server->service = g_strdup (service);
|
||||||
|
GST_RTSP_SERVER_UNLOCK (server);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -236,9 +270,15 @@ gst_rtsp_server_set_service (GstRTSPServer * server, const gchar * service)
|
||||||
gchar *
|
gchar *
|
||||||
gst_rtsp_server_get_service (GstRTSPServer * server)
|
gst_rtsp_server_get_service (GstRTSPServer * server)
|
||||||
{
|
{
|
||||||
|
gchar *result;
|
||||||
|
|
||||||
g_return_val_if_fail (GST_IS_RTSP_SERVER (server), NULL);
|
g_return_val_if_fail (GST_IS_RTSP_SERVER (server), NULL);
|
||||||
|
|
||||||
return g_strdup (server->service);
|
GST_RTSP_SERVER_LOCK (server);
|
||||||
|
result = g_strdup (server->service);
|
||||||
|
GST_RTSP_SERVER_UNLOCK (server);
|
||||||
|
|
||||||
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -256,7 +296,9 @@ gst_rtsp_server_set_backlog (GstRTSPServer * server, gint backlog)
|
||||||
{
|
{
|
||||||
g_return_if_fail (GST_IS_RTSP_SERVER (server));
|
g_return_if_fail (GST_IS_RTSP_SERVER (server));
|
||||||
|
|
||||||
|
GST_RTSP_SERVER_LOCK (server);
|
||||||
server->backlog = backlog;
|
server->backlog = backlog;
|
||||||
|
GST_RTSP_SERVER_UNLOCK (server);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -270,9 +312,15 @@ gst_rtsp_server_set_backlog (GstRTSPServer * server, gint backlog)
|
||||||
gint
|
gint
|
||||||
gst_rtsp_server_get_backlog (GstRTSPServer * server)
|
gst_rtsp_server_get_backlog (GstRTSPServer * server)
|
||||||
{
|
{
|
||||||
|
gint result;
|
||||||
|
|
||||||
g_return_val_if_fail (GST_IS_RTSP_SERVER (server), -1);
|
g_return_val_if_fail (GST_IS_RTSP_SERVER (server), -1);
|
||||||
|
|
||||||
return server->backlog;
|
GST_RTSP_SERVER_LOCK (server);
|
||||||
|
result = server->backlog;
|
||||||
|
GST_RTSP_SERVER_UNLOCK (server);
|
||||||
|
|
||||||
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -290,15 +338,16 @@ gst_rtsp_server_set_session_pool (GstRTSPServer * server,
|
||||||
|
|
||||||
g_return_if_fail (GST_IS_RTSP_SERVER (server));
|
g_return_if_fail (GST_IS_RTSP_SERVER (server));
|
||||||
|
|
||||||
old = server->session_pool;
|
|
||||||
|
|
||||||
if (old != pool) {
|
|
||||||
if (pool)
|
if (pool)
|
||||||
g_object_ref (pool);
|
g_object_ref (pool);
|
||||||
|
|
||||||
|
GST_RTSP_SERVER_LOCK (server);
|
||||||
|
old = server->session_pool;
|
||||||
server->session_pool = pool;
|
server->session_pool = pool;
|
||||||
|
GST_RTSP_SERVER_UNLOCK (server);
|
||||||
|
|
||||||
if (old)
|
if (old)
|
||||||
g_object_unref (old);
|
g_object_unref (old);
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -317,8 +366,10 @@ gst_rtsp_server_get_session_pool (GstRTSPServer * server)
|
||||||
|
|
||||||
g_return_val_if_fail (GST_IS_RTSP_SERVER (server), NULL);
|
g_return_val_if_fail (GST_IS_RTSP_SERVER (server), NULL);
|
||||||
|
|
||||||
|
GST_RTSP_SERVER_LOCK (server);
|
||||||
if ((result = server->session_pool))
|
if ((result = server->session_pool))
|
||||||
g_object_ref (result);
|
g_object_ref (result);
|
||||||
|
GST_RTSP_SERVER_UNLOCK (server);
|
||||||
|
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
@ -338,15 +389,16 @@ gst_rtsp_server_set_media_mapping (GstRTSPServer * server,
|
||||||
|
|
||||||
g_return_if_fail (GST_IS_RTSP_SERVER (server));
|
g_return_if_fail (GST_IS_RTSP_SERVER (server));
|
||||||
|
|
||||||
old = server->media_mapping;
|
|
||||||
|
|
||||||
if (old != mapping) {
|
|
||||||
if (mapping)
|
if (mapping)
|
||||||
g_object_ref (mapping);
|
g_object_ref (mapping);
|
||||||
|
|
||||||
|
GST_RTSP_SERVER_LOCK (server);
|
||||||
|
old = server->media_mapping;
|
||||||
server->media_mapping = mapping;
|
server->media_mapping = mapping;
|
||||||
|
GST_RTSP_SERVER_UNLOCK (server);
|
||||||
|
|
||||||
if (old)
|
if (old)
|
||||||
g_object_unref (old);
|
g_object_unref (old);
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -366,8 +418,61 @@ gst_rtsp_server_get_media_mapping (GstRTSPServer * server)
|
||||||
|
|
||||||
g_return_val_if_fail (GST_IS_RTSP_SERVER (server), NULL);
|
g_return_val_if_fail (GST_IS_RTSP_SERVER (server), NULL);
|
||||||
|
|
||||||
|
GST_RTSP_SERVER_LOCK (server);
|
||||||
if ((result = server->media_mapping))
|
if ((result = server->media_mapping))
|
||||||
g_object_ref (result);
|
g_object_ref (result);
|
||||||
|
GST_RTSP_SERVER_UNLOCK (server);
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* gst_rtsp_server_set_auth:
|
||||||
|
* @server: a #GstRTSPServer
|
||||||
|
* @auth: a #GstRTSPAuth
|
||||||
|
*
|
||||||
|
* configure @auth to be used as the authentication manager of @server.
|
||||||
|
*/
|
||||||
|
void
|
||||||
|
gst_rtsp_server_set_auth (GstRTSPServer * server, GstRTSPAuth * auth)
|
||||||
|
{
|
||||||
|
GstRTSPAuth *old;
|
||||||
|
|
||||||
|
g_return_if_fail (GST_IS_RTSP_SERVER (server));
|
||||||
|
|
||||||
|
if (auth)
|
||||||
|
g_object_ref (auth);
|
||||||
|
|
||||||
|
GST_RTSP_SERVER_LOCK (server);
|
||||||
|
old = server->auth;
|
||||||
|
server->auth = auth;
|
||||||
|
GST_RTSP_SERVER_UNLOCK (server);
|
||||||
|
|
||||||
|
if (old)
|
||||||
|
g_object_unref (old);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* gst_rtsp_server_get_auth:
|
||||||
|
* @server: a #GstRTSPServer
|
||||||
|
*
|
||||||
|
* Get the #GstRTSPAuth used as the authentication manager of @server.
|
||||||
|
*
|
||||||
|
* Returns: the #GstRTSPAuth of @server. g_object_unref() after
|
||||||
|
* usage.
|
||||||
|
*/
|
||||||
|
GstRTSPAuth *
|
||||||
|
gst_rtsp_server_get_auth (GstRTSPServer * server)
|
||||||
|
{
|
||||||
|
GstRTSPAuth *result;
|
||||||
|
|
||||||
|
g_return_val_if_fail (GST_IS_RTSP_SERVER (server), NULL);
|
||||||
|
|
||||||
|
GST_RTSP_SERVER_LOCK (server);
|
||||||
|
if ((result = server->auth))
|
||||||
|
g_object_ref (result);
|
||||||
|
GST_RTSP_SERVER_UNLOCK (server);
|
||||||
|
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
@ -426,17 +531,28 @@ gst_rtsp_server_set_property (GObject * object, guint propid,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Prepare a server socket for @server and make it listen on the configured port */
|
/**
|
||||||
static gboolean
|
* gst_rtsp_server_get_io_channel:
|
||||||
gst_rtsp_server_sink_init_send (GstRTSPServer * server)
|
* @server: a #GstRTSPServer
|
||||||
|
*
|
||||||
|
* Create a #GIOChannel for @server. The io channel will listen on the
|
||||||
|
* configured service.
|
||||||
|
*
|
||||||
|
* Returns: the GIOChannel for @server or NULL when an error occured.
|
||||||
|
*/
|
||||||
|
GIOChannel *
|
||||||
|
gst_rtsp_server_get_io_channel (GstRTSPServer * server)
|
||||||
{
|
{
|
||||||
int ret, sockfd;
|
GIOChannel *channel;
|
||||||
|
int ret, sockfd = -1;
|
||||||
struct addrinfo hints;
|
struct addrinfo hints;
|
||||||
struct addrinfo *result, *rp;
|
struct addrinfo *result, *rp;
|
||||||
#ifdef USE_SOLINGER
|
#ifdef USE_SOLINGER
|
||||||
struct linger linger;
|
struct linger linger;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
g_return_val_if_fail (GST_IS_RTSP_SERVER (server), NULL);
|
||||||
|
|
||||||
memset (&hints, 0, sizeof (struct addrinfo));
|
memset (&hints, 0, sizeof (struct addrinfo));
|
||||||
hints.ai_family = AF_UNSPEC; /* Allow IPv4 or IPv6 */
|
hints.ai_family = AF_UNSPEC; /* Allow IPv4 or IPv6 */
|
||||||
hints.ai_socktype = SOCK_STREAM; /* stream socket */
|
hints.ai_socktype = SOCK_STREAM; /* stream socket */
|
||||||
|
@ -449,6 +565,7 @@ gst_rtsp_server_sink_init_send (GstRTSPServer * server)
|
||||||
GST_DEBUG_OBJECT (server, "getting address info of %s/%s", server->address,
|
GST_DEBUG_OBJECT (server, "getting address info of %s/%s", server->address,
|
||||||
server->service);
|
server->service);
|
||||||
|
|
||||||
|
GST_RTSP_SERVER_LOCK (server);
|
||||||
/* resolve the server IP address */
|
/* resolve the server IP address */
|
||||||
if ((ret =
|
if ((ret =
|
||||||
getaddrinfo (server->address, server->service, &hints, &result)) != 0)
|
getaddrinfo (server->address, server->service, &hints, &result)) != 0)
|
||||||
|
@ -464,6 +581,15 @@ gst_rtsp_server_sink_init_send (GstRTSPServer * server)
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* make address reusable */
|
||||||
|
ret = 1;
|
||||||
|
if (setsockopt (sockfd, SOL_SOCKET, SO_REUSEADDR,
|
||||||
|
(void *) &ret, sizeof (ret)) < 0) {
|
||||||
|
/* warn but try to bind anyway */
|
||||||
|
GST_WARNING_OBJECT (server, "failed to reuse socker (%s)",
|
||||||
|
g_strerror (errno));
|
||||||
|
}
|
||||||
|
|
||||||
if (bind (sockfd, rp->ai_addr, rp->ai_addrlen) == 0) {
|
if (bind (sockfd, rp->ai_addr, rp->ai_addrlen) == 0) {
|
||||||
GST_DEBUG_OBJECT (server, "bind on %s", rp->ai_canonname);
|
GST_DEBUG_OBJECT (server, "bind on %s", rp->ai_canonname);
|
||||||
break;
|
break;
|
||||||
|
@ -472,26 +598,18 @@ gst_rtsp_server_sink_init_send (GstRTSPServer * server)
|
||||||
GST_DEBUG_OBJECT (server, "failed to bind socket (%s), try next",
|
GST_DEBUG_OBJECT (server, "failed to bind socket (%s), try next",
|
||||||
g_strerror (errno));
|
g_strerror (errno));
|
||||||
close (sockfd);
|
close (sockfd);
|
||||||
|
sockfd = -1;
|
||||||
}
|
}
|
||||||
freeaddrinfo (result);
|
freeaddrinfo (result);
|
||||||
|
|
||||||
if (rp == NULL)
|
if (sockfd == -1)
|
||||||
goto no_socket;
|
goto no_socket;
|
||||||
|
|
||||||
server->server_sock.fd = sockfd;
|
GST_DEBUG_OBJECT (server, "opened sending server socket with fd %d", sockfd);
|
||||||
|
|
||||||
GST_DEBUG_OBJECT (server, "opened sending server socket with fd %d",
|
|
||||||
server->server_sock.fd);
|
|
||||||
|
|
||||||
/* make address reusable */
|
|
||||||
ret = 1;
|
|
||||||
if (setsockopt (server->server_sock.fd, SOL_SOCKET, SO_REUSEADDR,
|
|
||||||
(void *) &ret, sizeof (ret)) < 0)
|
|
||||||
goto reuse_failed;
|
|
||||||
|
|
||||||
/* keep connection alive; avoids SIGPIPE during write */
|
/* keep connection alive; avoids SIGPIPE during write */
|
||||||
ret = 1;
|
ret = 1;
|
||||||
if (setsockopt (server->server_sock.fd, SOL_SOCKET, SO_KEEPALIVE,
|
if (setsockopt (sockfd, SOL_SOCKET, SO_KEEPALIVE,
|
||||||
(void *) &ret, sizeof (ret)) < 0)
|
(void *) &ret, sizeof (ret)) < 0)
|
||||||
goto keepalive_failed;
|
goto keepalive_failed;
|
||||||
|
|
||||||
|
@ -501,43 +619,42 @@ gst_rtsp_server_sink_init_send (GstRTSPServer * server)
|
||||||
* client. */
|
* client. */
|
||||||
linger.l_onoff = 1;
|
linger.l_onoff = 1;
|
||||||
linger.l_linger = 5;
|
linger.l_linger = 5;
|
||||||
if (setsockopt (server->server_sock.fd, SOL_SOCKET, SO_LINGER,
|
if (setsockopt (sockfd, SOL_SOCKET, SO_LINGER,
|
||||||
(void *) &linger, sizeof (linger)) < 0)
|
(void *) &linger, sizeof (linger)) < 0)
|
||||||
goto linger_failed;
|
goto linger_failed;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
/* set the server socket to nonblocking */
|
/* set the server socket to nonblocking */
|
||||||
fcntl (server->server_sock.fd, F_SETFL, O_NONBLOCK);
|
fcntl (sockfd, F_SETFL, O_NONBLOCK);
|
||||||
|
|
||||||
GST_DEBUG_OBJECT (server, "listening on server socket %d with queue of %d",
|
GST_DEBUG_OBJECT (server, "listening on server socket %d with queue of %d",
|
||||||
server->server_sock.fd, server->backlog);
|
sockfd, server->backlog);
|
||||||
if (listen (server->server_sock.fd, server->backlog) == -1)
|
if (listen (sockfd, server->backlog) == -1)
|
||||||
goto listen_failed;
|
goto listen_failed;
|
||||||
|
|
||||||
GST_DEBUG_OBJECT (server,
|
GST_DEBUG_OBJECT (server,
|
||||||
"listened on server socket %d, returning from connection setup",
|
"listened on server socket %d, returning from connection setup", sockfd);
|
||||||
server->server_sock.fd);
|
|
||||||
|
/* create IO channel for the socket */
|
||||||
|
channel = g_io_channel_unix_new (sockfd);
|
||||||
|
g_io_channel_set_close_on_unref (channel, TRUE);
|
||||||
|
|
||||||
GST_INFO_OBJECT (server, "listening on service %s", server->service);
|
GST_INFO_OBJECT (server, "listening on service %s", server->service);
|
||||||
|
GST_RTSP_SERVER_UNLOCK (server);
|
||||||
|
|
||||||
return TRUE;
|
return channel;
|
||||||
|
|
||||||
/* ERRORS */
|
/* ERRORS */
|
||||||
no_address:
|
no_address:
|
||||||
{
|
{
|
||||||
GST_ERROR_OBJECT (server, "failed to resolve address: %s",
|
GST_ERROR_OBJECT (server, "failed to resolve address: %s",
|
||||||
gai_strerror (ret));
|
gai_strerror (ret));
|
||||||
return FALSE;
|
goto close_error;
|
||||||
}
|
}
|
||||||
no_socket:
|
no_socket:
|
||||||
{
|
{
|
||||||
GST_ERROR_OBJECT (server, "failed to create socket: %s",
|
GST_ERROR_OBJECT (server, "failed to create socket: %s",
|
||||||
g_strerror (errno));
|
g_strerror (errno));
|
||||||
return FALSE;
|
|
||||||
}
|
|
||||||
reuse_failed:
|
|
||||||
{
|
|
||||||
GST_ERROR_OBJECT (server, "failed to reuse socket: %s", g_strerror (errno));
|
|
||||||
goto close_error;
|
goto close_error;
|
||||||
}
|
}
|
||||||
keepalive_failed:
|
keepalive_failed:
|
||||||
|
@ -562,18 +679,44 @@ listen_failed:
|
||||||
}
|
}
|
||||||
close_error:
|
close_error:
|
||||||
{
|
{
|
||||||
if (server->server_sock.fd >= 0) {
|
if (sockfd >= 0) {
|
||||||
close (server->server_sock.fd);
|
close (sockfd);
|
||||||
server->server_sock.fd = -1;
|
|
||||||
}
|
}
|
||||||
return FALSE;
|
GST_RTSP_SERVER_UNLOCK (server);
|
||||||
|
return NULL;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* default method for creating a new client object in the server to accept and
|
static void
|
||||||
* handle a client connection on this server */
|
unmanage_client (GstRTSPClient * client, GstRTSPServer * server)
|
||||||
|
{
|
||||||
|
GST_DEBUG_OBJECT (server, "unmanage client %p", client);
|
||||||
|
|
||||||
|
gst_rtsp_client_set_server (client, NULL);
|
||||||
|
|
||||||
|
GST_RTSP_SERVER_LOCK (server);
|
||||||
|
server->clients = g_list_remove (server->clients, client);
|
||||||
|
GST_RTSP_SERVER_UNLOCK (server);
|
||||||
|
|
||||||
|
g_object_unref (client);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* add the client to the active list of clients, takes ownership of
|
||||||
|
* the client */
|
||||||
|
static void
|
||||||
|
manage_client (GstRTSPServer * server, GstRTSPClient * client)
|
||||||
|
{
|
||||||
|
GST_DEBUG_OBJECT (server, "manage client %p", client);
|
||||||
|
gst_rtsp_client_set_server (client, server);
|
||||||
|
|
||||||
|
GST_RTSP_SERVER_LOCK (server);
|
||||||
|
g_signal_connect (client, "closed", (GCallback) unmanage_client, server);
|
||||||
|
server->clients = g_list_prepend (server->clients, client);
|
||||||
|
GST_RTSP_SERVER_UNLOCK (server);
|
||||||
|
}
|
||||||
|
|
||||||
static GstRTSPClient *
|
static GstRTSPClient *
|
||||||
default_accept_client (GstRTSPServer * server, GIOChannel * channel)
|
default_create_client (GstRTSPServer * server)
|
||||||
{
|
{
|
||||||
GstRTSPClient *client;
|
GstRTSPClient *client;
|
||||||
|
|
||||||
|
@ -581,26 +724,38 @@ default_accept_client (GstRTSPServer * server, GIOChannel * channel)
|
||||||
client = gst_rtsp_client_new ();
|
client = gst_rtsp_client_new ();
|
||||||
|
|
||||||
/* set the session pool that this client should use */
|
/* set the session pool that this client should use */
|
||||||
|
GST_RTSP_SERVER_LOCK (server);
|
||||||
gst_rtsp_client_set_session_pool (client, server->session_pool);
|
gst_rtsp_client_set_session_pool (client, server->session_pool);
|
||||||
/* set the media mapping that this client should use */
|
/* set the media mapping that this client should use */
|
||||||
gst_rtsp_client_set_media_mapping (client, server->media_mapping);
|
gst_rtsp_client_set_media_mapping (client, server->media_mapping);
|
||||||
|
/* set authentication manager */
|
||||||
|
gst_rtsp_client_set_auth (client, server->auth);
|
||||||
|
GST_RTSP_SERVER_UNLOCK (server);
|
||||||
|
|
||||||
|
return client;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* default method for creating a new client object in the server to accept and
|
||||||
|
* handle a client connection on this server */
|
||||||
|
static gboolean
|
||||||
|
default_accept_client (GstRTSPServer * server, GstRTSPClient * client,
|
||||||
|
GIOChannel * channel)
|
||||||
|
{
|
||||||
/* accept connections for that client, this function returns after accepting
|
/* accept connections for that client, this function returns after accepting
|
||||||
* the connection and will run the remainder of the communication with the
|
* the connection and will run the remainder of the communication with the
|
||||||
* client asyncronously. */
|
* client asyncronously. */
|
||||||
if (!gst_rtsp_client_accept (client, channel))
|
if (!gst_rtsp_client_accept (client, channel))
|
||||||
goto accept_failed;
|
goto accept_failed;
|
||||||
|
|
||||||
return client;
|
return TRUE;
|
||||||
|
|
||||||
/* ERRORS */
|
/* ERRORS */
|
||||||
accept_failed:
|
accept_failed:
|
||||||
{
|
{
|
||||||
GST_ERROR_OBJECT (server,
|
GST_ERROR_OBJECT (server,
|
||||||
"Could not accept client on server socket %d: %s (%d)",
|
"Could not accept client on server : %s (%d)", g_strerror (errno),
|
||||||
server->server_sock.fd, g_strerror (errno), errno);
|
errno);
|
||||||
gst_object_unref (client);
|
return FALSE;
|
||||||
return NULL;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -618,21 +773,26 @@ gboolean
|
||||||
gst_rtsp_server_io_func (GIOChannel * channel, GIOCondition condition,
|
gst_rtsp_server_io_func (GIOChannel * channel, GIOCondition condition,
|
||||||
GstRTSPServer * server)
|
GstRTSPServer * server)
|
||||||
{
|
{
|
||||||
|
gboolean result;
|
||||||
GstRTSPClient *client = NULL;
|
GstRTSPClient *client = NULL;
|
||||||
GstRTSPServerClass *klass;
|
GstRTSPServerClass *klass;
|
||||||
|
|
||||||
if (condition & G_IO_IN) {
|
if (condition & G_IO_IN) {
|
||||||
klass = GST_RTSP_SERVER_GET_CLASS (server);
|
klass = GST_RTSP_SERVER_GET_CLASS (server);
|
||||||
|
|
||||||
/* a new client connected, create a client object to handle the client. */
|
if (klass->create_client)
|
||||||
if (klass->accept_client)
|
client = klass->create_client (server);
|
||||||
client = klass->accept_client (server, channel);
|
|
||||||
if (client == NULL)
|
if (client == NULL)
|
||||||
goto client_failed;
|
goto client_failed;
|
||||||
|
|
||||||
/* can unref the client now, when the request is finished, it will be
|
/* a new client connected, create a client object to handle the client. */
|
||||||
* unreffed async. */
|
if (klass->accept_client)
|
||||||
gst_object_unref (client);
|
result = klass->accept_client (server, client, channel);
|
||||||
|
if (!result)
|
||||||
|
goto accept_failed;
|
||||||
|
|
||||||
|
/* manage the client connection */
|
||||||
|
manage_client (server, client);
|
||||||
} else {
|
} else {
|
||||||
GST_WARNING_OBJECT (server, "received unknown event %08x", condition);
|
GST_WARNING_OBJECT (server, "received unknown event %08x", condition);
|
||||||
}
|
}
|
||||||
|
@ -644,35 +804,19 @@ client_failed:
|
||||||
GST_ERROR_OBJECT (server, "failed to create a client");
|
GST_ERROR_OBJECT (server, "failed to create a client");
|
||||||
return FALSE;
|
return FALSE;
|
||||||
}
|
}
|
||||||
|
accept_failed:
|
||||||
|
{
|
||||||
|
GST_ERROR_OBJECT (server, "failed to accept client");
|
||||||
|
gst_object_unref (client);
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
static void
|
||||||
* gst_rtsp_server_get_io_channel:
|
watch_destroyed (GstRTSPServer * server)
|
||||||
* @server: a #GstRTSPServer
|
|
||||||
*
|
|
||||||
* Create a #GIOChannel for @server.
|
|
||||||
*
|
|
||||||
* Returns: the GIOChannel for @server or NULL when an error occured.
|
|
||||||
*/
|
|
||||||
GIOChannel *
|
|
||||||
gst_rtsp_server_get_io_channel (GstRTSPServer * server)
|
|
||||||
{
|
{
|
||||||
g_return_val_if_fail (GST_IS_RTSP_SERVER (server), NULL);
|
GST_DEBUG_OBJECT (server, "source destroyed");
|
||||||
|
g_object_unref (server);
|
||||||
if (server->io_channel == NULL) {
|
|
||||||
if (!gst_rtsp_server_sink_init_send (server))
|
|
||||||
goto init_failed;
|
|
||||||
|
|
||||||
/* create IO channel for the socket */
|
|
||||||
server->io_channel = g_io_channel_unix_new (server->server_sock.fd);
|
|
||||||
}
|
|
||||||
return server->io_channel;
|
|
||||||
|
|
||||||
init_failed:
|
|
||||||
{
|
|
||||||
GST_ERROR_OBJECT (server, "failed to initialize server");
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -687,24 +831,26 @@ init_failed:
|
||||||
GSource *
|
GSource *
|
||||||
gst_rtsp_server_create_watch (GstRTSPServer * server)
|
gst_rtsp_server_create_watch (GstRTSPServer * server)
|
||||||
{
|
{
|
||||||
g_return_val_if_fail (GST_IS_RTSP_SERVER (server), NULL);
|
|
||||||
|
|
||||||
if (server->io_watch == NULL) {
|
|
||||||
GIOChannel *channel;
|
GIOChannel *channel;
|
||||||
|
GSource *source;
|
||||||
|
|
||||||
|
g_return_val_if_fail (GST_IS_RTSP_SERVER (server), NULL);
|
||||||
|
|
||||||
channel = gst_rtsp_server_get_io_channel (server);
|
channel = gst_rtsp_server_get_io_channel (server);
|
||||||
if (channel == NULL)
|
if (channel == NULL)
|
||||||
goto no_channel;
|
goto no_channel;
|
||||||
|
|
||||||
/* create a watch for reads (new connections) and possible errors */
|
/* create a watch for reads (new connections) and possible errors */
|
||||||
server->io_watch = g_io_create_watch (channel, G_IO_IN |
|
source = g_io_create_watch (channel, G_IO_IN |
|
||||||
G_IO_ERR | G_IO_HUP | G_IO_NVAL);
|
G_IO_ERR | G_IO_HUP | G_IO_NVAL);
|
||||||
|
g_io_channel_unref (channel);
|
||||||
|
|
||||||
/* configure the callback */
|
/* configure the callback */
|
||||||
g_source_set_callback (server->io_watch,
|
g_source_set_callback (source,
|
||||||
(GSourceFunc) gst_rtsp_server_io_func, server, NULL);
|
(GSourceFunc) gst_rtsp_server_io_func, g_object_ref (server),
|
||||||
}
|
(GDestroyNotify) watch_destroyed);
|
||||||
return server->io_watch;
|
|
||||||
|
return source;
|
||||||
|
|
||||||
no_channel:
|
no_channel:
|
||||||
{
|
{
|
||||||
|
@ -719,7 +865,8 @@ no_channel:
|
||||||
* @context: a #GMainContext
|
* @context: a #GMainContext
|
||||||
*
|
*
|
||||||
* Attaches @server to @context. When the mainloop for @context is run, the
|
* Attaches @server to @context. When the mainloop for @context is run, the
|
||||||
* server will be dispatched.
|
* server will be dispatched. When @context is NULL, the default context will be
|
||||||
|
* used).
|
||||||
*
|
*
|
||||||
* This function should be called when the server properties and urls are fully
|
* This function should be called when the server properties and urls are fully
|
||||||
* configured and the server is ready to start.
|
* configured and the server is ready to start.
|
||||||
|
@ -739,6 +886,7 @@ gst_rtsp_server_attach (GstRTSPServer * server, GMainContext * context)
|
||||||
goto no_source;
|
goto no_source;
|
||||||
|
|
||||||
res = g_source_attach (source, context);
|
res = g_source_attach (source, context);
|
||||||
|
g_source_unref (source);
|
||||||
|
|
||||||
return res;
|
return res;
|
||||||
|
|
||||||
|
|
|
@ -17,31 +17,21 @@
|
||||||
* Boston, MA 02111-1307, USA.
|
* Boston, MA 02111-1307, USA.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include <stdio.h>
|
#ifndef __GST_RTSP_SERVER_H__
|
||||||
#include <stdlib.h>
|
#define __GST_RTSP_SERVER_H__
|
||||||
#include <unistd.h>
|
|
||||||
#include <errno.h>
|
|
||||||
#include <string.h>
|
|
||||||
#include <sys/time.h>
|
|
||||||
#include <sys/types.h>
|
|
||||||
#include <netinet/in.h>
|
|
||||||
#include <netdb.h>
|
|
||||||
#include <sys/socket.h>
|
|
||||||
#include <sys/wait.h>
|
|
||||||
#include <fcntl.h>
|
|
||||||
#include <arpa/inet.h>
|
|
||||||
|
|
||||||
#include <gst/gst.h>
|
#include <gst/gst.h>
|
||||||
|
|
||||||
|
G_BEGIN_DECLS
|
||||||
|
|
||||||
|
typedef struct _GstRTSPServer GstRTSPServer;
|
||||||
|
typedef struct _GstRTSPServerClass GstRTSPServerClass;
|
||||||
|
|
||||||
#include "rtsp-session-pool.h"
|
#include "rtsp-session-pool.h"
|
||||||
#include "rtsp-media-mapping.h"
|
#include "rtsp-media-mapping.h"
|
||||||
#include "rtsp-media-factory-uri.h"
|
#include "rtsp-media-factory-uri.h"
|
||||||
#include "rtsp-client.h"
|
#include "rtsp-client.h"
|
||||||
|
#include "rtsp-auth.h"
|
||||||
#ifndef __GST_RTSP_SERVER_H__
|
|
||||||
#define __GST_RTSP_SERVER_H__
|
|
||||||
|
|
||||||
G_BEGIN_DECLS
|
|
||||||
|
|
||||||
#define GST_TYPE_RTSP_SERVER (gst_rtsp_server_get_type ())
|
#define GST_TYPE_RTSP_SERVER (gst_rtsp_server_get_type ())
|
||||||
#define GST_IS_RTSP_SERVER(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GST_TYPE_RTSP_SERVER))
|
#define GST_IS_RTSP_SERVER(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GST_TYPE_RTSP_SERVER))
|
||||||
|
@ -52,43 +42,53 @@ G_BEGIN_DECLS
|
||||||
#define GST_RTSP_SERVER_CAST(obj) ((GstRTSPServer*)(obj))
|
#define GST_RTSP_SERVER_CAST(obj) ((GstRTSPServer*)(obj))
|
||||||
#define GST_RTSP_SERVER_CLASS_CAST(klass) ((GstRTSPServerClass*)(klass))
|
#define GST_RTSP_SERVER_CLASS_CAST(klass) ((GstRTSPServerClass*)(klass))
|
||||||
|
|
||||||
typedef struct _GstRTSPServer GstRTSPServer;
|
#define GST_RTSP_SERVER_GET_LOCK(server) (GST_RTSP_SERVER_CAST(server)->lock)
|
||||||
typedef struct _GstRTSPServerClass GstRTSPServerClass;
|
#define GST_RTSP_SERVER_LOCK(server) (g_mutex_lock(GST_RTSP_SERVER_GET_LOCK(server)))
|
||||||
|
#define GST_RTSP_SERVER_UNLOCK(server) (g_mutex_unlock(GST_RTSP_SERVER_GET_LOCK(server)))
|
||||||
|
|
||||||
|
/**
|
||||||
|
* GstRTSPServer:
|
||||||
|
*
|
||||||
|
* This object listens on a port, creates and manages the clients connected to
|
||||||
|
* it.
|
||||||
|
*/
|
||||||
struct _GstRTSPServer {
|
struct _GstRTSPServer {
|
||||||
GObject parent;
|
GObject parent;
|
||||||
|
|
||||||
|
GMutex *lock;
|
||||||
|
|
||||||
/* server information */
|
/* server information */
|
||||||
gchar *address;
|
gchar *address;
|
||||||
gchar *service;
|
gchar *service;
|
||||||
gint backlog;
|
gint backlog;
|
||||||
|
|
||||||
struct sockaddr_in server_sin;
|
|
||||||
|
|
||||||
/* socket and channels */
|
|
||||||
GstPollFD server_sock;
|
|
||||||
GIOChannel *io_channel;
|
|
||||||
GSource *io_watch;
|
|
||||||
|
|
||||||
/* sessions on this server */
|
/* sessions on this server */
|
||||||
GstRTSPSessionPool *session_pool;
|
GstRTSPSessionPool *session_pool;
|
||||||
|
|
||||||
/* media mapper for this server */
|
/* media mapper for this server */
|
||||||
GstRTSPMediaMapping *media_mapping;
|
GstRTSPMediaMapping *media_mapping;
|
||||||
|
|
||||||
|
/* authentication manager */
|
||||||
|
GstRTSPAuth *auth;
|
||||||
|
|
||||||
|
/* the clients that are connected */
|
||||||
|
GList *clients;
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* GstRTSPServerClass:
|
* GstRTSPServerClass:
|
||||||
*
|
*
|
||||||
* @accept_client: Create, configure, accept and return a new GstRTSPClient
|
* @create_client: Create, configure a new GstRTSPClient
|
||||||
* object that handles the new connection on @channel.
|
* object that handles the new connection on @channel.
|
||||||
|
* @accept_client: accept a new GstRTSPClient
|
||||||
*
|
*
|
||||||
* The RTSP server class structure
|
* The RTSP server class structure
|
||||||
*/
|
*/
|
||||||
struct _GstRTSPServerClass {
|
struct _GstRTSPServerClass {
|
||||||
GObjectClass parent_class;
|
GObjectClass parent_class;
|
||||||
|
|
||||||
GstRTSPClient * (*accept_client) (GstRTSPServer *server, GIOChannel *channel);
|
GstRTSPClient * (*create_client) (GstRTSPServer *server);
|
||||||
|
gboolean (*accept_client) (GstRTSPServer *server, GstRTSPClient *client, GIOChannel *channel);
|
||||||
};
|
};
|
||||||
|
|
||||||
GType gst_rtsp_server_get_type (void);
|
GType gst_rtsp_server_get_type (void);
|
||||||
|
@ -110,6 +110,9 @@ GstRTSPSessionPool * gst_rtsp_server_get_session_pool (GstRTSPServer *serve
|
||||||
void gst_rtsp_server_set_media_mapping (GstRTSPServer *server, GstRTSPMediaMapping *mapping);
|
void gst_rtsp_server_set_media_mapping (GstRTSPServer *server, GstRTSPMediaMapping *mapping);
|
||||||
GstRTSPMediaMapping * gst_rtsp_server_get_media_mapping (GstRTSPServer *server);
|
GstRTSPMediaMapping * gst_rtsp_server_get_media_mapping (GstRTSPServer *server);
|
||||||
|
|
||||||
|
void gst_rtsp_server_set_auth (GstRTSPServer *server, GstRTSPAuth *auth);
|
||||||
|
GstRTSPAuth * gst_rtsp_server_get_auth (GstRTSPServer *server);
|
||||||
|
|
||||||
gboolean gst_rtsp_server_io_func (GIOChannel *channel, GIOCondition condition,
|
gboolean gst_rtsp_server_io_func (GIOChannel *channel, GIOCondition condition,
|
||||||
GstRTSPServer *server);
|
GstRTSPServer *server);
|
||||||
|
|
||||||
|
|
|
@ -30,7 +30,15 @@ enum
|
||||||
PROP_LAST
|
PROP_LAST
|
||||||
};
|
};
|
||||||
|
|
||||||
GST_DEBUG_CATEGORY (rtsp_session_debug);
|
static const gchar session_id_charset[] =
|
||||||
|
{ 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o',
|
||||||
|
'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z', 'A', 'B', 'C', 'D',
|
||||||
|
'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S',
|
||||||
|
'T', 'U', 'V', 'W', 'X', 'Y', 'Z', '0', '1', '2', '3', '4', '5', '6', '7',
|
||||||
|
'8', '9', '$', '-', '_', '.', '+'
|
||||||
|
};
|
||||||
|
|
||||||
|
GST_DEBUG_CATEGORY_STATIC (rtsp_session_debug);
|
||||||
#define GST_CAT_DEFAULT rtsp_session_debug
|
#define GST_CAT_DEFAULT rtsp_session_debug
|
||||||
|
|
||||||
static void gst_rtsp_session_pool_get_property (GObject * object, guint propid,
|
static void gst_rtsp_session_pool_get_property (GObject * object, guint propid,
|
||||||
|
@ -62,8 +70,8 @@ gst_rtsp_session_pool_class_init (GstRTSPSessionPoolClass * klass)
|
||||||
|
|
||||||
klass->create_session_id = create_session_id;
|
klass->create_session_id = create_session_id;
|
||||||
|
|
||||||
GST_DEBUG_CATEGORY_INIT (rtsp_session_debug, "rtspsession", 0,
|
GST_DEBUG_CATEGORY_INIT (rtsp_session_debug, "rtspsessionpool", 0,
|
||||||
"GstRTSPSession");
|
"GstRTSPSessionPool");
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
|
@ -235,7 +243,9 @@ create_session_id (GstRTSPSessionPool * pool)
|
||||||
gint i;
|
gint i;
|
||||||
|
|
||||||
for (i = 0; i < 16; i++) {
|
for (i = 0; i < 16; i++) {
|
||||||
id[i] = g_random_int_range ('a', 'z');
|
id[i] =
|
||||||
|
session_id_charset[g_random_int_range (0,
|
||||||
|
G_N_ELEMENTS (session_id_charset))];
|
||||||
}
|
}
|
||||||
|
|
||||||
return g_strndup (id, 16);
|
return g_strndup (id, 16);
|
||||||
|
|
|
@ -22,10 +22,14 @@
|
||||||
#ifndef __GST_RTSP_SESSION_POOL_H__
|
#ifndef __GST_RTSP_SESSION_POOL_H__
|
||||||
#define __GST_RTSP_SESSION_POOL_H__
|
#define __GST_RTSP_SESSION_POOL_H__
|
||||||
|
|
||||||
#include "rtsp-session.h"
|
|
||||||
|
|
||||||
G_BEGIN_DECLS
|
G_BEGIN_DECLS
|
||||||
|
|
||||||
|
typedef struct _GstRTSPSessionPool GstRTSPSessionPool;
|
||||||
|
typedef struct _GstRTSPSessionPoolClass GstRTSPSessionPoolClass;
|
||||||
|
|
||||||
|
#include "rtsp-session.h"
|
||||||
|
|
||||||
#define GST_TYPE_RTSP_SESSION_POOL (gst_rtsp_session_pool_get_type ())
|
#define GST_TYPE_RTSP_SESSION_POOL (gst_rtsp_session_pool_get_type ())
|
||||||
#define GST_IS_RTSP_SESSION_POOL(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GST_TYPE_RTSP_SESSION_POOL))
|
#define GST_IS_RTSP_SESSION_POOL(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GST_TYPE_RTSP_SESSION_POOL))
|
||||||
#define GST_IS_RTSP_SESSION_POOL_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), GST_TYPE_RTSP_SESSION_POOL))
|
#define GST_IS_RTSP_SESSION_POOL_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), GST_TYPE_RTSP_SESSION_POOL))
|
||||||
|
@ -35,9 +39,6 @@ G_BEGIN_DECLS
|
||||||
#define GST_RTSP_SESSION_POOL_CAST(obj) ((GstRTSPSessionPool*)(obj))
|
#define GST_RTSP_SESSION_POOL_CAST(obj) ((GstRTSPSessionPool*)(obj))
|
||||||
#define GST_RTSP_SESSION_POOL_CLASS_CAST(klass) ((GstRTSPSessionPoolClass*)(klass))
|
#define GST_RTSP_SESSION_POOL_CLASS_CAST(klass) ((GstRTSPSessionPoolClass*)(klass))
|
||||||
|
|
||||||
typedef struct _GstRTSPSessionPool GstRTSPSessionPool;
|
|
||||||
typedef struct _GstRTSPSessionPoolClass GstRTSPSessionPoolClass;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* GstRTSPSessionPool:
|
* GstRTSPSessionPool:
|
||||||
* @max_sessions: the maximum number of sessions.
|
* @max_sessions: the maximum number of sessions.
|
||||||
|
|
|
@ -32,7 +32,7 @@ enum
|
||||||
PROP_LAST
|
PROP_LAST
|
||||||
};
|
};
|
||||||
|
|
||||||
GST_DEBUG_CATEGORY_EXTERN (rtsp_session_debug);
|
GST_DEBUG_CATEGORY_STATIC (rtsp_session_debug);
|
||||||
#define GST_CAT_DEFAULT rtsp_session_debug
|
#define GST_CAT_DEFAULT rtsp_session_debug
|
||||||
|
|
||||||
static void gst_rtsp_session_get_property (GObject * object, guint propid,
|
static void gst_rtsp_session_get_property (GObject * object, guint propid,
|
||||||
|
@ -63,6 +63,9 @@ gst_rtsp_session_class_init (GstRTSPSessionClass * klass)
|
||||||
g_param_spec_uint ("timeout", "timeout",
|
g_param_spec_uint ("timeout", "timeout",
|
||||||
"the timeout of the session (0 = never)", 0, G_MAXUINT,
|
"the timeout of the session (0 = never)", 0, G_MAXUINT,
|
||||||
DEFAULT_TIMEOUT, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
|
DEFAULT_TIMEOUT, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
|
||||||
|
|
||||||
|
GST_DEBUG_CATEGORY_INIT (rtsp_session_debug, "rtspsession", 0,
|
||||||
|
"GstRTSPSession");
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
|
@ -79,7 +82,8 @@ gst_rtsp_session_free_stream (GstRTSPSessionStream * stream)
|
||||||
GST_INFO ("free session stream %p", stream);
|
GST_INFO ("free session stream %p", stream);
|
||||||
|
|
||||||
/* remove callbacks now */
|
/* remove callbacks now */
|
||||||
gst_rtsp_session_stream_set_callbacks (stream, NULL, NULL, NULL, NULL);
|
gst_rtsp_session_stream_set_callbacks (stream, NULL, NULL, NULL, NULL, NULL,
|
||||||
|
NULL);
|
||||||
gst_rtsp_session_stream_set_keepalive (stream, NULL, NULL, NULL);
|
gst_rtsp_session_stream_set_keepalive (stream, NULL, NULL, NULL);
|
||||||
|
|
||||||
gst_rtsp_media_trans_cleanup (&stream->trans);
|
gst_rtsp_media_trans_cleanup (&stream->trans);
|
||||||
|
@ -549,6 +553,8 @@ gst_rtsp_session_stream_set_transport (GstRTSPSessionStream * stream,
|
||||||
* @stream: a #GstRTSPSessionStream
|
* @stream: a #GstRTSPSessionStream
|
||||||
* @send_rtp: a callback called when RTP should be sent
|
* @send_rtp: a callback called when RTP should be sent
|
||||||
* @send_rtcp: a callback called when RTCP should be sent
|
* @send_rtcp: a callback called when RTCP should be sent
|
||||||
|
* @send_rtp_list: a callback called when RTP should be sent
|
||||||
|
* @send_rtcp_list: a callback called when RTCP should be sent
|
||||||
* @user_data: user data passed to callbacks
|
* @user_data: user data passed to callbacks
|
||||||
* @notify: called with the user_data when no longer needed.
|
* @notify: called with the user_data when no longer needed.
|
||||||
*
|
*
|
||||||
|
@ -557,11 +563,14 @@ gst_rtsp_session_stream_set_transport (GstRTSPSessionStream * stream,
|
||||||
*/
|
*/
|
||||||
void
|
void
|
||||||
gst_rtsp_session_stream_set_callbacks (GstRTSPSessionStream * stream,
|
gst_rtsp_session_stream_set_callbacks (GstRTSPSessionStream * stream,
|
||||||
GstRTSPSendFunc send_rtp, GstRTSPSendFunc send_rtcp, gpointer user_data,
|
GstRTSPSendFunc send_rtp, GstRTSPSendFunc send_rtcp,
|
||||||
GDestroyNotify notify)
|
GstRTSPSendListFunc send_rtp_list, GstRTSPSendListFunc send_rtcp_list,
|
||||||
|
gpointer user_data, GDestroyNotify notify)
|
||||||
{
|
{
|
||||||
stream->trans.send_rtp = send_rtp;
|
stream->trans.send_rtp = send_rtp;
|
||||||
stream->trans.send_rtcp = send_rtcp;
|
stream->trans.send_rtcp = send_rtcp;
|
||||||
|
stream->trans.send_rtp_list = send_rtp_list;
|
||||||
|
stream->trans.send_rtcp_list = send_rtcp_list;
|
||||||
if (stream->trans.notify)
|
if (stream->trans.notify)
|
||||||
stream->trans.notify (stream->trans.user_data);
|
stream->trans.notify (stream->trans.user_data);
|
||||||
stream->trans.user_data = user_data;
|
stream->trans.user_data = user_data;
|
||||||
|
|
|
@ -21,8 +21,6 @@
|
||||||
|
|
||||||
#include <gst/rtsp/gstrtsptransport.h>
|
#include <gst/rtsp/gstrtsptransport.h>
|
||||||
|
|
||||||
#include "rtsp-media.h"
|
|
||||||
|
|
||||||
#ifndef __GST_RTSP_SESSION_H__
|
#ifndef __GST_RTSP_SESSION_H__
|
||||||
#define __GST_RTSP_SESSION_H__
|
#define __GST_RTSP_SESSION_H__
|
||||||
|
|
||||||
|
@ -43,6 +41,8 @@ typedef struct _GstRTSPSessionClass GstRTSPSessionClass;
|
||||||
typedef struct _GstRTSPSessionStream GstRTSPSessionStream;
|
typedef struct _GstRTSPSessionStream GstRTSPSessionStream;
|
||||||
typedef struct _GstRTSPSessionMedia GstRTSPSessionMedia;
|
typedef struct _GstRTSPSessionMedia GstRTSPSessionMedia;
|
||||||
|
|
||||||
|
#include "rtsp-media.h"
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* GstRTSPSessionStream:
|
* GstRTSPSessionStream:
|
||||||
* @trans: the media transport
|
* @trans: the media transport
|
||||||
|
@ -154,6 +154,8 @@ GstRTSPTransport * gst_rtsp_session_stream_set_transport (GstRTSPSessionStre
|
||||||
void gst_rtsp_session_stream_set_callbacks (GstRTSPSessionStream *stream,
|
void gst_rtsp_session_stream_set_callbacks (GstRTSPSessionStream *stream,
|
||||||
GstRTSPSendFunc send_rtp,
|
GstRTSPSendFunc send_rtp,
|
||||||
GstRTSPSendFunc send_rtcp,
|
GstRTSPSendFunc send_rtcp,
|
||||||
|
GstRTSPSendListFunc send_rtp_list,
|
||||||
|
GstRTSPSendListFunc send_rtcp_list,
|
||||||
gpointer user_data,
|
gpointer user_data,
|
||||||
GDestroyNotify notify);
|
GDestroyNotify notify);
|
||||||
void gst_rtsp_session_stream_set_keepalive (GstRTSPSessionStream *stream,
|
void gst_rtsp_session_stream_set_keepalive (GstRTSPSessionStream *stream,
|
||||||
|
|
|
@ -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