Merge branch 'master' into 0.11

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

4
.gitignore vendored
View file

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

View file

@ -3,11 +3,11 @@ DISTCHECK_CONFIGURE_FLAGS=--enable-gtk-doc
SUBDIRS = \
gst \
bindings \
m4 \
common \
pkgconfig \
docs \
examples
examples \
tests
DIST_SUBDIRS = $(SUBDIRS)
@ -16,13 +16,15 @@ EXTRA_DIST = \
AUTHORS COPYING NEWS README RELEASE REQUIREMENTS \
gst-rtsp.spec docs/design/gst-rtp-server-design
ACLOCAL_AMFLAGS = -I common/m4 -I m4
ACLOCAL_AMFLAGS = -I m4 -I common/m4
DISTCLEANFILES = _stdint.h gst-rtsp.spec
include $(top_srcdir)/common/release.mak
include $(top_srcdir)/common/po.mak
include $(top_srcdir)/common/coverage/lcov.mak
check-valgrind:
cd tests/check && make check-valgrind
@ -36,8 +38,42 @@ endif
# cruft: plugins that have been merged or moved or renamed
CRUFT_FILES = \
$(top_builddir)/common/shave \
$(top_builddir)/common/shave-libtool
$(top_builddir)/common/shave \
$(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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

@ -5,6 +5,11 @@ headers
#define NO_IMPORT_PYGOBJECT
#include <pygobject.h>
#include <gst/gst.h>
#include <gst/rtsp-server/rtsp-server.h>
#include <glib.h>
#ifdef HAVE_CONFIG_H
# include <config.h>
#endif
@ -24,29 +29,39 @@ typedef struct {
%%
import gobject.GObject as PyGObject_Type
import gobject.MainContext as PyGMainContext_Type
%%
override gst_rtsp_server_attach kwargs
static PyObject *
_wrap_gst_rtsp_server_attach (PyGObject *self,
PyObject *args, PyObject *keywords)
PyObject *args, PyObject *keywords)
{
static char *kwlist[] = {"context", NULL};
PyGMainContext *py_context = NULL;
GMainContext *context = NULL;
guint res;
static char *kwlist[] = {"context", NULL};
PyGMainContext *py_context = NULL;
GMainContext *context = NULL;
guint res;
if (!PyArg_ParseTupleAndKeywords (args, keywords,
"|O!:GstRTSPServer.__init__", kwlist,
&PyGMainContext_Type, &py_context))
return NULL;
if (!PyArg_ParseTupleAndKeywords (args, keywords,
"|O!:GstRTSPServer.__init__", kwlist,
&PyGMainContext_Type, &py_context))
return NULL;
if (py_context)
context = py_context->context;
if (py_context)
context = py_context->context;
pyg_begin_allow_threads;
res = gst_rtsp_server_attach (GST_RTSP_SERVER (self->obj), context);
pyg_end_allow_threads;
pyg_begin_allow_threads;
res = gst_rtsp_server_attach (GST_RTSP_SERVER (self->obj), context);
pyg_end_allow_threads;
return PyLong_FromLong (res);
return PyLong_FromLong (res);
}
%%
override gst_rtsp_server_create_watch kwargs
static PyObject *
_wrap_gst_rtsp_server_create_watch(PyGObject *self, PyObject *args, PyObject *keywords)
{
GSource *ret;
pyg_begin_allow_threads;
ret = gst_rtsp_server_create_watch(GST_RTSP_SERVER(self->obj));
pyg_end_allow_threads;
return pygobject_new((GObject *)ret);
}

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

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

View file

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

1
docs/.gitignore vendored Normal file
View file

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

View file

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

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

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

View file

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

View file

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

View file

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

View file

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

View file

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

2
examples/.gitignore vendored
View file

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

View file

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

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

@ -0,0 +1,115 @@
/* GStreamer
* Copyright (C) 2008 Wim Taymans <wim.taymans at gmail.com>
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Library General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Library General Public License for more details.
*
* You should have received a copy of the GNU Library General Public
* License along with this library; if not, write to the
* Free Software Foundation, Inc., 59 Temple Place - Suite 330,
* Boston, MA 02111-1307, USA.
*/
#include <gst/gst.h>
#include <gst/rtsp-server/rtsp-server.h>
static gboolean
timeout (GstRTSPServer * server, gboolean ignored)
{
GstRTSPSessionPool *pool;
pool = gst_rtsp_server_get_session_pool (server);
gst_rtsp_session_pool_cleanup (pool);
g_object_unref (pool);
return TRUE;
}
int
main (int argc, char *argv[])
{
GMainLoop *loop;
GstRTSPServer *server;
GstRTSPMediaMapping *mapping;
GstRTSPMediaFactory *factory;
GstRTSPAuth *auth;
gchar *basic;
gst_init (&argc, &argv);
loop = g_main_loop_new (NULL, FALSE);
/* create a server instance */
server = gst_rtsp_server_new ();
/* get the mapping for this server, every server has a default mapper object
* that be used to map uri mount points to media factories */
mapping = gst_rtsp_server_get_media_mapping (server);
/* make a media factory for a test stream. The default media factory can use
* gst-launch syntax to create pipelines.
* any launch line works as long as it contains elements named pay%d. Each
* element with pay%d names will be a stream */
factory = gst_rtsp_media_factory_new ();
gst_rtsp_media_factory_set_launch (factory, "( "
"videotestsrc ! video/x-raw-yuv,width=352,height=288,framerate=15/1 ! "
"x264enc ! rtph264pay name=pay0 pt=96 "
"audiotestsrc ! audio/x-raw-int,rate=8000 ! "
"alawenc ! rtppcmapay name=pay1 pt=97 " ")");
/* make a new authentication manager */
auth = gst_rtsp_auth_new ();
basic = gst_rtsp_auth_make_basic ("user", "admin");
gst_rtsp_auth_set_basic (auth, basic);
g_free (basic);
gst_rtsp_media_factory_set_auth (factory, auth);
g_object_unref (auth);
/* attach the test factory to the /test url */
gst_rtsp_media_mapping_add_factory (mapping, "/test", factory);
/* make another factory */
factory = gst_rtsp_media_factory_new ();
gst_rtsp_media_factory_set_launch (factory, "( "
"videotestsrc ! video/x-raw-yuv,width=352,height=288,framerate=30/1 ! "
"x264enc ! rtph264pay name=pay0 pt=96 )");
/* make a new authentication manager */
auth = gst_rtsp_auth_new ();
basic = gst_rtsp_auth_make_basic ("user2", "admin2");
gst_rtsp_auth_set_basic (auth, basic);
g_free (basic);
gst_rtsp_media_factory_set_auth (factory, auth);
g_object_unref (auth);
/* attach the test factory to the /test url */
gst_rtsp_media_mapping_add_factory (mapping, "/test2", factory);
/* don't need the ref to the mapper anymore */
g_object_unref (mapping);
/* attach the server to the default maincontext */
if (gst_rtsp_server_attach (server, NULL) == 0)
goto failed;
g_timeout_add_seconds (2, (GSourceFunc) timeout, server);
/* start serving */
g_main_loop_run (loop);
return 0;
/* ERRORS */
failed:
{
g_print ("failed to attach the server\n");
return -1;
}
}

View file

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

View file

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

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

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

View file

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

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

@ -0,0 +1,272 @@
/* GStreamer
* Copyright (C) 2010 Wim Taymans <wim.taymans at gmail.com>
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Library General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Library General Public License for more details.
*
* You should have received a copy of the GNU Library General Public
* License along with this library; if not, write to the
* Free Software Foundation, Inc., 59 Temple Place - Suite 330,
* Boston, MA 02111-1307, USA.
*/
#include <string.h>
#include "rtsp-auth.h"
enum
{
PROP_0,
PROP_LAST
};
GST_DEBUG_CATEGORY_STATIC (rtsp_auth_debug);
#define GST_CAT_DEFAULT rtsp_auth_debug
static void gst_rtsp_auth_get_property (GObject * object, guint propid,
GValue * value, GParamSpec * pspec);
static void gst_rtsp_auth_set_property (GObject * object, guint propid,
const GValue * value, GParamSpec * pspec);
static void gst_rtsp_auth_finalize (GObject * obj);
static gboolean default_setup_auth (GstRTSPAuth * auth, GstRTSPClient * client,
GQuark hint, GstRTSPClientState * state);
static gboolean default_check_method (GstRTSPAuth * auth,
GstRTSPClient * client, GQuark hint, GstRTSPClientState * state);
G_DEFINE_TYPE (GstRTSPAuth, gst_rtsp_auth, G_TYPE_OBJECT);
static void
gst_rtsp_auth_class_init (GstRTSPAuthClass * klass)
{
GObjectClass *gobject_class;
gobject_class = G_OBJECT_CLASS (klass);
gobject_class->get_property = gst_rtsp_auth_get_property;
gobject_class->set_property = gst_rtsp_auth_set_property;
gobject_class->finalize = gst_rtsp_auth_finalize;
klass->setup_auth = default_setup_auth;
klass->check_method = default_check_method;
GST_DEBUG_CATEGORY_INIT (rtsp_auth_debug, "rtspauth", 0, "GstRTSPAuth");
}
static void
gst_rtsp_auth_init (GstRTSPAuth * auth)
{
/* bitwise or of all methods that need authentication */
auth->methods = GST_RTSP_DESCRIBE |
GST_RTSP_ANNOUNCE |
GST_RTSP_GET_PARAMETER |
GST_RTSP_SET_PARAMETER |
GST_RTSP_PAUSE |
GST_RTSP_PLAY | GST_RTSP_RECORD | GST_RTSP_SETUP | GST_RTSP_TEARDOWN;
}
static void
gst_rtsp_auth_finalize (GObject * obj)
{
GstRTSPAuth *auth = GST_RTSP_AUTH (obj);
GST_INFO ("finalize auth %p", auth);
g_free (auth->basic);
G_OBJECT_CLASS (gst_rtsp_auth_parent_class)->finalize (obj);
}
static void
gst_rtsp_auth_get_property (GObject * object, guint propid,
GValue * value, GParamSpec * pspec)
{
GstRTSPAuth *auth = GST_RTSP_AUTH (object);
switch (propid) {
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, propid, pspec);
}
}
static void
gst_rtsp_auth_set_property (GObject * object, guint propid,
const GValue * value, GParamSpec * pspec)
{
GstRTSPAuth *auth = GST_RTSP_AUTH (object);
switch (propid) {
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, propid, pspec);
}
}
/**
* gst_rtsp_auth_new:
*
* Create a new #GstRTSPAuth instance.
*
* Returns: a new #GstRTSPAuth
*/
GstRTSPAuth *
gst_rtsp_auth_new (void)
{
GstRTSPAuth *result;
result = g_object_new (GST_TYPE_RTSP_AUTH, NULL);
return result;
}
/**
* gst_rtsp_auth_set_basic:
* @auth: a #GstRTSPAuth
* @basic: the basic token
*
* Set the basic token for the default authentication algorithm.
*/
void
gst_rtsp_auth_set_basic (GstRTSPAuth * auth, const gchar * basic)
{
g_free (auth->basic);
auth->basic = g_strdup (basic);
}
static gboolean
default_setup_auth (GstRTSPAuth * auth, GstRTSPClient * client,
GQuark hint, GstRTSPClientState * state)
{
if (state->response == NULL)
return FALSE;
/* we only have Basic for now */
gst_rtsp_message_add_header (state->response, GST_RTSP_HDR_WWW_AUTHENTICATE,
"Basic realm=\"GStreamer RTSP Server\"");
return TRUE;
}
/**
* gst_rtsp_auth_setup_auth:
* @auth: a #GstRTSPAuth
* @client: the client
* @uri: the requested uri
* @session: the session
* @request: the request
* @response: the response
*
* Add authentication tokens to @response.
*
* Returns: FALSE if something is wrong.
*/
gboolean
gst_rtsp_auth_setup_auth (GstRTSPAuth * auth, GstRTSPClient * client,
GQuark hint, GstRTSPClientState * state)
{
gboolean result = FALSE;
GstRTSPAuthClass *klass;
klass = GST_RTSP_AUTH_GET_CLASS (auth);
GST_DEBUG_OBJECT (auth, "setup auth");
if (klass->setup_auth)
result = klass->setup_auth (auth, client, hint, state);
return result;
}
static gboolean
default_check_method (GstRTSPAuth * auth, GstRTSPClient * client,
GQuark hint, GstRTSPClientState * state)
{
gboolean result = TRUE;
GstRTSPResult res;
if (state->method & auth->methods != 0) {
gchar *authorization;
result = FALSE;
res =
gst_rtsp_message_get_header (state->request, GST_RTSP_HDR_AUTHORIZATION,
&authorization, 0);
if (res < 0)
goto no_auth;
/* parse type */
if (g_ascii_strncasecmp (authorization, "basic ", 6) == 0) {
GST_DEBUG_OBJECT (auth, "check Basic auth");
if (auth->basic && strcmp (&authorization[6], auth->basic) == 0)
result = TRUE;
} else if (g_ascii_strncasecmp (authorization, "digest ", 7) == 0) {
GST_DEBUG_OBJECT (auth, "check Digest auth");
/* not implemented yet */
result = FALSE;
}
}
return result;
no_auth:
{
GST_DEBUG_OBJECT (auth, "no authorization header found");
return FALSE;
}
}
/**
* gst_rtsp_auth_check_method:
* @auth: a #GstRTSPAuth
* @client: the client
* @hint: a hint
* @state: client state
*
* Check if @client is allowed to perform the actions of @state.
*
* Returns: FALSE if the action is not allowed.
*/
gboolean
gst_rtsp_auth_check (GstRTSPAuth * auth, GstRTSPClient * client,
GQuark hint, GstRTSPClientState * state)
{
gboolean result = FALSE;
GstRTSPAuthClass *klass;
klass = GST_RTSP_AUTH_GET_CLASS (auth);
GST_DEBUG_OBJECT (auth, "check state");
if (klass->check_method)
result = klass->check_method (auth, client, hint, state);
return result;
}
/**
* gst_rtsp_auth_make_basic:
* @user: a userid
* @pass: a password
*
* Construct a Basic authorisation token from @user and @pass.
*
* Returns: the base64 encoding of the string @user:@pass. g_free()
* after usage.
*/
gchar *
gst_rtsp_auth_make_basic (const gchar * user, const gchar * pass)
{
gchar *user_pass;
gchar *result;
user_pass = g_strjoin (":", user, pass, NULL);
result = g_base64_encode ((guchar *) user_pass, strlen (user_pass));
g_free (user_pass);
return result;
}

View file

@ -0,0 +1,80 @@
/* GStreamer
* Copyright (C) 2010 Wim Taymans <wim.taymans at gmail.com>
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Library General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Library General Public License for more details.
*
* You should have received a copy of the GNU Library General Public
* License along with this library; if not, write to the
* Free Software Foundation, Inc., 59 Temple Place - Suite 330,
* Boston, MA 02111-1307, USA.
*/
#include <gst/gst.h>
#ifndef __GST_RTSP_AUTH_H__
#define __GST_RTSP_AUTH_H__
typedef struct _GstRTSPAuth GstRTSPAuth;
typedef struct _GstRTSPAuthClass GstRTSPAuthClass;
#include "rtsp-client.h"
#include "rtsp-media-mapping.h"
#include "rtsp-session-pool.h"
G_BEGIN_DECLS
#define GST_TYPE_RTSP_AUTH (gst_rtsp_auth_get_type ())
#define GST_IS_RTSP_AUTH(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GST_TYPE_RTSP_AUTH))
#define GST_IS_RTSP_AUTH_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), GST_TYPE_RTSP_AUTH))
#define GST_RTSP_AUTH_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), GST_TYPE_RTSP_AUTH, GstRTSPAuthClass))
#define GST_RTSP_AUTH(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GST_TYPE_RTSP_AUTH, GstRTSPAuth))
#define GST_RTSP_AUTH_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), GST_TYPE_RTSP_AUTH, GstRTSPAuthClass))
#define GST_RTSP_AUTH_CAST(obj) ((GstRTSPAuth*)(obj))
#define GST_RTSP_AUTH_CLASS_CAST(klass) ((GstRTSPAuthClass*)(klass))
/**
* GstRTSPAuth:
*
* The authentication structure.
*/
struct _GstRTSPAuth {
GObject parent;
/*< private >*/
gchar *basic;
GstRTSPMethod methods;
};
struct _GstRTSPAuthClass {
GObjectClass parent_class;
gboolean (*setup_auth) (GstRTSPAuth *auth, GstRTSPClient * client,
GQuark hint, GstRTSPClientState *state);
gboolean (*check_method) (GstRTSPAuth *auth, GstRTSPClient * client,
GQuark hint, GstRTSPClientState *state);
};
GType gst_rtsp_auth_get_type (void);
GstRTSPAuth * gst_rtsp_auth_new (void);
void gst_rtsp_auth_set_basic (GstRTSPAuth *auth, const gchar * basic);
gboolean gst_rtsp_auth_setup_auth (GstRTSPAuth *auth, GstRTSPClient * client,
GQuark hint, GstRTSPClientState *state);
gboolean gst_rtsp_auth_check_method (GstRTSPAuth *auth, GstRTSPClient * client,
GQuark hint, GstRTSPClientState *state);
/* helpers */
gchar * gst_rtsp_auth_make_basic (const gchar * user, const gchar * pass);
G_END_DECLS
#endif /* __GST_RTSP_AUTH_H__ */

File diff suppressed because it is too large Load diff

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

1
tests/.gitignore vendored Normal file
View file

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

9
tests/Makefile.am Normal file
View file

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

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

@ -0,0 +1,68 @@
/* GStreamer
* Copyright (C) 2008 Wim Taymans <wim.taymans at gmail.com>
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Library General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Library General Public License for more details.
*
* You should have received a copy of the GNU Library General Public
* License along with this library; if not, write to the
* Free Software Foundation, Inc., 59 Temple Place - Suite 330,
* Boston, MA 02111-1307, USA.
*/
#include <gst/gst.h>
#include <gst/rtsp-server/rtsp-server.h>
static gboolean
timeout (GMainLoop * loop, gboolean ignored)
{
g_main_loop_quit (loop);
return FALSE;
}
int
main (int argc, char *argv[])
{
GMainLoop *loop;
GstRTSPServer *server;
guint id;
gst_init (&argc, &argv);
loop = g_main_loop_new (NULL, FALSE);
/* create a server instance */
server = gst_rtsp_server_new ();
/* attach the server to the default maincontext */
if ((id = gst_rtsp_server_attach (server, NULL)) == 0)
goto failed;
g_timeout_add_seconds (2, (GSourceFunc) timeout, loop);
/* start serving */
g_main_loop_run (loop);
/* cleanup */
g_source_remove (id);
g_object_unref (server);
g_main_loop_unref (loop);
return 0;
/* ERRORS */
failed:
{
g_print ("failed to attach the server\n");
return -1;
}
}